Spring数据校验(LocalValidatorFactoryBean和MethodValidationPostProcessor的区别/@Valid和@Validated的区别)

JSR标准和Spring校验框架

JavaJSR-303标准的数据校验的核心接口是javax.validation.Validator,该接口根据目标对象中标注的校验注解进行数据校验,并得到校验结果。

Spring也有自己的校验框架,同时支持JSR-303标准的校验框架。SpringDataBinder在进行数据绑定时,同时调用校验框架完成数据校验工作。
Spring的校验框架包是org.springframework.validation,其中LocalValidatorFactoryBean同时实现了SpringValidatorJSR-303Validator接口,但是Spring本身没有提供JSR-303的实现,因此必须将实现了JSR-303jar放在类路径下。

配置校验框架的处理器

<mvc:annotation-driven	validator="validator" />
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor" />

上面配置了LocalValidatorFactoryBeanMethodValidationPostProcessor两个Bean,它们的区别:

  1. LocalValidatorFactoryBean同时实现了SpringValidatorJSR-303Validator接口
  2. LocalValidatorFactoryBean可以完成i18n
  3. MethodValidationPostProcessor可以实现在方法上校验基本数据包装类型和String类型等单独的对象,但是要在异常处理器中处理ConstraintViolationException异常
  4. 两个Bean可以同时存在

重要的两个注解@Valid和@Validated

这两个注解都是进行数据校验的标志,但是有区别:

  1. @Valid是JSR-303标准规定的;@Validated是Spring校验框架提供的
  2. @Valid可以在方法/成员变量/构造函数/方法参数上使用;@Validated可以在类/方法/方法参数上使用;区别在于成员变量上是否可以使用
  3. 由于@Valid可以在成员变量上使用,因此可以嵌套校验
  4. @Valid会把校验不通过的信息交给BindingResult中,因此在controller的方法中,@ValidBindingResult要同时存在
  5. @Validated可以在类上使用,可以配合MethodValidationPostProcessor实现校验基本数据包装类型和String类型等单独的对象

案例

  • 依赖

    <dependency>
    	<groupId>org.hibernate</groupId>
    	<artifactId>hibernate-validator</artifactId>
    	<version>5.2.4.Final</version>
    	<exclusions>
    		<exclusion>
    			<artifactId>validation-api</artifactId>
    			<groupId>javax.validation</groupId>
    		</exclusion>
    	</exclusions>
    </dependency>
    <dependency>
    	<groupId>javax.validation</groupId>
    	<artifactId>validation-api</artifactId>
    	<version>1.1.0.Final</version>
    </dependency>
    
  • @Validated

    @RestController
    @RequestMapping("/validated")
    @Validated
    public class ValidatedController {
        @RequestMapping("/test")
        public Object test(@NotNull(message = "不能为null") String name) {
            return new Object();
        }
    }
    
    @RestControllerAdvice
    public class ExceptionHandle {
        @ExceptionHandler(ConstraintViolationException.class)
        public Object constraintViolationException(ConstraintViolationException e) {
            StringBuilder stringBuilder = new StringBuilder();
            for (ConstraintViolation constraintViolation : e.getConstraintViolations()) {
                stringBuilder.append(constraintViolation.getMessage()).append(",");
            }
            if (stringBuilder.length() > 0) {
                stringBuilder.deleteCharAt(stringBuilder.length() - 1);
            }
            return stringBuilder.toString();
        }
    }
    
  • @Valid

    public class Person implements Serializable {
        @NotNull(message = "person.name_is_null")
        private String name;
        @Valid
        private Phone phone;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Phone getPhone() {
            return phone;
        }
        public void setPhone(Phone phone) {
            this.phone = phone;
        }
    }
    public class Phone implements Serializable {
        @NotNull(message = "phone.name_is_null")
        private String name;
        private String price;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getPrice() {
            return price;
        }
        public void setPrice(String price) {
            this.price = price;
        }
    }
    
    @ResponseBody
    @RequestMapping("/test")
    public Object test(@Valid Person person, BindingResult result) {
    	if(result != null){
    		if(result.hasErrors()){
    			for (FieldError fieldError : result.getFieldErrors()) {
    				System.out.println(fieldError.getDefaultMessage());
    			}
    		}
    	}
    	return new Object();
    }
    
  • 出错的使用

    @ResponseBody
    @RequestMapping("/test")
    public Object testBindingResult(@NotBlank String name, BindingResult result) {
    	if (result.hasErrors()) {
    		System.out.println(result.getFieldError("name").getDefaultMessage());
    	}
    	return new Object();
    }
    

    会报错:

    public Object test(@NotBlank String name, BindingResult result)
    严重: Servlet.service() for servlet [springmvc] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: An Errors/BindingResult argument is expected to be declared immediately after the model attribute, the @RequestBody or the @RequestPart arguments to which they apply: public com.p7.framework.common.ResultBean com.p7.framework.controller.BindingResultController.testBindingResult(java.lang.String,org.springframework.validation.BindingResult)] 
    
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值