SpringBoot数据校验hibernate-validator

一、数据校验

在web开发时,对于请求参数,一般上都需要进行参数合法性校验的,原先的写法时一个个字段一个个去判断,这种方式太不通用了,所以java的JSR 303: Bean Validation 1.0 规范就是解决这个问题的。JSR 303只是个规范,并没有具体的实现,目前通常都是用hibernate-validator进行统一参数校验。

二、Hibernate Validator 版本

Hibernate Validator是Hibernate团队最初的验证框架,现在被称为“Legacy Hibernate Validator”。Hibernate Validator 4.x是Bean Validation 1.0(JSR 303)的参考实现,而Hibernate Validator 5.x是Bean Validation 1.1(JSR 349)的参考实现,目前最新版的Hibernate Validator 6.x 是Bean Validation 2.0(JSR 380)的参考实现。

三、hibernate validator校验demo

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

3.1 校验对象数据

给bean配置Validation Annotations

import javax.validation.constraints.*;  // 注:不是用org.hibernate.validator.constraints
public class DemoModel {

    @NotBlank(message="用户名不能为空")
    @Length(min = 1, max = 20, message = "用户名应为1~20个字符")
    private String userName;

    @NotBlank(message="年龄不能为空")
    @Pattern(regexp="^[0-9]{1,2}$",message="年龄不正确")
    @Min(value = 18, message = "用户年龄必须大于18岁")
    @Max(value = 150, message = "用户年龄必须小于150岁")
    private String age;

    @AssertFalse(message = "必须为false")
    private Boolean isFalse;

    //如果是空,则不校验,如果不为空,则校验
    @Pattern(regexp="^[0-9]{4}-[0-9]{2}-[0-9]{2}$",message="出生日期格式不正确")
    private String birthday;

    @NotEmpty
    @Email(message = "邮箱格式不正确")
    private String email;

    // get set 省略.....
}

POST接口验证,BindingResult是验证不通过的格式化后的结果集合(如果不写,会返回一堆英文信息)

import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;

@RestController
@RequestMapping(value = "/demo")
public class HibernateValidatorController {

    @PostMapping("/2")
    public void demo2(@RequestBody @Valid DemoModel demo, BindingResult result){
        //POST请求传入的参数:{"userName":"dd","age":160,"isFalse":true,"birthday":"21010-21-12","email":"alanchen@"}
        if(result.hasErrors()){
            for (ObjectError error : result.getAllErrors()) {
                System.out.println(error.getDefaultMessage());
            }
        }
    }
}

验证请求参数时,在@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)

3.2 GET参数校验(@RequestParam参数校验)

使用@Valid注解,对RequestParam对应的参数进行注解,是无效的,需要在方法所在的Controller上加注解@Validated

@Validated
@RestController
@RequestMapping(value = "/demo")
public class HibernateValidatorController {

    @GetMapping("/1")
    public String demo1(@Email @RequestParam(required = true) String email) {
        return "Hello SpringBoot "+email;
    }
}

3.3 hibernate的校验模式

Hibernate Validator有以下两种验证模式:

  • 1、普通模式(默认是这个模式):普通模式会校验完所有的属性,然后返回所有的验证失败信息
  • 2、快速失败返回模式:快速失败返回模式只要有一个验证失败,则返回
    配置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;
    }
}

3.4返回验证信息提示

验证不通过时,抛出了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> violations = exs.getConstraintViolations();
            for (ConstraintViolation item : violations) {
          /**打印验证不通过的信息*/
                System.out.println(item.getMessage());
            }
        }
        return "bad request, " ;
    }
}

3.5 使用的是JSR annotations

所有的注解,应该使用JSR注解,即javax.validation.constraints,而不是org.hibernate.validator.constraints

  • @NotNull – validates that the annotated property value is not null

  • @AssertTrue – validates that the annotated property value is true

  • @Size – validates that the annotated property value has a size between the attributes min and max; can be applied to String, Collection, Map, and array properties

  • @Min – vValidates that the annotated property has a value no smaller than the value attribute

  • @Max – validates that the annotated property has a value no larger than the value attribute

  • @Email – validates that the annotated property is a valid email address

  • @NotEmpty – validates that the property is not null or empty; can be applied to String, Collection, Map or Array values

  • @NotBlank – can be applied only to text values and validated that the property is not null or whitespace

  • @Positive and @PositiveOrZero – apply to numeric values and validate that they are strictly positive, or positive including 0

  • @Negative and @NegativeOrZero – apply to numeric values and validate that they are strictly negative, or negative including 0

  • @Past and @PastOrPresent – validate that a date value is in the past or the past including the present; can be applied to date types including those added in Java 8

  • @Future and @FutureOrPresent – validates that a date value is in the future, or in the future including the present

四、关于前后端双层校验

项目中一般是前后端对数据进行双层验证,为什么不用一种就够了?前后端都写验证,会不会重复且浪费开发资源?简单来说

  • 1、前端验证是防“君子”,而后台验证是防“小人”
  • 2、不做前端数据验证,只做后端数据验证弊端:一般前端验证都有比较好的开源插件,使用简单且交互友好,比如邮箱验证,当用户输入一个错误的邮箱地址,输入光标离开输入框后,验证框架立即就会给出比较清晰友好的提示:邮箱格式错误,交互性更好。如果不做前端验证,只做后端验证,那么需要用户提交数据到后台后才能得到邮箱格式错误的提示,提示时间滞后,且多了一次无效的网络请求。
  • 3、不做后端数据验证,只做前端数据验证弊端:当“黑客”绕过前端,直接访问后端服务时,如果后端不做数据校验,就相当于战士上战场不穿防弹衣。

参考文章

  • http://hibernate.org/validator/faq/
  • https://www.baeldung.com/javax-validation
  • https://www.cnblogs.com/mr-yang-localhost/p/7812038.html

你可能感兴趣的:(SpringBoot数据校验hibernate-validator)