添加字典,指定自定义的序列化类
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside //让此注解可以被Jackson扫描到
@JsonSerialize(using = DictSerializer.class) //配置处理此注解的序列化处理类
public @interface Dict {
/**
* 数据code
* @return 返回类型: String
*/
String dicCode();
/**
* 数据Text
* @return 返回类型: String
*/
String dicText() default "";
/**
* 数据字典表
* @return 返回类型: String
*/
String dictTable() default "";
}
创建自定义序列化类继承JsonSerialize实现ContextualSerializer,实现返回结果转译:
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.jeeplus.common.utils.RedisUtils;
import com.jeeplus.common.utils.SpringContextHolder;
import com.jeeplus.modules.sys.service.DictTypeService;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
@Slf4j
public class DictSerializer extends StdSerializer<Object> implements ContextualSerializer {
private transient String dicCode;
private transient String dicText;
private transient String dicTable;
private transient static RedisUtils redisUtils;
public transient static String prefix = "dict";
static {
redisUtils = SpringContextHolder.getBean(RedisUtils.class);
}
protected DictSerializer() {
super(Object.class);
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty beanProperty) {
Dict dict = beanProperty.getAnnotation(Dict.class);
return createContextual(dict.dicCode(), dict.dicText(), dict.dictTable());
}
private JsonSerializer<?> createContextual(String dicCode, String dicText, String dictTable) {
DictSerializer serializer = new DictSerializer();
serializer.setDicCode(dicCode);
serializer.setDicText(dicText);
serializer.setDicTable(dictTable);
return serializer;
}
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) {
String dictCode = getDicCode();
if (StrUtil.isBlank(dictCode)) {
return;
}
if (Objects.isNull(value) || value.equals("")) {
value = "";
}
try {
String cacheKey;
if (StrUtil.isNotEmpty(dicTable)) {
cacheKey = String.join("::", prefix, String.join("_", dicTable, dictCode, dicText, String.valueOf(value)));
} else {
cacheKey = String.join("::", prefix, dictCode);
}
Map<Object, Object> cacheDictMap = redisUtils.hGetAll(cacheKey);
String label;
if (CollUtil.isEmpty(cacheDictMap)) {
Map<String, String> dictMap = translateDictValue(dictCode, dicText, dicTable, String.valueOf(value));
redisUtils.hPutAll(cacheKey, dictMap);
// 通过数据字典类型和value获取name
label = dictMap != null ? dictMap.get(value.toString()) : null;
} else {
// 通过数据字典类型和value获取name
label = cacheDictMap.get(value.toString()) != null ? cacheDictMap.get(value.toString()).toString() : null;
}
gen.writeObject(value);
// 在需要转换的字段上添加@Dict注解,注明需要引用的code,后端会在返回值中增加filedName_dictText的key,前端只需要取对应的 filedName_dictText 就可以直接使用
gen.writeFieldName(gen.getOutputContext().getCurrentName() + "_dictText");
gen.writeObject(label);
} catch (Exception e) {
log.error("错误信息:{}", e.getMessage(), e);
}
}
private Map<String, String> translateDictValue(String code, String text, String table, String value) {
if (StrUtil.isBlank(code)) {
return null;
}
Map<String, String> map = new HashMap<>();
if (StrUtil.isNotEmpty(table)) {
String textValue = SpringContextHolder.getBean(DictTypeService.class).translateDictFromTable(table, text, code, value);
map.put(value, textValue);
} else {
List<Map<String, String>> tmpValue = SpringContextHolder.getBean(DictTypeService.class).translateDict(code);
if (CollUtil.isNotEmpty(tmpValue)) {
for (Map<String, String> stringMap : tmpValue) {
map.put(stringMap.get("value"), stringMap.get("label"));
}
}
}
return map;
}
public String getDicCode() {
return dicCode;
}
public void setDicCode(String dicCode) {
this.dicCode = dicCode;
}
public String getDicText() {
return dicText;
}
public void setDicText(String dicText) {
this.dicText = dicText;
}
public String getDicTable() {
return dicTable;
}
public void setDicTable(String dicTable) {
this.dicTable = dicTable;
}
}
translateDictValue将查询到的字典保存到map中,因为序列化是需要每个对象都进行序列话操作,如果返回的是集合的话,就会进行很多次序列化操作,此时就需要对相同类型的字典进行缓存。
总结: 相比于使用 aop 切面的方式,使用序列化的方式能更好的处理嵌套对象的字典翻译
添加字典
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Dict {
/**
* 数据code
* @return 返回类型: String
*/
String dicCode();
/**
* 数据Text
* @return 返回类型: String
*/
String dicText() default "";
/**
* 数据字典表
* @return 返回类型: String
*/
String dictTable() default "";
}
定义切面类。具体的实现逻辑根据自己的项目实际情况实现就可以,主要是要用反射去获取类中的字段属性
@Aspect
@Component
@Slf4j
public class DictAspect {
/**
* 定义切点Pointcut
*/
@Pointcut("execution(public * com.xxxx.*..*.*Controller.*(..))")
public void dictPoint() {
}
@Around("dictPoint()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
long time1 = System.currentTimeMillis();
Object result = pjp.proceed();
long time2 = System.currentTimeMillis();
log.debug("获取JSON数据 耗时:" + (time2 - time1) + "ms");
long start = System.currentTimeMillis();
result = this.parseDictText(result);
long end = System.currentTimeMillis();
log.debug("注入字典到JSON数据 耗时" + (end - start) + "ms");
return result;
}
private Object parseDictText(Object result) {
return result;
}
/**
* 检测返回结果集中是否包含Dict注解
*
* @param records
* @return
*/
private Boolean checkHasDict(List<Object> records) {
if (CollectionUtil.isNotEmpty(records)) {
for (Field field : getAllFields(records.get(0))) {
if (!Objects.isNull(field.getAnnotation(Dict.class))) {
return true;
}
}
}
return false;
}
/**
* 获取类的所有属性,包括父类
*
* @param object
* @return
*/
public static Field[] getAllFields(Object object) {
Class<?> clazz = object.getClass();
List<Field> fieldList = new ArrayList<>();
while (clazz != null) {
fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
clazz = clazz.getSuperclass();
}
Field[] fields = new Field[fieldList.size()];
fieldList.toArray(fields);
return fields;
}
}