本文介绍在Spring Boot中实现对请求的数据进行校验。数据校验常用到概念:
本文主要包括如下内容:
功能:向服务发送请求,这个请求带上参数,服务需要对参数进行校验。
封装返回处理结果,如果code=200,则表示添加成功,code=400,则表示输入的数据异常
public class Result {
private int code;
private String message;
// set/get方法略
…
}
客户端的请求封装到这个dto中。使用校验注解注解此类的成员属性。这些注解的功能看名称就可以看出来。其中 @PhoneValidation就我们自定义的注解,这个后面会说明。每个注解里有个属性message,如果我们不想使用系统默认提供的报错信息,我们可以修改这个值
public class CustomerDto {
@Size(min=2, max=30)
private String name;
// 自定义错误信息
@NotEmpty(message = "自定义错误信息,Email不能为空")
@Email
private String email;
@NotNull
@Min(18) @Max(100)
private Integer age;
@NotNull
private Gender gender;
@DateTimeFormat(pattern="MM/dd/yyyy")
@NotNull @Past
private Date birthday;
// 自定义规则注解
@PhoneValidation
private String phone;
public enum Gender {
MALE, FEMALE
}
// set/get方法略
…
}
如果数据校验不通过,则Spring boot会抛出BindException异常,我们可以捕获这个异常并使用Result封装返回结果。通过@RestControllerAdvice定义异常捕获类
@RestControllerAdvice
public class BindExceptionHanlder {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(BindException.class)
public Result handleBindException(BindException ex) {
// ex.getFieldError():随机返回一个对象属性的异常信息。如果要一次性返回所有对象属性异常信息,则调用ex.getAllErrors()
FieldError fieldError = ex.getFieldError();
StringBuilder sb = new StringBuilder();
sb.append(fieldError.getField()).append("=[").append(fieldError.getRejectedValue()).append("]")
.append(fieldError.getDefaultMessage());
// 生成返回结果
Result errorResult = new Result();
errorResult.setCode(400);
errorResult.setMessage(sb.toString());
return errorResult;
}
}
提供Control层的对外接口
@RestController
public class ValidationCtrl {
private static final Logger logger = LoggerFactory
.getLogger(ValidationCtrl.class);
@RequestMapping(value = "/validation/save", method = RequestMethod.GET)
public Result saveCustomerPage(@Validated CustomerDto model) {
logger.info("Good" + model.getBirthday());
Result okResult = new Result();
okResult.setCode(200);
okResult.setMessage(JSONObject.toJSON(model).toString());
return okResult;
}
}
{ "code":200, "message":"{\"birthday\":477849600000,\"gender\":\"MALE\",\"phone\":\"13589567201\",\"name\":\"name\",\"age\":18,\"email\":\"[email protected]\"}" }
{ "code":400, "message":"name=[n]个数必须在2和30之间" }
{ "code":400, "message":"email=[]自定义错误信息,Email不能为空" }
功能:自定义校验注解,对输入手机进行合法性检查。并演示这个用法
定义自己的校验注解
头注解@Constraint属性validatedBy 指定真正执行校验的类PhoneValidationValidator
@Documented
// 指定真正实现校验规则的类
@Constraint(validatedBy = PhoneValidationValidator.class)
@Target( { ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface PhoneValidation {
String message() default "不是正确的手机号码";
Class>[] groups() default { }; Class extends Payload>[] payload() default { }; @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) @Retention(RUNTIME) @Documented @interface List { PhoneValidation[] value(); } }
真正执行校验的类,对输入的手机执行校验
public class PhoneValidationValidator implements ConstraintValidator<PhoneValidation, String> {
private static final Pattern PHONE_PATTERN = Pattern.compile(
"^((13[0-9])|(15[^4])|(18[0,2,3,5-9])|(17[0-8])|(147))\\d{8}$"
);
@Override
public void initialize(PhoneValidation constraintAnnotation) {
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if ( value == null || value.length() == 0 ) {
return true;
}
Matcher m = PHONE_PATTERN.matcher(value);
return m.matches();
}
}
public class CustomerDto {
// 自定义规则注解
@PhoneValidation
private String phone;
// set/get方法略
…
}
{ "code":200, "message":"{\"birthday\":477849600000,\"gender\":\"MALE\",\"phone\":\"13589567201\",\"name\":\"name\",\"age\":18,\"email\":\"[email protected]\"}" }
{ "code":400, "message":"phone=[13589567]不是正确的手机号码" }
所有的详细代码见github代码,请尽量使用tag v0.18,不要使用master,因为master一直在变,不能保证文章中代码和github上的代码一直相同