1. 描述
最近在写基于springmvc+ibatis, restfull 风格的后台api, 前端是ios和android, 数据库使用的mysql (连接池是druid),商品数据缓存到redis和Elasticsearch。
在数据库、后台(java编写)、前端(ios和android) 三者之间传输数据时,遇到了一个小问题,就是关于时间戳的问题。有个字段是actionTime
数据库: Timestamp
后台: javasql.Timestamp
前端: long
后台与数据库交互使用timestamp没什么问题,但是在后台与前端交互是需要返回json数据,时间戳需要是13位的数字。问题由此而展开。
- java读取数据库数据,通过ibatis直接转换到javaBean
- 将javaBean转换成json, 其中时间戳由Timestamp对象转换成数字,然后存入缓存(redis和Elasticsearch)
- 前端获取商品需,调用后台api ,后台从缓存读取数据(返回json字符串),然后再组合数据,在组合的过程中需要将json转换成javaBean,而在次转换过程中需要将json中的时间戳long型转换成Timestamp,而默认情况下是没法直接转换的(Long->Timestamp)
2. Bean2Json(Timestamp2Long)
使用jsonConfig注册一个自定义转换器,然后在此转换器中进行转换
//Product product = query db;
private static JsonConfig jsonConfig = new JsonConfig();
static{
jsonConfig.registerJsonValueProcessor(Date.class, new JsonDateValueProcessor());
jsonConfig.registerJsonValueProcessor(Timestamp.class, new JsonDateValueProcessor());
}
JSONObject json = JSONObject.fromObject(product, jsonConfig);
JsonDateValueProcessor.java
import net.sf.json.JsonConfig;
import net.sf.json.processors.JsonValueProcessor;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* Created by karl on 2014/12/4.
*
* 然后在调用JSONObject之前创建一个JsonConfig,并且将上一步定义的date转换器注册进去:
*
* JsonConfig jsonConfig = new JsonConfig();
jsonConfig.registerJsonValueProcessor(Date.class, new JsonDateValueProcessor());
jsonConfig.registerJsonValueProcessor(Timestamp.class, new JsonDateValueProcessor());
*/
public class JsonDateValueProcessor implements JsonValueProcessor {
private String format = null; //"yyyy-MM-dd";
public JsonDateValueProcessor() {
super();
}
public JsonDateValueProcessor(String format) {
super();
this.format = format;
}
@Override
public Object processArrayValue(Object o, JsonConfig jsonConfig) {
return process(o);
}
@Override
public Object processObjectValue(String s, Object o, JsonConfig jsonConfig) {
return process(o);
}
private Object process(Object value){
if(value instanceof Date || value instanceof Timestamp){
if(format!=null) {
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.CHINA);
return sdf.format(value);
}else{
long time = ((Date)value).getTime();
return new Long(time);
}
}else if(value instanceof Long){
return new Timestamp((Long)value);
}
return value == null ? null : value.toString();
}
}
3. Json2Bean(Long2Timestamp) 反序列化
注册一个与上述过程相反的过程,下面的支持将long->timestamp ,也支持string->timestamp.
使用方式如下:
String[] formats={"yyyy-MM-dd HH:mm:ss","yyyy-MM-dd"};
JSONUtils.getMorpherRegistry().registerMorpher(new TimestampMorpher(formats));
JSONObject json = JSONObject.fromObject(jsonString, jsonConfig);
TimestampMorpher.java
/**
* Created by karl on 2014/12/18.
*/
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import net.sf.ezmorph.MorphException;
import net.sf.ezmorph.object.AbstractObjectMorpher;
/*** 将json串中的日期字符串转换为bean中的Timestamp*/
public class TimestampMorpher extends AbstractObjectMorpher {
/*** 日期字符串格式*/
private String[] formats = null;
public TimestampMorpher(String[] formats) {
this.formats = formats;
}
public Object morph(Object value) {
if( value == null){
return null;
}
if( Timestamp.class.isAssignableFrom(value.getClass()) ){
return (Timestamp) value;
}
if( !supports( value.getClass()) ){
throw new MorphException( value.getClass() + " 是不支持的类型");
}
if(value instanceof Long){
Long time = (Long)value;
return new Timestamp(time);
}else if(value instanceof String) {
String strValue = (String) value;
SimpleDateFormat dateParser = null;
for (int i = 0; i < formats.length; i++) {
if (null == dateParser) {
dateParser = new SimpleDateFormat(formats[i]);
} else {
dateParser.applyPattern(formats[i]);
}
try {
return new Timestamp(dateParser.parse(strValue.toLowerCase()).getTime());
} catch (ParseException e) {
//e.printStackTrace();
}
}
}
return null;
}
@Override
public Class morphsTo() {
return Timestamp.class;
}
public boolean supports( Class clazz ){
// Long to Timestamp
// String to Timestamp
return (Long.class.isAssignableFrom( clazz ) | String.class.isAssignableFrom( clazz ));
}
}