解決問題:java返回對象中關(guān)于枚舉缠诅、字典數(shù)據(jù)的自動轉(zhuǎn)化哑蔫。
實現(xiàn)思路:
1钉寝、通過自定義注解 對需要轉(zhuǎn)化的字段進行標記,注解中可定義枚舉類型闸迷,若沒有定義枚舉則從數(shù)據(jù)字典獲取嵌纲。
2、自定義對象的BeanSerializerModifier腥沽,對做了標記的字段設(shè)置自定義的JsonSerializer逮走。
3、自定義JsonSerializer的實現(xiàn)今阳。
4师溅、自定義MappingJackson2HttpMessageConverter,并設(shè)置自定義的BeanSerializerModifier為默認處理方式盾舌。
5墓臭、將自定義的MappingJackson2HttpMessageConverter加入到HttpMessageConverters中,可以通過重寫WebMvcConfigurationSupport.extendMessageConverters的方式實現(xiàn)妖谴。
以下是具體的代碼實現(xiàn)窿锉,有些地方需要用戶根據(jù)實際情況自己實現(xiàn),比如從字典獲取數(shù)據(jù)等窖维。
自定義注解標記
import java.lang.annotation.*;
@Inherited
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Dict {
static enum Void {}
Class<? extends Enum<?>> enumType() default Void.class;
/**
* 默認值榆综,獲取不到字典則使用默認值
*
* @return ""
*/
String defaultValue() default "";
}
自定義BeanSerializerModifier,以下代碼中DictConstants.getDictCacheKey(valueStr)只是自定義key铸史,需要自己實現(xiàn)鼻疮。
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.hg.dcm.commons.core.HGBusinessException;
import com.hg.dcm.commons.core.SpringContextUtil;
import com.hg.energy.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@Slf4j
public class DictSerializerModifier extends BeanSerializerModifier {
@Override
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
for (BeanPropertyWriter beanProperty : beanProperties) {
Dict dict = beanProperty.getAnnotation(Dict.class);
if (dict != null) {
beanProperty.assignSerializer(new DictSerializer(dict));
}
}
return beanProperties;
}
/**
* 字典自定義序列化
*/
static class DictSerializer extends JsonSerializer<Object> {
/**
* 生成序列化字段后綴
*/
private static final String LABEL_SUFFIX = "Desc";
/**
* 字典配置信息
*/
private final Dict dict;
/**
* 枚舉獲取key方法
*/
private static final String[] KEY_METHODS = {"getValue", "getCode", "getStatus", "name"};
/**
* 獲取枚舉描述方法
*/
private static final String[] DESC_METHODS = {"getDesc"};
/**
* 構(gòu)造方法
*
* @param dict 字典描述
*/
public DictSerializer(Dict dict) {
this.dict = dict;
}
/**
* Method that can be called to ask implementation to serialize
* values of type this serializer handles.
*
* @param value Value to serialize; can <b>not</b> be null.
* @param gen Generator used to output resulting Json content
* @param provider Provider that can be used to get serializers for
* serializing Objects value contains, if any.
*/
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
provider.defaultSerializeValue(value, gen);
// 添加轉(zhuǎn)換之后的字段:xxxDesc
String fieldName = gen.getOutputContext().getCurrentName();
gen.writeStringField(fieldName.concat(LABEL_SUFFIX), value != null ? this.getDesc(dict, value) : null);
}
/**
* 獲取字典信息
* TODO
*
* @param dict 字典對象
* @param value 字典值
* @return
*/
private String getDesc(Dict dict, Object value) {
try {
// 先查詢是否是枚舉類型,查到則返回
String enumDesc = this.getEnumDesc(dict, value);
if (enumDesc != null) {
return enumDesc;
}
String valueStr = Objects.toString(value);
//獲取緩存key琳轿,可以自定義
String key = DictConstants.getDictCacheKey(valueStr);
// Redis 緩存操作類 這里建議優(yōu)先使用本地緩存, 本地緩存 -> redis -> Db
RedisService redis = SpringContextUtil.getBean(RedisService.class);
if (redis.exists(key)) {
return redis.get(key);
}
// 數(shù)據(jù)庫字典操作類
//redis.setEx(key, desc, 1, TimeUnit.HOURS);
return "字典數(shù)據(jù)";
} catch (Exception e) {
log.error("字典轉(zhuǎn)換:獲取字典描述異常,使用默認值:{}判沟,key:{}, dict:{}, 異常:{}", dict.defaultValue(), value, dict.enumType(), e.getMessage(), e);
return dict.defaultValue();
}
}
/**
* 獲取枚舉類型的描述信息
*
* @param dict 字典
* @param value 值
* @return 枚舉desc字段
*/
private String getEnumDesc(Dict dict, Object value) throws InvocationTargetException, IllegalAccessException {
if (dict == null || value == null) {
return null;
}
Class<? extends Enum<?>> et = dict.enumType();
if (Dict.Void.class.equals(et)) {
return null;
}
Enum<?>[] enums = et.getEnumConstants();
Method keyMethod = this.getMethod(et, KEY_METHODS);
if (keyMethod == null) {
// 自定義業(yè)務(wù)異常
throw new HGBusinessException(String.format("字典轉(zhuǎn)換:枚舉:%s,沒有方法:%s", et.getName(), Arrays.toString(KEY_METHODS)));
}
Method descMethod = this.getMethod(et, DESC_METHODS);
if (descMethod == null) {
throw new HGBusinessException(String.format("字典轉(zhuǎn)換:枚舉:%s,沒有方法:%s", et.getName(), Arrays.toString(DESC_METHODS)));
}
for (Enum<?> e : enums) {
if (value.equals(keyMethod.invoke(e))) {
return Objects.toString(descMethod.invoke(e));
}
}
log.error("字典轉(zhuǎn)換:通過枚舉轉(zhuǎn)換失敗耿芹,枚舉:{},值:{}挪哄,KeyMethod:{}吧秕,DescMethod:{}", et.getName(), value, Arrays.toString(KEY_METHODS), Arrays.toString(DESC_METHODS));
throw new HGBusinessException(String.format("字典轉(zhuǎn)換失敗,枚舉:%s迹炼,值:%s", et.getName(), value));
}
/**
* 獲取讀方法
*
* @param enumType 枚舉類
* @param methodNames 方法名稱
* @return Method
*/
private Method getMethod(Class<? extends Enum<?>> enumType, String... methodNames) {
for (String methodName : methodNames) {
try {
return enumType.getMethod(methodName);
} catch (NoSuchMethodException e) {
}
}
return null;
}
}
}
自定義MappingJackson2HttpMessageConverter
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
SimpleModule simpleModule = new SimpleModule().setSerializerModifier(new DictSerializerModifier());
builder.modules(simpleModule);
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
return new MappingJackson2HttpMessageConverter(builder.build());
}
將自定義的MappingJackson2HttpMessageConverter加入到HttpMessageConverters中
@Configuration
public class WebConfiguration extends WebMvcConfigurationSupport {
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(0,mappingJackson2HttpMessageConverter());
}
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
SimpleModule simpleModule = new SimpleModule().setSerializerModifier(new DictSerializerModifier());
builder.modules(simpleModule);
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
return new MappingJackson2HttpMessageConverter(builder.build());
}
}