• spring boot中使用Bean Validation做优雅的参数校验


    一、Bean Validation简介

    Bean Validation是Java定义的一套基于注解的数据校验规范,目前已经从JSR 303的1.0版本升级到JSR 349的1.1版本,再到JSR 380的2.0版本(2.0完成于2017.08),目前最新稳定版2.0.2(201909)
    对于spring boot应用,直接引用它提供的starter

    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-validationartifactId>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    二、常用注解

    常用注解如下:
    在这里插入图片描述
    直接在Controller层使用

    @RestController
    @RequestMapping("/app/api")
    @Validated
    @Slf4j
    public class SpringGuaranteeReportController {
    
        @RequestMapping("/sendSpringGuaranteeReport")
        public ResultObject<String> sendSpringGuaranteeReport(@Min(value = 1) @Max(value = 2) Integer mmsType,
                                                      @Min(value = 1) @Max(value = 2) Integer groupType,
                                                      @NotBlank String opTime) {
            …………
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    一个简单的接口,传入一个Person对象,加上@Valid启用校验,bindingResult里面就包含了参数校验的结果

    @Data
    public class Person {
        @NotBlank(message = "姓名不能为空")
        private String name;
        @NotBlank(message = "性别不能为空")
        private String sex;
        @NotNull(message = "年龄不能为空")
        @Max(value = 100, message = "年龄不能超过100")
        private Integer age;
        @Email(message = "电子邮箱格式错误")
        private String email;
        @Pattern(regexp = "^1[3|4|5|7|8][0-9]{9}$")
        private String phone;
        @NotEmpty(message = "兴趣不能为空")
        private List<String> hobby;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    这里做了判空和基本格式校验
    其中关于@NotEmpty、@NotNull、@NotBlank的区别:
    简单来说,在Integer或者自定义对象中使用@NotNull,在String上使用@NotBlank,在集合上使用NotEmpty

    三、配置类

    validate参数校验默认的是一个参数校验失败后,还会继续校验后面的参数,通过这个配置改成:校验参数时只要出现校验失败的情况,就立即抛出对应的异常,结束校验,不再进行后续的校验

    import org.hibernate.validator.HibernateValidator;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
    
    import javax.validation.Validation;
    import javax.validation.Validator;
    import javax.validation.ValidatorFactory;
    
    /**
     * validate参数校验默认的是一个参数校验失败后,还会继续校验后面的参数
     * 通过这个配置改成:校验参数时只要出现校验失败的情况,就立即抛出对应的异常,结束校验,不再进行后续的校验
     */
    @Configuration
    public class ValidationConfig {
        @Bean
        public Validator validator() {
            ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
                    .configure()
                    /**failFast的意思只要出现校验失败的情况,就立即结束校验,不再进行后续的校验*/
                    .failFast(true)
                    .buildValidatorFactory();
            return validatorFactory.getValidator();
        }
    
        @Bean
        public MethodValidationPostProcessor methodValidationPostProcessor() {
            MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
            methodValidationPostProcessor.setValidator(validator());
            return methodValidationPostProcessor;
        }
    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    validate参数校验失败后,返回的json数据可能并不是咱们最终想要的,下图就是校验失败后它默认返回的数据

    在这里插入图片描述
    一般情况下,咱们可能只需要图中标红的那个提示信息就OK了
    那怎么改它的返回数据呢?
    只要添加一个异常处理类就行了,捕获抛出的异常

    import com.ai.boy.common.R;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.context.support.DefaultMessageSourceResolvable;
    import org.springframework.validation.BindException;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import javax.servlet.http.HttpServletResponse;
    import javax.validation.ConstraintViolation;
    import javax.validation.ConstraintViolationException;
    import java.util.stream.Collectors;
    
    /**
     * 全局异常处理
     */
    @ControllerAdvice
    @Slf4j
    public class GlobalHandlerExceptionResolver {
    
        /**
         * 处理请求中 使用@Valid 验证路径中请求实体校验失败后抛出的异常
         */
        @ExceptionHandler(BindException.class)
        @ResponseBody
        public R BindExceptionHandler(BindException e) {
            String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
            return R.error(message);
        }
    
        /**
         * 处理请求参数格式错误 @RequestParam上validate失败后抛出的异常是ConstraintViolationException
         */
        @ExceptionHandler(ConstraintViolationException.class)
        @ResponseBody
        public R ConstraintViolationExceptionHandler(ConstraintViolationException e) {
            String message = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining());
            return R.error(message);
        }
    
        /**
         * 处理未知异常
         * */
        @ExceptionHandler(Exception.class)
        @ResponseBody
        public R error(HttpServletResponse response, Exception e){
            log.info("未知异常信息:{}",e.getMessage());
            return R.error("未知异常,请联系管理员!");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
  • 相关阅读:
    pygame制作游戏全套的
    【Matlab】蒙特卡罗法模拟圆周率+对应解析的GIF生成【超详细的注释和解释】
    RocketMq消息持久化(一)——存储架构设计概述
    Django——视图
    算法补天系列之——KMP算法,即字符串匹配算法
    快速写论文
    串的匹配 (KPM算法)
    数据异常问题分析方法
    哪吒汽车选择BlackBerry QNX为中国新能源轿跑——哪吒S保驾护航
    震惊 !!!DOM还能这么用,让我们跟随小编一起去看看吧 !
  • 原文地址:https://blog.csdn.net/weixin_45961836/article/details/134379701