一、數(shù)據(jù)綁定流程
1. Spring MVC 主框架將 ServletRequest 對象及目標(biāo)方法的入?yún)?shí)例傳遞給 WebDataBinderFactory 實(shí)例,以創(chuàng)建 DataBinder 實(shí)例對象
2. DataBinder 調(diào)用裝配在 Spring MVC 上下文中的ConversionService 組件進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換、數(shù)據(jù)格式化工作。將 Servlet 中的請求信息填充到入?yún)ο笾?/p>
3. 調(diào)用 Validator 組件對已經(jīng)綁定了請求消息的入?yún)ο筮M(jìn)行數(shù)據(jù)合法性校驗(yàn),并最終生成數(shù)據(jù)綁定結(jié)果BindingData 對象
4. Spring MVC 抽取 BindingResult 中的入?yún)ο蠛托r?yàn)錯(cuò)誤對象,將它們賦給處理方法的響應(yīng)入?yún)?/p>
5. Spring MVC 通過反射機(jī)制對目標(biāo)處理方法進(jìn)行解析,將請求消息綁定到處理方法的入?yún)⒅?。?shù)據(jù)綁定的核心部件是DataBinder,運(yùn)行機(jī)制如下



二、數(shù)據(jù)轉(zhuǎn)換
Spring MVC 上下文中內(nèi)建了很多轉(zhuǎn)換器,可完成大多數(shù) Java 類型的轉(zhuǎn)換工作。

三、自定義類型轉(zhuǎn)換器
(1)ConversionService 是 Spring 類型轉(zhuǎn)換體系的核心接口。
(2)可以利用 ConversionServiceFactoryBean 在 Spring 的 IOC容器中定義一個(gè)ConversionService. Spring 將自動識別出IOC 容器中的 ConversionService,并在 Bean 屬性配置及Spring MVC 處理方法入?yún)⒔壎ǖ葓龊鲜褂盟M(jìn)行數(shù)據(jù)的轉(zhuǎn)換。
(3)可通過 ConversionServiceFactoryBean 的 converters 屬性 注冊自定義的類型轉(zhuǎn)換器。?
四、Spring 支持的轉(zhuǎn)換器
Spring 定義了 3 種類型的轉(zhuǎn)換器接口,實(shí)現(xiàn)任意一個(gè)轉(zhuǎn)換器接口都可以作為自定義轉(zhuǎn)換器注冊到ConversionServiceFactroyBean 中:
(1)Converter<S,T>:將 S 類型對象轉(zhuǎn)為 T 類型對象
(2)ConverterFactory:將相同系列多個(gè) “同質(zhì)” Converter 封裝在一 起。如果希望將一種類型的對象轉(zhuǎn)換為另一種類型及其子類的對 象(例如將 String 轉(zhuǎn)換為 Number 及 Number 子類(Integer、Long、Double 等)對象)可使用該轉(zhuǎn)換器工廠類
(3)GenericConverter:會根據(jù)源類對象及目標(biāo)類對象所在的宿主類中的上下文信息進(jìn)行類型轉(zhuǎn)換
五、自定義轉(zhuǎn)換器示例
(1)input.jsp

(2)控制層

(3)自定義的轉(zhuǎn)換器

(4)配置

(5)輸入

(6)添加成功

六、關(guān)于 mvc:annotation-driven
<mvc:annotation-driven />會自動注冊RequestMappingHandlerMapping、RequestMappingHandlerAdapter 與ExceptionHandlerExceptionResolver 三個(gè)bean。
還將提供以下支持:
(1)支持使用 ConversionService 實(shí)例對表單參數(shù)進(jìn)行類型轉(zhuǎn)換
(2)支持使用 @NumberFormat annotation、@DateTimeFormat注解完成數(shù)據(jù)類型的格式化
(3)支持使用 @Valid 注解對 JavaBean 實(shí)例進(jìn)行 JSR 303 驗(yàn)證
(4)支持使用 @RequestBody 和 @ResponseBody 注解
既沒有配置<mvc:default-servlet-handler/>也沒有配置<mvc:annotation-driven/>

配置了<mvc:default-servlet-handler/>但沒有配置<mvc:annotation-driven/>

既配置了<mvc:default-servlet-handler/>又配置<mvc:annotation-driven/>

七、@InitBinder
由 @InitBinder 標(biāo)識的方法,可以對 WebDataBinder 對 象進(jìn)行初始化。WebDataBinder 是 DataBinder 的子類,用 于完成由表單字段到 JavaBean 屬性的綁定
@InitBinder方法不能有返回值,它必須聲明為void。
@InitBinder方法的參數(shù)通常是是 WebDataBinder



八、數(shù)據(jù)格式化
對屬性對象的輸入/輸出進(jìn)行格式化,從其本質(zhì)上講依然 屬于 “類型轉(zhuǎn)換” 的范疇。
Spring 在格式化模塊中定義了一個(gè)實(shí)現(xiàn)ConversionService 接口的FormattingConversionService 實(shí)現(xiàn)類,該實(shí)現(xiàn)類擴(kuò)展 了 GenericConversionService,因此它既具有類型轉(zhuǎn)換的 功能,又具有格式化的功能
FormattingConversionService 擁有一個(gè) FormattingConversionServiceFactroyBean 工廠類,? 后者用于在 Spring 上下文中構(gòu)造前者
FormattingConversionServiceFactroyBean 內(nèi)部已經(jīng)注冊了 :
(1)NumberFormatAnnotationFormatterFactroy:支持對數(shù)字類型的屬性 使用 @NumberFormat 注解
(2)JodaDateTimeFormatAnnotationFormatterFactroy:支持對日期類型 的屬性使用 @DateTimeFormat 注解
裝配了 FormattingConversionServiceFactroyBean 后,就可以在 Spring MVC 入?yún)⒔壎澳P蛿?shù)據(jù)輸出時(shí)使用注解驅(qū)動 了。
<mvc:annotation-driven/>默認(rèn)創(chuàng)建的ConversionService 實(shí)例即為FormattingConversionServiceFactroyBean
日期格式化
@DateTimeFormat 注解可對java.util.Date、java.util.Calendar、java.long.Long 時(shí)間 類型進(jìn)行標(biāo)注:
pattern 屬性:類型為字符串。指定解析/格式化字段數(shù)據(jù)的模式, 如:”yyyy-MM-dd hh:mm:ss”
iso 屬性:類型為 DateTimeFormat.ISO。指定解析/格式化字段數(shù)據(jù) 的ISO模式,包括四種:ISO.NONE(不使用) -- 默認(rèn)、ISO.DATE(yyyy-MM-dd) 、ISO.TIME(hh:mm:ss.SSSZ)、ISO.DATE_TIME(yyyy-MM-dd hh:mm:ss.SSSZ)
style 屬性:字符串類型。通過樣式指定日期時(shí)間的格式,由兩位字符組成,第一位表示日期的格式,第二位表示時(shí)間的格式:S:短日 期/時(shí)間格式、M:中日期/時(shí)間格式、L:長日期/時(shí)間格式、F:完整日期/時(shí)間格式、-:忽略日期或時(shí)間格式
數(shù)值格式化
@NumberFormat 可對類似數(shù)字類型的屬性進(jìn)行標(biāo) 注,它擁有兩個(gè)互斥的屬性:
style:類型為 NumberFormat.Style。用于指定樣式類型,包括三種:Style.NUMBER(正常數(shù)字類型)、Style.CURRENCY(貨幣類型)、 Style.PERCENT(? 百分?jǐn)?shù)類型)
pattern:類型為 String,自定義樣式, 如patter="#,###";



配置了這個(gè)還是沒有影響

轉(zhuǎn)換失敗


九、數(shù)據(jù)校驗(yàn)
JSR 303
JSR 303 是 Java 為 Bean 數(shù)據(jù)合法性校驗(yàn)提供的標(biāo)準(zhǔn)框架, 它已經(jīng)包含在 JavaEE 6.0 中 .
JSR 303 通過在 Bean 屬性上標(biāo)注類似于 @NotNull、@Max? 等標(biāo)準(zhǔn)的注解指定校驗(yàn)規(guī)則,并通過標(biāo)準(zhǔn)的驗(yàn)證接口對 Bean? 進(jìn)行驗(yàn)證

Hibernate Validator 擴(kuò)展注解
Hibernate Validator 是 JSR 303 的一個(gè)參考實(shí)現(xiàn),除支持 所有標(biāo)準(zhǔn)的校驗(yàn)注解外,它還支持以下的擴(kuò)展注解

Spring MVC 數(shù)據(jù)校驗(yàn)
Spring 4.0 擁有自己獨(dú)立的數(shù)據(jù)校驗(yàn)框架,同時(shí)支持 JSR303 標(biāo)準(zhǔn)的校驗(yàn)框架。
Spring 在進(jìn)行數(shù)據(jù)綁定時(shí),可同時(shí)調(diào)用校驗(yàn)框架完成數(shù)據(jù)校驗(yàn)工作。在 Spring MVC 中,可直接通過注解驅(qū)動的方式 進(jìn)行數(shù)據(jù)校驗(yàn)
Spring 的 LocalValidatorFactroyBean 既實(shí)現(xiàn)了 Spring 的Validator 接口,也實(shí)現(xiàn)了 JSR 303 的 Validator 接口。只要 在 Spring 容器中定義了一個(gè)LocalValidatorFactoryBean,即可將其注入到需要數(shù)據(jù)校驗(yàn)的 Bean 中。
Spring 本身并沒有提供 JSR303 的實(shí)現(xiàn),所以必須將JSR303 的實(shí)現(xiàn)者的 jar 包放到類路徑下。
<mvc:annotation-driven/>會默認(rèn)裝配好一個(gè)LocalValidatorFactoryBean,通過在處理方法的入?yún)⑸蠘?biāo)注 @valid 注解即可讓 Spring MVC 在完成數(shù)據(jù)綁定后執(zhí)行 數(shù)據(jù)校驗(yàn)的工作
在已經(jīng)標(biāo)注了 JSR303 注解的表單/命令對象前標(biāo)注一個(gè) @Valid,Spring MVC 框架在將請求參數(shù)綁定到該入?yún)ο?后,就會調(diào)用校驗(yàn)框架根據(jù)注解聲明的校驗(yàn)規(guī)則實(shí)施校驗(yàn)
Spring MVC 是通過對處理方法簽名的規(guī)約來保存校驗(yàn)結(jié)果 的:前一個(gè)表單/命令對象的校驗(yàn)結(jié)果保存到隨后的入?yún)⒅校@個(gè)保存校驗(yàn)結(jié)果的入?yún)⒈仨毷?BindingResult 或Errors 類型,這兩個(gè)類都位于org.springframework.validation 包中
需校驗(yàn)的 Bean 對象和其綁定結(jié)果對象或錯(cuò)誤對象時(shí)成對出現(xiàn)的,它們之間不允許聲明其他的入?yún)?/p>
Errors 接口提供了獲取錯(cuò)誤信息的方法,如 getErrorCount() 或getFieldErrors(String field)
BindingResult 擴(kuò)展了 Errors 接口
在目標(biāo)方法中獲取校驗(yàn)結(jié)果
在表單/命令對象類的屬性中標(biāo)注校驗(yàn)注解,在處理方法對 應(yīng)的入?yún)⑶疤砑?@Valid,Spring MVC 就會實(shí)施校驗(yàn)并將校 驗(yàn)結(jié)果保存在被校驗(yàn)入?yún)ο笾蟮?BindingResult 或Errors 入?yún)⒅小?/p>
常用方法:
FieldError getFieldError(String field)
List<FieldError> getFieldErrors()
Object getFieldValue(String field)
Int getErrorCount()
測試
(1)先導(dǎo)入相關(guān)的包

(2)給實(shí)體的屬性上添加校驗(yàn)的注解

(3)在控制層的入?yún)⑶凹由螥Valid,還有出錯(cuò)就轉(zhuǎn)向定制頁面

(4)驗(yàn)證結(jié)果

在頁面上顯示錯(cuò)誤
Spring MVC 除了會將表單/命令對象的校驗(yàn)結(jié)果保存到對 應(yīng)的 BindingResult 或 Errors 對象中外,還會將所有校驗(yàn) 結(jié)果保存到 “隱含模型”
即使處理方法的簽名中沒有對應(yīng)于表單/命令對象的結(jié)果 入?yún)?,校?yàn)結(jié)果也會保存在 “隱含對象” 中。
隱含模型中的所有數(shù)據(jù)最終將通過 HttpServletRequest 的 屬性列表暴露給 JSP 視圖對象,因此在 JSP 中可以獲取 錯(cuò)誤信息
在 JSP 頁面上可通過<form:errors path=“userName”>顯示錯(cuò)誤消息


提示消息的國際化
每個(gè)屬性在數(shù)據(jù)綁定和數(shù)據(jù)校驗(yàn)發(fā)生錯(cuò)誤時(shí),都會生成一 個(gè)對應(yīng)的 FieldError 對象。
當(dāng)一個(gè)屬性校驗(yàn)失敗后,校驗(yàn)框架會為該屬性生成 4 個(gè)消 息代碼,這些代碼以校驗(yàn)注解類名為前綴,結(jié)合modleAttribute、屬性名及屬性類型名生成多個(gè)對應(yīng)的消息代碼:例如 User 類中的 password 屬性標(biāo)準(zhǔn)了一個(gè) @Pattern 注 解,當(dāng)該屬性值不滿足 @Pattern 所定義的規(guī)則時(shí), 就會產(chǎn)生以下 4? 個(gè)錯(cuò)誤代碼:
Pattern.user.password
Pattern.password
Pattern.java.lang.String
Pattern
當(dāng)使用 Spring MVC 標(biāo)簽顯示錯(cuò)誤消息時(shí), Spring MVC 會查看WEB 上下文是否裝配了對應(yīng)的國際化消息,如果沒有,則顯示默認(rèn) 的錯(cuò)誤消息,否則使用國際化消息。


