驗證
概述
● 概述
1. 對輸入的數據(比如表單數據),進行必要的驗證,并給出相應的提示信息。
2. 對于驗證表單數據,springMVC提供了很多實用的注解, 這些注解由JSR303 驗證框架提供.
●JSR 303 驗證框架
1. JSR 303 的含義
JSR(Java Specification Request)是 Java 社區提案的縮寫,由 Java Community Process(JCP)管理。每個 JSR 對應一項 Java 技術規范,例如 JSR 303 即第 303 號提案
2. JSR 303 是 Java 為 Bean 數據合法性校驗提供的標準框架,它已經包含在 JavaEE 中
3. JSR 303 通過在 Bean 屬性上標注類似于 @NotNull、@Max 等標準的注解指定校驗規則, 并通過標準的驗證接口對 Bean 進行驗證
4. JSR 303 提供的基本驗證注解有:?
●HibernateValidator擴展注解
1.HibernateValidator和Hibernate沒有關系,只是JSR303實現的一個擴展.
2.HibernateValidator是JSR303的一個參考實現,除支持所有標準的校驗注解外,它還支 持以下的擴展注解:
3.擴展注解有如下
應用實例
1. 引入驗證和國際化相關的jar包
2.?修改Monster.java
@NotEmpty//表示該字段不能為null,或者String不為"",或者集合、映射的size != 0,這樣的情況。//Asserts that the annotated string, collection, map or array is not null or empty.private String name;@Range(min = 1, max = 200)//表示取值范圍在1-200之間private Integer age;
3.修改MonsterHandler.java
/*** 編寫方法,處理添加妖怪* 1.springmvc可以將提交的數據,按照參數名和對象的屬性名匹鹿配* 2.直接封裝到對象中->前面講解模型數據時,講過* String =>Integer* 3.@Valid Monster monster:表示對monster接收的數據進行校驗* 4.Errors errors表示如果校驗出現錯誤,將校驗的錯誤信息保存errors* 5.Map<String,Object>map表示如果校驗出現錯誤,將校驗的錯誤信息保存至map;同時保存monster對象(與errors的區別)* 6.校驗發生的時機: 在springmvc底層,反射調用目標方法時,會接收到http請求的數據,然后根據注解來進行驗證,* 在驗證過程中,如果出現了錯誤,就把錯誤信息填充errors 和 map*/@RequestMapping("/save")//這兒的monster,springMVC會進行自動裝配public String addMonster(@Valid Monster monster, Errors errors ,Map<String, Object> map) {System.out.println(monster);System.out.println("=========errors===========");List<ObjectError> allErrors = errors.getAllErrors();for(ObjectError error : allErrors) {System.out.println("error=" + error);}System.out.println("==========map============");for (Map.Entry<String,Object> entry : map.entrySet()) {System.out.println("key=" + entry.getKey() + " value=" + entry.getValue());}return "success";}
4.測試
和預期一樣,姓名空報錯,年齡超出范圍。
驗證信息回顯至頁面
1.修改monster_addUI.jsp,添加errors標簽
妖怪姓名:<s:input path="name" /><s:errors path="name"/><br><br>妖怪年齡:<s:input path="age" /><s:errors path="age"/><br><br>電子郵件:<s:input path="email"/><s:errors path="email"/><br><br>妖怪生日:<s:input path="birthday"/><s:errors path="birthday"/> 要求以"9999-11-11"的形式<br><br>妖怪薪水:<s:input path="salary"/>><s:errors path="salary"/> 要求以"123,890.12"的形式<br><br>
2.修改MonsterHandler
? ? ? ? 發現報錯,便阻止進入到下一個頁面,返回當前輸入頁面。
System.out.println("==========map============");for (Map.Entry<String,Object> entry : map.entrySet()) {System.out.println("key=" + entry.getKey() + " value=" + entry.getValue());}//交換了map和errors的代碼順序,是因為map有monster,通常不會為nullSystem.out.println("=========errors===========");if(errors.hasErrors()){List<ObjectError> allErrors = errors.getAllErrors();for(ObjectError error : allErrors) {System.out.println("error=" + error);}return "datavalid/monster_addUI";}return "success";
3.測試
? ? ? ? 可以看到返回的錯誤信息了。
國際化/自定義驗證信息
概念
????????國際化(簡稱?i18n,因“internationalization”一詞首尾字母間有18個字符)是指設計和開發軟件、產品或服務時,使其能夠適應不同語言、地區和文化需求的技術與流程。核心目標是無需重構代碼或設計,即可快速適配多語言和多區域市場。
應用實例
原始的生日和薪水報錯是用英文顯示的:
1.配置國際化文件,springMVC-servlet.xml中添加bean
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"><!--屬性作用: 配置國際化文件名字--><!--如果你這樣配的話,表示messageSource會到src/i18nXXX.properties去讀取錯誤信息--><property name="basename" value="i18n"/></bean>
2.創建src/i18n.properties
? ? ? ? 這兒的文件名,和上面的配置文件一致
? ? ? ? 等號=前面的key,來自于報錯代碼的第一個字段,比如:
????????????????[NotEmpty.monster.name, ...],[Range.monster.age, ...]
? ? ? ? 等號=后面的value值,是unicode編碼,可以在相應的工具網站“unicode編碼轉換工具”中查詢
NotEmpty.monster.name=\u59d3\u540d\u4e0d\u80fd\u4e3a\u7a7a
Range.monster.age=\u5e74\u9f84\u9700\u8981\u5728\u0031\u81f3\u0032\u0030\u0030\u5c81\u4e4b\u95f4
typeMismatch.monster.birthday=\u751f\u65e5\u683c\u5f0f\u4e0d\u6b63\u786e
typeMismatch.monster.salary=\u85aa\u6c34\u5fc5\u987b\u5168\u90e8\u662f\u6570\u5b57
?3.測試
? ? ? ? 可以看到報錯回顯的內容,全部按照自己定義的內容進行顯示了。??
細節說明和注意事項
1. 在需要驗證的 Javabean/POJO的字段上加上相應的驗證注解.
2. 目標方法上,在 JavaBean/POJO 類型的參數前, 添加 @Valid 注解. 告知 SpringMVC 該 bean 是需要驗證的
3. 在 @Valid 注解之后, 添加一個 Errors 或 BindingResult 類型的參數, 可以獲取到驗證 的錯誤信息
4. 需要使用 標簽來顯示錯誤消息, 這個標簽, 需要寫在 springMVC的標簽<s:form>內生效.
5. 錯誤消息的國際化文件i18n.properties, 中文需要是Unicode編碼,使用工具轉碼.
√ 格式: 驗證規則:表單modelAttribute值.屬性名 = 消息信息
√ NotEmpty.monster.name=\u540D\u5B57\u4E0D\u80FD\u4E3A\u7A7A
√ typeMismatch.monster.age=\u7C7B\u578B\u4E0D\u5339\u914D
6. 注解@NotNull 和 @NotEmpty 的區別說明
1) 查看源碼可以知道 :
@NotEmptyAsserts that the annotated string, collection, map or array is not {@code null} or empty.
2) 查看源碼可以知道 :
@NotNull*Theannotated element must not be {@code null}.* Accepts any type.
種類 | 修飾類型 | 作用 |
---|---|---|
@NotEmpty | String, collection, map | null || size=0 |
@NotNull | 任意類型 | null |
3) 解讀:如果是字符串驗證空, 建議使用 @NotEmpty
7. SpingMVC 驗證時,會根據不同的驗證錯誤, 返回對應的信息
注解的組合使用
1.注解可以組合使用比如
@Range+@NotNull
2.返回的錯誤信息,除了通過國際化進行配置外,還可以通過注解的屬性來修改
@NotNull(message="不能為空")
3.測試發現,同時配置了message和國際化的情況下,會優先顯示國際化配置的信息。
DataBinder工作機制-了解
圖例Spring MVC通過反射機制對目標方法進行解析,將請求消息綁定到處理方法的入參中。數據綁定的核心部件是DataBinder,運行機制如下
1.Tomcat封裝請求到ServletRequest
2.處理方法入參對象
3.進行數據類型轉換/格式化。ConversionService轉換服務,如果轉換出現錯誤,就會封裝到最后的5BindingResult中
4.進行數據校驗,出錯也會封裝到5BindResult中
5.返回數據轉換和數據校驗的結果
error的運行類型是BeanPropertyBindingResult
,?BeanPropertyBindingResult
實現了BindingResult
接口
取消屬性綁定
說明
在默認情況下,表單提交的數據都會和pojo類型的javabean屬性綁定,如果程序員在開發中,希望取消某個屬性的綁定,也就是說,不希望接收到某個表單對應的屬性的值,則可以通過
@InitBinder注解取消綁定
POJO(Plain Old Java Object - 簡單的 Java 對象):?一個普通的、不依賴特定框架的 Java 類。表單綁定的目標對象首先是一個 POJO。
JavaBean:?一種遵循特定嚴格約定(無參構造、私有屬性、公共標準 Getter/Setter)的 POJO。正是這些約定使得 Web 框架能夠自動將表單提交的數據綁定到對象的屬性上。
上面粗體子含義:?在 Spring MVC 等框架中,如果你創建一個符合 JavaBean 規范的類(比如?
User
),并將其作為控制器方法的參數(如?public String submitForm(User user)
),那么框架在默認情況下,就能自動將 HTTP 請求中提交的表單字段的值,通過調用該?User
?對象的對應 Setter 方法,填充到它的屬性中去。這就是“表單提交的數據都會和 POJO 類型的 JavaBean 屬性綁定”的意思。這里的“POJO 類型”強調目標是一個普通 Java 類,“JavaBean” 強調這個類需要遵循 JavaBean 規范以實現自動綁定。Entity:?一種特殊用途的 POJO/JavaBean,用于代表需要持久化到數據庫的業務核心對象。它通過注解添加了數據庫映射的元數據(映射到哪個表、哪個是主鍵、字段映射、關系映射等)。強調與數據庫的映射關系。
1.編寫一個方法,使用@InitBinder標識的該方法,可以對WebDataBinder對象進行初始化。
????????WebDataBinder是DataBinder的子類,用于完成由表單字段到JavaBean屬性的綁定
2.@InitBinder方法不能有返回值,它必須聲明為void.
3.@InitBinder方法的參數通常是是WebDataBinder
應用實例
1.給MonsterHandler.java添加方法
@InitBinderpublic void initBinder(WebDataBinder webDataBinder) {/*** 解讀* 1.方法上需要標注@InitBinder springmvc底層會初始化WebDataBinder* 2.調用webDataBinder.setDisallowedFields("name")表示取消指定屬性的綁定* 即:當表單提交字段為name時,就不在把接收到的name值,填充到model數據monster的name屬性* 3.機制:springmvc在底層通過反射調用目標方法時,接收到http請求的參數和值,使用反射+注解* 技術取消對指定屬性的填充* 4.setDisallowedFields支特可變參數,可以填寫多個字段。比如("name","email")* 5.如果我們取消某個屬性綁定,驗證就沒有意義了,應當把驗證的注解去掉,否則容易出錯* //@NotEmpty(message="不能為空")* private String name;*/webDataBinder.setDisallowedFields("name");}
2.測試
后臺輸出:
name='null'
注意這兒的'null'就是null的意思。