springmvc使用JSR-303進行校驗

源自:http://blog.csdn.net/tsingheng/article/details/42555307

下面提供一種springmvc的校驗方案,一般沒有校驗或者手動寫validator的話都要寫好多代碼好多if判斷,使用JSR-303規範校驗只需要在Pojo字段上加上相應的註解就可以實現校驗了

1.依賴的jar包,我直接貼pom了

  1. <properties>  
  2.     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
  3.     <spring.version>4.1.1.RELEASE</spring.version>  
  4. </properties>  
  5.   
  6. <dependencies>  
  7.     <dependency>  
  8.         <groupId>com.fasterxml.jackson.core</groupId>  
  9.         <artifactId>jackson-core</artifactId>  
  10.         <version>2.4.0</version>  
  11.     </dependency>  
  12.     <dependency>  
  13.         <groupId>com.fasterxml.jackson.core</groupId>  
  14.         <artifactId>jackson-databind</artifactId>  
  15.         <version>2.4.0</version>  
  16.     </dependency>  
  17.     <dependency>  
  18.         <groupId>commons-fileupload</groupId>  
  19.         <artifactId>commons-fileupload</artifactId>  
  20.         <version>1.3.1</version>  
  21.     </dependency>  
  22.     <dependency>  
  23.         <groupId>javax.servlet</groupId>  
  24.         <artifactId>javax.servlet-api</artifactId>  
  25.         <version>3.1.0</version>  
  26.     </dependency>  
  27.     <dependency>  
  28.         <groupId>javax.validation</groupId>  
  29.         <artifactId>validation-api</artifactId>  
  30.         <version>1.1.0.Final</version>  
  31.     </dependency>  
  32.     <dependency>  
  33.         <groupId>org.hibernate</groupId>  
  34.         <artifactId>hibernate-validator</artifactId>  
  35.         <version>5.1.3.Final</version>  
  36.     </dependency>  
  37.     <dependency>  
  38.         <groupId>org.springframework</groupId>  
  39.         <artifactId>spring-orm</artifactId>  
  40.         <version>${spring.version}</version>  
  41.     </dependency>  
  42.     <dependency>  
  43.         <groupId>org.springframework</groupId>  
  44.         <artifactId>spring-context</artifactId>  
  45.         <version>${spring.version}</version>  
  46.     </dependency>  
  47.     <dependency>  
  48.         <groupId>org.springframework</groupId>  
  49.         <artifactId>spring-web</artifactId>  
  50.         <version>${spring.version}</version>  
  51.     </dependency>  
  52.     <dependency>  
  53.         <groupId>org.springframework</groupId>  
  54.         <artifactId>spring-webmvc</artifactId>  
  55.         <version>${spring.version}</version>  
  56.     </dependency>  
  57.     <dependency>  
  58.         <groupId>org.springframework</groupId>  
  59.         <artifactId>spring-test</artifactId>  
  60.         <version>${spring.version}</version>  
  61.     </dependency>  
  62.     <dependency>  
  63.         <groupId>org.slf4j</groupId>  
  64.         <artifactId>slf4j-log4j12</artifactId>  
  65.         <version>1.7.7</version>  
  66.     </dependency>  
  67.     <dependency>  
  68.         <groupId>junit</groupId>  
  69.         <artifactId>junit</artifactId>  
  70.         <version>4.11</version>  
  71.         <scope>test</scope>  
  72.     </dependency>  
  73.     <dependency>  
  74.         <groupId>org.aspectj</groupId>  
  75.         <artifactId>aspectjweaver</artifactId>  
  76.         <version>1.8.4</version>  
  77.     </dependency>  
  78.     <dependency>  
  79.         <groupId>javax.el</groupId>  
  80.         <artifactId>javax.el-api</artifactId>  
  81.         <version>3.0.0</version>  
  82.     </dependency>  
  83. </dependencies>  
2.springmvc配置
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"  
  4.     xmlns:context="http://www.springframework.org/schema/context"  
  5.     xmlns:mvc="http://www.springframework.org/schema/mvc"  
  6.     xmlns:aop="http://www.springframework.org/schema/aop"  
  7.     xsi:schemaLocation="http://www.springframework.org/schema/beans   
  8.         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   
  9.         http://www.springframework.org/schema/tx   
  10.         http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  
  11.         http://www.springframework.org/schema/context  
  12.         http://www.springframework.org/schema/context/spring-context-3.0.xsd  
  13.         http://www.springframework.org/schema/mvc  
  14.         http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd  
  15.         http://www.springframework.org/schema/aop   
  16.         http://www.springframework.org/schema/aop/spring-aop.xsd">  
  17.   
  18.     <!-- 默認的註解映射的支持 -->  
  19.     <mvc:annotation-driven/>  
  20.     <context:annotation-config/>  
  21.     <aop:aspectj-autoproxy/>  
  22.   
  23.     <!-- 自動掃描的包名 -->  
  24.     <context:component-scan base-package="spring.test.web.controller"/>  
  25.       
  26.     <bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />  
  27.       
  28. </beans>  

3.寫java代碼了

先建一個User類

  1. public class User {  
  2.     @NotNull  
  3.     private String username;  
  4.       
  5.     @NotNull(message = "密碼不能爲空")  
  6.     private String password;  
  7.       
  8.     public String getUsername() {  
  9.         return username;  
  10.     }  
  11.       
  12.     public void setUsername(String username) {  
  13.         this.username = username;  
  14.     }  
  15.       
  16.     public String getPassword() {  
  17.         return password;  
  18.     }  
  19.       
  20.     public void setPassword(String password) {  
  21.         this.password = password;  
  22.     }  
  23.       
  24. }  
然後建一個controller試試
  1. @ResponseBody  
  2. @RequestMapping("/test1")  
  3. public AjaxResponse validateTest1(@Valid User user, BindingResult result){  
  4.     AjaxResponse ajaxResponse = new AjaxResponse();  
  5.     Map<String, Object> map = new HashMap<>();  
  6.     if(result.hasErrors()){  
  7.         ajaxResponse.setSuccess(false);  
  8.         ajaxResponse.setHasErrors(true);  
  9.         map.put("errors", result.getAllErrors());  
  10.     }  
  11.     else {  
  12.         map.put("now"new Date());  
  13.         map.put("user", user);  
  14.     }  
  15.     ajaxResponse.setData(map);  
  16.     return ajaxResponse;  
  17. }  

這個方法第一個參數上加了@Valid標註,第二個參數是必須的而且必須緊跟着@Valid參數之後,校驗結果都在這個result裏面

方法邏輯比較簡單,調用result.hasErrors()看校驗有沒有錯誤,有錯誤的話就把所有的錯誤放進結果返回給客戶端,如果沒有錯誤就返回當前時間跟user對象

然後寫個測試方法試試

  1. @Test  
  2. public void test1() throws Exception{  
  3.     this.mockMvc.perform(post("/validator/test1")).andDo(print());  
  4.     this.mockMvc.perform(post("/validator/test1").param("username""testusername").param("password""testpassword")).andDo(print());  
  5. }  

第一個請求的結果是
[javascript] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. {"success":false,"message":null,"hasErrors":true,"data":[{"name":"user","message":"may not be null"},{"name":"user","message":"密碼不能爲空"}]}  

第二個請求結果是
[javascript] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. {"success":true,"message":null,"hasErrors":false,"data":{"now":1420788232169,"user":{"username":"testusername","password":"testpassword"}}}  

很明顯第一次請求沒有用戶名和密碼兩個字段校驗都沒有通過,第二次是成功的

用起來還是很簡單的,但是如果我不想每次都在controller方法裏寫if(result.hasErrors())怎麼辦呢,寫個切面,把if寫在切面裏,如果有errors直接就返回了,不用再執行controller方法了

  1. @Aspect  
  2. public class ValidAspect {  
  3.       
  4.     @Autowired private Validator validator;  
  5.       
  6.     @Around("@annotation(org.springframework.web.bind.annotation.ResponseBody)")  
  7.     public Object doTest(ProceedingJoinPoint pjp) throws Throwable{  
  8.         MethodSignature signature = (MethodSignature) pjp.getSignature();  
  9.         Method method = signature.getMethod();  
  10.         if(!AjaxResponse.class.equals(method.getReturnType())){  
  11.             pjp.proceed();  
  12.         }  
  13.         Object[] args = pjp.getArgs();  
  14.         Annotation[][] annotations = method.getParameterAnnotations();  
  15.         for(int i = 0; i < annotations.length; i++){  
  16.             if(!hasValidAnnotation(annotations[i])){  
  17.                 continue;  
  18.             }  
  19.             if(!(i < annotations.length-1 && args[i+1instanceof BindingResult)){  
  20.                 //驗證對象後面沒有跟bindingResult,事實上如果沒有應該到不了這一步  
  21.                 continue;  
  22.             }  
  23.             BindingResult result = (BindingResult) args[i+1];  
  24.             if(result.hasErrors()){  
  25.                 AjaxResponse ajaxResponse = new AjaxResponse();  
  26.                 ajaxResponse.setSuccess(false);  
  27.                 ajaxResponse.setHasErrors(true);  
  28.                 ajaxResponse.setData(processErrors(result));  
  29.                 return ajaxResponse;  
  30.             }  
  31.         }  
  32.         return pjp.proceed();  
  33.     }  
  34.   
  35.     private boolean hasValidAnnotation(Annotation[] annotations){  
  36.         if(annotations == null){  
  37.             return false;  
  38.         }  
  39.         for(Annotation annotation : annotations){  
  40.             if(annotation instanceof Valid){  
  41.                 return true;  
  42.             }  
  43.         }  
  44.         return false;  
  45.     }  
  46.       
  47.     private List<BindingError> processErrors(BindingResult result){  
  48.         if(result != null && result.hasErrors()){  
  49.             List<BindingError> list = new ArrayList<BindingError>();  
  50.             for(ObjectError error : result.getAllErrors()){  
  51.                 BindingError be = new BindingError();  
  52.                 be.setMessage(error.getDefaultMessage());  
  53.                 be.setName(error.getObjectName());  
  54.                 list.add(be);  
  55.             }  
  56.             return list;  
  57.         }  
  58.         return null;  
  59.     }  
  60. }  

注意要在springmvc配置文件加一行<bean class="spring.test.web.aop.ValidAspect"/>

然後再寫個方法邏輯跟上面的類似

  1. @ResponseBody  
  2. @RequestMapping("/test2")  
  3. public AjaxResponse validateTest2(@Valid User user, BindingResult result){  
  4.     AjaxResponse ajaxResponse = new AjaxResponse();  
  5.     Map<String, Object> map = new HashMap<>();  
  6.     map.put("now"new Date());  
  7.     map.put("user", user);  
  8.     ajaxResponse.setData(map);  
  9.     return ajaxResponse;  
  10. }  

這裏沒有再去判斷hasErrors()了,然後測試一下

寫測試方式試一下

  1. @Test  
  2. public void test2() throws Exception{  
  3.     this.mockMvc.perform(post("/validator/test2")).andDo(print());  
  4.     this.mockMvc.perform(post("/validator/test2").param("username""testusername").param("password""testpassword")).andDo(print());  
  5. }  

第一個請求結果是
[javascript] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. {"success":false,"message":null,"hasErrors":true,"data":[{"name":"user","message":"密碼不能爲空"},{"name":"user","message":"may not be null"}]}  
第二個請求結果是
  1. {"success":true,"message":null,"hasErrors":false,"data":{"now":1420788479105,"user":{"username":"testusername","password":"testpassword"}}}  
效果跟上面是一樣的

當然我這個切面僅僅是個示範,我攔截的是帶有ResponseBody註解的方法,我這些方法會返回一個統一的格式,如果是要返回別的視圖就要自己定義註解加其他參數了

JSR-303原生支持的校驗註解也是有限的,如果要實現其他的驗證,可以自己拓展,拓展方法就下次再說了,我也纔剛接觸。


發佈了4 篇原創文章 · 獲贊 19 · 訪問量 39萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章