Hibernate Validator 自定义校验注解 SpringBoot
先说一下实现思路:
1.我们需要创建一个自定义注解和对应的校验类;注解用于定义使用校验的形式,校验类用于定义校验的方式(如何去进行校验)。
2.然后将注解和校验类进行关联。
3.最后在我们需要校验的实体类里面使用注解。
下面是我创建的三个自定义注解,分别 实现了,对于yyyyMMdd(默认,也可以更改)日期格式,HHmmss(默认,也可以更改 )时间格式,枚举值格式校验。
添加三个自定义注解,@Date,@Time和@Enums
@Date用于校验日期,@Time用于校验时间,@Enums用于校验枚举值
项目结构:
一些项目框架代码:
项目依赖:
1 <dependencies> 2 <dependency> 3 <groupId>org.springframework.boot</groupId> 4 <artifactId>spring-boot-starter-validation</artifactId> 5 </dependency> 6 <dependency> 7 <groupId>org.springframework.boot</groupId> 8 <artifactId>spring-boot-starter-web</artifactId> 9 </dependency> 10 11 <dependency> 12 <groupId>org.springframework.boot</groupId> 13 <artifactId>spring-boot-starter-test</artifactId> 14 <scope>test</scope> 15 <exclusions> 16 <exclusion> 17 <groupId>org.junit.vintage</groupId> 18 <artifactId>junit-vintage-engine</artifactId> 19 </exclusion> 20 </exclusions> 21 </dependency> 22 </dependencies>
Date.java Date枚举定义:
1 package com.hgd.validatortest.annotation; 2 3 import com.hgd.validatortest.Validators.DateValidator; 4 import javax.validation.Constraint; 5 import javax.validation.Payload; 6 import java.lang.annotation.ElementType; 7 import java.lang.annotation.Retention; 8 import java.lang.annotation.RetentionPolicy; 9 import java.lang.annotation.Target; 10 11 @Target({ ElementType.FIELD}) 12 @Retention(RetentionPolicy.RUNTIME) 13 @Constraint(validatedBy = DateValidator.class) 14 public @interface Date { 15 String message() default "日期格式错误"; 16 17 Class<?>[] groups() default { }; 18 19 Class<? extends Payload>[] payload() default { }; 20 21 String formatter() default "yyyyMMdd"; 22 }
注:枚举类这里的message,如果你在使用的时候,注解没有指定message的值,则最终校验结果返回的错误信息,就是这个默认的错误信息。formatter指定的是你需要校验的日期格式,可以在使用注解时指定,覆盖默认的日期格式。
Date 校验逻辑实现类: DateValidator.java
1 package com.hgd.validatortest.Validators; 2 3 import com.hgd.validatortest.annotation.Date; 4 5 import javax.validation.ConstraintValidator; 6 import javax.validation.ConstraintValidatorContext; 7 import java.time.LocalDate; 8 import java.time.format.DateTimeFormatter; 9 10 public class DateValidator implements ConstraintValidator<Date, String> { 11 12 private String formatter; 13 14 @Override 15 public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) { 16 if(s == null) 17 return true; 18 try { 19 LocalDate localDate = LocalDate.parse(s, DateTimeFormatter.ofPattern(formatter)); 20 }catch (Exception e){ 21 System.out.println("异常信息:"+e.getMessage()); 22 return false; 23 } 24 return true; 25 } 26 27 /** 28 * 获取注解中的值 29 */ 30 @Override 31 public void initialize(Date date) { 32 formatter = date.formatter(); 33 } 34 35 }
Time校验枚举定义:Time.java
1 package com.hgd.validatortest.annotation; 2 3 import com.hgd.validatortest.Validators.TimeValidator; 4 5 import javax.validation.Constraint; 6 import javax.validation.Payload; 7 import java.lang.annotation.ElementType; 8 import java.lang.annotation.Retention; 9 import java.lang.annotation.RetentionPolicy; 10 import java.lang.annotation.Target; 11 12 @Target({ ElementType.FIELD}) 13 @Retention(RetentionPolicy.RUNTIME) 14 @Constraint(validatedBy = TimeValidator.class) 15 public @interface Time { 16 String message() default "时间格式错误"; 17 18 Class<?>[] groups() default { }; 19 20 Class<? extends Payload>[] payload() default { }; 21 22 String formatter() default "HHmmss"; 23 }
Time校验逻辑实现类:TimeValidator.java
1 package com.hgd.validatortest.Validators; 2 3 import com.hgd.validatortest.annotation.Time; 4 5 import javax.validation.ConstraintValidator; 6 import javax.validation.ConstraintValidatorContext; 7 import java.time.LocalTime; 8 import java.time.format.DateTimeFormatter; 9 10 public class TimeValidator implements ConstraintValidator<Time, String> { 11 private String formatter; 12 13 @Override 14 public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) { 15 if(s == null) 16 return true; 17 try { 18 LocalTime localTime = LocalTime.parse(s, DateTimeFormatter.ofPattern(formatter)); 19 System.out.println("哈哈"); 20 }catch (Exception e){ 21 System.out.println("异常信息:"+e.getMessage()); 22 return false; 23 } 24 return true; 25 } 26 27 /** 28 * 获取注解中的值 29 */ 30 @Override 31 public void initialize(Time time) { 32 formatter = time.formatter(); 33 } 34 }
Enums校验的枚举定义:Enums.java
1 package com.hgd.validatortest.annotation; 2 3 import com.hgd.validatortest.Validators.EnumsValidator; 4 import com.hgd.validatortest.Validators.TimeValidator; 5 6 import javax.validation.Constraint; 7 import javax.validation.Payload; 8 import java.lang.annotation.ElementType; 9 import java.lang.annotation.Retention; 10 import java.lang.annotation.RetentionPolicy; 11 import java.lang.annotation.Target; 12 13 @Target({ ElementType.FIELD}) 14 @Retention(RetentionPolicy.RUNTIME) 15 @Constraint(validatedBy = EnumsValidator.class) 16 public @interface Enums { 17 String message() default "暂不支持的枚举值"; 18 19 Class<?>[] groups() default { }; 20 21 Class<? extends Payload>[] payload() default { }; 22 23 String[] enumCode (); 24 }
Enums 注解的校验逻辑实现类:EnumsValidator.java
1 package com.hgd.validatortest.Validators; 2 3 import com.hgd.validatortest.annotation.Enums; 4 5 import javax.validation.ConstraintValidator; 6 import javax.validation.ConstraintValidatorContext; 7 import java.util.Arrays; 8 import java.util.HashSet; 9 import java.util.Set; 10 11 public class EnumsValidator implements ConstraintValidator<Enums, String> { 12 13 private Set<String> enumSet; 14 @Override 15 public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) { 16 if(s==null) 17 return true; 18 return enumSet.contains(s); 19 } 20 /** 21 * 获取注解中的值 22 */ 23 @Override 24 public void initialize(Enums enums) { 25 enumSet = new HashSet<>(Arrays.asList(enums.enumCode())); 26 } 27 }
待校验的实体类:User.java
1 package com.hgd.validatortest.bean; 2 3 import com.hgd.validatortest.annotation.Date; 4 import com.hgd.validatortest.annotation.Enums; 5 import com.hgd.validatortest.annotation.Time; 6 import org.hibernate.validator.constraints.Length; 7 8 import javax.validation.constraints.Digits; 9 import javax.validation.constraints.NotBlank; 10 import javax.validation.constraints.PositiveOrZero; 11 12 public class User { 13 14 @NotBlank(message = "用户名不能为空") 15 @Length(max = 8,message = "用户名长度最大为8") 16 private String userName; 17 18 private String password; 19 20 @NotBlank(message = "金额") 21 @Digits(integer = 20,fraction = 2,message = "金额格式错误") 22 @PositiveOrZero(message = "金额需要为正数") 23 private String amount; 24 25 @Enums(enumCode = {"1","2"}) 26 private String operatorType; 27 28 @Date(message = "出生日期格式不正确") 29 private String birthDate; 30 31 @Time(message = "出生时间格式不正确") 32 private String birthTime; 33 34 public String getBirthTime() { 35 return birthTime; 36 } 37 38 public void setBirthTime(String birthTime) { 39 this.birthTime = birthTime; 40 } 41 42 public String getBirthDate() { 43 return birthDate; 44 } 45 46 public void setBirthDate(String birthDate) { 47 this.birthDate = birthDate; 48 } 49 50 public String getUserName() { 51 return userName; 52 } 53 54 public void setUserName(String userName) { 55 this.userName = userName; 56 } 57 58 public String getPassword() { 59 return password; 60 } 61 62 public void setPassword(String password) { 63 this.password = password; 64 } 65 66 public String getAmount() { 67 return amount; 68 } 69 70 public void setAmount(String amount) { 71 this.amount = amount; 72 } 73 74 public String getOperatorType() { 75 return operatorType; 76 } 77 78 @Override 79 public String toString() { 80 return "User{" + 81 "userName='" + userName + '\'' + 82 ", password='" + password + '\'' + 83 ", amount='" + amount + '\'' + 84 ", operatorType='" + operatorType + '\'' + 85 '}'; 86 } 87 88 public void setOperatorType(String operatorType) { 89 this.operatorType = operatorType; 90 } 91 }
Spring Boot的Controller:TestController.java
1 package com.hgd.validatortest.controller; 2 3 import com.hgd.validatortest.bean.User; 4 import org.springframework.web.bind.annotation.PostMapping; 5 import org.springframework.web.bind.annotation.RequestBody; 6 import org.springframework.web.bind.annotation.RequestMapping; 7 import org.springframework.web.bind.annotation.RestController; 8 9 import javax.validation.Valid; 10 11 @RestController 12 @RequestMapping("/test") 13 public class TestController { 14 @PostMapping("/user") 15 public String testUser(@RequestBody @Valid User user){ 16 String resultStr= ""; 17 System.out.println(user); 18 return resultStr; 19 } 20 21 }
Spring Boot 自定义全局异常捕获: MyExceptionHandler.java 这里是参考的网络上的代码:
1 package com.hgd.validatortest.handler; 2 3 import org.springframework.validation.BindException; 4 import org.springframework.validation.BindingResult; 5 import org.springframework.validation.ObjectError; 6 import org.springframework.web.bind.MethodArgumentNotValidException; 7 import org.springframework.web.bind.annotation.ExceptionHandler; 8 import org.springframework.web.bind.annotation.RestControllerAdvice; 9 10 import java.util.HashMap; 11 import java.util.Map; 12 13 @RestControllerAdvice 14 public class MyExceptionHandler { 15 //json格式 16 @ExceptionHandler(value = MethodArgumentNotValidException.class) 17 public Map<String,Object> errorHandler(MethodArgumentNotValidException ex) { 18 StringBuilder errorMsg = new StringBuilder(); 19 BindingResult re = ex.getBindingResult(); 20 for (ObjectError error : re.getAllErrors()) { 21 errorMsg.append(error.getDefaultMessage()).append(","); 22 } 23 errorMsg.delete(errorMsg.length() - 1, errorMsg.length()); 24 Map<String,Object> map = new HashMap(); 25 map.put("code", 400); 26 map.put("msg", errorMsg.toString()); 27 return map; 28 } 29 30 31 //表单格式 32 @ExceptionHandler(value = BindException.class) 33 public Map<String,Object> errorHandler(BindException ex) { 34 BindingResult result = ex.getBindingResult(); 35 StringBuilder errorMsg = new StringBuilder(); 36 for (ObjectError error : result.getAllErrors()) { 37 errorMsg.append(error.getDefaultMessage()).append(","); 38 } 39 errorMsg.delete(errorMsg.length() - 1, errorMsg.length()); 40 Map<String,Object> map = new HashMap(); 41 map.put("code", 400); 42 map.put("msg", errorMsg.toString()); 43 return map; 44 } 45 }
准备完成后,开始测试,工具用的是Postman: