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

【SpringBoot】 在SpringBoot中使用Hibernate Validate

SpringBoot整合Hibernate-Validator校验器