一个特殊需求,需要数据库实体对象转换成json的时候,key为数据库原表字段,value Date 转String,找了找博客,看了看fastjson的源码之后,决定重写JavaBeanSerializer 的 processKey 和 processValue 方法(这两个都是protected方法)
主要思路是解析mybatisplus 的 TableField 和 TableId 注解,转换key时碰到了个问题,由于早期的业务系统数据库命名不规范,无法通过Class.getDeclaredField(String name)直接获取该字段和对应注解信息,所以就只能获取所有字段然后一一进行字符小写比对,为了提高效率,定义了一个全局的静态ConcurrentHashMap作为缓存,这样一个Class就只需解析一次
EsJavaBeanSerializer.java
import com.alibaba.fastjson.serializer.*;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lvye.java.datacenter.common.annotation.LyAppendField;
import lvye.java.datacenter.common.utils.exception.BusinessException;
import java.lang.reflect.Field;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class EsJavaBeanSerializer extends JavaBeanSerializer {
public static volatile ConcurrentHashMap<String,String> fieldNameCache = new ConcurrentHashMap<String,String>() ;
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
public EsJavaBeanSerializer(Class<?> beanType) {
super(beanType);
}
public EsJavaBeanSerializer(Class<?> beanType, String... aliasList) {
super(beanType, aliasList);
}
public EsJavaBeanSerializer(Class<?> beanType, Map<String, String> aliasMap) {
super(beanType, aliasMap);
}
public EsJavaBeanSerializer(SerializeBeanInfo beanInfo) {
super(beanInfo);
}
protected String processKey(JSONSerializer jsonBeanDeser, Object object, String key, Object propertyValue) {
super.processKey(jsonBeanDeser, object, key, propertyValue);
Class tempClass = object.getClass();
if (tempClass != null) {
try {
if(fieldNameCache.containsKey(tempClass.toString().concat(key))){
key = fieldNameCache.get(tempClass.toString().concat(key));
}else{
List<Field> fields = new ArrayList<>();
fields.addAll(Arrays.asList(tempClass.getDeclaredFields())) ;
fields.addAll(Arrays.asList(tempClass.getSuperclass().getDeclaredFields())) ;
for(Field field:fields){
if(key.toLowerCase().equals(field.getName().toLowerCase())){
if(field.isAnnotationPresent(LyAppendField.class)){
LyAppendField annotation = field.getAnnotation(LyAppendField.class);
return annotation.value();
}
else if (field.isAnnotationPresent(TableId.class)) {
TableId annotation = field.getAnnotation(TableId.class);
return annotation.value();
} else if (field.isAnnotationPresent(TableField.class)) {
TableField annotation = field.getAnnotation(TableField.class);
return annotation.value();
}
fieldNameCache.putIfAbsent(tempClass.toString().concat(key),field.getName());
break ;
}
}
}
} catch (Exception e) {
throw new BusinessException("序列化错误");
}
}
return key;
}
protected Object processValue(JSONSerializer jsonBeanDeser, BeanContext beanContext, Object object, String key, Object propertyValue, int features) {
Object value = super.processValue(jsonBeanDeser,beanContext,object,key,propertyValue,features);
if(value != null){
if(value instanceof Date){
return formatDate((Date)value);
}else if (value instanceof LocalDateTime){
return formatLocalDateTime((LocalDateTime)value);
}
}
return value;
}
public static String formatLocalDateTime(LocalDateTime date) {
return formatter.format(date);
}
public static String formatDate(Date date) {
Instant instant = date.toInstant();
ZoneId zoneId = ZoneId.ofOffset("GMT", ZoneOffset.ofHours(8));
LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
return formatter.format(localDateTime);
}
}
EsSerializerConfig.java
public class EsSerializerConfig extends SerializeConfig {
public ObjectSerializer getObjectWriter(Class<?> clazz) {
ObjectSerializer writer = get(clazz);
if(writer == null ){
writer = new EsJavaBeanSerializer(clazz);
}
return writer;
}
}
使用
JSON.toJSONString(esBaseDto, new EsSerializerConfig() , SerializerFeature.WriteMapNullValue)
实体类
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("oms_order")
@LyKuduTable("presto::xxxxx.odsomsorder")
@LyEsIndex("order_oms_order")
public class OrderOmsOrder extends EsBaseDto<OrderOmsOrder> {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "订单id")
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@ApiModelProperty(value = "公司id")
@TableField("company_id")
private Long companyId;
@ApiModelProperty(value = "公司名称")
@TableField("company_name")
private String companyName;