一到踏、數(shù)據(jù)綁定流程
1. Spring MVC 主框架將 ServletRequest 對(duì)象及目標(biāo)方法的入?yún)?shí)例傳遞給 WebDataBinderFactory 實(shí)例韭脊,以創(chuàng)建 DataBinder 實(shí)例對(duì)象
2. DataBinder 調(diào)用裝配在 Spring MVC 上下文中的ConversionService 組件進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換芥被、數(shù)據(jù)格式化工作诽里。將 Servlet 中的請(qǐng)求信息填充到入?yún)?duì)象中
3. 調(diào)用 Validator 組件對(duì)已經(jīng)綁定了請(qǐng)求消息的入?yún)?duì)象進(jìn)行數(shù)據(jù)合法性校驗(yàn)手负,并最終生成數(shù)據(jù)綁定結(jié)果BindingData 對(duì)象
4. Spring MVC 抽取 BindingResult 中的入?yún)?duì)象和校驗(yàn)錯(cuò)誤對(duì)象,將它們賦給處理方法的響應(yīng)入?yún)?/p>
5. Spring MVC 通過反射機(jī)制對(duì)目標(biāo)處理方法進(jìn)行解析茬祷,將請(qǐng)求消息綁定到處理方法的入?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 將自動(dòng)識(shí)別出IOC 容器中的 ConversionService,并在 Bean 屬性配置及Spring MVC 處理方法入?yún)⒔壎ǖ葓龊鲜褂盟M(jìn)行數(shù)據(jù)的轉(zhuǎn)換最盅。
(3)可通過 ConversionServiceFactoryBean 的 converters 屬性 注冊(cè)自定義的類型轉(zhuǎn)換器突雪。?
四、Spring 支持的轉(zhuǎn)換器
Spring 定義了 3 種類型的轉(zhuǎn)換器接口檩禾,實(shí)現(xiàn)任意一個(gè)轉(zhuǎn)換器接口都可以作為自定義轉(zhuǎn)換器注冊(cè)到ConversionServiceFactroyBean 中:
(1)Converter<S,T>:將 S 類型對(duì)象轉(zhuǎn)為 T 類型對(duì)象
(2)ConverterFactory:將相同系列多個(gè) “同質(zhì)” Converter 封裝在一 起挂签。如果希望將一種類型的對(duì)象轉(zhuǎn)換為另一種類型及其子類的對(duì) 象(例如將 String 轉(zhuǎn)換為 Number 及 Number 子類(Integer、Long盼产、Double 等)對(duì)象)可使用該轉(zhuǎn)換器工廠類
(3)GenericConverter:會(huì)根據(jù)源類對(duì)象及目標(biāo)類對(duì)象所在的宿主類中的上下文信息進(jìn)行類型轉(zhuǎn)換
五、自定義轉(zhuǎn)換器示例
(1)input.jsp
(2)控制層
(3)自定義的轉(zhuǎn)換器
(4)配置
(5)輸入
(6)添加成功
六勺馆、關(guān)于 mvc:annotation-driven
<mvc:annotation-driven />會(huì)自動(dòng)注冊(cè)RequestMappingHandlerMapping戏售、RequestMappingHandlerAdapter 與ExceptionHandlerExceptionResolver 三個(gè)bean侨核。
還將提供以下支持:
(1)支持使用 ConversionService 實(shí)例對(duì)表單參數(shù)進(jìn)行類型轉(zhuǎn)換
(2)支持使用 @NumberFormat annotation、@DateTimeFormat注解完成數(shù)據(jù)類型的格式化
(3)支持使用 @Valid 注解對(duì) 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)識(shí)的方法搓译,可以對(duì) WebDataBinder 對(duì) 象進(jìn)行初始化。WebDataBinder 是 DataBinder 的子類锋喜,用 于完成由表單字段到 JavaBean 屬性的綁定
@InitBinder方法不能有返回值些己,它必須聲明為void。
@InitBinder方法的參數(shù)通常是是 WebDataBinder
八嘿般、數(shù)據(jù)格式化
對(duì)屬性對(duì)象的輸入/輸出進(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)注冊(cè)了 :
(1)NumberFormatAnnotationFormatterFactroy:支持對(duì)數(shù)字類型的屬性 使用 @NumberFormat 注解
(2)JodaDateTimeFormatAnnotationFormatterFactroy:支持對(duì)日期類型 的屬性使用 @DateTimeFormat 注解
裝配了 FormattingConversionServiceFactroyBean 后赛糟,就可以在 Spring MVC 入?yún)⒔壎澳P蛿?shù)據(jù)輸出時(shí)使用注解驅(qū)動(dòng) 了。
<mvc:annotation-driven/>默認(rèn)創(chuàng)建的ConversionService 實(shí)例即為FormattingConversionServiceFactroyBean
日期格式化
@DateTimeFormat 注解可對(duì)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 可對(duì)類似數(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)證接口對(duì) 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ū)動(dòng)的方式 進(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/>會(huì)默認(rèn)裝配好一個(gè)LocalValidatorFactoryBean,通過在處理方法的入?yún)⑸蠘?biāo)注 @valid 注解即可讓 Spring MVC 在完成數(shù)據(jù)綁定后執(zhí)行 數(shù)據(jù)校驗(yàn)的工作
在已經(jīng)標(biāo)注了 JSR303 注解的表單/命令對(duì)象前標(biāo)注一個(gè) @Valid庵楷,Spring MVC 框架在將請(qǐng)求參數(shù)綁定到該入?yún)?duì)象 后罢艾,就會(huì)調(diào)用校驗(yàn)框架根據(jù)注解聲明的校驗(yàn)規(guī)則實(shí)施校驗(yàn)
Spring MVC 是通過對(duì)處理方法簽名的規(guī)約來保存校驗(yàn)結(jié)果 的:前一個(gè)表單/命令對(duì)象的校驗(yàn)結(jié)果保存到隨后的入?yún)⒅校@個(gè)保存校驗(yàn)結(jié)果的入?yún)⒈仨毷?BindingResult 或Errors 類型尽纽,這兩個(gè)類都位于org.springframework.validation 包中
需校驗(yàn)的 Bean 對(duì)象和其綁定結(jié)果對(duì)象或錯(cuò)誤對(duì)象時(shí)成對(duì)出現(xiàn)的咐蚯,它們之間不允許聲明其他的入?yún)?/p>
Errors 接口提供了獲取錯(cuò)誤信息的方法,如 getErrorCount() 或getFieldErrors(String field)
BindingResult 擴(kuò)展了 Errors 接口
在目標(biāo)方法中獲取校驗(yàn)結(jié)果
在表單/命令對(duì)象類的屬性中標(biāo)注校驗(yàn)注解弄贿,在處理方法對(duì) 應(yīng)的入?yún)⑶疤砑?@Valid春锋,Spring MVC 就會(huì)實(shí)施校驗(yàn)并將校 驗(yàn)結(jié)果保存在被校驗(yàn)入?yún)?duì)象之后的 BindingResult 或Errors 入?yún)⒅小?/p>
常用方法:
FieldError getFieldError(String field)
List<FieldError> getFieldErrors()
Object getFieldValue(String field)
Int getErrorCount()
測(cè)試
(1)先導(dǎo)入相關(guān)的包
(2)給實(shí)體的屬性上添加校驗(yàn)的注解
(3)在控制層的入?yún)⑶凹由螥Valid,還有出錯(cuò)就轉(zhuǎn)向定制頁面
(4)驗(yàn)證結(jié)果
在頁面上顯示錯(cuò)誤
Spring MVC 除了會(huì)將表單/命令對(duì)象的校驗(yàn)結(jié)果保存到對(duì) 應(yīng)的 BindingResult 或 Errors 對(duì)象中外差凹,還會(huì)將所有校驗(yàn) 結(jié)果保存到 “隱含模型”
即使處理方法的簽名中沒有對(duì)應(yīng)于表單/命令對(duì)象的結(jié)果 入?yún)⑵诒迹r?yàn)結(jié)果也會(huì)保存在 “隱含對(duì)象” 中。
隱含模型中的所有數(shù)據(jù)最終將通過 HttpServletRequest 的 屬性列表暴露給 JSP 視圖對(duì)象危尿,因此在 JSP 中可以獲取 錯(cuò)誤信息
在 JSP 頁面上可通過<form:errors path=“userName”>顯示錯(cuò)誤消息
提示消息的國際化
每個(gè)屬性在數(shù)據(jù)綁定和數(shù)據(jù)校驗(yàn)發(fā)生錯(cuò)誤時(shí)呐萌,都會(huì)生成一 個(gè)對(duì)應(yīng)的 FieldError 對(duì)象。
當(dāng)一個(gè)屬性校驗(yàn)失敗后谊娇,校驗(yàn)框架會(huì)為該屬性生成 4 個(gè)消 息代碼肺孤,這些代碼以校驗(yàn)注解類名為前綴,結(jié)合modleAttribute、屬性名及屬性類型名生成多個(gè)對(duì)應(yīng)的消息代碼:例如 User 類中的 password 屬性標(biāo)準(zhǔn)了一個(gè) @Pattern 注 解渠旁,當(dāng)該屬性值不滿足 @Pattern 所定義的規(guī)則時(shí), 就會(huì)產(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 會(huì)查看WEB 上下文是否裝配了對(duì)應(yīng)的國際化消息船逮,如果沒有顾腊,則顯示默認(rèn) 的錯(cuò)誤消息,否則使用國際化消息挖胃。