一、自定义类型转换器
1). 为什么需要自定义的类型转换器 ?
因为Struts不能自动完成字符串到引用类型的转换。
2). 如何定义类型转换器?
I. 开发类型转换器的类: 扩展 StrutsTypeConverter 类;
II. 配置类型转换器。
有两种配置方式
①. 基于字段的配置:
> 在字段所在的 Model(可能是 Action,也可能是一个JavaBean) 的包下, 新建一个 ModelClassName-conversion.properties 文件
> 在该文件中输入键值对: fieldName=类型转换器的全类名。(fieldName即带转换字段的名称)
> 两个相关结论:
·第一次使用该转换器时创建实例.
·类型转换器是单实例的!
②. 基于类型的配置:
> 在 src 下新建 xwork-conversion.properties文件
> 键入: 待转换的类型=类型转换器的全类名.
> 两个相关结论:
·在当前 Struts2 应用被加载时创建实例.
· 在这种情况下类型转换器被创建了两次,即不是单实例的(了解 )
二、示例
1)基于字段的配置方式
修改“Struts2类型转换(一)”的JSP代码如下:(JSP页面的名称为index.jsp)
1 <s:form action="testConversion" theme="simple"> 2 Age: <s:textfield name="age" label="Age"></s:textfield> 3 ${fieldErrors.age[0]} 4 <s:fielderror fieldName="age"></s:fielderror> 5 <br><br> 6 7 Birth: <s:textfield name="birth"></s:textfield> 8 <s:fielderror fieldName="birth"></s:fielderror> 9 <br><br> 10 <s:submit></s:submit> 11 </s:form>
当Model为一个Action时,Java代码如下:
package com.atguigu.struts2.app; import java.util.Date; import com.opensymphony.xwork2.ActionSupport; public class ConversionAction extends ActionSupport{ private int age; private Date birth; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } public String execute(){ System.out.println("age: " + age); System.out.println("birth: " + birth); return "success"; } }
定义String与Date之间的类型转换器如下:
1 package com.atguigu.struts2.app.converters; 2 3 import java.text.DateFormat; 4 import java.text.ParseException; 5 import java.text.SimpleDateFormat; 6 import java.util.Date; 7 import java.util.Map; 8 9 import javax.servlet.ServletContext; 10 11 import org.apache.struts2.ServletActionContext; 12 import org.apache.struts2.util.StrutsTypeConverter; 13 14 public class DateConverter extends StrutsTypeConverter { 15 16 private DateFormat dateFormat; 17 18 public DateConverter() { 19 System.out.println("DateConverter's constructor..."); 20 21 //获取当前 WEB 应用的初始化参数 pattern 22 /** 23 * web.xml的根节点中添加有如下配置: 24 * <context-param> 25 * <param-name>pattern</param-name> 26 * <param-value>yyyy-MM-dd HH:mm:ss</param-value> 27 * </context-param> 28 */ 29 ServletContext servletContext = ServletActionContext.getServletContext(); 30 System.out.println(servletContext); 31 String pattern = servletContext.getInitParameter("pattern"); 32 dateFormat = new SimpleDateFormat(pattern); 33 } 34 35 @Override 36 public Object convertFromString(Map context, String[] values, Class toClass) { 37 38 System.out.println("convertFromString..."); 39 40 if(toClass == Date.class){ 41 if(values != null && values.length > 0){ 42 String value = values[0]; 43 try { 44 return dateFormat.parseObject(value); 45 } catch (ParseException e) { 46 e.printStackTrace(); 47 } 48 } 49 } 50 51 //若没有转换成功, 则返回 values 52 return values; 53 } 54 55 @Override 56 public String convertToString(Map context, Object o) { 57 58 System.out.println("convertToString..."); 59 60 if(o instanceof Date){ 61 Date date = (Date) o; 62 return dateFormat.format(date); 63 } 64 65 //若转换失败返回 null 66 return null; 67 } 68 69 }
对应的配置文件名称为:ConversionAction-conversion.properties,配置内容如下:
birth=com.atguigu.struts2.app.converters.DateConverter
当Model为一个JavaBean时,Java代码如下:
1 //JavaBean为Customer 2 package com.atguigu.struts2.model; 3 4 import java.util.Date; 5 6 public class Customer { 7 8 private int age; 9 10 public void setAge(int age) { 11 this.age = age; 12 } 13 14 public int getAge() { 15 return age; 16 } 17 18 private Date birth; 19 20 public void setBirth(Date birth) { 21 this.birth = birth; 22 } 23 24 public Date getBirth() { 25 return birth; 26 } 27 28 @Override 29 public String toString() { 30 return "Customer [age=" + age + ", birth=" + birth + "]"; 31 } 32 33 } 34 35 //Action代码,Action实现了ModelDriven接口 36 package com.atguigu.struts2.app; 37 38 import com.atguigu.struts2.model.Customer; 39 import com.opensymphony.xwork2.ActionSupport; 40 import com.opensymphony.xwork2.ModelDriven; 41 42 public class ConversionAction extends ActionSupport implements ModelDriven<Customer>{ 43 44 public String execute(){ 45 System.out.println("model: " + model); 46 return "success"; 47 } 48 49 private Customer model; 50 51 @Override 52 public Customer getModel() { 53 model = new Customer(); 54 return model; 55 } 56 57 }
对应的配置文件名称为:Customer-conversion.properties,配置内容如下:
birth=com.atguigu.struts2.app.converters.DateConverter
struts.xml中的基本配置如下:
<action name="testConversion" class="com.atguigu.struts2.app.ConversionAction"> <result>/success.jsp</result> <result name="input">/index.jsp</result> </action>
通过以上代码即可完成字符串与Date类型之间的类型转换工作。
2)基于类型的配置方式
在基于类型的配置方式中,JSP页面代码与Action的代码都与基于字段的配置方式的代码相同,但是在类型转换器的代码有所不同:
1 package com.atguigu.struts2.app.converters; 2 3 import java.text.DateFormat; 4 import java.text.ParseException; 5 import java.text.SimpleDateFormat; 6 import java.util.Date; 7 import java.util.Map; 8 9 import javax.servlet.ServletContext; 10 11 import org.apache.struts2.ServletActionContext; 12 import org.apache.struts2.util.StrutsTypeConverter; 13 14 public class DateConverter extends StrutsTypeConverter { 15 16 private DateFormat dateFormat; 17 18 public DateConverter() { 19 System.out.println("DateConverter's constructor..."); 20 } 21 22 public DateFormat getDateFormat(){ 23 if(dateFormat == null){ 24 //获取当前 WEB 应用的初始化参数 pattern 25 /** 26 * web.xml的根节点中添加如下配置: 27 * <context-param> 28 * <param-name>pattern</param-name> 29 * <param-value>yyyy-MM-dd HH:mm:ss</param-value> 30 * </context-param> 31 */ 32 ServletContext servletContext = ServletActionContext.getServletContext(); 33 System.out.println(servletContext); 34 String pattern = servletContext.getInitParameter("pattern"); 35 dateFormat = new SimpleDateFormat(pattern); 36 } 37 38 return dateFormat; 39 } 40 41 @Override 42 public Object convertFromString(Map context, String[] values, Class toClass) { 43 44 System.out.println("convertFromString..."); 45 46 if(toClass == Date.class){ 47 if(values != null && values.length > 0){ 48 String value = values[0]; 49 try { 50 return getDateFormat().parseObject(value); 51 } catch (ParseException e) { 52 e.printStackTrace(); 53 } 54 } 55 } 56 57 //若没有转换成功, 则返回 values 58 return values; 59 } 60 61 @Override 62 public String convertToString(Map context, Object o) { 63 64 System.out.println("convertToString..."); 65 66 if(o instanceof Date){ 67 Date date = (Date) o; 68 return getDateFormat().format(date); 69 } 70 71 //若转换失败返回 null 72 return null; 73 } 74 75 }
★★★★★注意:关于两种配置方法情况下类型转换器创建时机不同引出的问题
在基于字段配置的方式下,类型转换器的创建时机是在第一次使用该类型转换器的时候,因此对于dateFormat的初始化工作可以在其构造方法中完成,而在基于类型的配置方式下,类型转换器是在Struts2应用被加载时创建的,由于这时ServletContext对象还未被装载到ServletActionContext中,因此获取到的servletContext对象为null,就不能在类型转换器的构造方法中对dateFormat进行初始化,因此要在使用时判断dateFormat是否为null,然后在执行操作。
基于类型配置方式的配置文件名称为:xwork-conversion.properties,配置内容如下:
java.util.Date=com.atguigu.struts2.app.converters.DateConverter
三、关于示例的说明
以上示例中对于字符串与java.util.Date类型之间的转换,在教程中所演示时无论在页面输入日期格式为“yyyy-MM-dd HH:mm:ss”,还是"yyyy/MM/dd HH:mm:ss",不使用类型转换器Struts2框架都无法正常进行转换,而自己在进行测试的时候,只要按照中文语言环境下的格式输入日期“yyyy-MM-dd”或"yyyy-MM-dd HH:mm:ss"都可以正常执行,而不需要使用类型转换器。
在网上查找后网友给出的相关解释及解决方法如下:
1)Struts2中转换Date类型的问题:http://polaris.blog.51cto.com/1146394/315403/
2)网友给出另一个解决方法:在struts.xml中定义参数:<constant name="struts.locale" value="zh_CN" />
注:该Struts2学习教程来自尚硅谷-佟刚-Struts2教程,感谢尚硅谷及佟刚老师的分享。