传统的参数校验
在平常的开发中,为了保证程序的正确运行和数据的正确性,通常前端传导过来的数据需要校验,而我们一般会把校验逻辑写在service层,导致service 层的业务代码有很多重复代码,所以选择了Bean Validation。
Validation 注解说明
@Valid 被注释的元素是一个对象,需要检查此对象的所有字段值
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min) 被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期
@Pattern(value) 被注释的元素必须符合指定的正则表达式
@Email 被注释的元素必须是电子邮箱地址
@Length(min=, max=) 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range(min=, max=) 被注释的元素必须在合适的范围内
@NotBlank 被注释的字符串的必须非空
@URL(protocol=,host=, port=, regexp=, flags=) 被注释的字符串必须是一个有效的url
@CreditCardNumber 被注释的字符串必须通过Luhn校验算法,银行卡,信用卡等号码一般都用Luhn计算合法性
@ScriptAssert(lang=, script=, alias=) 要有Java Scripting API 即JSR 223("Scripting for the JavaTM Platform")的实现
@SafeHtml(whitelistType=,additionalTags=) classpath中要有jsoup包
Bean Validation 的使用
- pom.xml 的导入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
- 在controller层加入注解 @Validated
@RequestMapping(path = "/placeOrder", method=RequestMethod.POST)
public GeneralResult placeOrder(@Validated @RequestBody Order order)
{
GeneralResult result = new GeneralResult();
orderService.placeOrder(result, order);
return result;
}
- 在模型上加入注解
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import com.smile.vtoken.aop.ValidateErrorCode;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Order {
private Long orderId;
@NotEmpty(message = "用户编号不能为空")
@ValidateErrorCode(value = "601")
private String userId;
@NotEmpty(message = "股票代码不能为空")
@ValidateErrorCode(value = "606")
private String stockCode;
@NotEmpty(message = "数量不能为空")
@Min(value = 0,message = "输入数量不能小于0 ")
@ValidateErrorCode(value = "602")
private String amount;
@NotEmpty(message = "价格不能为空")
@ValidateErrorCode(value = "603")
private String price;
@NotEmpty(message = "买卖方向不能为空,只能是sell或者buy")
@ValidateErrorCode(value = "604")
private String orderType;
@NotEmpty(message = "accountId 不能为空")
@ValidateErrorCode(value = "605")
private Integer accountId;
private Long createTime;
private Long updateTime;
private String fee;
private String filledAmount;
private String filledCashAmount;
}
4.为了保证每一个参数都返回对应的错误码,加入了@ValidateErrorCode注解
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface ValidateErrorCode {
/** 校验错误码 code */
String value() default "200";
}
- 全局异常统一处理
package com.smile.vtoken.utils.exception;
import java.lang.reflect.Field;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.smile.vtoken.aop.ValidateErrorCode;
import com.smile.vtoken.constants.ErrorCode;
import com.smile.vtoken.utils.GeneralResult;
@RestControllerAdvice(annotations = RestController.class)
public class GlobalExceptionHandlerAdvice {
@ExceptionHandler(MethodArgumentNotValidException.class)
public GeneralResult methodArgumentNotValidException(MethodArgumentNotValidException e) {
// 从异常对象中拿到ObjectError对象
GeneralResult result = new GeneralResult();
ErrorCode errorCode = ErrorCode.INVALID_REQ_PARAMS;
String errorMsg = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
// 参数的Class对象,等下好通过字段名称获取Field对象
Class<?> parameterType = e.getParameter().getParameterType();
// 拿到错误的字段名称
String fieldName = e.getBindingResult().getFieldError().getField();
Field field = null;
try {
field = parameterType.getDeclaredField(fieldName);
} catch (NoSuchFieldException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (SecurityException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// 获取Field对象上的自定义注解
ValidateErrorCode annotation = field.getAnnotation(ValidateErrorCode.class);
if (annotation != null) {
errorCode.setCode(annotation.value());
}
errorCode.setMsg(errorMsg);
result.setErr(errorCode);
// 然后提取错误提示信息进行返回
return result;
}
}