前邊我們說過了 Http協議 有兩個缺陷 一個是無狀態 、 一個是純文本 。 純文本也就是說Http請求中的內容都是以字元串的形式發送的。 但是Java又是一個強類型語言,所以將一個字元串轉換成Java中的數據類型這一重任就落在了Struts2的肩膀上。 類型轉換最常見的可能就是將將10/29/20 ...
- 前邊我們說過了 Http協議 有兩個缺陷一個是無狀態、一個是純文本。
- 純文本也就是說Http請求中的內容都是以字元串的形式發送的。
- 但是Java又是一個強類型語言,所以將一個字元串轉換成Java中的數據類型這一重任就落在了Struts2的肩膀上。
- 類型轉換最常見的可能就是將將10/29/2015轉換為一個date類型等。
- 關於類型轉換我們要做的主要有兩件事:
- 類型轉換失敗後的處理。
- 特殊類型的自定義類型轉換器。
類型轉換失敗消息處理
- 類型轉換失敗:
- 若 Action 類沒有實現 ValidationAware 介面: Struts 在遇到類型轉換錯誤時仍會繼續調用其 Action 方法, 就好像什麼都沒發生一樣.
- 若 Action 類實現 ValidationAware 介面:Struts 在遇到類型轉換錯誤時將不會繼續調用其 Action 方法:
- Struts 將檢查相關 action 元素的聲明是否包含著一個 name=input 的 result.
- 如果有, Struts 將把控制權轉交給那個 result 元素;
- 若沒有 input 結果, Struts 將拋出一個異常
- 實現
ValidationAware
介面,在之前的文章中我們提到,我們可以繼承com.opensymphony.xwork2.ActionSupport
類的形式來實現ValidationAware
介面, 在ActionSupport 中已經幫我們實現好了
- 類型轉換出錯時如何處理
- 如果我們輸入錯誤的數字,想轉換為年齡;當我們的 result name="input" 的時候,會返回到這個結果頁面。
- 但是對於這種錯誤的提示,我們需要處理
- 類型轉換錯誤消息的定製
- 作為預設的 default 攔截器的一員, ConversionError 攔截器負責添加與類型轉換有關的出錯消息(前提: Action 類必須實現了 ValidationAware 介面)和保存各請求參數的原始值.
- 若欄位標簽使用的不是 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>
標簽顯示錯誤消息
- 每一條出錯消息都被打包在一個 HTML span 元素里, 可以通過覆蓋其行標為 errorMessage 的那個 css 樣式來改變出錯消息的格式.
<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便簽
- ![刪除的模板
自定義類型轉換器
- 定製類型轉換器
- 自定義類型轉換器必須實現
ongl.TypeConverter
介面或對這個介面的某種具體實現做擴展 - 擴展 StrutsTypeConverter 類
- 在大多數類型轉換器里, 需要提供從 String 類型到非 String 類型和與此相反的轉換功能
- 在 StrutsTypeConverter 中有兩個抽象方法:
- 配置自定義的類型轉換器
- 在應用程式里使用一個自定義的類型轉換器之前, 必須先對它進行配置. 這種配置既可以基於欄位, 也可以基於類型
- 基於欄位類型轉換配置-局部轉換器
- 可以為某個 Model(該 Model 類也可能是 Action) 的各個屬性分別配置一個自定義的轉換器.
- 創建一個屬性文件: ModelClassName-conversion.properties, 該文件需和相對應的 Model(Model有可能是一個Action) 類放在同一個目錄下
- fieldName=Converter全類名,例如:
birth=org.pan.struts2.conver.DateConverter
- 基於類型-全局轉換器
- 在資源目錄下,src 或者 其他的 resources 創建
xwork-conversion.properties
文件 - 在 xwork-conversion.properties 文件里把每一個需要進行類型轉換的類與一個類型轉換器關聯起來
java.util.Date=org.pan.struts2.conver.DateConverter
- 若類型轉換失敗,給出自定義的信息。
- 在資源目錄下,src 或者 其他的 resources 創建
複雜屬性,集合協同工作
- 複雜屬性
- 類型轉換與複雜屬性配合使用
- 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="經理名稱"></s:textfield> <s:textfield name="user.mgr.birth" label="經理生日"></s:textfield> <s:submit value="添加"></s:submit> </s:form>
- 集合協同
- 類型轉換與 Collection 配合使用
國際化
- 概述
- 在程式設計領域, 把在無需改寫源代碼即可讓開發出來的應用程式能夠支持多種語言和數據格式的技術稱為國際化.
- 與國際化對應的是本地化, 指讓一個具備國際化支持的應用程式支持某個特定的地區
- Struts2 國際化是建立在 Java 國際化基礎上的:
- 為不同國家/語言提供對應的消息資源文件
- Struts2 框架會根據請求中包含的
- Locale 載入對應的資源文件
- 通過程式代碼取得該資源文件中
- 指定 key 對應的消息
- Struts2 框架會根據請求中包含的
- 預設攔截器棧中有一個
i18n攔截器
,這個攔截器用來設置當前Locale
信息- 當i18n攔截器被調用時,他會先去查找request_locale這個請求參數,它會根據乾參數來創建一個Locale對象。並將Locale對象放入進session域中。之後在載入國際化資源文件時就根據剛剛創建的Locale對象
- 當i18n攔截的請求中沒有request_locale這個參數,
- 它會先去session中獲取Locale對象,如果session中,則直接使用該對象
如果session中沒有,則會根據用戶瀏覽器信息或本地伺服器的信息去創建一個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
屬性指定臨時的國際化資源文件
- 總結:
- 國際化資源文件載入的順序如何呢 ?
- 離當前 Action 較近的將被優先載入.
- 假設我們在某個
ChildAction
中調用了getText("username")
:
- (1)載入和 ChildAction 的類文件在同一個包下的系列資源文件 ChildAction.properties
- (2)載入 ChildAction 實現的介面 IChild,且和 IChildn 在同一個包下 IChild.properties 系列資源文件。
- (3)載入 ChildAction 父類 Parent,且和 Parent 在同一個包下的 baseName 為 Parent.properties 系列資源文件。
- (4) 若 ChildAction 實現 ModelDriven 介面,則對於getModel()方法返回的model 對象,重新執行第(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"> 標簽
來獲取
<!-- 如果是配置了頁面國際化資源文件,
那麼國際的內容只能在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 解析,使用%{}
- 帶占位符:
- 在
- Struts2 直接在國際化消息資源文件中通過 “${}” 使用表達式,該表達式將從值棧中獲取對應的屬性值(對象棧 和 Map 棧)
- 不帶占位符:
- Action 訪問國際化消息:
- 若 Action 類繼承了 ActionSupport ,則可調用 TextProvider 介面的 getText 方法。
- JSP 頁面訪問國際化消息:
- 利用超鏈接實現動態載入國際化資源文件
- Struts2 使用 i18n 攔截器 處理國際化,並且將其註冊在預設的攔截器中
- i18n攔截器在執行Action方法前,自動查找請求中一個名為
request_locale 的參數
。 - 如果該參數存在,攔截器就將其作為參數,轉換成Locale對象,並將其設為用戶預設的
Locale
(代表國家/語言環境)。並把其設置為 session 的 WW_TRANS_I18N_LOCALE 屬性 - 若
request 沒有名為request_locale 的參數,則 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>