springboot使用hibernate validator校验

一、参数校验

在开发中经常需要写一些字段校验的代码,比如字段非空,字段长度限制,邮箱格式验证等等,写这些与业务逻辑关系不大的代码个人感觉有两个麻烦:

验证代码繁琐,重复劳动
方法内代码显得冗长
每次要看哪些参数验证是否完整,需要去翻阅验证逻辑代码
hibernate validator(官方文档)提供了一套比较完善、便捷的验证实现方式。

spring-boot-starter-web包里面有hibernate-validator包,不需要引用hibernate validator依赖。

二、hibernate validator校验demo

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的校验模式

细心的读者肯定发现了:上面例子中一次性返回了所有验证不通过的集合,通常按顺序验证到第一个字段不符合验证要求时,就可以直接拒绝请求了。Hibernate Validator有以下两种验证模式:

返回目录

1. 普通模式(默认是这个模式)

普通模式(会校验完所有的属性,然后返回所有的验证失败信息)

返回目录

2. 快速失败返回模式

快速失败返回模式(只要有一个验证失败,则返回)

两种验证模式配置方式:(参考官方文档

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的两种校验

配置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、请求参数校验

如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());
            }
        }
    }

2.GET参数校验(@RequestParam参数校验)

使用校验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注解来使得验证生效。如下所示:

a.此时需要使用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;
    }

b.方法所在的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);
    }
}

c.返回验证信息提示

可以看到:验证不通过时,抛出了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, " ;
    }
}

d.验证

浏览器服务请求地址: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

这里附上一张飞机票

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值