1. 程式人生 > >spring中方法級驗證引數

spring中方法級驗證引數

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