本来想在项目里直接用Easy-Trans来做字典翻译,用的时候发现,这个组件不支持原生的mybatis.
于是直接自己写了一个。废话不多说,直接上代码。就两个文件。
import java.lang.annotation.*;
/**
* 字典翻译注解,用于实体类字段自动翻译
*/
@Target(ElementType.FIELD) // 作用于字段
@Retention(RetentionPolicy.RUNTIME) // 运行时生效
@Documented
public @interface DictTrans {
/** 字典key(对应Redis中的字典类型) */
String dictKey();
/** 目标翻译字段名(存储翻译结果的字段) */
String targetField();
}
我这里是直接从redis中取出来进行字典进行翻译
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.geek.common.constant.CacheConstants;
import com.geek.common.core.redis.RedisCache;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.*;
/**
* 字典翻译切面,自动处理@DictTrans注解的字段翻译
*/
@Aspect
@Component
@Slf4j
public class DictTransAspect {
@Resource
private RedisCache redisCache;
/**
* 切入点:拦截Service层所有返回实体/集合的方法
* (根据实际工程调整包路径,确保覆盖业务Service)
*/
@AfterReturning(
pointcut = "execution(* com.geek.system.service..*(..))", // 拦截system.service包下所有方法
returning = "result" // 方法返回值
)
public void doDictTrans(Object result) {
if (result == null) return;
// 处理集合类型(List/Set等)
if (result instanceof Collection<?>) {
Collection<?> collection = (Collection<?>) result;
collection.forEach(this::processEntity);
} else {
// 处理单个实体
processEntity(result);
}
}
/**
* 处理单个实体对象的字典翻译
*/
private void processEntity(Object entity) {
if (entity == null) return;
Class<?> entityClass = entity.getClass();
// 获取实体类所有字段(含父类私有字段)
List<Field> allFields = getAllFields(entityClass);
for (Field field : allFields) {
// 检查字段是否标注@DictTrans注解
DictTrans dictTrans = field.getAnnotation(DictTrans.class);
if (dictTrans == null) continue;
try {
// 1. 获取源字段(编码字段)的值
field.setAccessible(true); // 允许访问私有字段
String sourceValue = (String) field.get(entity);
if (sourceValue == null) continue; // 编码值为null则跳过
// 2. 从Redis获取JSON数组字符串并解析为映射(修正类型不匹配问题)
String dictKey = dictTrans.dictKey();
String redisFullKey = CacheConstants.SYS_DICT_KEY + dictKey;
// 直接获取JSONArray对象(无需字符串解析)
JSONArray dictJsonArray = (JSONArray) redisCache.getCacheObject(redisFullKey);
if (dictJsonArray == null || dictJsonArray.isEmpty()) {
log.error("字典翻译失败:Redis中未找到键[{}]或JSON数组为空", redisFullKey);
continue;
}
// 步骤3:构建dictValue -> dictLabel的映射
Map<String, String> dictMap = new HashMap<>();
for (int i = 0; i < dictJsonArray.size(); i++) {
JSONObject dictItem = dictJsonArray.getJSONObject(i);
String dictValue = dictItem.getString("dictValue");
String dictLabel = dictItem.getString("dictLabel");
dictMap.put(dictValue, dictLabel);
}
// 获取翻译后的值(补充缺失步骤)
String translatedValue = dictMap.get(sourceValue);
if (translatedValue == null) {
log.warn("字典翻译警告:字典key[{}]中无编码[{}]的映射", dictKey, sourceValue);
}
// 4. 反射设置目标字段(翻译结果字段)的值
String targetFieldName = dictTrans.targetField();
Field targetField = entityClass.getDeclaredField(targetFieldName);
targetField.setAccessible(true);
targetField.set(entity, translatedValue);
} catch (NoSuchFieldException e) {
log.error("字典翻译反射异常:目标字段[{}]不存在", dictTrans.targetField(), e);
} catch (IllegalAccessException e) {
log.error("字典翻译反射异常:字段访问权限不足", e);
}
}
}
/**
* 获取类的所有字段(含父类私有字段)
*/
private List<Field> getAllFields(Class<?> clazz) {
List<Field> fields = new ArrayList<>();
while (clazz != null && clazz != Object.class) { // 遍历至Object类停止
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
clazz = clazz.getSuperclass(); // 处理父类字段
}
return fields;
}
}
使用方式,直接在实体字段上用注解 @DictTrans
dictKey是对应的字典的key
targetField是翻译后映射的字段
@DictTrans(dictKey = "transaction_type", targetField = "transactionTypeName")
private String transactionType ;
private String transactionTypeName;
981



被折叠的 条评论
为什么被折叠?



