上一篇,自定义注解+拦截器,实现字段加解密操作,奈何公司的这个项目里没有字典值翻译的功能,正好可以再自定义注解+拦截器方式的基础上,扩展一下
第一步,新建一个注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Dict {
    //对应数据字典的code
    String dictCode();
}
第二步,新建拦截器
@Component
@Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})})
public class DictInterceptor implements Interceptor {
    @Resource
    private DictInfoService dictInfoService;
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //取出查询的结果
        Object resultObject = invocation.proceed();
        if (null != resultObject) {
            // 对结果中的字典值进行翻译
            dictInfoService.parseDictValue(resultObject);
        }
        return resultObject;
    }
}
第三步,新建接口
public interface DictInfoService {
    /**
     * 翻译字典值
     *
     * @param result 待翻译字段外层对象
     */
    <T> T parseDictValue(T result);
}
第四步,新建实现类
@Service
public class DictInfoServiceImpl implements DictInfoService {
    public static final Logger log = LoggerFactory.getLogger(DictInfoServiceImpl.class);
    public static final String suffix = "DictName";
    @Override
    public <T> T parseDictValue(T result) {
        // 返回需要翻译字段
        List<Field> fields = this.checkAndGetFields(result);
        // 解密字段不为空,解密
        if (!CollectionUtils.isEmpty(fields)) {
            for (int i = 0; i < fields.size(); i++) {
                // 解密
                T translation = this.translation(fields.get(i), result);
                result= translation;
            }
        }
        return result;
    }
    /**
     * 返回需要翻译字段
     */
    private <T> List<Field> checkAndGetFields(T t) {
        // 数据为空直接返回
        if (null == t) {
            return null;
        }
        if (t instanceof Collection) {
            // 如果是集合,返回集合中元素的类中需要加解密的敏感信息字段
            Collection<?> rc = (Collection<?>) t;
            if (!CollectionUtils.isEmpty(rc)) {
                Object next = rc.iterator().next();
                if (null != next) {
                    return ReflectUtils.getAllField(next.getClass(), Dict.class);
                }
            }
        } else {
            // 返回需要加解密的敏感信息字段
            return ReflectUtils.getAllField(t.getClass(), Dict.class);
        }
        return null;
    }
    /**
     * 翻译
     */
    private <T> T translation(Field field, Object o) {
        // 如果是集合,则遍历出实体,逐个解密
        if (o instanceof Collection) {
            List<Object> originalList = (List<Object>) o;
            ExecutorService executor = ForkJoinPool.commonPool(); // 使用公共的ForkJoinPool
            List<Future<Object>> futures = new ArrayList<>(originalList.size());
            for (int i = 0; i < originalList.size(); i++) {
                Object originalElement = originalList.get(i);
                Future<Object> future = executor.submit(() -> {
                    Object transformedElement = this.translationObj(field, originalElement);
                    return transformedElement;
                });
                futures.add(future);
            }
            for (int i = 0; i < futures.size(); i++) {
                try {
                    Object transformedElement = futures.get(i).get();
                    originalList.set(i, transformedElement);
                } catch (InterruptedException | ExecutionException e) {
                    // 处理异常
                    e.printStackTrace();
                }
            }
            executor.shutdown(); // 关闭线程池
        } else {
            o=this.translationObj(field, o);
        }
        return (T) o;
    }
    /**
     * 对象中字段解密
     */
    private Object translationObj(Field field, Object o) {
        try {
            // 访问private变量的变量值
            field.setAccessible(true);
            // 字段值
            Object value = field.get(o);
            Dict dict = field.getAnnotation(Dict.class);
            if(dict!=null){
                //从数据字典中查询code对应的k-v值
                List<SysDictData> dictDatas = DictUtils.getDictCache(dict.dictCode());
                if(dictDatas!=null){
                    Map<String, String> dictMap = dictDatas.stream()
                            .collect(Collectors.toMap(
                                    SysDictData::getDictValue, // key
                                    SysDictData::getDictLabel  // value
                            ));
                    //字段转换
                    String key = field.getName();
                    String convertValue = dictMap.get(value);
                    String json = configureObjectMapper().writeValueAsString(o);
                    JSONObject jsonObject = JSONObject.parseObject(json);
                    jsonObject.put(field.getName()+suffix,convertValue);
                    if(StringUtils.isNotEmpty(jsonObject.toString())){
                        o = configureObjectMapper().readValue(jsonObject.toString(), o.getClass());
                    }
                }
            }
        } catch (Exception e) {
            log.error("字段翻译失败,类={}, 字段={}", o.getClass().getName(), field.getName(), e);
        }
        return o;
    }
    public static ObjectMapper configureObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        // 添加对Java 8时间API的支持
        objectMapper.registerModule(new JavaTimeModule());
        SimpleModule module = new SimpleModule()
                .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
        objectMapper.registerModule(module);
        return objectMapper;
    }
}
自定义序列化器
public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    @Override
    public void serialize(LocalDateTime localDateTime, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        String formattedDateTime = localDateTime.format(FORMATTER);
        gen.writeString(formattedDateTime);
    }
}
由于在于ObjectMapper默认不支持Java 8的时间类型LocalDateTime。还需要显式地添加对Java 8时间API的支持。
 添加依赖:确保项目中引入了jackson-datatype-jsr310库,这个库提供了对Java 8时间API的支持。
 注册模块:除了自定义序列化器外,还需注册JavaTimeModule或相应的自定义模块。
第五步,应用
要查询实体类中的字段上加上注解
 /**
     * 性别
     */
    @Schema(description = "性别 ")
    @TableField("gender")
    @Dict(dictCode = "sys_user_sex")
    private String gender;
    /**
     * 性别名称
     */
    @TableField(exist = false)
    private String genderDictName;
    /**
     * 民族
     */
    @Schema(description = "民族")
    @TableField("ethnicity")
    @Dict(dictCode = "zc_ethnic_group")
    private String ethnicity;
    /**
     * 民族名称
     */
    @TableField(exist = false)
    private String ethnicityDictName;
查询结果
 



















