7.類型轉(zhuǎn)換、消息處理與國際化
@(10_Struts2)[JavaEE, Struts2]
- 前邊我們說過了 Http協(xié)議 有兩個缺陷一個是無狀態(tài)茶袒、一個是純文本。
- 純文本也就是說Http請求中的內(nèi)容都是以字符串的形式發(fā)送的凉馆。
- 但是Java又是一個強類型語言薪寓,所以將一個字符串轉(zhuǎn)換成Java中的數(shù)據(jù)類型這一重任就落在了Struts2的肩膀上。
- 類型轉(zhuǎn)換最常見的可能就是將將10/29/2015轉(zhuǎn)換為一個date類型等澜共。
- 關于類型轉(zhuǎn)換我們要做的主要有兩件事:
- 類型轉(zhuǎn)換失敗后的處理预愤。
- 特殊類型的自定義類型轉(zhuǎn)換器。
類型轉(zhuǎn)換失敗消息處理
-
類型轉(zhuǎn)換失敗:
若 Action 類沒有實現(xiàn) ValidationAware 接口: Struts 在遇到類型轉(zhuǎn)換錯誤時仍會繼續(xù)調(diào)用其 Action 方法, 就好像什么都沒發(fā)生一樣.
-
若 Action 類實現(xiàn) ValidationAware 接口:Struts 在遇到類型轉(zhuǎn)換錯誤時將不會繼續(xù)調(diào)用其 Action 方法:
- Struts 將檢查相關 action 元素的聲明是否包含著一個 name=input 的 result.
- 如果有, Struts 將把控制權(quán)轉(zhuǎn)交給那個 result 元素;
- 若沒有 input 結(jié)果, Struts 將拋出一個異常
實現(xiàn)
ValidationAware
接口咳胃,在之前的文章中我們提到,我們可以繼承com.opensymphony.xwork2.ActionSupport
類的形式來實現(xiàn)ValidationAware
接口旷太, 在ActionSupport 中已經(jīng)幫我們實現(xiàn)好了
-
類型轉(zhuǎn)換出錯時如何處理
- 如果我們輸入錯誤的數(shù)字展懈,想轉(zhuǎn)換為年齡;當我們的 result name="input" 的時候供璧,會返回到這個結(jié)果頁面存崖。
- 錯誤的年齡
- 但是對于這種錯誤的提示,我們需要處理
-
類型轉(zhuǎn)換錯誤消息的定制
- 作為默認的 default 攔截器的一員, ConversionError 攔截器負責添加與類型轉(zhuǎn)換有關的出錯消息(前提: Action 類必須實現(xiàn)了 ValidationAware 接口)和保存各請求參數(shù)的原始值.
- 若字段標簽使用的不是 simple 主題, 則非法輸入字段將導致一條有著如上圖格式的出錯消息睡毒。
-
覆蓋默認的出錯消息
- 在對應的
Action
類所在的包中新建ActionClassName.properties
文件, ClassName 即為包含著輸入字段的 Action 類的類名 - 在屬性文件中添加如下鍵值對: invalid.fieldvalue.fieldName=Customer Message
- 在對應的
# EmployeeAction.properties
invalid.fieldvalue.age=年齡格式不正確来惧,請重新輸入!
- 自定義的消息
-
定制出錯消息的樣式:
- 每一條出錯消息都被打包在一個 HTML span 元素里, 可以通過覆蓋其行標為 errorMessage 的那個 css 樣式來改變出錯消息的格式.
- 顯示錯誤消息: 如果是 simple 主題, 可以通過
<s:fielderror fieldName=“filedname”></s:fielderror>
標簽顯示錯誤消息 - 通過s:fielderror 標簽
<s:form action="emp_update" theme="simple">
<s:hidden name="id"></s:hidden>
姓名:<s:textfield name="name"></s:textfield> <br>
年齡:<s:textfield name="age" ></s:textfield>
<!-- 通過標簽獲取錯誤消息 -->
<span style="color:red"><s:fielderror fieldName="age"></s:fielderror></span><br>
部門: <s:textfield name="dept"></s:textfield><br>
職務:<s:textfield name="role"></s:textfield><br>
<s:submit value="修改"></s:submit>
</s:form>
- 但是對于這種錯誤消息的格式我們是可以修改的演顾,修改其默認的 freemark 模板
- 在struts2-core-2.3.15.3.jar 的 /template/simple/fielderror.ftl供搀,這是 struts2 默認自帶的錯誤消息模板隅居,我們在 src 路徑下建立相同的包和模板,并且修改里面的 html 標簽葛虐。刪除文件中錯誤消息的 的 ul胎源、li、span便簽
![刪除的模板
- 效果
自定義類型轉(zhuǎn)換器
定制類型轉(zhuǎn)換器
-
自定義類型轉(zhuǎn)換器必須實現(xiàn)
ongl.TypeConverter
接口或?qū)@個接口的某種具體實現(xiàn)做擴展 -
擴展 StrutsTypeConverter 類
- 在大多數(shù)類型轉(zhuǎn)換器里, 需要提供從 String 類型到非 String 類型和與此相反的轉(zhuǎn)換功能
- 在 StrutsTypeConverter 中有兩個抽象方法:
-
配置自定義的類型轉(zhuǎn)換器
- 在應用程序里使用一個自定義的類型轉(zhuǎn)換器之前, 必須先對它進行配置. 這種配置既可以基于字段, 也可以基于類型
-
基于字段類型轉(zhuǎn)換配置-局部轉(zhuǎn)換器
- 可以為某個 Model(該 Model 類也可能是 Action) 的各個屬性分別配置一個自定義的轉(zhuǎn)換器.
- 創(chuàng)建一個屬性文件: ModelClassName-conversion.properties, 該文件需和相對應的 Model(Model有可能是一個Action) 類放在同一個目錄下
- fieldName=Converter全類名屿脐,例如:
birth=org.pan.struts2.conver.DateConverter
-
基于類型-全局轉(zhuǎn)換器
- 在資源目錄下涕蚤,src 或者 其他的 resources 創(chuàng)建
xwork-conversion.properties
文件 - 在 xwork-conversion.properties 文件里把每一個需要進行類型轉(zhuǎn)換的類與一個類型轉(zhuǎn)換器關聯(lián)起來
java.util.Date=org.pan.struts2.conver.DateConverter
- 若類型轉(zhuǎn)換失敗,給出自定義的信息的诵。
- 在資源目錄下涕蚤,src 或者 其他的 resources 創(chuàng)建
復雜屬性万栅,集合協(xié)同工作
- 復雜屬性
- 類型轉(zhuǎn)換與復雜屬性配合使用
- form 標簽的 name 屬性可以被映射到一個屬性的屬性.
- 復雜屬性
<s:form action="user_add">
<s:textfield name="user.name" label="姓名"></s:textfield>
<s:textfield name="user.gender" label="性別"></s:textfield>
<s:textfield name="user.address" label="地址"></s:textfield>
<s:textfield name="user.mgr.name" label="經(jīng)理名稱"></s:textfield>
<s:textfield name="user.mgr.birth" label="經(jīng)理生日"></s:textfield>
<s:submit value="添加"></s:submit>
</s:form>
-
集合協(xié)同
- 類型轉(zhuǎn)換與 Collection 配合使用
國際化
-
概述
- 在程序設計領域, 把在無需改寫源代碼即可讓開發(fā)出來的應用程序能夠支持多種語言和數(shù)據(jù)格式的技術(shù)稱為國際化.
- 與國際化對應的是本地化, 指讓一個具備國際化支持的應用程序支持某個特定的地區(qū)
- Struts2 國際化是建立在 Java 國際化基礎上的:
- 為不同國家/語言提供對應的消息資源文件
- Struts2 框架會根據(jù)請求中包含的
- Locale 加載對應的資源文件
- 通過程序代碼取得該資源文件中
- 指定 key 對應的消息
- Struts2 框架會根據(jù)請求中包含的
-
默認攔截器棧中有一個
i18n攔截器
,這個攔截器用來設置當前Locale
信息- 當i18n攔截器被調(diào)用時西疤,他會先去查找request_locale這個請求參數(shù)烦粒,它會根據(jù)干參數(shù)來創(chuàng)建一個Locale對象。并將Locale對象放入進session域中瘪阁。之后在加載國際化資源文件時就根據(jù)剛剛創(chuàng)建的Locale對象
當i18n攔截的請求中沒有request_locale這個參數(shù)撒遣,
它會先去session中獲取Locale對象,如果session中管跺,則直接使用該對象
如果session中沒有义黎,則會根據(jù)用戶瀏覽器信息或本地服務器的信息去創(chuàng)建一個Locale對象并使用。
-
配置國際化資源文件
-
Action 范圍資源文件:
- 在Action類文件所在的路徑建立名為
ActionName_language_country.properties
的文件
- 在Action類文件所在的路徑建立名為
-
包范圍資源文件:
- 在包的根路徑下建立文件名為
package_language_country.properties
的屬性文件豁跑,一旦建立廉涕,處于該包下的所有 Action 都可以訪問該資源文件。 - 注意:包范圍資源文件的 baseName 就是package艇拍,不是Action所在的包名狐蜕。
- 在包的根路徑下建立文件名為
- 全局資源文件
- 命名方式:
basename_language_country.properties
-
struts.xml
<constant name="struts.custom.i18n.resources" value="baseName"/>
- 命名方式:
-
Action 范圍資源文件:
<!-- 配置國際化資源 -->
<constant name="struts.custom.i18n.resources" value="i18n"/>
- 臨時指定資源文件:
<s:i18n.../>
標簽的name
屬性指定臨時的國際化資源文件
- 總結(jié):
- 國際化資源文件加載的順序如何呢 ?
- 離當前 Action 較近的將被優(yōu)先加載.
- 假設我們在某個
ChildAction
中調(diào)用了getText("username")
:
- (1)加載和 ChildAction 的類文件在同一個包下的系列資源文件 ChildAction.properties
- (2)加載 ChildAction 實現(xiàn)的接口 IChild,且和 IChildn 在同一個包下 IChild.properties 系列資源文件卸夕。
- (3)加載 ChildAction 父類 Parent层释,且和 Parent 在同一個包下的 baseName 為 Parent.properties 系列資源文件。
- (4) 若 ChildAction 實現(xiàn) ModelDriven 接口快集,則對于getModel()方法返回的model 對象贡羔,重新執(zhí)行第(1)步操作。
- (5) 查找當前包下 package.properties 系列資源文件个初。
- (6) 沿著當前包上溯乖寒,直到最頂層包來查找 package.properties 的系列資源文件。
- (7) 查找 struts.custom.i18n.resources 常量指定 baseName 的系列資源文件院溺。
- (8) 直接輸出該key的字符串值楣嘁。
- Action 范圍國際化
- package 范圍國際化
- 全局的國際化
- 首先需要去 struts.xml 中指定baseName
<!-- 指定國際化 baseName, 以便于建立全局的國際化資源文件 -->
<constant name="struts.custom.i18n.resources" value="myI18n"></constant>
- 全局的配置
-
在這還需要講到一種方式:在頁面國際化資源
- 如果我們在資源路徑下建立好了 國際化資源,但是沒有在 struts.xml 中配置 baseName
- 我們可以使用
<s:i18n name="baseName"> 標簽
來獲取
<!-- 如果是配置了頁面國際化資源文件,
那么國際的內(nèi)容只能在i18n標簽中使用逐虚,一旦離開i18n標簽則不能使用 -->
<s:i18n name="myI18n">
<s:text name="username"></s:text>
<s:form>
<s:textfield name="username" key="username"></s:textfield>
<s:password name="password" key="password"></s:password>
<s:submit key="submit"></s:submit>
</s:form>
</s:i18n>
-
訪問國際化消息
-
JSP 頁面訪問國際化消息:
- 不帶占位符:
<s:text name="key"/>
- 表單元素的 label 屬性:可替換為 key 或使用 getText() 方法聋溜,并對其進行強制 OGNL 解析,使用%{}
- 帶占位符:
- 在 <s:text.../> 標簽中使用多個 <s:param.../> 標簽來填充消息中的占位符痊班。
- Struts2 直接在國際化消息資源文件中通過 “${}” 使用表達式勤婚,該表達式將從值棧中獲取對應的屬性值(對象棧 和 Map 棧)
- 不帶占位符:
-
Action 訪問國際化消息:
- 若 Action 類繼承了 ActionSupport ,則可調(diào)用 TextProvider 接口的 getText 方法涤伐。
-
-
利用超鏈接實現(xiàn)動態(tài)加載國際化資源文件
- Struts2 使用 i18n 攔截器 處理國際化馒胆,并且將其注冊在默認的攔截器中
- i18n攔截器在執(zhí)行Action方法前,自動查找請求中一個名為
request_locale 的參數(shù)
凝果。 - 如果該參數(shù)存在祝迂,攔截器就將其作為參數(shù),轉(zhuǎn)換成Locale對象器净,并將其設為用戶默認的
Locale
(代表國家/語言環(huán)境)型雳。并把其設置為 session 的 WW_TRANS_I18N_LOCALE 屬性 - 若
request 沒有名為request_locale 的參數(shù),則 i18n 攔截器會從 Session 中獲取 WW_TRANS_I18N_LOCALE 的屬性值
山害,若該值不為空纠俭,則將該屬性值設置為瀏覽者的默認Locale - 若 session 中的 WW_TRANS_I18N_LOCALE 的屬性值為空,則從 ActionContext 中獲取 Locale 對象浪慌。
<!-- 必須是 struts 請求,使得 i18 攔截器工作 -->
<a href="userLogin.action?request_locale=en_US">English</a>
<a href="userLogin.action?request_locale=zh_CN">中文</a>