springboot使用hibernate validator
Posted 欧欧专栏
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot使用hibernate validator相关的知识,希望对你有一定的参考价值。
前言
在开发中经常需要写一些字段校验的代码,比如字段非空,字段长度限制,邮箱格式验证等等,写这些与业务逻辑关系不大的代码个人感觉有两个麻烦:
- 验证代码繁琐,重复劳动
- 方法内代码显得冗长
- 每次要看哪些参数验证是否完整,需要去翻阅验证逻辑代码
hibernate validator(官方文档)提供了一套比较完善、便捷的验证实现方式。
spring-boot-starter-web
包里面有hibernate-validator
包,不需要引用hibernate validator依赖。
一、常见的注解
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=) 被注释的元素必须在合适的范围内
二、hibernate validator校验demo
先来看一个简单的demo
public class StudentDto { @NotBlank(message="名称不能为空") private String name; @NotBlank(message="年级不能为空") @Pattern(regexp="^[0-9]{1,2}$",message="年级不正确") private String grade; @Min(value=6,message="年龄必须大于6") @Max(value=12,message="年龄必须小于12") private int age; @Past(message="出生日期必须是过去的日期") private Date birthDate; ....set get方法省略
@ApiOperation(value="hibernate validate验证") @PostMapping("/validate") public Object validate(@RequestBody @Valid StudentDto studentDto,BindingResult result){ Map<String,Object> retMap = new HashMap<String,Object>(); if(result.hasErrors()){ for (ObjectError error : result.getAllErrors()) { System.out.println(error.getDefaultMessage()); } } return retMap; }
post接口请求,输入
{
"age": 1,
"birthDate": "2019-12-20",
"grade": "string",
"name": "string"
}
结果输入
年级不正确
年龄必须大于6
三、hibernate的校验模式
细心的读者肯定发现了:上面例子中一次性返回了所有验证不通过的集合,通常按顺序验证到第一个字段不符合验证要求时,就可以直接拒绝请求了。Hibernate Validator有以下两种验证模式:
1、普通模式(默认是这个模式)
普通模式(会校验完所有的属性,然后返回所有的验证失败信息)
2、快速失败返回模式
快速失败返回模式(只要有一个验证失败,则返回),(hibernate.validator.fail_fast:true 快速失败返回模式 false 普通模式)
@Configuration public class ValidatorConfiguration { @Bean public Validator validator(){ ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class ) .configure()
//(hibernate.validator.fail_fast:true 快速失败返回模式 false 普通模式) .addProperty( "hibernate.validator.fail_fast", "true" ) .buildValidatorFactory(); Validator validator = validatorFactory.getValidator(); return validator; } }
四、hibernate的两种校验
1、@RequestBody校验
以上所述是@RequestBody校验
2、@RequestParam校验
一般在处理Get请求(或参数比较少)的时候,会使用@RequestParam校验方式:如
@ApiOperation(value="hibernate validate param验证")
@GetMapping("/validateParem")
public Object validateParam(
@RequestParam(name = "grade", required = true) int grade,
@RequestParam(name = "classroom", required = true) int classroom){
Map<String,Object> retMap = new HashMap<String,Object>();
System.out.println(grade + "," + classroom);
return retMap;
}
使用@Valid注解,对RequestParam对应的参数进行注解,是无效的,需要使用@Validated注解来使得验证生效。如下所示:
a.此时需要使用MethodValidationPostProcessor 的Bean:
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
postProcessor.setValidator(validator());
return postProcessor;
}
b.方法所在的Controller上加注解@Validated
@RestController @Validated public class HelloController { @ApiOperation(value="hibernate validate param验证") @GetMapping("/validateParem") public Object validateParam( @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){ Map<String,Object> retMap = new HashMap<String,Object>(); System.out.println(grade + "," + classroom); return retMap; } }
c.返回验证信息提示
可以看到:验证不通过时,抛出了ConstraintViolationException异常,使用同一捕获异常处理:
@ControllerAdvice @Component public class GlobalExceptionHandler { @ExceptionHandler @ResponseBody @ResponseStatus 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, " ; } }
d.验证
浏览器发起请求 http://localhost:8080/validateParem?grade=11111&classroom=22222
配置快速失败返回的MethodValidationPostProcessor 时输出信息如下:
年级只能从1-9
3、model校验
a.需要引入的包
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
b.待校验的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;
c.验证model
@Autowired private Validator validator; @RequestMapping("/validateModel") public void demo3(){ Demo2 demo2 = new Demo2(); demo2.setAge("111"); demo2.setHigh(1500); 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()); } }
b.验证
后台会打印如下信息:
range在[150,250]之间
4、对象级联校验
对象内部包含另一个对象作为属性,属性上加@Valid,可以验证作为属性的对象内部的验证:(验证Demo2示例时,可以验证Demo2的字段)
a.待验证的model Demo2,Demo3
@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;
b.级联校验
@Autowired private Validator validator; @GetMapping("/validateModelCascade") 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()); } }
c.验证,后台打印如下:
length长度在[5,17]之间
5、分组校验
暂无
五、自定义验证器
暂无
六、参考资料
参考资料:
转自:https://www.cnblogs.com/mr-yang-localhost/p/7812038.html
引用:http://docs.jboss.org/hibernate/validator/4.2/reference/zh-CN/html_single/#validator-gettingstarted
以上是关于springboot使用hibernate validator的主要内容,如果未能解决你的问题,请参考以下文章
springboot使用hibernate validator校验
如何使用 springboot 和 hibernate 传递 jdbc 参数?
SpringMVC 项目中 创建SpringBoot,使用Hibernate和JPA
SpringMVC 项目中 创建SpringBoot,使用Hibernate和JPA