上一篇博客中介绍了使用validation-api结合spring validation验证restful接口参数,但是有时候需要对请求数据的格式是否规范进行验证。比如用户注册填写的身份证、邮箱地址等,一般情况我们都是在业务代码中获取身份证或邮箱地址后使用正则表达式校验是否合法,使得业务代码中包含大量的数据校验代码。
比如下面这段代码对邮箱地址正确性的校验:
public final class Constants {
/**
* email校验正则表达式
*/
public static final String EMAIL_VALIDATION_REGP="^([a-zA-Z0-9_\\.\\-])+\\@(([a-zA-Z0-9\\-])+\\.)+([a-zA-Z0-9]{2,4})+$";
}
@Override
public void addUser(User user) {
String email=user.getEmail();
//
if (!Pattern.matches(Constants.EMAIL_VALIDATION_REGP,email)) {
throw new BusinessException("邮箱地址格式不正确");
}
}
要解决上面这段代码存在的问题,这时就轮到自定义Constraint出手了,使用自定义的验证约束可以将数据验证的从业务代码中抽取出来,在编写接口时只需要关注业务而不用再关注数据的格式是否合法,使用起来十分的方便。
一、编写自定义约束校验
使用自定义约束包含两部分
1.编写一个自定义注解,用来标注需要校验的字段
@Documented
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Constraint(validatedBy = EmailConstraintValidator.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface EmailConstraint {
String message() default "email格式错误";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
2.编写一个自定义Constraint Validator实现ConstraintValidator接口,在接口的泛型参数中使用第一步定义的注解(EmailConstraint),重写接口中的isValid方法,在该方法中编写数据的校验规则。
public class EmailConstraintValidator implements ConstraintValidator<EmailConstraint,Object> {
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
System.out.println("start validate ");
return VerifyUtil.verifyEmail(value.toString());
}
}
二、在实体类中使用自定义注解
@Getter
@Setter
public class Movie {
private String id;
@NotEmpty(message = "Movie name cannot be empty")
private String name;
@NotNull(message = "电影时长不能为空")
private Integer duration;
@NotNull(message = "演员不能为空")
@NotEmpty(message = "演员不能为空")
private List<@Valid Actor> actors;
@NotEmpty(message = "电影描述不能为空")
private String description;
/**
* 使用自定义注解验证邮箱格式是否合法
*/
@EmailConstraint(message = "邮箱地址格式不正确")
@NotEmpty(message = "邮箱地址不能为空")
private String email;
}
三、在Controller中使用@Validated注解及方法参数中使用@Valid注解
@Validated
@RestController
@RequestMapping(value = "/movies")
public class MovieController {
@PostMapping
public ResponseResult addMovie(@RequestBody @Valid Movie movie) {
movieService.addMovie(movie);
System.out.println("test");
System.out.println(movie);
return ResponseResult.success();
}
}
四、使用postmain测试自定义注解的校验