美文网首页spring boot
Spring Boot 项目参数校验的常见使用场景

Spring Boot 项目参数校验的常见使用场景

作者: ef6f9c30080a | 来源:发表于2019-07-23 10:38 被阅读70次

    可以说几乎所有的应用场景中,参数验证都在编写业务逻辑前完成,严格确保进来的数据是合法且符合要求的。

    Java Web 开发领域,也早有较为完善的 Bean Validation 为 Java Bean 验证定义了相应的元数据模型和 API。首先,在项目中引入 web 模块的依赖:

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

    Hibernate Validator 是 Bean Validation 的一种实现 . Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,以及一些附加的 constraint。如果想了解更多请查看 http://www.hibernate.org/subprojects/validator.html

    具体以及常用的 constraint 包含如下:

    @Data
    public class Validate {
    
        // 空和非空检查: @Null、@NotNull、@NotBlank、@NotEmpty
    
        @Null(message = "验证是否为 null")
        private Integer isNull;
    
        @NotNull(message = "验证是否不为 null, 但无法查检长度为0的空字符串")
        private Integer id;
    
        @NotBlank(message = "检查字符串是不是为 null,以及去除空格后长度是否大于0")
        private String name;
    
        @NotEmpty(message = "检查是否为 NULL 或者是 EMPTY")
        private List<String> stringList;
    
        // Boolean值检查: @AssertTrue、@AssertFalse
    
        @AssertTrue(message = " 验证 Boolean参数是否为 true")
        private Boolean isTrue;
    
        @AssertFalse(message = "验证 Boolean 参数是否为 false ")
        private Boolean isFalse;
    
        // 长度检查: @Size、@Length
    
        @Size(min = 1, max = 2, message = "验证(Array,Collection,Map,String)长度是否在给定范围内")
        private List<Integer> integerList;
    
        @Length(min = 8, max = 30, message = "验证字符串长度是否在给定范围内")
        private String address;
    
        // 日期检查: @Future、@FutureOrPresent、@Past、@PastOrPresent
    
        @Future(message = "验证日期是否在当前时间之后")
        private Date futureDate;
    
        @FutureOrPresent(message = "验证日期是否为当前时间或之后")
        private Date futureOrPresentDate;
    
        @Past(message = "验证日期是否在当前时间之前")
        private Date pastDate;
    
        @PastOrPresent(message = "验证日期是否为当前时间或之前")
        private Date pastOrPresentDate;
    
        // 其它检查: @Email、@CreditCardNumber、@URL、@Pattern、@ScriptAssert、@UniqueElements
    
        @Email(message = "校验是否为正确的邮箱格式")
        private String email;
    
        @CreditCardNumber(message = "校验是否为正确的信用卡号")
        private String creditCardNumber;
    
        @URL(protocol = "http", host = "127.0.0.1", port = 8080, message = "校验是否为正确的URL地址")
        private String url;
    
        @Pattern(regexp = "^1[3|4|5|7|8][0-9]{9}$", message = "正则校验是否为正确的手机号")
        private String phone;
    
        // 对关联对象元素进行递归校验检查
    
        @Valid
        @UniqueElements(message = "校验集合中的元素是否唯一")
        private List<CalendarEvent> calendarEvent;
    
        @Data
        @ScriptAssert(lang = "javascript", script = "_this.startDate.before(_this.endDate)",
                message = "通过脚本表达式校验参数")
        private class CalendarEvent {
    
            private Date startDate;
    
            private Date endDate;
    
        }
    
        // 数值检查: @Min、@Max、@Range、@DecimalMin、@DecimalMax、@Digits
    
        @Min(value = 0, message = "验证数值是否大于等于指定值")
        @Max(value = 100, message = "验证数值是否小于等于指定值")
        @Range(min = 0, max = 100, message = "验证数值是否在指定值区间范围内")
        private Integer score;
    
        @DecimalMin(value = "10.01", inclusive = false, message = "验证数值是否大于等于指定值")
        @DecimalMax(value = "199.99", message = "验证数值是否小于等于指定值")
        @Digits(integer = 3, fraction = 2, message = "限制整数位最多为3,小数位最多为2")
        private BigDecimal money;
    
    }
    

    常见的前后端分离开发模式,数据通信通常以 JSON 为主。针对 POST 和 PUT 请求,一般通过新建域(对象)模型来进行数据绑定和校验,constraint 通常附加在这些域模型的字段上(如上):

         /**
         * Valid注解标明要对参数对象进行数据校验
         */
        @PutMapping
        @PostMapping
        public Map<String, Object> test01(@RequestBody @Valid Validate validate, BindingResult bindingResult) {
            Map<String, Object> map = new HashMap<>(4);
    
            if (bindingResult.hasErrors()) {
                String errorMsg = bindingResult.getFieldErrors().stream().map(FieldError::getDefaultMessage)
                        .collect(Collectors.joining(","));
                map.put("errorMsg", errorMsg);
            }
    
            map.put("params", validate.toString());
            return map;
        }
    

    此外,对于 GET 和 DELETE 请求,参数通常为 key1=value1&key2=value2 这种形式。默认情况下,Hibernate Validator 只能对 Object 属性进行校验,并不能对单个参数进行校验,Spring 在此基础上进行了扩展,通过配置 MethodValidationPostProcessor 处理器,可以实现对方法参数的拦截校验。

    @Configuration
    public class ValidateConfig {
    
        /**
         * 配置MethodValidationPostProcessor拦截器,以实现对方法参数的校验
         */
        @Bean
        public MethodValidationPostProcessor methodValidationPostProcessor() {
            return new MethodValidationPostProcessor();
        }
    
    }
    

    注意,要在 Controller 类上明确标明 @Validated

    @Validated
    @RestController
    @RequestMapping("validate")
    public class ValidateController {
    
        @GetMapping
        @DeleteMapping
        public Map<String, Object> test02(@NotNull(message = "id不能为空") @Range(min = 1, max = 100, message = "id最小为1最大为100") Integer id,
                                                               @NotBlank(message = "email不能为空") @Email(message = "邮箱格式错误") String email,
                                                               @ModelAttribute @Valid Validate validate) {
            Map<String, Object> map = new HashMap<>(4);
    
            map.put("id", id);
            map.put("email", email);
            map.put("params", validate.toString());
    
            return map;
        }
    
    }
    
    

    上述这种形式的参数要是校验失败,错误提示明显并不友好,通过捕获此类异常就可以解决,这里就不再介绍了。

    参考链接

    JSR 303 - Bean Validation 介绍及最佳实践
    SpringBoot-服务端参数验证-JSR-303验证框架

    示例源码
    欢迎关注我的个人公众号:超级码里奥
    如果这对您有帮助,欢迎点赞和分享,转载请注明出处

    相关文章

      网友评论

        本文标题:Spring Boot 项目参数校验的常见使用场景

        本文链接:https://www.haomeiwen.com/subject/dsjplctx.html