自定义注解+拦截器+多线程,实现字典值的翻译

上一篇,自定义注解+拦截器,实现字段加解密操作,奈何公司的这个项目里没有字典值翻译的功能,正好可以再自定义注解+拦截器方式的基础上,扩展一下

第一步,新建一个注解


@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;

查询结果
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值