SpringMVC支持的數據校驗是JSR303的標準,通過在bean的屬性上打上annotation @NotNull @Max等進行驗證。JSR303提供有很多annotation藉口,而SpringMVC對於這些驗證是使用hibernate的實現,所以我們需要添加hibernate的一個validator包:
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.4.1.Final</version> </dependency>hibernate除了JSR303的標準之外還額外提供了其他的驗證annotation。
以下是JSR303和hibernate額外支持的驗證annotation,這個表是我在IBM官網找到的:
Bean Validation 中的 constraint
表 1. Bean Validation 中內置的 constraint
表 2. Hibernate Validator 附加的 constraint
貼出一下IBM這篇文章的地址:https://www.ibm.com/developerworks/cn/java/j-lo-jsr303/如果我們需要在SpringMVC中使用validator需要定義一個bean
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
然後 <mvc:annotation-driven />會自動掃描上下文去發現這個bean。
然後在相應的類屬性中綁定相關的驗證annotation,下面以User類爲例:
@NumberFormat(pattern = "#,###.##") @DecimalMax(value = "2000") @DecimalMin(value = "1000") @NotNull private long balance;使用Pattern註解可以直接綁定正則表達式:
@Pattern(regexp = "w{6,20}") private String username;
以下是精簡過的User類:
public class User{ private int userId; @Pattern(regexp = "w{6,20}") private String username; private String pwd; @DateTimeFormat(pattern = "yyyy-MM-dd") private Date registerDate; @NumberFormat(pattern = "#,###.##") @DecimalMax(value = "2000") @DecimalMin(value = "1000") @NotNull private long balance; }然後我們可以在controller中進行驗證測試:
@RequestMapping("/validator.html") public ModelAndView validatorTest(@Valid User user){ ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("user",user); modelAndView.setViewName("user/main"); return modelAndView; }
注意需要打上@Valid 註解標記需要進行屬性驗證。
我們嘗試去調用這個處理器會發現,只要驗證不成功就直接報錯:
但是我們並不希望這樣,希望如果在發現驗證錯誤的時候跳轉至合適的頁面,然後發現其錯誤並提示用戶,所以我們需要用到BindingResult類去獲得驗證的結果,BindingResult的常用方法有如下這些:
List<FieldError> getFieldErrors(); //獲得驗證失敗的字段錯誤信息
FieldError getFieldError(String var1); //獲得相應屬性名的驗證錯誤信息
Object getFieldValue(String var1); //獲得屬性的值
int getErrorCount(); //錯誤的數量
boolean hasErrors(); //是否存在錯誤
所以我們可以改成這樣:
@RequestMapping("/validator.html") public ModelAndView validatorTest(@Valid User user,BindingResult bindingResult){ ModelAndView modelAndView = new ModelAndView(); if (bindingResult.hasErrors()) { modelAndView.setViewName("user/login"); } else { modelAndView.addObject("user", user); modelAndView.setViewName("user/main"); } return modelAndView; }
然後我們喜歡在頁面上顯示錯誤,可以使用SpringMVC提供的form標籤庫,我們就以登錄頁面爲例,雖然這個頁面的業務不太切合實際業務,但是爲了方便演示就這樣寫:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <html> <head> <title>Register</title> </head> <body> <form:form modelAttribute="user" method="post" action="formatter.html"> <form:errors path="*"/> <p>userId:<input type="text" name="userId"/></p> <p>username:<input type="text" name="username"/></p> <p>password:<input type="password" name="password"/></p> <form:errors path="balance"/> <p>balance:<input type="text" name="balance"/></p> <form:errors path="registerDate"/> <p>registerDate:<input type="text" name="registerDate"/></p> <button type="submit">Login</button> </form:form> <img src="<c:url value="/test/test.jpeg" />"/> </body> </html>
注意幾個重點即可:
1、使用標籤庫
2、使用<form:from>的標籤然後定義這個提交的modelAttribute名稱。
3、將使用標籤<form:error path="相應的屬性">path屬性可以使用通配符*代表輸出全部錯誤。
4、在controller的處理方法中在user對象的入參中打上annotation @ModelAttribute,如下:
@RequestMapping("/formatter.html") public ModelAndView userDetail(@ModelAttribute("user") @Valid User user, BindingResult bindingResult) { ModelAndView modelAndView = new ModelAndView(); if (bindingResult.hasErrors()) { modelAndView.setViewName("user/login"); } else { modelAndView.addObject("user", user); modelAndView.setViewName("user/main"); } return modelAndView; }
然後我們嘗試進行方法這個頁面,並輸入無法通過驗證的表單數據:
然後我們希望可以輸出的是中文,需要使用國際化,Spring也支持這一操作,只要添加一個bean:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource" p:basename="conf/i18n/messages"></bean>
這裏bean有一個basename屬性,這個屬性就是相應的國際化配置文件位置,以下是配置文件的內容[文件位置:conf/i18n/messages.properties]:
DecimalMin.user.balance=請輸入大於等於1000的數 DecimalMax.user.balance=請輸入小於等於2000的數可以看到格式是<驗證的annotation名稱>.<modelAttribute名稱>.<驗證參數名稱>=相應的錯誤提示。
然後當再次測試時就會發現輸出的是中文的了。
最後說兩句:其實我們沒有必要在Spring中輸出這些錯誤提示,因爲一般情況下這些驗證都會又前段JS完成,而且現在也有angularJS這種強大的JS框架足夠完成驗證工作,我們的驗證目的是避免有用戶沒有經過JS驗證直接提交參數,從業務安全性去考慮使用服務器驗證,而不是爲了在界面顯示這寫驗證提示信息。而且現在也比較少直接提交form表單了,基本上大部分都是依賴於ajax。而且angularJS那種單頁面應用程序也受到很多開發的青睞,所以說我們最終服務器驗證是作爲一個最後防線,從而提供安全可靠的服務。