1. 參數校驗
-
spring-boot-starter-web包裏面有hibernate-validator包,不需要引用hibernate validator依賴。
2. hibernate validator校驗demo
1. 導入包
import org.hibernate.validator.constraints.NotBlank;
import javax.validation.constraints.AssertFalse;
import javax.validation.constraints.Pattern;
2. demo
@Getter
@Setter
@NoArgsConstructor
public class DemoModel {
@NotBlank(message="用戶名不能爲空")
private String userName;
@NotBlank(message="年齡不能爲空")
@Pattern(regexp="^[0-9]{1,2}$",message="年齡不正確")
private String age;
@AssertFalse(message = "必須爲false")
private Boolean isFalse;
/**
* 如果是空,則不校驗,如果不爲空,則校驗
*/
@Pattern(regexp="^[0-9]{4}-[0-9]{2}-[0-9]{2}$",message="出生日期格式不正確")
private String birthday;
}
3. 結果返回
@RequestMapping("/demo2")
public void demo2(@RequestBody @Valid DemoModel demo, BindingResult result){
if(result.hasErrors()){
for (ObjectError error : result.getAllErrors()) {
System.out.println(error.getDefaultMessage());
}
}
}
4. 傳入參數
{"userName":"dd","age":120,"isFalse":true,"birthday":"21010-21-12"}
5. 輸出結果
出生日期格式不正確
必須爲false
年齡不正確
3. hibernate的校驗模式
1. 普通模式(默認爲該模式)
- 會校驗所有屬性,然後返回所有的驗證失敗信息。
2. 快速失敗返回模式
- 只要有一個校驗失敗則返回。
3. 設置方式
// failFast: true 快速失敗返回模式,false 普通模式
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure()
.failFast( true )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
// hibernate.validator.fail_fast: true 快速失敗返回模式,false 普通模式
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure()
.addProperty( "hibernate.validator.fail_fast", "true" )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
4. hibernate的校驗
-
配置hibernate Validator爲快速返回模式:
@Configuration public class ValidatorConfiguration { @Bean public Validator validator(){ ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class ) .configure() .addProperty( "hibernate.validator.fail_fast", "true" ) .buildValidatorFactory(); Validator validator = validatorFactory.getValidator(); return validator; } }
1. 請求參數校驗
- 驗證請求參數時,在 @RequestBody DemoModel demo 之間加註解 @Valid,然後在後面加 BindindResult 即可;多個參數,可以添加多個 @Valid 和 BindindResult。
public void test()(@RequestBody @Valid DemoModel demo, BindingResult result)
public void test()(@RequestBody @Valid DemoModel demo, BindingResult result,@RequestBody @Valid DemoModel demo2, BindingResult result2)
@RequestMapping("/demo2")
public void demo2(@RequestBody @Valid DemoModel demo, BindingResult result){
if(result.hasErrors()){
for (ObjectError error : result.getAllErrors()) {
System.out.println(error.getDefaultMessage());
}
}
}
2. GET參數校驗(@RequestParam參數校驗)
-
controller
@RequestMapping(value = "/demo3", method = RequestMethod.GET) public void demo3(@RequestParam(name = "grade", required = true) int grade,@RequestParam(name = "classroom", required = true) int classroom) { System.out.println(grade + "," + classroom); }
- 使用 @Valid 註解對 RequestParam 對應的參數時無效的,需要使用 @Validated 註解來使驗證生效。
-
MethodValidationPostProcessor 的 Bean
@Bean public MethodValidationPostProcessor methodValidationPostProcessor() { /**默認是普通模式,會返回所有的驗證不通過信息集合*/ return new MethodValidationPostProcessor(); }
-
或者可對 MethodValidationPostProcessor 進行設置 Validator
- 此時不是使用 Validator 進行驗證,Validator 的配置不起作用
@Bean public MethodValidationPostProcessor methodValidationPostProcessor() { MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor(); /**設置validator模式爲快速失敗返回*/ postProcessor.setValidator(validator()); return postProcessor; } @Bean public Validator validator(){ ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class ) .configure() .addProperty( "hibernate.validator.fail_fast", "true" ) .buildValidatorFactory(); Validator validator = validatorFactory.getValidator(); return validator; }
-
方法所在的Controller上加註解 @Validated
@RequestMapping("/validation") @RestController @Validated public class ValidationController { /**如果只有少數對象,直接把參數寫到Controller層,然後在Controller層進行驗證就可以了。*/ @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); } }
-
返回驗證信息提示
- 驗證不通過,拋出來 ConstraintViolationException 異常,使用統一捕獲異常處理
@ControllerAdvice @Component public class GlobalExceptionHandler { @ExceptionHandler @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public String handle(ValidationException exception) { if(exception instanceof ConstraintViolationException){ ConstraintViolationException exs = (ConstraintViolationException) exception; Set<ConstraintViolation<?>> violations = exs.getConstraintViolations(); for (ConstraintViolation<?> item : violations) { /**打印驗證不通過的信息*/ System.out.println(item.getMessage()); } } return "bad request, " ; } }
-
驗證
http://localhost:8080/validation/demo3?grade=18&classroom=888
3. model校驗
-
model
@Data public class Demo2 { @Length(min = 5, max = 17, message = "length長度在[5,17]之間") private String length; /**@Size不能驗證Integer,適用於String, Collection, Map and arrays*/ @Size(min = 1, max = 3, message = "size在[1,3]之間") private String age; @Range(min = 150, max = 250, message = "range在[150,250]之間") private int high; @Size(min = 3,max = 5,message = "list的Size在[3,5]") private List<String> list; }
-
校驗
@Autowired private Validator validator; @RequestMapping("/demo3") public void demo3(){ Demo2 demo2 = new Demo2(); demo2.setAge("111"); demo2.setHigh(150); demo2.setLength("ABCDE"); demo2.setList(new ArrayList<String>(){{add("111");add("222");add("333");}}); Set<ConstraintViolation<Demo2>> violationSet = validator.validate(demo2); for (ConstraintViolation<Demo2> model : violationSet) { System.out.println(model.getMessage()); } }
4. 對象級聯校驗
- 對象內部包含另一個對象作爲屬性,屬性上加 @Valid,可以驗證作爲屬性的對象內部的驗證
-
demo
@Data public class Demo2 { @Size(min = 3,max = 5,message = "list的Size在[3,5]") private List<String> list; @NotNull @Valid private Demo3 demo3; } @Data public class Demo3 { @Length(min = 5, max = 17, message = "length長度在[5,17]之間") private String extField; }
-
校驗
/**前面配置了快速失敗返回的Bean*/ @Autowired private Validator validator; @RequestMapping("/demo3") public void demo3(){ Demo2 demo2 = new Demo2(); demo2.setList(new ArrayList<String>(){{add("111");add("222");add("333");}}); Demo3 demo3 = new Demo3(); demo3.setExtField("22"); demo2.setDemo3(demo3); Set<ConstraintViolation<Demo2>> violationSet = validator.validate(demo2); for (ConstraintViolation<Demo2> model : violationSet) { System.out.println(model.getMessage()); } }
5. 分組校驗
-
校驗接口
public interface GroupA { } public interface GroupB { }
-
demo
@Data public class Person { @NotBlank @Range(min = 1,max = Integer.MAX_VALUE,message = "必須大於0",groups = {GroupA.class}) /**用戶id*/ private Integer userId; @NotBlank @Length(min = 4,max = 20,message = "必須在[4,20]",groups = {GroupB.class}) /**用戶名*/ private String userName; @NotBlank @Range(min = 0,max = 100,message = "年齡必須在[0,100]",groups={Default.class}) /**年齡*/ private Integer age; @Range(min = 0,max = 2,message = "性別必須在[0,2]",groups = {GroupB.class}) /**性別 0:未知;1:男;2:女*/ private Integer sex; }
- GroupA校驗字段userId
- GroupB校驗字段userName、sex
- Default校驗字段age(Default使Validator自帶的默認分組)
-
驗證
- 只驗證GroupA和GroupB的分組,以下示例代碼
@RequestMapping("/demo5") public void demo5(){ Person p = new Person(); /**GroupA驗證不通過*/ p.setUserId(-12); /**GroupA驗證通過*/ //p.setUserId(12); p.setUserName("a"); p.setAge(110); p.setSex(5); Set<ConstraintViolation<Person>> validate = validator.validate(p, GroupA.class, GroupB.class); for (ConstraintViolation<Person> item : validate) { System.out.println(item); } }
@RequestMapping("/demo6") public void demo6(@Validated({GroupA.class, GroupB.class}) Person p, BindingResult result){ if(result.hasErrors()){ List<ObjectError> allErrors = result.getAllErrors(); for (ObjectError error : allErrors) { System.out.println(error); } } }
-
組序列
- 指定組的驗證順序,前面組驗證不通過,後面組不驗證
// GroupA > GroupB > Default @GroupSequence({GroupA.class, GroupB.class, Default.class}) public interface GroupOrder { }
5. 自定義校驗器
1. 大小寫校驗器
public enum CaseMode {
UPPER,
LOWER;
}
@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = CheckCaseValidator.class)
@Documented
public @interface CheckCase {
String message() default "";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
CaseMode value();
}
public class CheckCaseValidator implements ConstraintValidator<CheckCase, String> {
private CaseMode caseMode;
public void initialize(CheckCase checkCase) {
this.caseMode = checkCase.value();
}
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
if (s == null) {
return true;
}
if (caseMode == CaseMode.UPPER) {
return s.equals(s.toUpperCase());
} else {
return s.equals(s.toLowerCase());
}
}
}
2. Demo
public class Demo{
@CheckCase(value = CaseMode.LOWER,message = "userName必須是小寫")
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
3. Validator配置
@Bean
public Validator validator(){
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure()
.addProperty( "hibernate.validator.fail_fast", "true" )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
return validator;
}
4. 校驗測試
@RequestMapping("/demo4")
public void demo4(){
Demo demo = new Demo();
demo.setUserName("userName");
Set<ConstraintViolation<Demo>> validate = validator.validate(demo);
for (ConstraintViolation<Demo> dem : validate) {
System.out.println(dem.getMessage());
}
}
6. 常見的註解
No. | 註解 | 解釋 |
---|---|---|
01 | @Null | 檢查該字段爲空 |
02 | @NotNull | 不能爲 null |
03 | @NotBlank | 不能爲空,檢查時會將空格忽略 |
04 | @NotEmpty | 不能爲空,這裏的空是指空字符串 |
05 | @AssertTrue | 用於boolwan字段,只能爲true |
06 | @AssertFalse | 用於boolwan字段,只能爲false |
07 | @CreditCardNumber | 對信用卡進行一個大致的校驗 |
08 | @DecimalMin(value) | 數值類型,只能小於或等於value |
09 | @DecimalMax(value) | 數值類型,只能大於或等於value |
10 | @Digits(integer=2,fraction=20) | 限制必須爲一個小數,整數部分位數不能超過integer,小數部分位數不能超過fraction |
11 | 檢查是否是一個有效的email地址 | |
12 | @Past | 檢查該字段的日期是否屬於過去的日期 |
13 | @Future | 檢查該字段的日期是否屬於將來的日期 |
14 | @Length(min=,max=) | 檢查該字段的長度是否在min和max之間,只能用於字符串 |
15 | @Size(min=,max=) | 檢查該字段的size是否在min和max之間,可以是字符串、數組、集合、map等 |
16 | @Min(value) | 小於等於value |
17 | @Max(value) | 大於等於value |
18 | @URL(protocol=,host,port) 檢查是否是一個有效的URL,如果提供來protocol,host等,則該url還需滿足提供的條件 | |
19 | @Valid | 該註解只要用於字段爲一個包含其他對象的集合或map或數組的字段,或該字段直接爲一個其他對象的引用(這樣在檢查當前對象的同時也會檢查該字段所引用的對象) |