Spring 系列篇之数据处理

本篇文章主要讲解Spring 提供的对象合法性验证接口org.springframework.validation.Validator,顺带提及一下javax.validation.Validator,注意本篇文章未加特别说明的Validator一律指org.springframework.validation.Validator

接口定义

org.springframework.validation.Validator

Validator 是Spring 为我们提供了一套验证对象的接口,接口定义如下:

public interface Validator {
    boolean supports(Class clazz);
    void validate(Object target, Errors errors);
}

从定义上我们可以猜到Validator主要就是验证对象是否合法,并将验证结果添加到Errors对象中。多的不解释,先上几行代码!

    // (1) javax.validation.Validator 
    private final Validator nativeValidator = Validation.buildDefaultValidatorFactory().getValidator();
    // (2) SpringValidatorAdapter 对象实现了javax.validation.Validator 和 org.springframework.validation.Validator两接口 
    private final SpringValidatorAdapter validatorAdapter = new SpringValidatorAdapter(nativeValidator);
    //messageSource
    private final StaticMessageSource messageSource = new StaticMessageSource();

    @Test  // SPR-13406
    public void testNoStringArgumentValue() throws Exception {
        // (3) 需要被验证的对象  
        TestBean testBean = new TestBean();
        testBean.setPassword("pass");
        testBean.setConfirmPassword("pass");
        // (4) Error对象,用于存储验证错误信息  
        BeanPropertyBindingResult errors = new BeanPropertyBindingResult(testBean, "testBean");
        //实际验证方法
        validatorAdapter.validate(testBean, errors);
        //获取验证结果
        assertThat(errors.getFieldErrorCount("password"), is(1));
        assertThat(errors.getFieldValue("password"), is("pass"));
        FieldError error = errors.getFieldError("password");
        assertNotNull(error);
        // (5) 利用messageSource获取错误描述信息 
        assertThat(messageSource.getMessage(error, Locale.ENGLISH), is("Size of Password must be between 8 and 128"));
        //检查错误原因
        assertTrue(error.contains(ConstraintViolation.class));
        //获取具体错误原因对象
        assertThat(error.unwrap(ConstraintViolation.class).getPropertyPath().toString(), is("password"));
        assertThat(SerializationTestUtils.serializeAndDeserialize(error.toString()), is(error.toString()));
    }

以上是org.springframework.validation.beanvalidation2.SpringValidatorAdapterTests单元测试片段代码,我们主要从上面标注的([1,2,3,4,5])来入手了解我们的Spring Validator的功能与原理

(1) javax.validation.Validator

这是validation-api中的比较重量级的接口,其功能也是验证对象的合法性,Constrain once, validate everywhere这是官网标语。我们在来看一张图

validator support JSR

这张图明确表明了,validation-api版本与JSR对应关系,如果不知道JSR是什么,老铁这里不用纠结,你只需要知道,这里的JSR就是验证对象合法性的一些规范(而实现了这套规范的有hibernate-validator)如下图是一些注解规范:
Validate Annotation

这些规范语义很清楚,就不过多解释。那么javax.validation.Validator为什么会出现在这里了?很简单,一句话不要重复造轮子在这里体现,也就是说Spring 的Validator是包含了我们JSR303,JSR349等规范了的,并且还是使用的hibernate-validator实现。

(2) SpringValidatorAdapter

SpringValidatorAdapter是Validator的一个实现类,我们在看看其类图,可以知道SpringValidatorAdapter是实现了Validatorjavax.validation.Validator两个接口的。

SpringValidatorAdapter

(3) 需要被验证的对象

我们看看TestBean的定义

@Same(field = "password", comparingField = "confirmPassword")
@Same(field = "email", comparingField = "confirmEmail")
static class TestBean {

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

    private String confirmPassword;

    @Pattern(regexp = "[\\w.'-]{1,}@[\\w.'-]{1,}")
    private String email;

    @Pattern(regexp = "[\\p{L} -]*", message = "Email required")
    private String confirmEmail;
}

可以看到这个类已经被很多注解修饰,这里的注解也就是我们需要验证的规则。@Size@Patternvalidator-api中定义的hibernate-validator已经完全实现了验证功能,而@Same是Spring Test自定义的
注解,如下:

@Documented
@Constraint(validatedBy = {SameValidator.class})
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(SameGroup.class)
@interface Same {
    。。。。
}

这里我们重点看@Constraint(validatedBy = {SameValidator.class}) 这就是@Same验证逻辑的实现类,当然这个类必须实现ConstraintValidator接口,以下是接口定义

public interface ConstraintValidator {
        //注解的元信息
    default void initialize(A constraintAnnotation) {
    }
        //验证方法
    boolean isValid(T value, ConstraintValidatorContext context);
}

(4) Errors对象,用于存储验证错误信息

通过下图左边可以看到Errors接口提供了添加错误信息和获取错误信息的接口,这也是Spring为我们提供的统一处理和获取Error信息的接口。而右边就是我们BeanPropertyBindingResult的一个关系类图,也就Errors接口的具体实现类。

Errors

(5) 利用messageSource获取错误描述信息

这里很和谐的和Spring的MessageResource搭配使用。以下是DefaultMessageCodesResolver.resolveMessageCodes方法为生成code的规则。

code生成规则

总结

现在我们在对Spring Validator 的功能做次总结

  • 支持 hibernate-validate 实现的 validator-api
  • 对错误信息提供了友好的封装
  • 错误信息能够无缝结合MessageSource,以便提供国际化支持

使用

Service 中使用

@Service
@Validated  
//Validated 注意 一定要在类上 因为切面是用的 
//Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true) 
// 代码源自MethodValidationPostProcessor
public class HelloService {

   //参数使用 Valid
    public void say(@Valid Hello hello) {
        System.out.println("xxx");
    }
}

Controller 中使用

@RequestMapping("say")
//此处使用Validated 或者 Valid 都可以
//ModelAttributeMethodProcessor.determineValidationHints 判断 Validated 或者 Valid 
//使用Errors 可以接收错误信息,不用Errors会直接抛异常到前端
public String say(@Validated Hello hehe, Errors errors) 

感谢

感谢各位老铁花时间观看!
欢迎留言指正!
内容持续更新!

你可能感兴趣的:(Spring 系列篇之数据处理)