Struts2學習筆記(七)——類型轉換

一、自動類型轉換java

Struts2內部提供大量類型轉換器,用來完成數據類型轉換問題:數組

  • String和boolean、Boolean:完成字符串與布爾值之間的轉換
  • String和char、Character:往常字符串與字符之間的轉換
  • String和int、Integer:完成字符串與整型之間的轉換
  • String和long、Long:完成字符串與長整型值之間的轉換
  • String和double、Double:完成字符串與雙精度浮點值的轉換
  • String和float、Float:完成字符串和單精度浮點之間的轉換
  • String和Date:完成字符串和日期類型之間的轉換,能夠接收yyyy-MM-dd格式字符串
  • String和數組:能夠將多個同名參數,轉換到數組中
  • String和Map、List:支持將數據保存到List或者Map集合

自動類型轉換例子:app

表單信息:框架

1 <form action="${pageContext.servletContext.contextPath}/converterAction.action">
2     name:<input type="text" name="name"><br>
3     password:<input type="password" name="password"><br>
4     age:<input type="text" name="age"><br>
5     birthday:<input type="text" name="birthday"><br>
6     hobby:<input name="hobby" type="checkbox" value="music">music
7         <input name="hobby" type="checkbox" value="movie">movie<br>
8     <input type="submit" value="提交">
9 </form>

Action類:jsp

 1 public class ConverterAction extends ActionSupport {
 2     private String name;
 3     private String password;
 4     private int age;
 5     private Date birthday;
 6     private String[] hobby;
 7     
 8     public String getName() {
 9         return name;
10     }
11     public void setName(String name) {
12         this.name = name;
13     }
14     public String getPassword() {
15         return password;
16     }
17     public void setPassword(String password) {
18         this.password = password;
19     }
20     public int getAge() {
21         return age;
22     }
23     public void setAge(int age) {
24         this.age = age;
25     }
26     public Date getBirthday() {
27         return birthday;
28     }
29     public void setBirthday(Date birthday) {
30         this.birthday = birthday;
31     }
32     public String[] getHobby() {
33         return hobby;
34     }
35     public void setHobby(String[] hobby) {
36         this.hobby = hobby;
37     }
38     
39     @Override
40     public String execute() throws Exception {
41         System.out.println("name: " + name);
42         System.out.println("password: " + password);
43         System.out.println("age: " + age);
44         System.out.println("birthday: " + birthday);
45         System.out.print("hobby: ");
46         for (int i = 0; i < hobby.length; i++) {
47             System.out.print(hobby[i]);
48             if (i != hobby.length - 1) {
49                 System.out.print(", ");
50             }
51         }
52         return SUCCESS;
53     }
54 }

前臺輸入信息:ide

後臺顯示信息:函數

二、自定義類型轉換this

  1)基於OGNL的類型轉換器spa

  Struts2的類型轉換器其實是基於OGNL實現的,都須要實現一個TypeConverter接口,該接口位於ognl.jar包內。該接口定義了一個convertValue()方法,實現該接口的類型轉換器實現類都須要重寫該方法來進行類型轉換。3d

1 public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName, Object value, Class toType);

  因爲TypeConverter接口的convertValue()方法過於複雜,OGNL還提供了一個實現TypeConverter接口的類DefaultTypeConverter,開發者只要繼承該類,就能夠開發類型轉換器的實現類。DefaultTypeConverter類的子類須要重寫convertValue()方法,來實現字符串類型與複合類型之間的雙向轉換,convertValue()方法有三個參數:Map context:該參數爲類型轉換環境的上下文內容;Object value:該參數爲須要轉換的參數,是一個字符串數組;Class toType:該參數指的是轉換目標的類型。

  在Struts2中並無直接使用ognl.DefaultTypeConverter實現類,甚至都沒有使用ognl.TypeConverter接口,而是本身定義了一個與ognl.TypeConverter接口同樣的TypeConverter接口,該接口位於com.opensymphony.xwork2.conversion包下,其名稱和接口函數定義徹底相同。Struts2自行定義TypeConverter接口的目的在於對外屏蔽類型轉換的實現細節,從而可以將Struts2對TypeConverter的擴展實現歸入到Struts2的容器中進行管理,從而方便對OGNL原始的TypeConverter接口進行擴展並支持更加普遍的類型轉換邏輯。

  在Struts2的com.opensymphony.xwork2.conversion包下DefaultTypeConverter實現類有3個convertValue方法:

因此咱們在繼承com.opensymphony.xwork2.conversion包下DefaultTypeConverter實現類的時候能夠直接重寫convertValue(Object value, Class toType)方法便可。

不管是繼承ongl包下的DefaultTypeConverter仍是繼承com.opensymphony.xwork2.conversion包下DefaultTypeConverter,在自定義類型轉換的時候,實現方式都同樣。

  2)基於Struts2的類型轉換器

  Struts2框架提供了一個類型轉換器的StrutsTypeConverter抽象類,能夠繼承該類來開發自定義的類型轉換器實現類。 該抽象類實際上繼承了DefaultTypeConverter類,在該類的基礎上進行了簡化。StrutsTypeConverter類中提供了兩個抽象方法,分別實現"form字符串參數-Struts複合類型"之間的雙向轉換。

三、註冊類型轉換器

Struts2框架中使用自定義類型轉換器須要註冊,這樣Struts2框架在處理用戶請求的時候才知道使用哪一個類型轉換器進行轉換。Struts2有兩種方式註冊類型轉換器:

 1)註冊局部類型轉換器

  局部類型轉換器僅僅對某個Action的屬性其做用,註冊局部類型轉換器須要創建一個命名規則爲ActionName-conversion.properties的屬性文件,該屬性文件保存在與Action類文件相同的目錄下。ActionName就是使用類型轉換器的Action類的類名,而-conversion.properties是固定的格式。該文件是一個標準的屬性文件,內容爲標準的Key-Value格式,該鍵值對定義以下:

1 <!--propertyName爲要進行轉換的屬性名-->
2 propertyName=類型轉換器

若是在model中有兩個類User和Product,它們都有Date類型屬性,都須要在頁面上輸入,可是它們格式不同,例如:

  User birthday 格式:yyyy/MM/dd

  Product producttime 格式:yyyy-MM-dd

若是遇到這種狀況,能夠在model所在的包下建立註冊的properties文件,名稱的命名規則爲modelname-conversion.properties,該屬性文件的內容和上面的同樣:

1 <!--propertyName爲要進行轉換的屬性名-->
2 propertyName=類型轉換器

 2)註冊全局類型轉換器

  全局類型轉換器對全部Action的特定屬性都會生效,註冊一個全局類型轉換器,須要創建一個xwork-conversion.properties屬性文件,該文件須要保存在class路徑的根目錄下,如WEB-INF/classes。該文件的內容爲"複合類型-對應的類型轉換器",其中複合類型就是Action中須要進行類型轉換的屬性所屬於的類型,對應的類型轉換器就是轉換該複合類型的對應轉換器,好比要對Date類型的屬性進行轉換:

java.util.Date=com.sunny.converter.DateConverter

四、類型轉換器的實現

在類型轉換器的實現例子中自定義類型轉換器繼承的是DefaultTypeConverter,註冊局部類型轉換器。

表單信息:

1 <form action="${pageContext.servletContext.contextPath}/converterAction.action">
2     name:<input type="text" name="name"><br>
3     password:<input type="password" name="password"><br>
4     age:<input type="text" name="age"><br>
5     birthday:<input type="text" name="birthday"><br>
6     hobby:<input name="hobby" type="checkbox" value="music">music
7         <input name="hobby" type="checkbox" value="movie">movie<br>
8     <input type="submit" value="提交">
9 </form>

自定義類型轉換器類:

 1 public class DateConverter extends DefaultTypeConverter {
 2     @Override
 3     public Object convertValue(Object value, Class toType) {
 4         if (value == null || toType == null) {
 5             return false;
 6         }
 7         
 8         if (toType != Date.class) {
 9             return false;
10         }
11         
12         /*
13          * 對於DefaultTypeConverter轉換器而言,它必須考慮到最通用的情形,
14          * 所以他把全部請求參數都視爲字符串數組而不是字符串。
15          */
16         if (value instanceof String[]) {
17             String str[] = (String[])value;
18             if (str[0] != null && str[0].length() > 0) {
19                 SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
20                 try {
21                     //把請求參數轉換成特定格式的date類
22                     return sdf.parse(str[0]);
23                 } catch (ParseException e) {
24                     /*
25                      *  在struts2框架裏,自定義的類型轉換器,
26                      *  若是咱們不手動拋出異常,struts2框架只捕獲異常,可是並不拋出。
27                      *  因此框架就會認爲類型轉換器轉換成功,轉向成功頁面。
28                      */
29                     throw new RuntimeException(e);
30                 }
31             }
32         }
33         return new Date();
34     }
35 }

註冊局部類型轉換器,對Date類型的birthday進行轉換,接收yyyy/MM/dd類型字符串:

1 birthday=com.sunny.converter.DateConverter

Action類:

 1 public class ConverterAction extends ActionSupport {
 2     private String name;
 3     private String password;
 4     private int age;
 5     private Date birthday;
 6     private String[] hobby;
 7     
 8     public String getName() {
 9         return name;
10     }
11     public void setName(String name) {
12         this.name = name;
13     }
14     public String getPassword() {
15         return password;
16     }
17     public void setPassword(String password) {
18         this.password = password;
19     }
20     public int getAge() {
21         return age;
22     }
23     public void setAge(int age) {
24         this.age = age;
25     }
26     public Date getBirthday() {
27         return birthday;
28     }
29     public void setBirthday(Date birthday) {
30         this.birthday = birthday;
31     }
32     public String[] getHobby() {
33         return hobby;
34     }
35     public void setHobby(String[] hobby) {
36         this.hobby = hobby;
37     }
38     
39     @Override
40     public String execute() throws Exception {
41         System.out.println("name: " + name);
42         System.out.println("password: " + password);
43         System.out.println("age: " + age);
44         System.out.println("birthday: " + birthday);
45         System.out.print("hobby: ");
46         for (int i = 0; i < hobby.length; i++) {
47             System.out.print(hobby[i]);
48             if (i != hobby.length - 1) {
49                 System.out.print(", ");
50             }
51         }
52         return SUCCESS;
53     }
54 }

前臺輸入信息:

後臺顯示信息:

注意事項:

  • 在進行自定義類型轉換時,若是轉換錯誤,咱們不手動拋出異常,struts2框架只捕獲異常,並不拋出,框架就會認爲轉換成功,轉向成功頁面,因此必定要手動拋出異常。
  • 不論是自動類型轉換仍是自定義類型轉換,若是類型轉換錯誤,會跳轉到input視圖,若是在struts.xml文件中沒有name值爲"input"的<result>,會跳轉到錯誤頁面。

五、錯誤處理機制

 Struts2的錯誤處理是由conversionError攔截器自動完成的,當發生類型轉換錯誤時,conversionError攔截器攔截此錯誤並封裝成fieldError,將此錯誤信息放入ActionContext中,並返回input邏輯視圖,咱們前面提到過此時必須在struts.xml文件中有name值爲"input"的<result>,在jsp頁面中可使用<s:fielderror/>便可顯示錯誤信息,默認顯示的錯誤信息是在屬性文件xwork-messages.properties中定義的:

1 xwork.error.action.execution=Error during Action invocation
2 xwork.exception.missing-action=There is no Action mapped for action name {0}.
3 xwork.exception.missing-package-action=There is no Action mapped for namespace {0} and action name {1}.
4 xwork.default.invalid.fieldvalue=Invalid field value for field "{0}".

當birthday輸入格式錯誤時,根據action中的<result name="input">/error.jsp</result>會跳轉到error.jsp頁面,

jsp頁面信息:

1 <body>
2 <s:fielderror fieldName="birthday"/>
3 </body>

jsp頁面顯示信息:

若是咱們須要配置顯示的錯誤信息,有方式有兩種:
1)在國際化資源文件中配置
xwork.default.invalid.fieldvalue={0},錯誤;
在項目中創建一個國際化資源文件converter.properties,文件名能夠隨便,在文件中輸入下面內容:
xwork.default.invalid.fieldvalue={0},錯誤;
而後,在struts.xml文件中配置<constant name="struts.custom.i18n.resources" value="com.sunny.action.converter" />
 1 <struts>
 2     <constant name="struts.devMode" value="true" />
 3     <constant name="struts.custom.i18n.resources" value="com.sunny.action.converter" />
 4     <package name="default" namespace="/" extends="struts-default">
 5         <action name="converterAction" class="com.sunny.action.ConverterAction">
 6             <result>/success.jsp</result>
 7             <result name="input">/error.jsp</result>
 8         </action>
 9     </package>
10 
11 </struts>

說明:資源文件的定義有好幾種方式,會在國際化中講到

若是birthday輸入格式錯誤,顯示以下:

2)配置Action特定屬性錯誤信息
在Action所在包中,建立ActionName.properties,在文件中配置提示信息: invalid.fieldvalue.屬性名= 錯誤信息,其中invalid.fieldvalue爲固定格式
invalid.fieldvalue.birthday=日期類型轉換錯誤,要求格式必須是yyyy/MM/dd;
顯示效果:
這種配置方式的內容:invalid.fieldvalue.birthday=日期類型轉換錯誤,要求格式必須是yyyy/MM/dd;也能夠配置在國際化資源文件中,一樣能夠起做用。
注意:類型轉換的Action在struts.xml中配置所在包須要extends="struts-default",所以在此文件中包含conversionError攔截器
相關文章
相關標籤/搜索