本篇文章主要講解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
主要就是驗證對象是否合法,并將驗證結(jié)果添加到Errors
對象中。多的不解釋瓣喊,先上幾行代碼!
// (1) javax.validation.Validator
private final Validator nativeValidator = Validation.buildDefaultValidatorFactory().getValidator();
// (2) SpringValidatorAdapter 對象實現(xiàn)了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);
//獲取驗證結(jié)果
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));
//獲取具體錯誤原因?qū)ο? assertThat(error.unwrap(ConstraintViolation.class).getPropertyPath().toString(), is("password"));
assertThat(SerializationTestUtils.serializeAndDeserialize(error.toString()), is(error.toString()));
}
以上是org.springframework.validation.beanvalidation2.SpringValidatorAdapterTests
單元測試片段代碼肝劲,我們主要從上面標(biāo)注的([1,2,3,4,5])
來入手了解我們的Spring Validator的功能與原理
(1) javax.validation.Validator
這是validation-api
中的比較重量級的接口,其功能也是驗證對象的合法性担敌,Constrain once, validate everywhere
這是官網(wǎng)標(biāo)語摔敛。我們在來看一張圖
這張圖明確表明了,
validation-api
版本與JSR對應(yīng)關(guān)系全封,如果不知道JSR是什么马昙,老鐵這里不用糾結(jié),你只需要知道刹悴,這里的JSR就是驗證對象合法性的一些規(guī)范(而實現(xiàn)了這套規(guī)范的有hibernate-validator
)如下圖是一些注解規(guī)范:這些規(guī)范語義很清楚行楞,就不過多解釋。那么
javax.validation.Validator
為什么會出現(xiàn)在這里了土匀?很簡單子房,一句話不要重復(fù)造輪子
在這里體現(xiàn),也就是說Spring 的Validator
是包含了我們JSR303
,JSR349
等規(guī)范了的,并且還是使用的hibernate-validator
實現(xiàn)证杭。
(2) SpringValidatorAdapter
SpringValidatorAdapter是Validator
的一個實現(xiàn)類田度,我們在看看其類圖,可以知道SpringValidatorAdapter
是實現(xiàn)了Validator
和javax.validation.Validator
兩個接口的。
(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;
}
可以看到這個類已經(jīng)被很多注解修飾解愤,這里的注解也就是我們需要驗證的規(guī)則镇饺。@Size
和@Pattern
是validator-api
中定義的hibernate-validator
已經(jīng)完全實現(xiàn)了驗證功能,而@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
驗證邏輯的實現(xiàn)類,當(dāng)然這個類必須實現(xiàn)ConstraintValidator
接口异希,以下是接口定義
public interface ConstraintValidator<A extends Annotation, T> {
//注解的元信息
default void initialize(A constraintAnnotation) {
}
//驗證方法
boolean isValid(T value, ConstraintValidatorContext context);
}
(4) Errors對象健盒,用于存儲驗證錯誤信息
通過下圖左邊可以看到Errors接口提供了添加錯誤信息
和獲取錯誤信息
的接口,這也是Spring為我們提供的統(tǒng)一處理和獲取Error信息的接口宠互。而右邊就是我們BeanPropertyBindingResult
的一個關(guān)系類圖味榛,也就Errors
接口的具體實現(xiàn)類。
(5) 利用messageSource獲取錯誤描述信息
這里很和諧的和Spring的MessageResource
搭配使用予跌。以下是DefaultMessageCodesResolver.resolveMessageCodes
方法為生成code的規(guī)則搏色。
總結(jié)
現(xiàn)在我們在對Spring Validator
的功能做次總結(jié)
- 支持 hibernate-validate 實現(xiàn)的 validator-api
- 對錯誤信息提供了友好的封裝
- 錯誤信息能夠無縫結(jié)合MessageSource,以便提供國際化支持
使用
Service 中使用
@Service
@Validated
//Validated 注意 一定要在類上 因為切面是用的
//Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true)
// 代碼源自MethodValidationPostProcessor
public class HelloService {
//參數(shù)使用 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)
感謝
感謝各位老鐵花時間觀看!
歡迎留言指正券册!
內(nèi)容持續(xù)更新频轿!