一、類型轉換的意義
對于一個智能的MVC架構而言,不可避免的需要實作類型轉換.因為B/S(浏覽器/伺服器)結構應用的請求參數是通過浏覽器發送到伺服器的,這些參數不可能有豐富的資料類型,是以必須在伺服器端完成資料類型的轉換
MVC架構是一個表現層解決方案,理應提供類型轉換的支援,Struts2提供了功能非常強大的類型轉換支援.
二、表現層資料的處理
1、對于web應用而言,表現層主要用于與使用者互動,包括收集使用者輸入資料,向使用者呈現伺服器的狀态。是以表現層的資料的流向主要有兩個方向:輸入資料和輸出資料。
2、對于輸入資料:則需要完成由字元串資料向多種類型資料的轉化。程式通常無法自動完成,需要在代碼中手動轉化
3、對于輸出資料:不管是java或是jsp都支援多種資料類型的直接輸出。
4、表現層另外一個資料處理是:資料校驗,分為客戶校驗和伺服器端校驗.後邊會重點講解
三、類型轉換
1、HTTP參數都是字元串類型。 儲存的資料可能是字元串、數字、布爾、日期時間等或者JavaBean類型。 手工的類型轉換,比如将字元串轉換為日期,通過: 通過request.getParameter方法擷取字元串; 檢查是否為空; 通過DateFormat.parse方法将字元串轉換為Date對象
2、Struts2類型轉換
Struts2内置的類型轉換
String和boolean 完成字元串與布爾值之間的轉換
String和char 往常字元串與字元之間的轉換
String和int、Integer 完成字元串與整型之間的轉換
String和Long 完成字元串與長整型值之間的轉換
String和double、Double 完成字元串與雙精度浮點值的轉換
String和Float 完成字元串和單精度浮點之間的轉換
String和Date 完成字元串和日期類型之間的轉換,日期格式使用格式使用者請求所在Locale的SHORT格式
String和數組 在預設的情況,數組元素是字元串,如果使用者定義類型轉換器,也可以是其它複合資料類型
String和Map、List
Struts2内置的類型轉換
String和boolean 完成字元串與布爾值之間的轉換
String和char 往常字元串與字元之間的轉換
String和int、Integer 完成字元串與整型之間的轉換
String和Long 完成字元串與長整型值之間的轉換
String和double、Double 完成字元串與雙精度浮點值的轉換
String和Float 完成字元串和單精度浮點之間的轉換
String和Date 完成字元串和日期類型之間的轉換,日期格式使用格式使用者請求所在Locale的SHORT格式
String和數組 在預設的情況,數組元素是字元串,如果使用者定義類型轉換器,也可以是其它複合資料類型
String和Map、List
3、内置類型轉換

4、Struts類型轉換的API
Struts2的類型轉換器實際上是基于OGNL實作的,在OGNL項目中有一個ognl.TypeConverter接口,這個接口就是實作類型轉換器必須實作的接口。該接口定義如下:
public interface TypeConverter {
public Object convertValue(Map arg0, Object arg1, Member arg2, String arg3,
Object arg4, Class arg5) {
return null;
}
實作類型轉換器必須實作上面的TypeConverter,不過上面的接口裡的方法過于複雜,是以OGNL項目還提供了一個該接口實作類:ognl.DefaultTypeConverter,通過繼承該類實作自己類型轉換器.該類定義如下:
public class DefaultTypeConverter extends Object implements TypeConverter{
public Object convertValue(Map<String,Object> context, Object value, Class toType) {
}
……//其他的方法
}
ConvertValue方法的作用
該方法完成類型轉換,不過這種類型轉換是雙向的,當需要把字元串轉化對象執行個體時,通過該方法實作,當把對象執行個體轉換成字元串時也通過該方法實作。這種轉換是通過toType參數類型是需要轉換的目标類型。是以可以根據toType參數來判斷轉換方向。
ConvertValue方法參數和傳回意義
第一個參數:context是類型轉換環境的上下文
第二個參數:value是需要轉換的參數,根據轉換方向的不同value參數的值也是不一樣的。
第三個參數:toType是轉換後的目标類型
該方法的傳回值是類型轉換後的值。該值的類型也會随着轉換的方向的改變而改變。由此可見轉換的convertValue方法接受需要轉換的值,需要轉換的目标類型為參數,然後傳回轉換後的目标值
Value為什麼是一個字元串數組?
對于DefaultTypeConverter轉換器而言,它必須考慮到最通用的情形,是以他把所有請求參數都視為字元串數組而不是字元串。相當于getParameterValues()擷取的參數值
四、類型轉換器的實作
1、第一步注冊頁面
2、第二步驟:實作User封裝類
3、第三步驟:實作Action類
5、第五步驟:實作類型轉換器的注冊,注冊方式有以下三種:
1、注冊局部類型轉換器:局部類型轉換器僅僅對某個Action的屬性其作用
2、注冊全局類型轉換器:全局類型轉換器對所有Action的特定屬性都會生效
3、使用JDK1.5的注釋來注冊類型轉換器:通過注冊方式來生成類型轉換器
6、局部類型轉換器注冊
注冊檔案名格式:ActionName-conversion.properties:ActionName是需要轉換器生效的Action的類名,後面的-conversion.properties字元串是固定部分
以上檔案時典型的properties檔案,檔案有key-value對組成.檔案内容為:propertyName=類型轉換器類
下面是UserAction-conversion.properties檔案的内容:
#指定UserAction中的user屬性需要使用redarmy.user.UserConverter類完成類型轉換
user=redarmy.user.UserConverter
注意:以上properties檔案一定要與UserAction在同一個包中
即上述案例可采用上面的方式實作局部類型轉換
7、全局類型轉換器
注冊名的檔案格式:xwork-conversion.properties檔案該檔案也是properties檔案,其内容也是由”複合類型=對應的類型轉換器類”項組成的。
以下是xwork-conversion.properties檔案内容:
#指定所有redarmy.user.User類的類型轉換器為redarmy.user.UserConverter
redarmy.user.User=redarmy.user.UserConverter
注意:xwork-conversion.properties檔案必須為class檔案夾下即在src下面建立
五、Struts2自定義類型轉換
在Struts2中提供了StrutsTypeConverter類來簡化自定義類型轉換的設計,這個類有兩個抽象方法需要實作:
(1) public Object convertFromString(Map context, String[] values, Class toClass) ;
用于String類型資料轉成自定義類型的處理方法
參數:
context --- 與Action有關的上下文資訊
values --- 從請求中擷取的參數值
toClass --- 要轉換的目标類型
(2) public String convertToString(Map context, Object obj) ;
用于自定義類型轉換成String
參數:
context --- 與Action有關的上下文資訊
obj --- 自定義類型對象
執行個體分析:一個日期類型轉換的設計和配置
(1) 設計MyDateTypeConverter,繼承StrutsTypeConverter,覆寫其中的兩個方法,參考代碼如下:
public Object convertFromString(Map context, String[] values, Class toClass) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try{
Date v = sdf.parse(values[0]);
return v;
}catch(Exception e){
e.printStackTrace();
return new Date();
}
}
續
public String convertToString(Map context, Object obj) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
Date v = (Date)obj;
return sdf.format(v);
}
雖然Struts2預設可支援String和Date的轉換,但僅支援短格式和本地化有關日期格式轉換,不一定符合自己的需要,我們需要實作自己的類型轉換。
(2) 為UserInfo類增加一個birthday屬性,其類型為java.util.Date
public class UserInfo {
private Integer id;
private String name;
private String password;
private Date birthday;
...
}
(3)為UserInfo這個元件配置該類型轉換器
首先,以UserInfo元件的類名為基礎建立一個特性檔案,檔案命名格式為類名-conversion.properties
比如UserInfo-conversion.properties
該檔案必須和UserInfo元件在同一個包下。
該特性檔案内容格式如下:
birthday=demo.converter.MyDateTypeConverter
說明:
birthday 為UserInfo元件中java.util.Date類型的屬性名
demo.converter.MyDateTypeConverter為自定義轉換實作類
Strus2架構為我們考慮到這一點,提供了一種簡單的處理方式。
将類型轉換器配置為全局級别,隻需編寫一個名為xwork-conversion.properties的特性檔案,該檔案必須位于/WEB-INF/classes目錄下,内容如下:
java.util.Date=demo.converter.MyDateTypeConverter
六、自定義類型轉換器
java.util.Date類型的屬性可以接收格式為2009-07-20的請求參數值。但如果我們需要接收格式為20091221的請求參數,我們必須定義類型轉換器,否則struts2無法自動完成類型轉換。
import java.util.Date;
public class HelloWorldAction {
private Date createtime;
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
}
public class DateConverter extends DefaultTypeConverter {
@Override public Object convertValue(Map context, Object value, Class toType) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
try {
if(toType == Date.class){//當字元串向Date類型轉換時
String[] params = (String[]) value;// Request.getParameterValues()
return dateFormat.parse(params[0]);
}else if(toType == String.class){//當Date轉換成字元串時
Date date = (Date) value;
return dateFormat.format(date);
}
} catch (ParseException e) {}
return null;
}
}
将上面的類型轉換器注冊為局部類型轉換器:
在Action類所在的包下放置ActionClassName-conversion.properties檔案,ActionClassName是Action的類名,後面的-conversion.properties是固定寫法,對于本例而言,檔案的名稱應為HelloWorldAction-conversion.properties 。在properties檔案中的内容為:
屬性名稱=類型轉換器的全類名
對于本例而言, HelloWorldAction-conversion.properties檔案中的内容為:
createtime= cn.csdn.conversion.DateConverter
将上面的類型轉換器注冊為全局類型轉換器:
在WEB-INF/classes下放置xwork-conversion.properties檔案 。在properties檔案中的内容為:
待轉換的類型=類型轉換器的全類名
對于本例而言, xwork-conversion.properties檔案中的内容為:
java.util.Date= cn.csdn.conversion.DateConverter
java.util.Date類型的屬性可以接收格式為2009-07-20的請求參數值。但如果我們需要接收格式為20091221的請求參數,我們必須定義類型轉換器,否則struts2無法自動完成類型轉換。
import java.util.Date;
public class HelloWorldAction {
private Date createtime;
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
}
public class DateConverter extends DefaultTypeConverter {
@Override public Object convertValue(Map context, Object value, Class toType) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
try {
if(toType == Date.class){//當字元串向Date類型轉換時
String[] params = (String[]) value;// Request.getParameterValues()
return dateFormat.parse(params[0]);
}else if(toType == String.class){//當Date轉換成字元串時
Date date = (Date) value;
return dateFormat.format(date);
}
} catch (ParseException e) {}
return null;
}
}
将上面的類型轉換器注冊為局部類型轉換器:
在Action類所在的包下放置ActionClassName-conversion.properties檔案,ActionClassName是Action的類名,後面的-conversion.properties是固定寫法,對于本例而言,檔案的名稱應為HelloWorldAction-conversion.properties 。在properties檔案中的内容為:
屬性名稱=類型轉換器的全類名
對于本例而言, HelloWorldAction-conversion.properties檔案中的内容為:
createtime= cn.csdn.conversion.DateConverter
将上面的類型轉換器注冊為全局類型轉換器:
在WEB-INF/classes下放置xwork-conversion.properties檔案 。在properties檔案中的内容為:
待轉換的類型=類型轉換器的全類名
對于本例而言, xwork-conversion.properties檔案中的内容為:
java.util.Date= cn.csdnconversion.DateConverter