我們知道通過HTTP提交到後台的數據,都是字符串的形式,而我們需要的數據類型當然不只字符串類型一種。所以,我們需要類型轉換!
在Struts2中,類型轉換的概念除了用於將界面傳遞過來的字符串轉換為特定的類型(convertFromString)之外,還可以用於將特定的類型轉換為字符串(即當我們在JSP中要把某種類型的對象呈現的時候,要將它轉換為字符串來顯示)(converterToString)。
在Struts2中,支持全局類型轉換和局部類型轉換兩種方式。所謂全局類型轉換,即在所有的action/model中,都用同一個類型轉換器來轉換某種特定類型的對象;而局部類型轉換,意思就是針對某個action/model中的屬性所定義的特定的類型轉換器。
問題1: 如何覆蓋默認的錯誤消息?
1). 在對應的 Action 類所在的包中新建
ActionClassName.properties 文件, ActionClassName 即為包含著輸入字段的 Action 類的類名
2). 在屬性文件中添加如下鍵值對: invalid.fieldvalue.fieldName=xxx
問題2: 如果是 simple 主題, 還會自動顯示錯誤消息嗎? 如果不會顯示, 怎麼辦 ?
1). 通過 debug 標簽, 可知若轉換出錯, 則在值棧的 Action(實現了 ValidationAware 接口) 對象中有一個 fieldErrors 屬性.
該屬性的類型為 Map<String, List<String>> 鍵: 字段(屬性名), 值: 錯誤消息組成的 List. 所以可以使用 LE 或 OGNL 的方式
來顯示錯誤消息: ${fieldErrors.age[0]}
2). 還可以使用 s:fielderror 標簽來顯示. 可以通過 fieldName 屬性顯示指定字段的錯誤.
問題3. 若是 simple 主題, 且使用 <s:fielderror fieldName="age"></s:fielderror> 來顯示錯誤消息, 則該消息在一個
ul, li, span 中. 如何去除 ul, li, span 呢 ?
在 template.simple 下面的 fielderror.ftl 定義了 simple 主題下, s:fielderror 標簽顯示錯誤消息的樣式. 所以修改該
配置文件即可. 在 src 下新建 template.simple 包, 新建 fielderror.ftl 文件, 把原生的 fielderror.ftl 中的內容
復制到新建的 fielderror.ftl 中, 然後剔除 ul, li, span 部分即可.
問題4. 如何自定義類型轉換器 ?
1). 為什麼需要自定義的類型轉換器 ? 因為 Struts 不能自動完成 字符串 到 引用類型 的 轉換.
2). 如何定義類型轉換器:
I. 開發類型轉換器的類: 擴展 StrutsTypeConverter 類.
II. 配置類型轉換器:
有兩種方式
①. 基於字段的配置:
> 在字段所在的 Model(可能是 Action, 可能是一個 JavaBean) 的包下, 新建一個 ModelClassName-conversion.properties 文件
> 在該文件中輸入鍵值對: fieldName=類型轉換器的全類名.
> 第一次使用該轉換器時創建實例.
> 類型轉換器是單實例的!
②. 基於類型的配置:
> 在 src 下新建 xwork-conversion.properties
> 鍵入: 待轉換的類型=類型轉換器的全類名.
> 在當前 Struts2 應用被加載時創建實例.
不管是全局類型轉換,還是局部類型轉換,其轉換器的編寫方法是相同的!只要繼承StrutsTypeConverter,重寫其中的方法即可。
即針對整個系統中同樣類型的屬性定義轉換器
只需:
1、 在類路徑的根目錄下定義xwork-conversion.properties文件
2、 在文件中用這樣的格式聲明哪個類型使用哪個轉換器:
a) 屬性類型的全路徑類名=轉換器的全路徑類名
3、 Struts2將能自動發現這個文件,並根據其中的定義,對特定的類型調用你指定的類型轉換器進行類型轉換
比如Point類型:
package cn.com.leadfar.model;
public class Point {
private int left;
private int right;
public int getLeft() {
return left;
}
public void setLeft(int left) {
this.left = left;
}
public int getRight() {
return right;
}
public void setRight(int right) {
this.right = right;
}
}
針對Point類型的轉換器:
package cn.com.leadfar.struts2.actions;
import Java.util.Map;
import org.apache.struts2.util.StrutsTypeConverter;
import cn.com.leadfar.model.Point;
public class PointConverter extends StrutsTypeConverter {
@Override
public Object convertFromString(Map context, String[] value, Class toType) {
//TODO 前提條件判斷
String p = value[0];
String[] ps = p.split(",");
int left = Integer.parseInt(ps[0]);
int right = Integer.parseInt(ps[1]);
Point point = new Point();
point.setLeft(left);
point.setRight(right);
return point;
}
@Override
public String convertToString(Map context, Object point) {
Point p = (Point)point;
return p.getLeft()+"-"+p.getRight();
}
}
xwork-conversion.properties文件的內容如下:
cn.com.leadfar.model.Point=cn.com.leadfar.struts2.actions.PointConverter
即針對某個Action或Model的屬性定義的轉換器
1、在與Action/Model類同一個包下面,定義 Action/Model類名-conversion.properties 文件
2、文件內部用這樣的格式來聲明哪個屬性需要用哪個類型轉換器:
屬性名=轉換器的全路徑類名
比如:對於java.util.Date類型,我們可以聲明不同的類使用不同的類型轉換器
package cn.com.leadfar.model;
import java.util.Date;
public class User {
private Date endDate;
public Date getEndDate() {
return endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
}
package cn.com.leadfar.struts2.actions;
import java.util.Date;
import cn.com.leadfar.model.Point;
import cn.com.leadfar.model.User;
import com.opensymphony.xwork2.ModelDriven;
public class UserAction implements ModelDriven{
private User user;
private Date beginDate;
@Override
public Object getModel() {
if(user == null){
user = new User();
}
return user;
}
public String add(){
return "success";
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Date getBeginDate() {
return beginDate;
}
public void setBeginDate(Date beginDate) {
this.beginDate = beginDate;
}
}
假設我們希望UserAction類中的beginDate屬性和User類中endDate屬性,分別使用不同的類型轉換器,如下所示:
package cn.com.leadfar.struts2.actions;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Map;
import org.apache.struts2.util.StrutsTypeConverter;
public class BeginDateConverter extends StrutsTypeConverter {
private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
@Override
public Object convertFromString(Map context, String[] value, Class toType) {
String d = value[0];
try {
return format.parse(d);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
@Override
public String convertToString(Map context, Object date) {
return format.format(date);
}
}
package cn.com.leadfar.struts2.actions;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Map;
import org.apache.struts2.util.StrutsTypeConverter;
public class EndDateConverter extends StrutsTypeConverter {
private SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd");
@Override
public Object convertFromString(Map context, String[] value, Class toType) {
String d = value[0];
try {
return format.parse(d);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
@Override
public String convertToString(Map context, Object date) {
return format.format(date);
}
}
那麼,我們需要在User類的包:cn.com.leadfar.model下面,創建一個文件,命名如下:
User-conversion.properties,文件的內容如下:
endDate=cn.com.leadfar.struts2.actions.EndDateConverter
表示User類中的endDate屬性,使用EndDateConverter這個類型轉換器。
然後,在UserAction類所在的包:cn.com.leadfar.struts2.actions下面,再創建一個文件,命名如下:
UserAction-conversion.properties,文件的內容如下:
beginDate=cn.com.leadfar.struts2.actions.BeginDateConverter
表示UserAction類中的beginDate屬性,使用BeginDateConveter這個類型轉換器。
注:在Struts1中只支持全局類型轉換,而不支持局部類型轉換!
初始化參數可以配置到web.xml中
類型轉換與復雜屬性配合使用(可以被映射到一個屬性的屬性)
類型轉換與Collection配合使用(常見於需要快速錄入批量數據的場合)