今天跑程序的时候莫名其妙的出现了下面的一个异常:

java.lang.NoSuchMethodException:com.ca.agent.model.mybatis.ApprovalInforCangra.setSubDate([Ljava.lang.String;)

这类异常信息在以前是处理过的,按照以前的思路在eclipse的调试模式下看看具体的情况,不过这次比较奇怪,根本没进入到对应的Action类中就抛出了此异常信息,进一步查找发现,在调用拦截器方法的时候就抛出了此异常信息,还有没有想明白的就是对应的功能我是测试过好多次的,之前这一块是没有任何问题的!不过现在事实是却抛出了异常信息,一定是那里出错了,到底是那里哪?查找了大半个下午也没找到对应的解决方案,应该是我忽略了什么地方,一时半会可能也想不起来了,找位同事帮忙吧!于是找来同事G来帮忙,最终找到了问题的原因!Struts2默认可支持String和Date的转换,但仅支持短格式和本地化有关日期格式转换,前几天我将自己的IE浏览器的语言环境改成了英语的!而对于yyyy-MM-dd这种日期类型,在英语语言中是没法匹配的,由于Struts2匹配日期时,使用了Locale,所以使用英文的语言环境,就导致了此问题的出现,把中文设置为默认语言环境后,再测试,没问题了!

转载自:http://polaris.blog.51cto.com/1146394/315403

Web开发会涉及到很多类型转换的情况。我们知道,页面中的一切值都是字符串类型,而到后台,我们需要的可能是其他各种类型;同时,页面显示也是字符串类型。这就涉及到Web中基本的类型转换问题:从String转换为各种类型与从各种类型转换为String类型。

在Java Web开发中,进行上述转换一般有以下几种:
1、在Servlet中,这一切的转换我们得自己写代码完成;
2、在Struts1.x中,我们通过apache commons-beanutils中的converters来帮助完成这些事情;
3、在Struts2中,使用的则是基于ongl的类型转换;
……

由 于类型转换的通用性,因而Web框架都会实现大多数类型的转换功能,而不需要程序员编码实现。然而,对于java.util.Date这种类型的转换,各 大框架似乎做得都不尽如人意。如:在Struts1.x中,该类型的转换就会有问题,很多人建议使用java.sql.Date这种类型来解决日期转换的 问题(实际上可以自定义一个类型转换器来解决该问题)。在Struts2中,这个问题似乎依然存在,也许你从来没有遇到过。的确,一般人确实不会遇到,会 觉得没有这个问题。下面就是我遇到的问题与解决方法。

日期类型的转换,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类型的转换,可以自己定义一个转换器。以下来自 http://www.javaeye.com/wiki/struts2/1365-passing-parameters-in-struts2 中的一个类型转换器定义(不适合国际化的环境),如需要,你可以定义自己的转换器:

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;
        }
}

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

参看:

http://ollevere.iteye.com/blog/1431947

http://www.jb51.net/article/35465.htm

http://struts2.group.iteye.com/group/wiki/1365-passing-parameters-in-struts2

Struts2中Date日期转换的问题的更多相关文章

  1. MYSQL中的日期转换

    MYSQL中的日期转换 网址: http://www.eygle.com/digest/2006/09/mysql_date_convert.html 对于每个类型拥有的值范围以及并且指定日期何时间值 ...

  2. java中的日期转换

    在java中有两种Date对象,一种是java.sql.Date,另一种是java.util.Date 一.java.sql.Date对象: 这种Date对象使用了进行数据库操作的,它对应了数据库中的 ...

  3. 填坑:Java 中的日期转换

    我们之前讨论过时间,在Java 中有一些方法会出现横线?比如Date 过期方法. 参考文章:知识点:java一些方法会有横线?以Date 过期方法为例 Java中的日期和时间处理方法 Date类(官方 ...

  4. SpringBoot+MyBatis Plus对Map中Date格式转换的处理

    在 SpringBoot 项目中, 如何统一 JSON 格式化中的日期格式 问题 现在的关系型数据库例如PostgreSQL/MySQL, 都已经对 JSON 类型提供相当丰富的功能, 项目中对于不需 ...

  5. hive中的日期转换函数

    1.unix时间戳转时间函数   语法: from_unixtime(bigintunixtime[, string format]) 返回值: string   说明: 转化UNIX时间戳(从197 ...

  6. Date()日期转换和简单计算

    /** * 判断是否为闰年 * @param year * @return */ public boolean isLeap ( int year ) { if ( (year % 4 == 0 &a ...

  7. sqlServer数据库中的日期转换

    今天开发过程中涉及到 sqlServer数据库数据同步至mysql数据,所以对日期格式转换需求,查到了一些关于sqlServer 的日期转换内容: 一般存入数据库中的时间格式为yyyy-mm-ddhh ...

  8. mysql中的日期转换函数(类似oracle中的to_date)

    最近使用mysql开发一个项目,发现没有像之前在用oracle数据中那样有to_date方法.mysql中实现日期格式化的方法为date_to_str('日期字符串','日期格式'),而且mysql中 ...

  9. 为什么你SQL Server中SQL日期转换出错了呢?

    开发人员有时候使用类似下面SQL将字符串转换为日期时间类型,乍一看,这样的SQL的写法是没有什么问题的.但是这样的SQL其实有时候就是一个定时炸弹,随时可能出现问题(),下面简单对这种情况进行一个简单 ...

随机推荐

  1. Zabbix监控mysql performance

    介绍 zabbix监控mysql性能,使用zabbix自带的mysql监控模板,可以监控以下内容OPS(增删改查).mysql慢查询数量.mysql请求\响应流量带宽 配置 新建mysql监控用户 G ...

  2. HDU 4006The kth great number(K大数 +小顶堆)

    The kth great number Time Limit:1000MS     Memory Limit:65768KB     64bit IO Format:%I64d & %I64 ...

  3. 后台动态添加的button,如何触发button_click事件?

    后台动态添加的button,需要在Page_Load或者Page_Init重新动态生成才能执行button_click public Panel GetContrlType() { Panel pan ...

  4. redis-window 集群配置

    参考文章: 1.http://www.cnblogs.com/zr520/p/5057141.html (主从配置) 2.http://www.cnblogs.com/lori/p/5825691.h ...

  5. 【译文】JNI编程

    原文链接: https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html   没有逐字翻译,解说了文章的大 ...

  6. AD域组策略-只显示指定的控制面板选项配置方法

    操作方法: 1.打开组策略管理器,新建一个组策略并右击编辑. 2,找到隐藏指定的“控制面板”项并双击打开:并参照设置: 填入要显示的控制面板项目,比如: joystick.cpl 表示将显示“游戏控制 ...

  7. php php-5.6.4.tar.bz2 apache 兼容问题 child pid 27858 exit signal Segmentation fault

    环境 [root envirotar]# uname -a Linux i2..el6.x86_64 # SMP Thu Jul :: UTC x86_64 x86_64 x86_64 GNU/Lin ...

  8. D2js 的邦联式架构

    d2js 的接口单独看有点像小手工业者,每个人摆弄着自己的小功能,但是在 update 的一声号令下,它们也可以组合起来,发挥出整体的功效,变为流水线上的工人--这一切是自然而隐蔽的进行的,小手工业者 ...

  9. ecshop后台新功能权限的添加

    1.在后台“推荐管理”里添加“推荐人分成”.“会员分成”两个操作功能以及权限    index.php?act=menu    incluedes/inc_priv.php:权限对照表.inc_men ...

  10. pycharm快捷键及一些常用设置

    pycharm快捷键及一些常用设置,有需要的朋友可以参考下. Alt+Enter 自动添加包 Ctrl+t SVN更新 Ctrl+k SVN提交 Ctrl + / 注释(取消注释)选择的行 Ctrl+ ...