Struts2+Hibernate项目中的时间和日期问题

数据表中的 datetime 的数据如何通过 json 传送给前端仅展示其日期,而不展示时间

数据表列的类型是 datetime,数据格式如下:

2022-07-13 02:07:05

hibernate 的映射类型 date 或者 timestamp,如下:

<property generated="never" lazy="false" name="startDate" type="timestamp">
	<column name="start_date"/>
</property>
<!--或者-->
<property generated="never" lazy="false" name="startDate" type="java.util.Date">
	<column name="start_date"/>
</property>

实体类属性的类型是 date 或者 timestamp,如下:

private Timestamp startDate;// 或 java.util.Date
private Timestamp endDate;

前端日期控件的类型是 date,如下:

<input id="startDate" type="date" name="project.startDate" value="${project.startDate}"/>

后端返回给前端的数据格式是 json,如下:

{"project":{"code":"pm0001","endDate":"2021-12-08T00:00:00","id":34,"name":"pm0001","startDate":"2021-12-08T00:00:00"}}

其实就是将 Action 对象的属性值转换成 json 串 返回给前端。

其中的日期时间格式如下:

2021-12-08T00:00:00

就这样的日期时间格式,前端的 date 控件是无法将其展示出来的,但是你把前端日期控件改成 datetime-local,是可以正常展示的。但是如果你非要使用 date 日期控件展示呢?那么就可以在实体类的有关日期时间属性的 getter 方法上加上注解 @JSON(format = "yyyy-MM-dd"),这样传送给前端日期格式就会变成 2021-12-08,date 控件才能将其展示出来。

注:在项目 struts2-hibernate-pms 的恢复项目信息功能中有遇到这个问题

日期控件

 <input id="endDate" type="datetime-local" name="project.endDate" value="${project.endDate}"/>

2021-12-08T00:00:00,2021-12-08 00:00:00 这种格式的日期时间,date 控件无法将其显示出来。

2021-12-08T00:00:00 这种格式的日期时间,datetime-local 控件无法将其展示出来。

2021-12-08 这种格式的日期数据,datetime-local 控件无法将其展示出来。

datetime-local 控件传送给服务端的日期时间格式为:2022-08-27T10:41:00

日期时间数据展示问题

实体类属性的数据类型:Timestamp 或者 java.util.Date
数据表对应列的数据类型:datatime
hibernate的映射类型:java.util.Date 或者 timestamp
在封装成实体类对象时,日期时间的格式是正常的:2021-12-08 00:00:00,所以可以直接将其赋值给前端的 datetime-local 控件展示出来。

如果实体类属性的数据类型是 Timestamp,把 hibernate 的映射类型改成 date,则在封装数据时会报错。如果实体类属性的数据类型是 java.util.Date,把 hibernate 的映射类型改成 date,不会报错,会得到日期 2021-12-08。

日期时间数据存储问题

场景一

实体类属性的数据类型:java.util.Date
数据表对应列的数据类型:datatime
hibernate的映射类型:java.util.Date 或者 timestamp
前端日期时间控件类型是:datetime-local,你输入的是 2021-12-08 02:15:35 这种格式的日期时间,实际传送给服务端的格式是这样的:2022-08-18T11:04:35

struts2 的注入参数数据的拦截器会构造一个实体类对象,获取所有的参数数据,这些参数数据都是字符串类型的。例如获取字符串 2022-08-18T11:04,会将这个字符串转换成 java.util.Date 对象,再调用实体类对象对应的 setter 方法将上述对象存储到实体类对象中,所有的参数数据存储到实体类对象后,再调用 Action 对象对应的 setter 方法将实体类对象存储到 Action 对象中,这就是完成参数数据的注入,最终是注入到 Action 对象对应的属性中(严格讲应该是 Action 对象的属性对应的成员变量中)。

最终将 2021-12-08T02:15:35 转换成 Date 对象,这个对象的输出的结果如下:

Thu Aug 04 00:00:00 CST 2022

虽然可以成功转换成 Date 对象,但是时间被阉割了。

怎么办?

写转换器将字符串 2021-12-08T02:15:35 转换成 Date 对象。

第一步写转换器类,我这里写一个将字符串转换成Date对象或者Timestamp对象的转换器:

package priv.lwx.datetime.converter;

import org.apache.struts2.util.StrutsTypeConverter;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

/**
 * 将字符串的日期时间转换成Date对象或者Timestamp对象
 *
 * @author liaowenxiong
 * @date 2022/8/13 21:06
 */

public class Converter extends StrutsTypeConverter {
    
    
  DateFormat[] df = {
    
    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"),
          new SimpleDateFormat("yyyyMMdd"),
          new SimpleDateFormat("yyyy年MM月dd日")};

  /**
   * @param context 当前上下文环境
   * @param values  jsp表单提交的字符串参数
   * @param toClass 要转换为的目标类型,这个在配置文件xwork-conversion.properties指定中
   */
  @Override
  public Object convertFromString(Map context, String[] values, Class toClass) {
    
    
    // values里面只有一个元素,就是请求参数的值
    System.out.println(values[0]);
    // 判断字符串数组的内容不能为空
    if (values == null || values.length == 0) {
    
    
      return null;
    }
    // 转换失败继续下一个格式的转换; 转换成功就直接返回
    for (int i = 0; i < df.length; i++) {
    
    
      try {
    
    
        String datetime = values[0].replaceAll("T", " ") + ":00";
        Date date = df[i].parse(datetime);
        if (toClass == Date.class) {
    
    
          // 判断要转换的目标类型是不是Date
          return date;
        } else if (toClass == Timestamp.class) {
    
    
          // 判断要转换的目标类型是不是Timestamp
          // System.out.println(date);
          return new Timestamp(date.getTime());
        }
      } catch (ParseException e) {
    
    
        continue;
      }
    }
    return null;
  }

  @Override
  public String convertToString(Map context, Object o) {
    
    
    if (o instanceof Date) {
    
    
      // 判断o是不是Date的实例
      Date date = (Date) o;
      return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
    }
    if (o instanceof Timestamp) {
    
    
      // 判断o是不是Timestamp的实例
      Timestamp timestamp = (Timestamp) o;
      //输出的格式是yyyy-MM-dd
      return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timestamp);
    }
    return null;
  }

}

第二步写配置文件 xwork-conversion.properties,内容为:

java.util.Date=priv.lwx.pms.converter.Converter

等号左边指定你要转换的目标类型,在调用转换器方法时,会根据这个类型获取其 Class 对象,传入转换器方法中。等号右边就是转换器类的全限定名。

上面的配置文件是全局性的,放置在 resources 目录下,如果是针对某个类中的某些属性进行转换,则将配置文件放置在该类所在的目录下。配置文件名称规则:类名-conversion.properties,配置文件内容规则:属性名称=类型转换器类的全限定名

场景二

实体类属性的数据类型:Timestamp
数据表对应列的数据类型:datatime
hibernate的映射类型:timestamp 或者 java.util.Date
前端日期时间控件类型是:datetime-local,你输入的是 2021-12-08 02:15:35 这种格式的日期时间

[‘2022-08-27T10:41’, ] 无法转换成 Timestamp 对象或者 Date 对象,报错了。

Unexpected Exception caught setting 'project.endDate' on 'class priv.lwx.pms.action.ProjectCreateAction: Error setting expression 'project.endDate' with value ['2022-08-27T10:41', ]

怎么办?
写转换器,将 2022-08-27T10:41 转换成 Timestamp 对象。转换器类就用上述的,配置文件中的内容如下:

java.sql.Timestamp=priv.lwx.pms.converter.Converter

场景三

实体类属性的数据类型:java.util.Date
前端日期时间控件类型是:datetime-local,你输入的是 2021-12-08 02:15:35 这种格式的日期时间

前端对日期时间进行处理,将 2021-12-08T02:15:35 处理成 2021-12-08 02:15:35 再传送给服务端。如果 Action 对应的属性的类型是 Date,那么 struts2 注入数据的拦截器会将这个字符串转换成 Date 对象,有趣的是,在转换的时候 2021-12-08 02:15:35 中的时间部分还是会被阉割掉。你把 Date 打印到控制台看到的结果如下:

参数startDate的值:2022-08-12 01:29:00
startDate:Fri Aug 12 00:00:00 CST 2022

怎么办?
写转换器将 2021-12-08T02:15:35 日期转换成 Date 对象,那么前端就不要处理了,没用!

场景四

实体类属性的数据类型:Timestamp
前端日期时间控件类型是:datetime-local,你输入的是 2021-12-08 02:15:35 这种格式的日期时间

前端对日期时间进行处理,将 2021-12-08T02:15:35 处理成 2021-12-08 02:15:35 再传送给服务端。如果 Action 对应的属性的类型是 Timestamp,那么 struts2 注入数据的拦截器会将这个字符串转换成 Timestamp 对象,结果报错了:

Unexpected Exception caught setting 'startDate' on 'class priv.lwx.datetime.action.CreateProjectAction: Error setting expression 'startDate' with value ['2022-08-15 02:35:00', '2022-08-15T02:35', ]

怎么办?

写转换器,实体类属性的类型是 Timestamp,而服务端收到的日期时间的数据类型是字符串,那么就写一个将字符串转换成 Timestamp的转换器

第一步写转换器类,我这里写一个将字符串转换成Date对象或者Timestamp对象的转换器:

package priv.lwx.datetime.converter;

import org.apache.struts2.util.StrutsTypeConverter;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

/**
 * 将字符串的日期时间转换成Date对象或者Timestamp对象
 *
 * @author liaowenxiong
 * @date 2022/8/13 21:06
 */

public class Converter extends StrutsTypeConverter {
    
    
  DateFormat[] df = {
    
    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"),
          new SimpleDateFormat("yyyyMMdd"),
          new SimpleDateFormat("yyyy年MM月dd日")};

  /**
   * @param context 当前上下文环境
   * @param values  jsp表单提交的字符串参数
   * @param toClass 要转换为的目标类型,这个在配置文件xwork-conversion.properties指定中
   */
  @Override
  public Object convertFromString(Map context, String[] values, Class toClass) {
    
    
    // values里面只有一个元素,就是请求参数的值
    System.out.println(values[0]);
    // 判断字符串数组的内容不能为空
    if (values == null || values.length == 0) {
    
    
      return null;
    }
    // 转换失败继续下一个格式的转换; 转换成功就直接返回
    for (int i = 0; i < df.length; i++) {
    
    
      try {
    
    
        String datetime = values[0].replaceAll("T", " ") + ":00";
        Date date = df[i].parse(datetime);
        if (toClass == Date.class) {
    
    
          // 判断要转换的目标类型是不是Date
          return date;
        } else if (toClass == Timestamp.class) {
    
    
          // 判断要转换的目标类型是不是Timestamp
          // System.out.println(date);
          return new Timestamp(date.getTime());
        }
      } catch (ParseException e) {
    
    
        continue;
      }
    }
    return null;
  }

  @Override
  public String convertToString(Map context, Object o) {
    
    
    if (o instanceof Date) {
    
    
      // 判断o是不是Date的实例
      Date date = (Date) o;
      return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
    }
    if (o instanceof Timestamp) {
    
    
      // 判断o是不是Timestamp的实例
      Timestamp timestamp = (Timestamp) o;
      //输出的格式是yyyy-MM-dd
      return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timestamp);
    }
    return null;
  }

}

第二步写配置文件 xwork-conversion.properties,内容为:

java.sql.Timestamp=priv.lwx.datetime.converter.Converter

等号左边指定你要转换的目标类型,在调用转换器方法时,会根据这个类型获取其 Class 对象,传入转换器方法中。等号右边就是转换器类的全限定名。

上面的配置文件是全局性的,放置在 resources 目录下,如果是针对某个类中的某些属性进行转换,则将配置文件放置在该类所在的目录下。配置文件名称规则:类名-conversion.properties,配置文件内容规则:属性名称=类型转换器类的全限定名

猜你喜欢

转载自blog.csdn.net/liaowenxiong/article/details/125644685