1. Struts2中的类型转换
我们知道通过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配合使用(常见于需要快速录入批量数据的场合)