`
paddy.w
  • 浏览: 498219 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Struts2的Date类型转换

阅读更多
        昨天随便写了个小例子,前台页面有个文本框输入的是日期格式(yyyy-mm-dd),action中用的是Date类型。运行了一下,struts2正确的进行了类型转换。今天再次运行时,控制台报错,大体意思就是找不到一个参数是String类型的set方法。我就奇怪了,struts2不是内置了Date的类型转换么,昨天运行的也好好的,今天怎么回事?然后查了一下,找到这篇文章,和我遇到的问题一模一样:
        http://polaris.blog.51cto.com/1146394/315403
        下面截取转贴一下:

        日期类型的转换,Web开发中几乎都会遇到,我现在做得项目也不例外。在开发的过程中,也许就像你一样,我没有对日期类型的转换做任何特殊的处理,而且Struts2也很好的帮我完成了转换。然而同事测试的时候却出现了一个“莫名其妙”的问题:输入一个常用格式的日期类型yyyy-MM-dd,到后台却报错:找不到对应的set方法——setEffDate(Ljava.lang.String)。的确,程序中只有setEffDate(java.util.Date)这个方法,没有setEffDate(Ljava.lang.String)这个方法。从Ljava.lang.String可以看出,传到后台的String类型并没有转换成Date类型,因而报错。

        一开始,我以为是我UT没做好,于是在自己的电脑上模拟同事的测试,结果一点问题也没有。这就奇怪了。经过自己分析,觉得可能是IE浏览器的原因,因为同事测试用的是IE,而我用的是FireFox。于是在自己的机子上用IE测试,同时在同事机子上用FireFox测试,结果这两次测试都没有出现上面的问题。虽然没有找到问题所在,但可以初步肯定:IE的问题,但似乎又不完全是IE的问题,因为在我的电脑上的IE(版本与同事一样,都是IE6)没有上述问题。这就奇怪了,是什么问题呢,真是百思不得其解。

        这个时候,我想起了之前遇到的一个不解得情况:从后台获得的日期类型在页面上显示时,跟上面情况一样,在同事的IE中,日期显示的格式竟然是:yyyy-MM-ddTHH:mm:ss。多了一个T,真是莫名其妙,而且只在同事的IE浏览器中出现(当时解决方法是在JS中将'T'替换为空格,没有去深究,但现在必须的深究了)。yyyy-MM-ddTHH:mm:ss这种日期格式有吗?于是查询JDK:在SimpleDateFormat类中找到了该日期格式,这种格式是“美国语言环境中日期和时间的模式之一”。原来还真有这种格式。竟然这是美国语言中使用的日期格式,而Struts2是美国人开发的,也许跟这个有点关系。于是查看Struts2中关于Date类型转换的源码。
        在XWorkBasicConverter类中
private Object doConvertToDate(Map<String, Object> context, Object value, Class toType) {
	Date result = null;

	if (value instanceof String && value != null && ((String) value).length() > 0) {
		String sa = (String) value;
		Locale locale = getLocale(context);

		DateFormat df = null;
		if (java.sql.Time.class == toType) {
			df = DateFormat.getTimeInstance(DateFormat.MEDIUM, locale);
		} else if (java.sql.Timestamp.class == toType) {
			Date check = null;
			SimpleDateFormat dtfmt = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT,
					DateFormat.MEDIUM,
					locale);
			SimpleDateFormat fullfmt = new SimpleDateFormat(dtfmt.toPattern() + MILLISECOND_FORMAT,
					locale);

			SimpleDateFormat dfmt = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT,
					locale);

			SimpleDateFormat[] fmts = {fullfmt, dtfmt, dfmt};
			for (SimpleDateFormat fmt : fmts) {
				try {
					check = fmt.parse(sa);
					df = fmt;
					if (check != null) {
						break;
					}
				} catch (ParseException ignore) {
				}
			}
		} else if (java.util.Date.class == toType) {
			Date check = null;
			DateFormat[] dfs = getDateFormats(locale);
			for (DateFormat df1 : dfs) {
				try {
					check = df1.parse(sa);
					df = df1;
					if (check != null) {
						break;
					}
				}
				catch (ParseException ignore) {
				}
			}
		}
		//final fallback for dates without time
		if (df == null) {
			df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
		}
		try {
			df.setLenient(false); // let's use strict parsing (XW-341)
			result = df.parse(sa);
			if (!(Date.class == toType)) {
				try {
					Constructor constructor = toType.getConstructor(new Class[]{long.class});
					return constructor.newInstance(new Object[]{Long.valueOf(result.getTime())});
				} catch (Exception e) {
					throw new XWorkException("Couldn't create class " + toType + " using default (long) constructor", e);
				}
			}
		} catch (ParseException e) {
			throw new XWorkException("Could not parse date", e);
		}
	} else if (Date.class.isAssignableFrom(value.getClass())) {
		result = (Date) value;
	}
	return result;
}

private DateFormat[] getDateFormats(Locale locale) {
	DateFormat dt1 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, locale);
	DateFormat dt2 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, locale);
	DateFormat dt3 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale);

	DateFormat d1 = DateFormat.getDateInstance(DateFormat.SHORT, locale);
	DateFormat d2 = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
	DateFormat d3 = DateFormat.getDateInstance(DateFormat.LONG, locale);

	DateFormat rfc3399 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");

	DateFormat[] dfs = {dt1, dt2, dt3, rfc3399, d1, d2, d3}; //added RFC 3339 date format (XW-473)
	return dfs;
}


        其中SHORT、MEDIUM、LONG在JDK中的DateFormat类中有说明。
        从这句DateFormat rfc3399 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");可以看出,Struts2硬编码使用了这样一种格式。然而,Struts2中这种格式是放在最后的,为啥只有同事的IE浏览器测试时使用的是这种格式呢?(在调试时,用同时IE,日期输入中按这种格式输入,还真的没有问题了)这说明,同时的电脑中,前面六种DateFormat都没有匹配,查看DateFormat中关于SHORT、MEDIUM、LONG的说明,可以知道,对于yyyy-MM-dd这种日期类型,在英语语言中是没法匹配的,由于Struts2匹配日期时,使用了Locale,可见,同事的IE浏览器默认的语言环境是英语。一经查看,果然如此,把中文设置为默认语言环境,再测试,没问题了。终于知道了原因。

        个人觉得,Struts2中,最后一种日期模式写死成美国标准,不是很好。

        针对这个问题,我们没法要求客户一定设置中文为默认浏览器的语言环境。因而对于Date类型的转换,可以自己定义一个转换器。以下来自[url]http://www.iteye.com/wiki/struts2/1365-passing-parameters-in-struts2 [/url]中的一个类型转换器定义(不适合国际化的环境),如需要,你可以定义自己的转换器:

public class DateConverter extends DefaultTypeConverter {

        private static final Logger logger = Logger.getLogger(DateConverter.class);

        private static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

        private static final String DATE_PATTERN = "yyyy-MM-dd";
        
        private static final String MONTH_PATTERN = "yyyy-MM";

        /**
         * Convert value between types
         */
        @SuppressWarnings("unchecked")
        public Object convertValue(Map ognlContext, Object value, Class toType) {
                Object result = null;
                if (toType == Date.class) {
                        result = doConvertToDate(value);
                } else if (toType == String.class) {
                        result = doConvertToString(value);
                }
                return result;
        }

        /**
         * Convert String to Date
         *
         * @param value
         * @return
         */
        private Date doConvertToDate(Object value) {
                Date result = null;

                if (value instanceof String) {
                        result = DateUtils.parseDate((String) value, new String[] { DATE_PATTERN, DATETIME_PATTERN, MONTH_PATTERN });

                        // all patterns failed, try a milliseconds constructor
                        if (result == null && StringUtils.isNotEmpty((String)value)) {

                                try {
                                        result = new Date(new Long((String) value).longValue());
                                } catch (Exception e) {
                                        logger.error("Converting from milliseconds to Date fails!");
                                        e.printStackTrace();
                                }

                        }

                } else if (value instanceof Object[]) {
                        // let's try to convert the first element only
                        Object[] array = (Object[]) value;

                        if ((array != null) && (array.length >= 1)) {
                                value = array[0];
                                result = doConvertToDate(value);
                        }

                } else if (Date.class.isAssignableFrom(value.getClass())) {
                        result = (Date) value;
                }
                return result;
        }

        /**
         * Convert Date to String
         *
         * @param value
         * @return
         */
        private String doConvertToString(Object value) {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATETIME_PATTERN);
                String result = null;
                if (value instanceof Date) {
                        result = simpleDateFormat.format(value);
                }
                return result;
        }
}


        可以将该转换器注册为全局的:在src(eclipse)下建立xwork-conversion.properties文件,内容为:java.util.Date=你的类型转换器的完整限定类名

        再多说几句,我的系统是英文的,用的是chrome浏览器测试的。问题是,一天之内这系统环境都没变过,为啥前一次就通过了,后一次就通不过呢……到现在也没搞明白=。=
分享到:
评论

相关推荐

    struts2自定义类型转换器

    使用struts2提供的转化器,实现Date类型的数据转换

    struts2 Date转换问题

    NULL 博文链接:https://happywaterlife.iteye.com/blog/1602352

    自己写的struts2类型转换器

    服务器可以接收到的来自用户的数据只能是字符串或者是字符串数组,而在服务器上的对象中 ,这些数据往往有多种不同的类型,如日期(Date) 整数(int) 浮点数... 要实现 上述的转换 ,Struts2中 提供了 converter。

    如何解决struts2日期类型转换

    在Struts2中,一般的内置类型都会在由系统自动进行转换.但是Date类型好像有时候行,有时候不行。比如我这次,本地运行正常,一上测试服务器就不行了。这个转换类是从网上看的:

    struts2讲义_吴峻申

    7.1 Struts2类型转换使用介绍 135 7.1.1 基本数据类型转换功能 135 7.1.2 List集合类型数据类型转换功能 138 7.1.3 Set集合类型数据类型转换功能 141 7.2 类型转换发生异常处理方案 144 7.2.1 Struts2自带异常提示 ...

    struts的form不能初始化java.util.Date类型

    NULL 博文链接:https://maserkinger.iteye.com/blog/719937

    struts2总结第二章

    Struts2总结第二章 一、 局部类型转换: a) 写Date类型转换类 b) 在要进行Date类型转换的类的同一包下,新建一个properties文件 i. 名称为Date类型的数据所在的类的名称-conversion.properties ii. 内容为 name:该...

    深入浅出Struts2(附源码)

    作者处处从实战出发,在丰富的示例中直观地探讨了许多实用的技术,如数据类型转换、文件上传和下载、提高Struts 2应用的安全性、调试与性能分析、FreeMarker、Velocity、Ajax,等等。跟随作者一道深入Struts 2,聆听...

    Struts2 国际化字符串 拦截器

    2. 使用java.text.MessageFormat中的字符串格式,格式为{ 参数序号(从0开始), 格式类形(number | date | time | choice), 格式样式},例如: validation.between=Date must between {0, date, short} and {1, ...

    struts的input标签支持日期格式化输出

    修改struts标签text,使其支持日期类型的格式化输出。 用法:(例) ...3.页面中遇到Timestamp或Date类型的,自动转换成"yyyy-MM-dd HH:mm:ss"格式, simpleDateFormat还可以其它的格式,如"yyyy-MM-dd"等。

    深入浅出Struts 2 .pdf(原书扫描版) part 1

    如数据类型转换、文件上传和下载、Struts2应用的安全性、调试与性能分析、FreeMarker、Velocily、Ajax,等等。跟随作者一道深入Struts2。聆听大量来之不易的经验之谈。你对Struts2开发框架的理解和应用水平都将更上...

    适合初学者的SSH项目(CRUD、Oracle、Date)

    适合SSH初学者的CRUD项目,使用了Oracle,包含struts中datetimepicker控件的使用,及java端与Oracle端,Date数据类型转换的解决方案。

    struts登录demo(包括时间属性)

    3.其中有Date类型。默认是java.sql.Date,这样actionform可以自动转化。 4.使用java.util.Date,则需要写个转换器。然后注到服务器中。 这个例子可以参考博客:...

    Struts in Action中文版

    2. 深入 STRUTS架构..................................................................................37 2.1. 随便谈谈......................................................................................

    struts in Action

    2. 深入STRUTS 架构..................................................................................37 2.1. 随便谈谈.......................................................................................

    Java学习笔记-个人整理的

    {1.6}数据类型转换}{26}{section.1.6} {1.7}方法}{26}{section.1.7} {1.8}运算符}{27}{section.1.8} {1.8.1}自增运算}{28}{subsection.1.8.1} {1.8.1.1}Postincrement}{28}{subsubsection.1.8.1.1} {1.8.1.2}...

    freemarker总结

    2,使用+运算符时,如果一边是数字,一边是字符串,就会自动将数字转换为字符串再连接,如:${3 + "5"},结果是:35 使用内建的int函数可对数值取整,如: ${ (x/2)?int } ${ 1.1?int } ${ 1.999?int } ${ -1.1?int } ...

    JavaServer Faces 2.0完全参考手册(JSF2.0中文版) 1/2

    1.2.4 apachestruts 1.2.5 spring框架和springmvc 1.2.6 javaserverfaces的诞生 1.3 javaserver faces设计目标 1.4 jsf应用程序架构 1.4.1 jsf请求处理生命周期 1.4.2 jsf导航模型 第2章 构建一个简单的javaserver ...

Global site tag (gtag.js) - Google Analytics