标签:exce 限制 生效 比较 oss nta specific 生日 model
在开发中经常需要写一些字段校验的代码,比如字段非空,字段长度限制,邮箱格式验证等等,写这些与业务逻辑关系不大的代码个人感觉有两个麻烦:
hibernate validator(官方文档)提供了一套比较完善、便捷的验证实现方式。
spring-boot-starter-web
包里面有hibernate-validator
包,不需要引用hibernate validator依赖。
先来看一个简单的demo,添加了Validator的注解:
import org.hibernate.validator.constraints.NotBlank;
import javax.validation.constraints.AssertFalse;
import javax.validation.constraints.Pattern;
@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; }
POST接口验证,BindingResult是验证不通过的结果集合:
@RequestMapping("/demo2") public void demo2(@RequestBody @Valid DemoModel demo, BindingResult result){ if(result.hasErrors()){ for (ObjectError error : result.getAllErrors()) { System.out.println(error.getDefaultMessage()); } } }
POST请求传入的参数:{"userName":"dd","age":120,"isFalse":true,"birthday":"21010-21-12"}
输出结果:
出生日期格式不正确
必须为false
年龄不正确
参数验证非常方便,字段上注解+验证不通过提示信息即可代替手写一大堆的非空和字段限制验证代码。下面深入了解下参数校验的玩法。
细心的读者肯定发现了:上面例子中一次性返回了所有验证不通过的集合,通常按顺序验证到第一个字段不符合验证要求时,就可以直接拒绝请求了。Hibernate Validator有以下两种验证模式:
普通模式(会校验完所有的属性,然后返回所有的验证失败信息)
快速失败返回模式(只要有一个验证失败,则返回)
两种验证模式配置方式:(参考官方文档)
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();
配置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; } }
如demo里示例的,验证请求参数时,在@RequestBody DemoModel demo之间加注解 @Valid,然后后面加BindindResult即可;多个参数的,可以加多个@Valid和BindingResult,如:
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()); } } }
使用校验bean的方式,没有办法校验RequestParam的内容,一般在处理Get请求(或参数比较少)的时候,会使用下面这样的代码:
@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注解来使得验证生效。如下所示:
@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; }
@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
没有配置快速失败返回的MethodValidationPostProcessor 时输出信息如下:
年级只能从1-9
班级最大只能99
配置了快速失败返回的MethodValidationPostProcessor 时输出信息如下:
年级只能从1-9
浏览器服务请求地址:http://localhost:8080/validation/demo3?grade=0&classroom=0
没有配置快速失败返回的MethodValidationPostProcessor 时输出信息如下:
年级只能从1-9
班级最小只能1
配置了快速失败返回的MethodValidationPostProcessor 时输出信息如下:
年级只能从1-9
待校验的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; }
验证model,以下全部验证通过:
@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()); } }
对象内部包含另一个对象作为属性,属性上加@Valid,可以验证作为属性的对象内部的验证:(验证Demo2示例时,可以验证Demo2的字段)
@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; }
Set<ConstraintViolation<Demo2>> violationSet = validator.validate(demo2);
可以校验Demo3的extField字段。
Bean Validation 中内置的 constraint
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max=, min=) 被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期
@Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式
Hibernate Validator 附加的 constraint
@NotBlank(message =) 验证字符串非null,且长度必须大于0
@Email 被注释的元素必须是电子邮箱地址
@Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range(min=,max=,message=) 被注释的元素必须在合适的范围内
springboot使用hibernate validator校验
标签:exce 限制 生效 比较 oss nta specific 生日 model
原文地址:http://www.cnblogs.com/mr-yang-localhost/p/7812038.html