SpringBoot Validator 参数校验配置

SpringBoot Validator 参数校验常用配置

    • 一:常用注解
    • 二:附加注解
    • 三: 用BindingResult接收错误信息
    • 四: group分类属性
    • 五:不用BindingResult的情况.写在Exception统一配置类中
    • 六:方法中验证对象属性

简介
Spring Validation 是在Spring Context下的,在Spring Boot项目中,我们引入spring-boot-starter-web便会引入进来,Spring Validation是对Hibernate Validator的二次封装,使我们可以更方便的在Spring MVC中完成自动校验。
Hibernate Validator是对JSR-303(Bean Validation)的参考实现。Hibernate Validator 提供了JSR-303规范中所有内置constraint的实现,除此之外还有一些附加的constraint。
JSR-303定义的constraint:

一:常用注解

Constraint Description
@Null 被注解的元素必须为null
@NotNull 被注解的元素必须不为null
@AssertTure 被注解的元素必须为ture
@AssertFalse 被注解的元素必须为false
@Min(value) 被注解的元素必须是数字且必须大于等于指定值
@Max(value) 被注解的元素必须是数字且必须小于等于指定值
@DecimalMin(value) 被注解的元素必须是数字且必须大于等于指定值
@DecimalMax(value) 被注解的元素必须是数字且必须小于等于指定值
@Size(max, min) 被注解的元素必须在指定的范围内
@Digits(integer, fraction) 被注解的元素必须是数字且其值必须在给定的范围内
@Past 被注解的元素必须是一个过去的日期
@Future 被注解的元素必须是一个将来的日期
@Pattern(value) 被注解的元素必须符合给定正则表达式

二:附加注解

Hibernate Validator附加实现的constraint

Constraint Description
@Email 被注解的元素必须是Email地址
@Length(min, max) 被注解的元素长度必须在指定的范围内
@NotEmpty 被注解的元素必须
@Range 被注解的元素(可以是数字或者表示数字的字符串)必须在给定的范围内
@URL 被注解的元素必须是URL

当然,我们也可以自定义实现,自定义实现在下面使用中在讲吧。
使用
在开始使用之前,先做好准备工作,创建一个Spring Boot项目,然后引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

三: 用BindingResult接收错误信息

只需要引入这个依赖就可以了。
使用@Validated注解拦截校验
在Controller中,我们需要校验前端传递过来的参数,我们可以这么写

@RestController
public class TestController {

    @PostMapping("/test")
    public Object test(@RequestBody @Validated User user, BindingResult result) {
        if (result.hasErrors()) {
            return result.getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.toList());
        }
        return user;
    }
}

只需要在需要校验的实体前面打上@Validated注解就可以了,这时候,如果我们传递的参数符合要求,则会正常返回。否则返回:


[
    "age字段不合法",
    "name字段不合法"
]

它会将我们所有不合法信息一次性全部返回,在日常开发中,我们可以吧校验BindingResult是否有错误信息的校验统一抽出到一个工具类中去做处理,使用项目中统一格式返回错误信息就好。这就是一个最简单的校验示例了,其他注解也都是类似的,就不多举例了,可以自己尝试着玩玩。

四: group分类属性

在日常开发中想必都曾遇到过这样的需求,比如这个age这个字段,我想要这个字段只在PC端校验,在App端不做限制,这就需要用到分组校验了,每个注解都提供了一个group属性,利用这个属性就可以轻易做到以上需求。比如在User上的注解中加入group属性,指定其被校验的group:

public class User {

    @Length(min = 1, max = 22, message = "name字段不合法", groups = {App.class, PC.class})
    private String name;
    @Min(value = 1, message = "age字段不合法", groups = PC.class)
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

在Controller中的@Validated中指定当前group:

@RestController
public class TestController {

    @PostMapping("/test")
    public Object test(@RequestBody @Validated(App.class) User user, BindingResult result) {
        if (result.hasErrors()) {
            return result.getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.toList());
        }
        return user;
    }
}

这时候我再使用两个不合法字段访问返回:

[
    "name字段不合法"
]

可以看到,它并没有对age字段进行校验。这就是它的分组校验。


五:不用BindingResult的情况.写在Exception统一配置类中


@ControllerAdvice
@RestController
@Slf4j
public class GlobalExceptionHandler {




    @ExceptionHandler(BindException.class)
    public Object validExceptionHandler(BindException e){
        FieldError fieldError = e.getBindingResult().getFieldError();
        assert fieldError != null;
        log.error(fieldError.getField() + ":" + fieldError.getDefaultMessage());
        // 将错误的参数的详细信息封装到统一的返回实体
        return  CreditQueryResp.failure(NormalExceptionEnum.PARAM_EXCEPTION.getCode(),fieldError.getDefaultMessage()) ;
    }


    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Object validExceptionHandler(MethodArgumentNotValidException e){
        FieldError fieldError = e.getBindingResult().getFieldError();
        assert fieldError != null;
        log.error(fieldError.getField() + ":" + fieldError.getDefaultMessage());
        return CreditQueryResp.failure(NormalExceptionEnum.PARAM_EXCEPTION.getCode(),fieldError.getDefaultMessage()) ;
    }

    @ExceptionHandler(Throwable.class)
    CreditQueryResp handleException(Throwable throwable){
        if(throwable instanceof  NullPointerException ){
            return  CreditQueryResp.failure(NormalExceptionEnum.PARAM_EXCEPTION.getCode(),throwable.getMessage());
        }if(throwable instanceof BusinessException){
            BusinessException businessException=(BusinessException)throwable;
            return CreditQueryResp.failure(businessException.getBizCode().getCode(),businessException.getMessage()) ;
        }
        log.error("异常信息:{}",throwable);
        return    CreditQueryResp.failure(NormalExceptionEnum.SYSTEM_EXCEPTION.getCode(), NormalExceptionEnum.SYSTEM_EXCEPTION.getMessage()) ;
    }
}

六:方法中验证对象属性


@Component
public class ValidatorUtil {

    private static Validator validator;
    private static SmartValidator validatorAdapter;

    static {
        // 快速返回模式
        validator = Validation.byProvider(HibernateValidator.class)
                .configure()
                .failFast(true)
                .buildValidatorFactory()
                .getValidator();

        validatorAdapter=getValidatorAdapter(validator);
    }

    public static Validator getValidator() {
        return validator;
    }

    private static SmartValidator getValidatorAdapter(Validator validator) {
        if (validatorAdapter == null) {
            validatorAdapter = new SpringValidatorAdapter(validator);
        }
        return validatorAdapter;
    }


    public  Object  validator(Person person){
        BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
        validatorAdapter.validate(person, result);
        if (result.hasErrors()) {
            return result.getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.toList());
        }
        return person;
    }


}

controller代码

   @RequestMapping("/hello")
    public String  sayHello(@RequestBody Person person){
         validator.validator(person);
        return "success";
    }

entity代码:

@Data
public class Person {

    @NotNull(message = "姓名不能为空" )
    private  String  name ;

    @Max(value = 18,message = "年龄不能超过18岁")@Min(value = 10,message = "年龄不能小于10岁")
    private Integer age ;

    private String format ;


}

调用这个工具类,就可以在方法中验证对象的属性了

总结
项目中往往有很多地方需要用到空判断 , 一般会有全局异常拦截类,所以一般就不会用BindingResult 去接受错误的参数.group区分入口 ,也可以方法中对对象进行判断,应该在项目的check上面应该足够了

你可能感兴趣的:(spring,springBoot)