文章字数:809,阅读全文大约需要3分钟
整理自原文
环境 1 2 3 4 5 <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.9.Final</version> </dependency>
如果使用的是SpringBoot
,这个依赖是自带的。
校验Controller入参的对象
添加校验
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Data @AllArgsConstructor @NoArgsConstructor public class Account { private String id; @NotNull @Length (max = 20 ) private String userName; @NotNull @Pattern (regexp = "[A-Z][a-z][0-9]" ) private String passWord; @DateTimeFormat (pattern = "yyy-MM-dd" ) private Date createTime; private String alias; @Max (10 ) @Min (1 ) private Integer level; private Integer vip; }
使用
1 2 3 4 5 6 @PostMapping ("/saveAccount" ) public Object saveAccount (@RequestBody @Valid Account account) { accountService.saveAccount(account); return "保存成功" ; }
Controller方法上直接校验 在类上需要添加注解@Validated
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @RequestMapping ("/validation" )@RestController @Validated public class ValidationController { @RequestMapping (value = "/demo3" , method = RequestMethod.GET) public void demo3 (@Range(min = 1 , max = 9 , message = "年级只能从1-9" ) @RequestParam (name = "grade" , required = true ) int grade, @Min (value = 1 , message = "班级最小只能1" ) @Max (value = 99 , message = "班级最大只能99" ) @RequestParam (name = "classroom" , required = true ) int classroom) { System.out.println(grade + "," + classroom); } }
使用工具类校验
工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 import java.util.ArrayList;import java.util.List;import java.util.Set;import javax.validation.ConstraintViolation;import javax.validation.Validation;import javax.validation.Validator;import lombok.Data;import org.hibernate.validator.HibernateValidator;public class ValidationUtil { private static Validator validator = Validation.byProvider(HibernateValidator.class ).configure ().failFast (false ).buildValidatorFactory ().getValidator () ; public static <T> ValidResult validateBean (T t,Class<?>...groups) { ValidResult result = new ValidationUtil().new ValidResult(); Set<ConstraintViolation<T>> violationSet = validator.validate(t,groups); boolean hasError = violationSet != null && violationSet.size() > 0 ; result.setHasErrors(hasError); if (hasError) { for (ConstraintViolation<T> violation : violationSet) { result.addError(violation.getPropertyPath().toString(), violation.getMessage()); } } return result; } public static <T> ValidResult validateProperty (T obj, String propertyName) { ValidResult result = new ValidationUtil().new ValidResult(); Set<ConstraintViolation<T>> violationSet = validator.validateProperty(obj, propertyName); boolean hasError = violationSet != null && violationSet.size() > 0 ; result.setHasErrors(hasError); if (hasError) { for (ConstraintViolation<T> violation : violationSet) { result.addError(propertyName, violation.getMessage()); } } return result; } @Data public class ValidResult { private boolean hasErrors; private List<ErrorMessage> errors; public ValidResult () { this .errors = new ArrayList<>(); } public boolean hasErrors () { return hasErrors; } public void setHasErrors (boolean hasErrors) { this .hasErrors = hasErrors; } public List<ErrorMessage> getAllErrors () { return errors; } public String getErrors () { StringBuilder sb = new StringBuilder(); for (ErrorMessage error : errors) { sb.append(error.getPropertyPath()).append(":" ).append(error.getMessage()).append(" " ); } return sb.toString(); } public void addError (String propertyName, String message) { this .errors.add(new ErrorMessage(propertyName, message)); } } @Data public class ErrorMessage { private String propertyPath; private String message; public ErrorMessage () { } public ErrorMessage (String propertyPath, String message) { this .propertyPath = propertyPath; this .message = message; } } }
使用
1 2 3 4 5 6 7 8 9 10 11 12 @Test public void test5 () throws IOException { Account account = new Account(); account.setAlias("kalakala" ); account.setUserName("wokalakala" ); account.setPassWord("密码" ); ValidationUtil.ValidResult validResult = ValidationUtil.validateBean(account); if (validResult.hasErrors()){ String errors = validResult.getErrors(); System.out.println(errors); } }
自定义规则
注解上必须有 @Constraint(validatedBy = {** .class}) 注解标注,validateBy 的值就是校验逻辑的实现类,实现类必须实现接口ConstraintValidator
自定义注解 必须包含 message ,groups,payload 属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 import org.apache.commons.lang3.time.DateUtils;import javax.validation.Constraint;import javax.validation.ConstraintValidator;import javax.validation.ConstraintValidatorContext;import javax.validation.Payload;import java.lang.annotation.Documented;import java.lang.annotation.Retention;import java.lang.annotation.Target;import java.text.ParseException;import java.util.Date;import static java.lang.annotation.ElementType.*;import static java.lang.annotation.RetentionPolicy.RUNTIME;@Target ({FIELD})@Retention (RUNTIME)@Documented @Constraint (validatedBy = {DateValidator.DateValidatorInner.class }) public @interface DateValidator { String message () default "日期格式不匹配 {dateFormat}"; /** * 必须的属性 * 用于分组校验 */ Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; /** * 非必须 */ String dateFormat() default " yyyy-MM-dd HH:mm:ss"; /** * 必须实现 ConstraintValidator接口 */ class DateValidatorInner implements ConstraintValidator<DateValidator, String> { private String dateFormat; @Override public void initialize(DateValidator constraintAnnotation) { this.dateFormat = constraintAnnotation.dateFormat(); } /** * 校验逻辑的实现 * @param value 需要校验的 值 * @return 布尔值结果 */ @Override public boolean isValid(String value, ConstraintValidatorContext context) { if (value == null) { return true; } if(" ".equals(value)){ return true; } try { Date date = DateUtils.parseDate(value, dateFormat); return date != null; } catch (ParseException e) { return false; } } } }
使用
1 2 @DateValidator (dateFormat = "yyyy-MM-dd" )private String day;
分组校验 同一个对象在不同业务下验证规则可能不一样
声明规则时指定分组(不写默认是Default.class分组)1 2 @DateValidator (dateFormat = "yyyy-MM-dd" ,groups = {AccountService.class }) private String birthday ;
验证规则时加入分组1 2 3 4 5 ValidationUtil.ValidResult validResult = ValidationUtil.validateBean(account, AccountService.class ) ; if (validResult.hasErrors()){ String errors = validResult.getErrors(); System.out.println(errors); }
其它常用规则 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @AssertFalse @AssertTrue 检验boolean类型的值 @DecimalMax @DecimalMin 限定被标注的属性的值的大小 @Digits(intege=,fraction=) 限定被标注的属性的整数位数和小数位数 @Future检验给定的日期是否比现在晚 @Past 校验给定的日期是否比现在早 @Max检查被标注的属性的值是否小于等于给定的值 @Min检查被标注的属性的值是否大于等于给定的值 @NotNull检验被标注的值不为空 @Null 检验被标注的值为空 @Pattern(regex=,flag=) 检查该字符串是否能够在match指定的情况下被regex定义的正则表达式匹配 @Size(min=,max=) 检查被标注元素的长度 @Valid递归的对关联的对象进行校验
配合使用的全局异常处理 1 2 3 4 5 6 7 8 9 10 11 @RestControllerAdvice public class ExceptionControllerAdvice { @ExceptionHandler (MethodArgumentNotValidException.class ) public String MethodArgumentNotValidExceptionHandler (MethodArgumentNotValidException e ) { ObjectError objectError = e.getBindingResult().getAllErrors().get(0 ); return objectError.getDefaultMessage(); } }
不抛异常,手动判断 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @RestController @RequestMapping ("user" )public class UserController { @Autowired private UserService userService; @PostMapping ("/addUser" ) public String addUser (@RequestBody @Valid User user, BindingResult bindingResult) { for (ObjectError error : bindingResult.getAllErrors()) { return error.getDefaultMessage(); } return userService.addUser(user); } }