因为工作原因,最近主攻Exj了,Ext可真是个好东西,不过由于新学,问题也不少,什么乱码啦,日期格式啦,搞得人头都大了,不过还好,现在互联网这么发达,查查baidu,google几乎就能找到自己要的答案,不过关于日期格式的问题,网上少了几篇详细的,有价值的文章,所以,今天我就来说说这个日期格式的问题,这也是我刚刚在实际项目解决的问题。
我先描述一下我的项目吧
项目架构是:struts2.0 + spring + hibernate + extjs 3.0
数据库为:mysql
首先我需要做一个EditGridPanel,显示的一个用户列表(一个List<User>),在这个用户列表里有一个单元格要以“年-月-日”的格式显示用户生日,这个单元格要求能用DateField控件修改。
(...今天不说ssh2,所以我直接说和Extjs相关的部分了)
基于这个要求,我首先想到后台可以用JSONObject这个类把后台的javabean转换为json类型的数据,然后通过printwriter流把数据传递到前台,下面是相关代码:
- Action.java:
- ....
- JSONObject jsonObject = JSONObject.fromObject(pageBean,UtilBox.configJson());
- HttpServletResponse response = this.getHttpServletResponse();
- PrintWriter pw = response.getWriter();
- pw.write(jsonObject.toString());
- ...
Action.java:
....
JSONObject jsonObject = JSONObject.fromObject(pageBean,UtilBox.configJson());
HttpServletResponse response = this.getHttpServletResponse();
PrintWriter pw = response.getWriter();
pw.write(jsonObject.toString());
...
有人要问了,pageBean是个什么东西?我这样说吧,为了实现Extjs的分页,我写了一个PageBeanlei类,里面就两个属性,一个是List,用于放用户信息的集合,另一个是这个list的总条数,怎么样,这个pageBean不用多说了吧?关键是后面这个UtilBox.configJson(),这又是个啥呢?这是一个JsonConfig类型的参数,用于解析第一个参数里的属性类型,UtilBox就是我自己写的一个工具类,为了复用嘛,下面是它的代码:
- Utilbox.java :
- ....
- public static JsonConfig configJson(){
- JsonConfig jcf = new JsonConfig();
- jcf.registerJsonValueProcessor(Date.class, new JsonDateValueProcessor());
- return jcf;
- }
- ....
Utilbox.java :
....
public static JsonConfig configJson(){
JsonConfig jcf = new JsonConfig();
jcf.registerJsonValueProcessor(Date.class, new JsonDateValueProcessor());
return jcf;
}
....
简单几行代码。等等。。这个Extjs的日期格式有什么关系啊?
之所以要写这个,是因为json-lib对java的日期格式仿佛未作任何处理,通过打印Action里json.toString发现,传回前台的json是的格式为:{"date":17,"day":0",hour":17,........."year":109},这样显然加重了对日期解析的苦难,于是我们可以通过实现json-lib预留的扩展接口JsonValueProcessor来完成对日期的解析,
- jcf.registerJsonValueProcessor(Date.class, new JsonDateValueProcessor());
jcf.registerJsonValueProcessor(Date.class, new JsonDateValueProcessor());
这里表示,遇到Date类型的参数,我们将用JsonDateValueProcessor这个类来解析。JsonDateValueProcessor是我自己定义的一个实现了JsonValueProcessor的类,下面是它的代码:
- JsonDateValueProcessor .java:
- public class JsonDateValueProcessor implements JsonValueProcessor {
- private String format = "yyyy-MM-dd";
- public JsonDateValueProcessor() {
- }
- public Object processArrayValue(Object value, JsonConfig jcf) {
- String[] obj = {};
- if(value instanceof Date[]){
- SimpleDateFormat sdf = new SimpleDateFormat(format);
- Date[] dates = (Date[])value;
- obj = new String[dates.length];
- for(int i=0;i<dates.length;i++){
- obj[i] = sdf.format(dates[i]).trim();
- }
- }
- return obj;
- }
- public Object processObjectValue(String key, Object value, JsonConfig jcf) {
- if(value instanceof Date){
- String str = new SimpleDateFormat(format).format((Date)value);
- return str.trim();
- }
- return value==null?null:value.toString();
- }
JsonDateValueProcessor .java:
public class JsonDateValueProcessor implements JsonValueProcessor {
private String format = "yyyy-MM-dd";
public JsonDateValueProcessor() {
}
public Object processArrayValue(Object value, JsonConfig jcf) {
String[] obj = {};
if(value instanceof Date[]){
SimpleDateFormat sdf = new SimpleDateFormat(format);
Date[] dates = (Date[])value;
obj = new String[dates.length];
for(int i=0;i<dates.length;i++){
obj[i] = sdf.format(dates[i]).trim();
}
}
return obj;
}
public Object processObjectValue(String key, Object value, JsonConfig jcf) {
if(value instanceof Date){
String str = new SimpleDateFormat(format).format((Date)value);
return str.trim();
}
return value==null?null:value.toString();
}
好了,完成这样的工作后,我们再看看Action里的json.toString后的结果是什么样的呢?{"birthday":"1970-10-01".....}这样的json数据对于Extjs来讲,好解析多了吧~?
好,如果你自己搭建的Extjs只是需要显示日期格式,那这样就可以了
不过我的项目是要求不仅能显示,还要能通过DateField修改,这样新的问题就出现了.
般我们的前台代码Ext.grid.ColumnModel里会这样写,以便显示日期格式:
- ....
- {header:"birthday",dataIndex:"birthday".......renderer:new Ext.util.Format.dateRenderer("Y-m-d"),
- ....
如果你前台这样写的话,那恭喜你,你的显示日期那列将不再正确显示时间,而是显示为"NaN-NaN-NaN",是吧?呵呵,问我怎么知道的?因为最开始我也是这么错的。 为什么会是错的呢?让我们来看看Ext.format.dateRenderer的源代码(开源的东西就是好),它的源代码是这样的:
- dateRenderer : function(format) {
- return function(v) {
- return Ext.util.Format.date(v, format);、
- }
- }
可以看出,我们传会来的值,被当做日期又被格式化了一次,我们传回来的是日期吗?以前是,经过昨天后台代码的修改,我们传回来的仅仅是个字符串了,至于为什么要这么改,请看昨天写的“Extjs日期格式问题(一) ”,那咋办?有的朋友应该已经想到了,既然是字符串,那就直接显示呗,不用renderer了,于是前台代码Ext.grid.ColumnModel里就变成了:
- ....
- {header:"birthday",dataIndex:"birthday".......),
- ....
可以负责任的告诉你,这样写,绝对可以正确显示了,这样是不是感觉更简单了呢?
但是,基于我项目里的要求,这个问题并没有解决完,因为在这里不是一个简单的gridpanel,而是一个editgridpanel,所以还得定义一个editor,于是有了下面这样一段代码:
- ....
- {header:"birthday",dataIndex:"birthday".......,
- editor:new Ext.grid.GridEditor(new Ext.form.DateField({format:"Y-m-d"})),
- ....
加了这个DateField控件后,每次可以正常的选择日期,但是选择完日期后,grid里显示的格式就又不正确了,这次显示的内容成了: "Wed Mar 04 1970......",这样的格式一看就是个日期,这样显示的原因当然是因为我们没有写renderer进行格式化处理的缘故。。。
说到这里,有人应该已经想到解决办法了,另外有些人可能就抓狂了,这renderer加了不能正常显示,不加也不能正常显示,这很矛盾啊。。
问题往往到了最矛盾的时候,也是到了解决的时候,现在我把解决代码贴出来,大家一看就明白了。多的不说,看代码:
- renderer:function(value){
- if(value instanceof Date){
- return new Date(value).format("Y-m-d");
- }else{
- return value;
- }
- }
简单吧?自己写renderer就是了。。