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

news2024/12/23 18:24:35

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

第一步,新建一个注解


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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2080112.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IO进程线程8月27日

1&#xff0c;思维导图 2&#xff0c;使用两个线程分别复制文件的上下两部分到同一个文件 #include<myhead.h> sem_t fastsem; //pthread_mutex_t fastmutex; void *capy_up(void *c) { // pthread_mutex_lock(&fastmutex);int len*(int *)c;int fp1open("./1…

STM32的IAP

STM32的IAP(In-Application Programming,在应用编程)地址主要涉及IAP程序本身的存储地址以及它所要操作的应用程序(APP)的存储地址。这些地址通常与STM32的FLASH存储器映射相关,并且可以根据具体的STM32型号和IAP程序的设计进行调整。 1. IAP程序存储地址 IAP程序本身…

可视耳勺好用吗?四大可视挖耳勺超值好物分享!

在近年来&#xff0c;可视挖耳勺以其高效的清洁效能&#xff0c;逐渐成为备受青睐的护理产品设备。面对市面上琳琅满目的可视挖耳勺品牌&#xff0c;其质量参差不齐&#xff0c;用户在选择时往往面临着挑战。劣质可视挖耳勺不仅不能达到应有的清洁效果&#xff0c;还可能由于不…

我要做全栈:自学前端第一天

大家好&#xff0c;今天要介绍的是我自学前端的一些经验。 前端想要知道学习哪些内容&#xff0c;首先要知道前端的结构是什么样的&#xff0c;前端是有哪些东西构成的。 所以我先了解了前端的构成是由三部分&#xff1a; 1、HTML&#xff1a;定义了网页的结构 2、CSS&…

DDOS攻击学习-渗透测试-域名信息收集

文章目录 wordpress漏洞利用域名信息收集域名介绍域名分类 whoiswhois反查子域名收集子域名发现网络空间安全搜索引擎SSL证书查询js文件发现子域名 wordpress漏洞利用 这个一般都需要安装wordpress服务使用wpscan扫描&#xff0c;但现在一般很少人知道或者使用wordpress所以这个…

Tkinter Checkbutton设置了一个多选,为什么初始值都是勾选的:

代码如下&#xff1a; from tkinter import *master Tk()renyuan ["唐僧", "沙僧", "悟空", "八戒"]def r_change():rec ""ci 0for el in vars:rec el.get() "、"ci 1rec "九点" rec "离…

论文速览【LLM】 —— 【ORLM】Training Large Language Models for Optimization Modeling

标题&#xff1a;ORLM: Training Large Language Models for Optimization Modeling文章链接&#xff1a;ORLM: Training Large Language Models for Optimization Modeling代码&#xff1a;Cardinal-Operations/ORLM发表&#xff1a;2024领域&#xff1a;使用 LLM 解决运筹优化…

浙商之源——龙游商帮丨情义担当与信誉丰碑——姜益大布行

在龙游这片古老而繁华的土地上&#xff0c;流传着一段关于龙商精神的光辉篇章——姜益大的故事。这不仅是一段商业传奇&#xff0c;更是龙游商人智慧、勇气与诚信的生动写照。 初来乍到&#xff0c;逆锋起笔 清朝同治六年(1867)&#xff0c;安徽绩溪人姜德明在龙游商帮朋友点拨…

《JavaEE进阶》----2.<Spring前传:Maven项目管理工具>

本篇博客讲解我们在使用Spring框架时所要用到的Maven这个项目管理工具 它可以更方便的管理我们的项目&#xff0c;比如通过 1.常用的Maven命令来进行编译、测试、打包、清理包等等&#xff0c;不仅如此&#xff0c; 2.Maven还可以对依赖进行管理&#xff0c;方便我们添加依赖、…

信息打点-资产泄露CMS识别Git监控SVNDS_Store备份

知识点&#xff1a; 1、CMS指纹识别源码获取方式&#xff1b; 2、习惯&配置&特性等获取方式&#xff1b; 3、托管资产平台资源搜索监控&#xff1b; 详细点&#xff1a; 参考&#xff1a;https://www.secpulse.com/archives/124398.html 源码泄露原因&#xff1a; …

fastjson序列化时过滤字段的方法

在使用fastjson进行序列化时&#xff0c;可能需要根据实际需求过滤掉某些字段&#xff0c;以避免将敏感信息或不必要的字段发送到客户端。fastjson提供了多种灵活的方式来实现这一需求。以下整理了fastjson序列化时过滤字段的几种常用方法。 方法一&#xff1a;使用fastjson的…

Windows10激活__“亲测有效”无需秘钥

目录 前言 1. 鼠标“右键”点击“开始菜单” 2. 点击选择“Windows PowerShell&#xff08;管理员&#xff09;” 3. 在该终端窗口&#xff0c;输入“ irm "https://get.activated.win" |iex ” 4. 按下“Enter”键&#xff0c;回车执行该命令 5. 按下数字键盘…

如何使用 Python 和 Selenium 解决 Cloudflare 验证码

在网络自动化测试或网页数据抓取的过程中&#xff0c;Cloudflare验证码是许多开发者遇到的棘手问题。这一验证码设计的初衷是为了保护网站免受恶意攻击&#xff0c;但它也给合法的自动化操作带来了不小的挑战。 那么&#xff0c;使用Python和Selenium&#xff0c;是否有办法有…

PCL 点云ISS关键点提取算法

目录 一、概述二、代码示例三、运行结果📌 结果预览 🔗接上篇 Python 点云ISS关键点提取算法 一、概述 点云ISS关键点(Intrinsic Shape Signatures):利用点云中每个点的局部邻域的协方差矩阵来分析局部几何结构。协方差矩阵的特征值可以揭示局部几何形状的显著性。通…

通过websock实现实时刷新前端(可实现进度条)

业务场景&#xff1a; 领导让我们做一个根据进度实时刷新的进度条&#xff0c;如下所示 后面去网上查了下&#xff0c;可以通过websocket这种双向通信协议的持久链接实现。 配置 创建配置类&#xff0c;启用websocket支持 import org.springframework.context.annotation.…

进阶-task1-深度学习理论基础

学习目标&#xff1a; 从不同的角度更好地优化神经网络 熟悉临界点等与优化有关的常见的概念网络优化失败的常见原因常用的解决/优化方案 具体内容&#xff1a; 网络优化常见的问题&#xff1f; 损失函数Loss不再下降&#xff0c;但是收敛值不合理 深层网络反而不如浅层网…

【扩散模型(七)】IP-Adapter 与 IP-Adapter Plus 的具体区别是什么?

系列文章目录 【扩散模型&#xff08;二&#xff09;】IP-Adapter 从条件分支的视角&#xff0c;快速理解相关的可控生成研究【扩散模型&#xff08;三&#xff09;】IP-Adapter 源码详解1-训练输入 介绍了训练代码中的 image prompt 的输入部分&#xff0c;即 img projection…

19c库启动报ORA-600 kcbzib_kcrsds_1---惜分飞

一套19c的库由于某种情况,发现异常,当时的技术使用隐含参数强制拉库,导致数据库启动报ORA-00704 ORA-600 kcbzib_kcrsds_1错误 2024-08-24T06:11:25.49430408:00 ALTER DATABASE OPEN 2024-08-24T06:11:25.49437008:00 TMI: adbdrv open database BEGIN 2024-08-24 06:11:25.49…

Iptables-快速上手

Iptables firewall 防火墙Iptables简述一、Iptables的四表五链1.filter表2.nat表3.raw表4. mangle表5.数据包的流通过程 二、快速上手1. 查看规则2. 规则详细3. 添加规则4. 自定义链 三、关于iptables和docker1. 背景2. 解决方案 firewall 防火墙 从逻辑上讲&#xff0c;可以分…

【国外比较权威的免费的卫星数据网站】

国外比较权威的免费卫星数据网站有多个&#xff0c;它们各自在数据覆盖范围、分辨率、以及数据种类等方面具有不同的特点和优势。以下是一些推荐的网站&#xff1a; NASA Worldview 网址&#xff1a;https://worldview.earthdata.nasa.gov/简介&#xff1a;NASA Worldview显示…