概述
從一個HTML表單到Action對象,類型轉換是從字符串到非字符串。
把請求參數映射到action屬性的工作由
Parameters
攔截器負責,它是默認的defaultStack
攔截器中的一員,Parameters
攔截器可以自動完成字符串和基本數據類型之間轉換。
關於類型轉換錯誤
當類型轉換失敗時
若Action類沒有實現
ValidationAware
接口
Struts在遇到類型轉換錯誤時仍會繼續調用其Action方法,就好像什麼都沒發生一樣若Action類實現
ValidationAware
接口
Struts在遇到類型轉換錯誤時將不會調用其Action方法,Struts將檢查相關action
元素的聲明是否包含着一個name=input
的result
。如果有,Struts將把控制權轉交給那個result
元素,如果沒有,Struts將拋出一個異常。所以一般情況下需要實現
ValidationAware
接口,但是該接口有很多方法需要實現,而我們有時候不需要用到那麼多方法,ActionSupport
已經有該接口的實現了,所以我們可以通過繼承ActionSupport
來間接實現ValidationAware
接口
類型轉換錯誤消息的定製
作爲默認的
default
攔截器的一員,ConversionError
攔截器負責添加與類型轉換有關的出錯信息與保存各請求參數的原始值,前提是Action類必須實現了ValidationAware
接口。如果字段標籤使用的不是simple主題,則非法輸入字段的話將會打印一條出錯信息。但是有時候我們需要自己定義出錯信息。所以需要覆蓋出錯信息。
覆蓋默認的出錯信息
在對應的Action類所在的包中新建ActionClassName.properties
文件,ActionClassName
即爲包含着輸入字段的Action類的類名。
在屬性文件中添加如下鍵對invalid.fieldvalue.fieldName=xxx
,注意,不能使用平時的字符。native2ascii
命令可以進行編碼轉換。
例如設置爲invalid.fieldvalue.age=\u9519\u8bef\u7684\u5e74\u9f84
,則錯誤消息會打印:錯誤的年齡-
其錯誤消息其實是存在值棧棧頂的,舉個例子,有一個
有一個age
字段非法輸入,通過s:debug
標籤我們就可以發現,其結構如下:
fieldErrors
字段存放着錯誤消息。
因此如果是simple主題的話,雖然不會自動的打印錯誤消息,但是我們也可以手動的顯示錯誤消息:${fieldErrors.age[0]}
。也可以使用<s:fielderror fieldName="錯誤字段名"></s:fielderror>
,對於上述的例子是<s:fielderror fieldName="age"></s:fielderror>
。 <s:fielderror></s:fielderror>
標籤顯示錯誤消息的樣式是在template.simple
目錄下的fielderror.ftl
文件中定義的。我們要修改其顯示樣式時修改配置文件即可。可以在java代碼目錄下新建template.simple
包,新建fielderror.ftl
文件,然後進行替換。
定義類型轉換器
Struts2不能自動完成字符串到引用類型的轉換,有時候需要自己定義類型轉換器。
自定義類型轉換器必須實現
ongl.TypeConverter
接口或對這個接口的某種實現進行擴展,一般是對StrutsTypeConverter
類。定義類型轉換器的步驟
先開發類型轉換器類,再配置類型轉換器。
類型轉換器有兩種配置方式。
- 基於字段的配置
在字段所在的Model(可能是Action,可能是一個JavaBean)的包下,新建一個ModelClassName-converter.properties
,然後在該文件中輸入鍵值對:fieldName(待轉換的字段名)=類型轉換器的全類名
。
類型轉換器是單實例的。在第一次使用該轉換器時創建實例。- 基於類型的配置
在src下新建xwork-conversion.properties
文件,鍵入:待轉換的類型=類型轉換器的全類名
。
在當前Struts2應用被加載時創建實例。
-
有一點值得注意
如果使用第二種配置方式,並且要在定義類型轉換器時需要使用到web.xml
文件中的配置參數,那麼就不能在類型轉換器的構造器中來初始化,應該提供一個方法來初始化,因爲第二種方式類型轉換器初始化的時候,ServletContext
對象還沒裝配到ServletActionContext
中,因此該對象爲空,就獲取不到配置參數。
關於兩種配置方式的Demo
首先定義一個DateConverter
類繼承StrutsTypeConverter
:
package struts.app2;
import org.apache.struts2.util.StrutsTypeConverter;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
public class DateConverter extends StrutsTypeConverter {
private DateFormat dateFormat;
public DateConverter() {
dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
}
@Override
public Object convertFromString(Map map, String[] strings, Class aClass) {
System.out.println("convertFromString");
if(aClass == Date.class){
if (strings != null && strings.length > 0){
String value = strings[0];
try {
return dateFormat.parseObject(value);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
//若沒有轉換成功,則返回
return strings;
}
@Override
public String convertToString(Map map, Object o) {
System.out.println("convertToString");
if (o instanceof Date){
Date date = (Date) o;
return dateFormat.format(date);
}
return (String) o;
}
}
第一種配置方式:
然後在該類所在的包下新建ConversionAction-conversion.properties
文件:
birth=struts.app2.DateConverter
第二種配置方式:
在src
目錄下新建xwork-conversion.properties
文件,配置如下:
java.util.Date=struts.app2.DateConverter
類型轉換與複雜屬性配合使用
這裏的複雜屬性是指一個對象中套一個對象,例如有一個類Department
,其成員變量有個manager
,這個成員變量又是一個對象
public class Department {
private String deptName;
private Manager manager;
}
public class Manager {
private String name;
private Date birth;
}
在這兩個類中,涉及到的類型有String
和Date
,我們在上面說到字符串和基本數據類型之間會自動轉換。Date
到字符串的轉換我們也已經寫了。那麼在對於下面的代碼會自動轉換嗎?
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<s:form action="testComplextProperty">
<!--映射屬性的屬性 -->
<s:textfield name="deptName" label="DeptName"></s:textfield>
<s:textfield name="manager.name" label="MgrName"></s:textfield>
<s:textfield name="manager.birth" label="MgrBirth"></s:textfield>
<s:submit></s:submit>
</s:form>
</body>
</html>
上面的代碼中manager.name
和manager.birth
,就屬於我們說的複雜屬性。把其代碼補充完整後去運行發現其可以轉換。只要其最裏面的屬性支持自動轉換(name字段
)的或者是有自定義類型轉換(birth字段
)的,就可以實現轉換