關於表單數據驗證有不少中方法,這裏我僅介紹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數據庫。