SpringMVC4+thymeleaf3的一個簡單實例(篇四:form表單數據驗證)

關於表單數據驗證有不少中方法,這裏我僅介紹JSR303註解驗證。
JSR303僅僅是一個規範,這裏咱們要用到它的一個實現:hibernate-validator。html


注意在spring的配置文件spring-mvc.xml中要有這句代碼:<mvc:annotation-driven/>,有了它,spring框架會自動加載classpath的jsr303的實現。java

開工以前,咱們須要引入如下lib文件到WEB-INF/lib,並添加到classpath:
validation-api-1.1.0.Final.jar
classmate-1.3.1.jar
jboss-logging-3.3.0.Final.jar
hibernate-validator-5.3.2.Final.jar
以上jar文件都在hibernate-validator-5.3.2.Final-dist.zip這裏,官網下載http://hibernate.org/validator/

延續前面篇節的內容。

1、修改AnimalForm.Java類,在oname,ocount,memo字段上分別加上驗證註解,代碼以下:web

 1     package com.zoo.web.form;  
 2       
 3     import javax.validation.constraints.NotNull;  
 4     import javax.validation.constraints.Size;  
 5       
 6     import org.hibernate.validator.constraints.NotEmpty;  
 7     import org.hibernate.validator.constraints.Range;  
 8       
 9     public class AnimalForm {  
10       
11         private long id;  
12           
13         @NotEmpty(message="動物名: 不能爲空")   
14         private String oname;  
15           
16         @Range(min = 1, message="數量: 必須大於0")  
17         @NotNull(message="數量: 不能爲空")  
18         private int ocount;  
19           
20         @Size(max = 10, message="備註: 長度不能超過10個字符")  
21         private String memo;  
22       
23         /** 省略getter和setter **/  
24       
25           
26     }  

解釋
@NotEmpty:這個註解表示檢查oname字段是否是爲空字符串""或者是否是爲null,若是是則給出提示信息:"動物名:不能爲空"。
它支持的類型包括:字符序列CharSequence(CharBuffer, Segment, String, StringBuffer, StringBuilder);集合Collection(ArrayList, HashSet, Stack, Vector等,不少);Map以及數組arrays。它將檢查所給對象的是否是爲empty或者null,empty也就是長度爲0,對於字符串來講就是""。

@NotNull:檢查所標註元素ocount不能爲null,若是是則給出提示信息:「數量:不能爲空」。
它支持任意類型,檢查標註對象是否爲null。注意和@NotEmpty的區別,她不檢查對象是否是爲empty。empty對於字符串來講是空字符串,對於集合以及map或數組來講就是所含元素數量爲0。

@Range(min=, max=):表示ocount元素的最小值是1,若是小於1,則給出信息:「數量:必須大於0」。
支持類型:BigDecimal, BigInteger, CharSequence, byte, short, int, long 以及這些原始類型對應的wrapper(包裝類)。它將檢查所給對象的值是否是大於等於min且小於等於max。

@Size(min=, max=):檢查memo對象的長度不能超過10, 不然提示:「備註:長度不能超過10個字符」。
適用於CharSequence, Collection, Map 以及數組,檢查標註對象的size是大於等於min而且小於等於max。

注意這麼作驗證是有問題的,好比oname輸入幾個空格它會驗證經過,而對於ocount,在輸入整數的狀況下這徹底沒有問題,可是若是咱們輸入帶小數點的數字或者輸入非數字,或者空字符串的時候程序就會出現exception,這不是咱們所但願的,具體的改進代碼咱們在篇末說明。

關於hibernate validator詳細介紹請參閱 reference http://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/

2、修改ZooController裏的doAdd方法正則表達式

 1     @RequestMapping(path = "/list", params = {"save"}, method = RequestMethod.POST)  
 2         public String doAdd(Model model, @Valid AnimalForm form, BindingResult result){  
 3             System.out.println("動物名:" + form.getOname());  
 4             System.out.println("數量:" + form.getOcount());  
 5             System.out.println("備註:" + form.getMemo());  
 6             if(result.hasErrors()){  
 7                 model.addAttribute("MSG", "出錯啦!");  
 8             }else{  
 9                 model.addAttribute("MSG", "提交成功!");  
10             }  
11             return "zoolist";  
12         }  

解釋:
方法中Model參數,用於存聽任意數據以便傳遞到頁面,注意Model僅僅是一個接口,spring框架會幫咱們實例化具體的類並設置到該方法當中;上例咱們在該model裏放了一個key爲「MSG」的attribute,頁面上經過表達式就能夠取得其值。

@Valid AnimalForm form,@Valid表示要對該form進行驗證,具體驗證規則就是根據上面【一】裏提到;spring框架會根據字段名稱將頁面傳遞過來的值綁定到animalForm中。

BindingResult result,spring框架會將驗證結果設置到該參數,並將該參數放到model傳遞給頁面。

springMVC是很是靈活的,如下幾種寫法能夠達到一樣的效果:
(1)spring

 1     @RequestMapping(path = "/list", params = {"save"}, method = RequestMethod.POST)  
 2         public ModelAndView doAdd(@Valid AnimalForm form, BindingResult result){  
 3             ModelAndView model = new ModelAndView();  
 4             System.out.println("動物名:" + form.getOname());  
 5             System.out.println("數量:" + form.getOcount());  
 6             System.out.println("備註:" + form.getMemo());  
 7             if(result.hasErrors()){  
 8                 model.addObject("MSG", "出錯啦!");  
 9             }else{  
10                 model.addObject("MSG", "提交成功!");  
11             }  
12             model.setViewName("zoolist");  
13             return model;  
14         }  

(2)數據庫

 1     @RequestMapping(path = "/list", params = {"save"}, method = RequestMethod.POST)  
 2         public ModelAndView doAdd(ModelAndView model, @Valid AnimalForm form, BindingResult result){  
 3             System.out.println("動物名:" + form.getOname());  
 4             System.out.println("數量:" + form.getOcount());  
 5             System.out.println("備註:" + form.getMemo());  
 6             if(result.hasErrors()){  
 7                 model.addObject("MSG", "出錯啦!");  
 8             }else{  
 9                 model.addObject("MSG", "提交成功!");  
10             }  
11             model.setViewName("zoolist");  
12             return model;  
13         }  

(3)api

1     @RequestMapping(path = "/list", params = {"save"}, method = RequestMethod.POST)  
2         public String doAdd(@Valid AnimalForm form, BindingResult result){  
3             System.out.println("動物名:" + form.getOname());  
4             System.out.println("數量:" + form.getOcount());  
5             System.out.println("備註:" + form.getMemo());  
6       
7             return "zoolist";  
8         }  

注意(1)(2)僅僅是ModelAndView實例化的方式不一樣而已,一個是本身手動實例化,一個是框架實例化;數組


(3)中咱們去掉了model參數,但這並不影響咱們的驗證以及將驗證結果傳遞到頁面,只不過是你不能經過model設置一些attribute到頁面了。瀏覽器


這裏說一下Model和ModelAndView的區別:
Model主要用於將數據傳遞到頁面,通常採用model.addAttribute("key", object)的方式,頁面經過各類表達式將其顯示出來;
ModelAndView有兩個做用,一個是上面Model的做用;另外一個就是能夠設置view,也就是跳轉方向,view既能夠是字符串,也能夠是View類型的object。

3、添加代碼到zoolist.htmlspring-mvc

1     <div th:text="${MSG}">這裏是信息提示.</div>  
2         <br>  
3             <div th:errors="${animalForm.oname}"></div>  
4             <div th:errors="${animalForm.ocount}"></div>  
5             <div th:errors="${animalForm.memo}"></div>  

完整的內容:

    <!DOCTYPE html>  
    <html xmlns:th="http://www.thymeleaf.org">  
    <head>  
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
    <title>zoo list</title>  
    </head>  
    <body>  
    <a href='.'>首頁</a>->動物列表  
        <br><br>  
            <div th:text="${MSG}">這裏是信息提示.</div>  
        <br>  
            <div th:errors="${animalForm.oname}"></div>  
            <div th:errors="${animalForm.ocount}"></div>  
            <div th:errors="${animalForm.memo}"></div>  
        <br>  
        <form id="iform" th:action="@{/list.html?save}" th:method="post" th:object="${animalForm}">  
            <table border="1">    
              <tr>   
                <th>動物名稱</th>    
                <th>數量</th>   
                <th>備註</th>  
                <th>Action</th>  
              </tr>    
              <tr>   
                <td><input type="text" name="oname" value="" th:value="*{oname}"/></td>  
                <td><input type="text" name="ocount" value="" th:value="*{ocount}"/></td>  
                <td><input type="text" name="memo" value="" th:value="*{memo}"/></td>  
                <td><input type="submit" value="添加"/></td>  
              </tr>  
            </table>  
        </form>  
        <hr>  
        <table border="1">    
          <tr>  
            <th>序號</th>  
            <th>動物名稱</th>    
            <th>數量</th>   
            <th>備註</th>  
          </tr>  
          <tr>  
            <td>1</td>  
            <td>大馬猴</td>  
            <td>10</td>  
            <td>機靈古怪,俏皮活潑</td>  
          </tr>  
          <tr>  
            <td>2</td>  
            <td>大熊貓</td>  
            <td>80</td>  
            <td>體型笨重,喜歡吃竹子</td>  
          </tr>  
          <tr>  
            <td>3</td>  
            <td>澳洲羊駝</td>  
            <td>13</td>  
            <td>長相奇特,大國人俗稱其草泥馬</td>  
          </tr>  
          <tr>  
            <td>4</td>  
            <td>峨眉山猴</td>  
            <td>90</td>  
            <td>不怕人,有時候發賤搶遊客麪包吃</td>  
          </tr>  
        </table>  
    </body>  
    </html>  

解釋:
<div th:text="${MSG}">這裏是信息提示.</div>,還記得前面controller的代碼中咱們在返回頁面的model中放了一個attribute名字叫「MSG」麼,對了,在這裏咱們就能夠經過表達式th:text="${MSG}"取得其值了。thymeleaf解析這個標籤的時候會將「這裏是信息提示.」這個字符串替換成「MSG」對應的內容。

<div th:errors="${animalForm.oname}"></div>,thymeleaf使用th:errors表達式能夠取得錯誤信息的內容,${animalForm.oname}表示取得animalForm裏oname字段的錯誤信息;若是驗證oname字段時出現錯誤,那麼在這個div裏面會顯示出該錯誤信息。

關於thymeleaf的validate表達式詳細介紹請參閱 http://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html#validation-and-error-messages

好了,咱們該修改的都完成了,重啓tomcat進入瀏覽器吧,個人效果以下:
驗證有錯誤的狀況:

驗證經過的效果:

好啦,若是你也作到這個樣子,也就算達到本篇的目的了,這個頁面雖然很簡陋,用的也都是靜態數據,但這基本上展現瞭如何使用@valid作form驗證。

關於驗證改進:
對於oname:咱們能夠換成@NotBlank註解,它能夠將全是空格的字符串做爲空字符串,和@NotEmpty不一樣的是,@NotBlank只可用於CharSequence類型,並檢查該元素是否爲null或者該元素通過trim以後的長度是否爲0。

對於ocount:咱們把驗證代碼修改成:

    @NotBlank(message="數量: 不能爲空")  
    @Pattern(regexp="[1-9]{1,3}", message="數量X: 必須爲正整數,而且0<X<1000")  
    private String ocount; 

@Pattern,一看便知這是用正則表達式作檢查,[1-9]{1,3}表示三位正整數而且要大於0。
若是你對正則表達式還不瞭解,能夠參閱javaSE的api文檔:http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html


對於一些特殊的驗證,你能夠定義本身的驗證類,既能夠實現springMVC的validator接口,也能夠實現JSR303的註解約束方式驗證,這裏採用JSR303方式。
1, 建立package:com.zoo.constraint,以及com.zoo.constraint.impl。
2, 在com.zoo.constraint中定義Annotation類型Memo:

 1     package com.zoo.constraint;  
 2       
 3     import static java.lang.annotation.ElementType.FIELD;  
 4     import static java.lang.annotation.ElementType.METHOD;  
 5     import static java.lang.annotation.RetentionPolicy.RUNTIME;  
 6       
 7     import java.lang.annotation.Retention;  
 8     import java.lang.annotation.Target;  
 9       
10     import javax.validation.Constraint;  
11     import javax.validation.Payload;  
12       
13     import com.zoo.constraint.impl.MemoValidator;  
14       
15     @Retention(RUNTIME)  
16     @Target({ FIELD, METHOD })  
17     @Constraint(validatedBy=MemoValidator.class)  
18     public @interface Memo {  
19           
20         String message() default "請輸入正確的備註";  
21           
22         Class<?>[] groups() default {};  
23           
24         Class<? extends Payload>[] payload() default {};  
25     }  

3, 在com.zoo.constraint.impl中定義類MemoValidator:

 1     package com.zoo.constraint.impl;  
 2       
 3     import java.util.HashSet;  
 4       
 5     import javax.validation.ConstraintValidator;  
 6     import javax.validation.ConstraintValidatorContext;  
 7       
 8     import com.zoo.constraint.Memo;  
 9       
10     public class MemoValidator implements ConstraintValidator<Memo, String> {  
11       
12         @Override  
13         public void initialize(Memo arg0) {  
14         }  
15       
16         @Override  
17         public boolean isValid(String arg0, ConstraintValidatorContext arg1) {  
18             HashSet<String> memoSet = new HashSet<String>();  
19             memoSet.add("圈養");  
20             memoSet.add("散養");  
21             return memoSet.contains(arg0);  
22         }  
23       
24     }  

4, 修改AnimalForm類:

 1     package com.zoo.web.form;  
 2       
 3     import javax.validation.constraints.Pattern;  
 4       
 5     import org.hibernate.validator.constraints.NotBlank;  
 6       
 7     import com.zoo.constraint.Memo;  
 8       
 9     public class AnimalForm {  
10       
11         private long id;  
12           
13         @NotBlank(message="動物名: 不能爲空")   
14         private String oname;  
15           
16         @Pattern(regexp="[1-9]{1,3}", message="數量X不能爲空,必須爲正整數,而且0<X<1000")  
17         private String ocount;  
18           
19         @Memo(message = "備註不能爲空,且只能填寫\"圈養\",或者\"散養\"")  
20         private String memo;  
21       
22         /** getters and setters **/  
23     }  

ok!重啓tomcat,進入瀏覽器,在三個字段都不輸入的狀況下,個人界面以下:

 

 本篇就此結束,是否是很簡單呢,這裏只是拋磚引玉作一個極簡的介紹,如需深刻了解請參閱官方文檔。下一篇是數據持久化之保存在MySQL數據庫。

相關文章
相關標籤/搜索