spring validation 的几种方式

@Validated

@Valid

Validator

ConstraintValidator

MethodValidationPostProcessor

@Data
public static class User {
    @Length(min = 4, message = "名称最小{min}个字符")
    private String userName;
    // 嵌套验证
    @Valid
    @NotNull
    private UserInfo userInfo;
}

@Data
public static class UserInfo {
    @NotBlank(message = "性别不为空")
    private String gender;
    @NotNull(message = "年龄不为空")
    private String age;
}

@Validated

@RestController
@RequestMapping("/validated")
public class ValidatedController {
    @RequestMapping(method = { RequestMethod.POST })
    public String validated(@Validated User user) {
        System.out.println(user);
        System.out.println("enter validated");
        return "success";
    }
    @RequestMapping(value = "requestBody", method = { RequestMethod.POST })
    public String validatedRequestBody(@RequestBody @Validated User user) {
        System.out.println(user);
        System.out.println("enter validatedRequestBody");
        return "success";
    }
}

@Valid

@RestController
@RequestMapping("/valid")
public class ValidController {
    @RequestMapping(method = { RequestMethod.POST })
    public String valid(@Valid User user) {
        System.out.println(user);
        System.out.println("enter valid");
        return "success";
    }
    @RequestMapping(value = "requestBody", method = { RequestMethod.POST })
    public String validRequestBody(@RequestBody @Valid User user) {
        System.out.println(user);
        System.out.println("enter validRequestBody");
        return "success";
    }
}

@Valid可以实现嵌套校验
@Validated可以进行分组校验

Validator

实现 org.springframework.validation.Validator 接口方式

@RequestMapping("/myInitBinder")
@Controller
public class InitBinderController {

   @Autowired
   private UserValidator userValidator;
   @InitBinder
   public void initBinder(WebDataBinder binder) {
       binder.addValidators(userValidator);
   }
   @RequestMapping(value = { "/validator" }, method = { RequestMethod.POST })
   @ResponseBody
   public String validator(@Validated User user) {
      System.out.println(user);
      return "success";
   }
}
@Component
public static class UserValidator implements Validator {
   @Override
   public boolean supports(Class<?> clazz) {
      // 只支持User类型对象的校验
      return User.class.equals(clazz);
   }
   @Override
   public void validate(Object target, Errors errors) {
      User user = (User) target;
      String userName = user.getUserName();
      if (StringUtils.isEmpty(userName) || userName.length() < 8) {
         errors.rejectValue("userName", "valid.userNameLen",
               new Object[] { "minLength", 8 }, "用户名不能少于{1}位");
      }
   }
}

ConstraintValidator

实现 javax.validation.ConstraintValidator 接口方式

@Same(field = "password", comparingField = "confirmPassword")
@Data
public static class TestBean {

    @Size(min = 8, max = 128)
    private String password;

    private String confirmPassword;
}
@Documented
@Constraint(validatedBy = {SameValidator.class})
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(SameGroup.class)
@interface Same {
    String message() default "{org.springframework.validation.beanvalidation.Same.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    String field();

    String comparingField();

    @Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @interface List {
        Same[] value();
    }
}
public static class SameValidator implements ConstraintValidator<Same, Object> {
    private String field;
    private String comparingField;
    private String message;
    public void initialize(Same constraintAnnotation) {
        field = constraintAnnotation.field();
        comparingField = constraintAnnotation.comparingField();
        message = constraintAnnotation.message();
    }
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        BeanWrapper beanWrapper = new BeanWrapperImpl(value);
        Object fieldValue = beanWrapper.getPropertyValue(field);
        Object comparingFieldValue = beanWrapper.getPropertyValue(comparingField);
        boolean matched = ObjectUtils.nullSafeEquals(fieldValue, comparingFieldValue);
        if (matched) {
            return true;
        }
        else {
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate(message)
                    .addPropertyNode(field)
                    .addConstraintViolation();
            return false;
        }
    }
}
@RequestMapping(value = "constraintValidator", method = {RequestMethod.POST})
public String constraintValidator(@Validated TestBean testBean) {
    System.out.println(testBean);
    return "success";
}
@RequestMapping(value = "constraintValidator2", method = {RequestMethod.POST})
public String constraintValidator2(TestBean testBean) {
    BeanPropertyBindingResult errors = new BeanPropertyBindingResult(testBean, "testBean");
    validatorAdapter.validate(testBean, errors);
    System.out.println(errors);
    return "success";
}

以上几种都可以使用 @Validated和@Valid 到 @RequestMapping 参数上,调用逻辑如下:

// org.springframework.validation.DataBinder
public void validate(Object... validationHints) {
   Object target = getTarget();
   Assert.state(target != null, "No target to validate");
   BindingResult bindingResult = getBindingResult();
   // Call each validator with the same binding result
   for (Validator validator : getValidators()) {
      if (!ObjectUtils.isEmpty(validationHints) && validator instanceof SmartValidator) {
         ((SmartValidator) validator).validate(target, bindingResult, validationHints);
      }
      else if (validator != null) {
         validator.validate(target, bindingResult);
      }
   }
}

通过实现 ConstraintValidator 的方式可以通过 API 方式调用 :

// SmartValidator
void validate(Object target, Errors errors)
void validate(Object target, Errors errors, Object... validationHints);

MethodValidationPostProcessor

public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor
      implements InitializingBean {
   private Class<? extends Annotation> validatedAnnotationType = Validated.class;
   @Override
   public void afterPropertiesSet() {
      Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);
      this.advisor = new DefaultPointcutAdvisor(pointcut, createMethodValidationAdvice(this.validator));
   }
   protected Advice createMethodValidationAdvice(@Nullable Validator validator) {
      return (validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor());
   }
}

被 @Validated 注解的类会被代理,通过 MethodValidationInterceptor 处理方法级的验证

@RequestMapping(value = "method", method = {RequestMethod.GET})
public String method() {
    helloService.hello(1, null);
    System.out.println("enter validatedRequestBody");
    return "success";
}
@Validated(Default.class)
public interface HelloService {
    @NotEmpty String hello(@NotNull @Min(10) Integer id, @NotNull String name);
    void validatedUser(@Valid  User user);
}
@Slf4j
@Service
public static class HelloServiceImpl implements HelloService {
    @Override
    public String hello(Integer id, String name) {
        User user = new User();
        HelloService helloService = (HelloService) AopContext.currentProxy();
        helloService.validatedUser(user);
        return null;
    }
    @Override
    public void validatedUser(User user) {
        System.out.println(user);
    }
}

相关类定义

// ValidationAutoConfiguration
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@ConditionalOnMissingBean(Validator.class)
public static LocalValidatorFactoryBean defaultValidator() {
   LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
   MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
   factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
   return factoryBean;
}
@Bean
@ConditionalOnMissingBean
public static MethodValidationPostProcessor methodValidationPostProcessor(Environment environment,
      @Lazy Validator validator, ObjectProvider<MethodValidationExcludeFilter> excludeFilters) {
   FilteredMethodValidationPostProcessor processor = new FilteredMethodValidationPostProcessor(
         excludeFilters.orderedStream());
   boolean proxyTargetClass = environment.getProperty("spring.aop.proxy-target-class", Boolean.class, true);
   processor.setProxyTargetClass(proxyTargetClass);
   processor.setValidator(validator);
   return processor;
}
// WebMvcAutoConfiguration#EnableWebMvcConfiguration
@Bean
@Override
public Validator mvcValidator() {
   if (!ClassUtils.isPresent("javax.validation.Validator", getClass().getClassLoader())) {
      return super.mvcValidator();
   }
   return ValidatorAdapter.get(getApplicationContext(), getValidator());
}
// ValidatorAdapter
public static Validator get(ApplicationContext applicationContext, Validator validator) {
   if (validator != null) {
      return wrap(validator, false);
   }
   return getExistingOrCreate(applicationContext);
}
private static Validator getExistingOrCreate(ApplicationContext applicationContext) {
   Validator existing = getExisting(applicationContext);
   if (existing != null) {
      return wrap(existing, true);
   }
   return create();
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

huohuosh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值