Spring中開啟方法級驗證
在spring中只需要注冊了MethodValidationPostProcessor就能開啟方法級驗證,在調用方法時如果參數或返回值無法滿足對應的限制就無法完成調用
下面以springboot項目為例。
首先在spring容器內放入MethodValidationPostProcessor
@SpringBootApplication
public class App {
public static void main(String[] args) throws Exception {
SpringApplication.run(new Object[]{App.class}, args);
}
@Bean
public MethodValidationPostProcessor mvp(){
return new MethodValidationPostProcessor();
}
}
之后就可以開始方法級驗證了
@RestController
@Validated
public class MyControler {
@RequestMapping("/a")
public @Size(min=1) String a(@Size(min=1) String a){
return a;
}
}
如上,首先需要加上Validated注解(spring4.3.2在類上加了有效,方法上加了無效),之后在方法的參數或返回值是哪個就可以加上對應的校驗規則了
校驗規則
spring支持jsr303以及hibernate中的校驗規則
@AssertFalse 對應參數為false
@AssertTrue 對應參數為true
@DecimalMax("1") 對應小數的最大值
@DecimalMin("1") 對應小數的最小值
@Digits(integer=1,fraction = 2) 對應數字整數(integer)和小數(fraction)位數
@Future Date只接受將來的時間
@Past Date只接受過去的時間
@Max(100) 數字最大值
@Min(100) 數字最小值
@NotNull 不接受Null值
@Null 只接受Null值
@Pattern(regexp="^a$") 正則表達式regexp為表達式
@Size(min=1,max=2) 參數的長度min/max為最小/最大長度
hibernate validation
@CreditCardNumber Luhn算法校驗,用於防止用戶錯誤輸入,並不真實校驗信用卡號
@EAN 歐洲商品標碼校驗
@Email 郵箱校驗
@Length 校驗string的長度
@LuhnCheck Luhn算法校驗
@NotBlank 字符串非null非空
@NotEmpty 字符串、集合、map非空
@ParameterScriptAssert 使用腳本進行校驗支持JSR223腳本
@Range 匹配數字或表示數字的字符串的取值范圍
@SafeHtml 校驗是否包含惡意腳本
@URL 合法URL
異常處理
在校驗遇到非法的參數/返回時會拋出ConstraintViolationException,可以通過getConstraintViolations獲得所有沒有通過的校驗ConstraintViolation集合,可以通過它們來獲得對應的消息。
實現原理
MethodValidationPostProcessor繼承了AbstractBeanFactoryAwareAdvisingPostProcessor,從名字可以看出它是一個AdvisingBeanPostProcessor。
在初始化后由於實現了InitializingBean,會運行afterPropertiesSet,其中會設置pointcut和advisor,是使用aop的方法實現的校驗。
在校驗失敗的異常堆棧中也可以看出
javax.validation.ConstraintViolationException: null
at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:136) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655) ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at blog.MyControler$$EnhancerBySpringCGLIB$$4b158379.a(<generated>) ~[main/:na]
...
使用的是CGLIB進行的aop