两个类文件,实现根据返回的id显示对应的人员信息增强返回

news2024/12/24 13:55:29

后台与前台交互时,由于后台存放的原始信息可能就是一些id或code,要经过相应的转换才能很好地在前台展示。

比如: select id, user_id from user

直接返回给前台时,前台可能要根据你这个user_id作为参数,再请求一次后台,获取对应的人员信息实体,以作人员信息展示。

这样多了一次IO,同时还要根据不同的场景写很多的重复代码。比如第一次IO时就连接查出对应的返回实体,或者本来不需要后续又需要这些实体就又要补上代码。

这些重复性的工作抽像出通用的代码解决,我的做法是这样:

1、首先我的人员信息是有缓存的

2、自定义一个注解@BaseId(第一个类文件)

3、写一个AOP(第二个类文件)

这个AOP在@Controller方法返回前,校验返回的实体是固定的泛型且泛型参数对应的实体类中存在被@BaseId注解的变量,就基于这个变量生成一个人员信息实体,加进这个返回实体中返回给前台。下面且看代码:

一、注解类

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface BaseId {
}

二、AOP类

/**
 * 对GetMapping接口的返回做条件性增强,
 * 1、返回的类型为TableDataInfo的。里面的rows对应的实体类如果有@BaseId的,增加对应的StaffMain字段返回
 *
 * @author wack
 * @version 1.0
 * @since 2023/8/3
 */
@Aspect
@Slf4j
@Component
public class GetResponseAspect {
    private static final String STAFF_MAIN = "xxx.xxx.basis.model.staff.StaffMain";
    @Autowired
    private IStaffService staffService;

    @AfterReturning(pointcut = "@annotation(getMapping)", returning = "jsonResult")
    public void beforeReturnIng(JoinPoint joinPoint, Object jsonResult, GetMapping getMapping) throws ClassNotFoundException {
        if (jsonResult instanceof TableDataInfo) {
            List rows = ((TableDataInfo) jsonResult).getRows();
            List newRows = new ArrayList();
            if (CollectionUtils.isNotEmpty(rows) && rows.get(0) != null) {
                Class<?> returnModel = rows.get(0).getClass();
                Field[] declaredFields = returnModel.getDeclaredFields();
                if (Arrays.stream(declaredFields).filter(obj -> obj.getAnnotation(BaseId.class) != null).findAny().isPresent()) {
                    for (Object row : rows) {
                        // 找到注解为baseId的字段,生成一个新的StaffMain 字段来承载对应的人员信息
                        DynamicObject dynamicBean = new DynamicObject();
                        Map<String, Class> allPropertyType = dynamicBean.getAllPropertyType(row);
                        Map<String, Object> allPropertyValue = dynamicBean.getAllPropertyValue(row);
                        for (Field declaredField : declaredFields) {
                            if (declaredField.getAnnotation(BaseId.class) != null) {
                                String fieldValue = ReflectUtils.getFieldValue(row, declaredField.getName());
                                allPropertyType.put(declaredField.getName() + "Staff", Class.forName(STAFF_MAIN));
                                allPropertyValue.put(declaredField.getName() + "Staff", staffService.getStaffCacheInfo(fieldValue));
                            }
                        }
                        dynamicBean.addProperty(allPropertyType, allPropertyValue);
                        row = dynamicBean.getObject();
                        newRows.add(row);
                    }
                    if (CollectionUtils.isNotEmpty(newRows)) ((TableDataInfo) jsonResult).setRows(newRows);
                }
            }
        }
    }

    class DynamicObject {
        private Object object; //对象
        private BeanMap beanMap; //对象的属性
        private BeanGenerator beanGenerator; //对象生成器
        private Map<String, Class> allProperty; //对象的<属性名, 属性名对应的类型>

        /**
         * 给对象属性赋值
         *
         * @param property
         * @param value
         */
        public void setValue(String property, Object value) {
            beanMap.put(property, value);
        }

        private void setValue(Object object, Map<String, Class> property) {
            for (String propertyName : property.keySet()) {
                if (allProperty.containsKey(propertyName)) {
                    Object propertyValue = ReflectUtils.getFieldValue(object, propertyName);
                    this.setValue(propertyName, propertyValue);
                }
            }
        }

        private void setValue(Map<String, Object> propertyValue) {
            for (Map.Entry<String, Object> entry : propertyValue.entrySet()) {
                this.setValue(entry.getKey(), entry.getValue());
            }
        }

        /**
         * 通过属性名获取属性值
         *
         * @param property
         * @return
         */
        public Object getValue(String property) {
            return beanMap.get(property);
        }

        /**
         * 获取该bean的实体
         *
         * @return
         */
        public Object getObject() {
            return this.object;
        }

        private Object generateObject(Map propertyMap) {
            if (null == beanGenerator) {
                beanGenerator = new BeanGenerator();
            }

            Set keySet = propertyMap.keySet();
            for (Iterator i = keySet.iterator(); i.hasNext(); ) {
                String key = (String) i.next();
                beanGenerator.addProperty(key, (Class) propertyMap.get(key));
            }
            return beanGenerator.create();
        }

        /**
         * 添加属性名与属性值
         *
         * @param propertyType
         * @param propertyValue
         */
        public void addProperty(Map propertyType, Map propertyValue) {
            if (null == propertyType) {
                throw new RuntimeException("动态添加属性失败!");
            }
            Object oldObject = object;
            object = generateObject(propertyType);
            beanMap = BeanMap.create(object);

            if (null != oldObject) {
                setValue(oldObject, allProperty);
            }
            setValue(propertyValue);
            if (null == allProperty) {
                allProperty = propertyType;
            } else {
                allProperty.putAll(propertyType);
            }
        }

        /**
         * 获取对象中的所有属性名与属性值
         *
         * @param object
         * @return
         * @throws ClassNotFoundException
         */
        public Map<String, Class> getAllPropertyType(Object object) throws ClassNotFoundException {
            Map<String, Class> map = new HashMap<>();
            Field[] fields = object.getClass().getDeclaredFields();
            for (int index = 0; index < fields.length; index++) {
                Field field = fields[index];
                String propertyName = field.getName();
                String typeName = field.getGenericType().getTypeName();
                if ("long".equals(typeName)) {
                    typeName = "java.lang.Long";
                }
                if ("int".equals(typeName)) {
                    typeName = "java.lang.Integer";
                }
                if ("float".equals(typeName)) {
                    typeName = "java.lang.Float";
                }
                if ("double".equals(typeName)) {
                    typeName = "java.lang.Double";
                }
                if ("boolean".equals(typeName)) {
                    typeName = "java.lang.Boolean";
                }
                if ("char".equals(typeName)) {
                    typeName = "java.lang.Character";
                }
                if (typeName.indexOf("List") > -1) {
                    typeName = "java.util.List";
                }
                Class<?> propertyType = Class.forName(typeName);
                map.put(propertyName, propertyType);
            }
            defaultEndType(map);
            return map;
        }

        private void defaultEndType(Map<String, Class> map) {
            map.put("createId", String.class);
            map.put("modifyId", String.class);
            map.put("createDate", Date.class);
            map.put("modifyDate", Date.class);
        }

        /**
         * 获取对象中的所有属性名与属性值
         *
         * @param object
         * @return
         */
        public Map<String, Object> getAllPropertyValue(Object object) {
            Map<String, Object> map = new HashMap<>();
            Field[] fields = object.getClass().getDeclaredFields();
            for (int index = 0; index < fields.length; index++) {
                Field field = fields[index];
                String propertyName = field.getName();
                Object propertyValue = ReflectUtils.getFieldValue(object, propertyName);
                map.put(propertyName, propertyValue);
            }
            defaultEndValue(object,map);
            return map;
        }

        private void defaultEndValue(Object object,Map<String, Object> map) {
            map.put("createId", ReflectUtils.getFieldValue(object, "createId"));
            map.put("modifyId", ReflectUtils.getFieldValue(object, "modifyId"));
            map.put("createDate", ReflectUtils.getFieldValue(object, "createDate"));
            map.put("modifyDate", ReflectUtils.getFieldValue(object, "modifyDate"));
        }
    }
}

在实体类中加注解

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

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

相关文章

DingoDB多模向量数据库,大模型时代的数据觉醒

大模型技术迸发的烟花点燃了整个AI产业链。继各类生成式模型、行业大模型、AI基础软件后&#xff0c;“大模型的海马体”——向量数据库&#xff0c;成为当前最为灼热的AI技术焦点。 在九章云极DataCanvas“变革”产品发布会上重磅亮相的DingoDB多模向量数据库&#xff0c;将多…

杭州高职画室哪家好?如何选择高职画室?高职美术学习选哪家画室?

随着越来越多的画室开始涉足高职美术培训&#xff0c;根据杭州高职画室的美术学生及其家长所知&#xff0c;由于普通高中和高职联考之间存在巨大差异&#xff0c;因此许多普通高中的画室的高职班并未取得太大的成功。因此&#xff0c;小编为正在寻找画室的你提供介绍&#xff1…

pycryptodomex安装过程踩坑解决

前言&#xff1a;装TA&#xff0c;要用pycryptodomex&#xff0c;但出现了toolchain\py版本不匹配&#xff0c;网络上太多方法&#xff0c;五花八门&#xff0c;我需要记录整理下思路&#xff0c;所以作此文 Cryptodome是Python语言的加密和解密库&#xff0c;它是PyCrypto和Cr…

Linux文件系统结构

目录 文件系统结构 当前工作目录&#xff0c;pwd(print work directory) 文件名称&#xff0c;隐藏文件 列出当前目录的内容 ls 查看文件类型 file 绝对路径相对路径&#xff0c;cd 文件系统结构 所有的文件&#xff0c;文件夹&#xff0c;所有的结构都是存在一个叫根目录…

旋转矩阵左乘的理解

关于矩阵左乘和右乘的区别&#xff0c;看了不少数学解释&#xff0c;大概是我水平不够&#xff0c;不是很懂的样子。但本来我也是做应用&#xff0c;抛开理论不谈&#xff0c;看看左乘的实际的使用情况。 1. 关于矩阵及下标的描述 这个非常的重要&#xff0c;如果没有定义好矩…

LeetCode54.螺旋矩阵

这道题一看好像在哪做过一样&#xff0c;好像是写剑指offer里面的状态机的时候写过类似的&#xff0c;就是定义4个方向&#xff0c;它就是按右&#xff0c;下&#xff0c;左&#xff0c;上的规律螺旋的&#xff0c;所以只要拿4个方向给他循环就可以&#xff0c;我是用一个表示方…

多线程应用——线程池

线程池 文章目录 线程池1.什么是线程池2.为什么要用线程池3.怎么使用线程池4.工厂模式5.自己实现一个线程池6.创建系统自带的线程池6.1 拒绝策略6.2 线程池的工作流程 1.什么是线程池 字面意思&#xff0c;一次创建多个线程&#xff0c;放在一个池子(集合类)&#xff0c;用的时…

2023年MySQL实战核心技术第三篇

目录 六 . 事务隔离&#xff1a;为什么改了还看不见&#xff1f; 6.1 解释&#xff1a; 6.2 隔离性与隔离级别 6.2.1 SQL 标准的事务隔离级别&#xff1a; 6.2.2 事务隔离级别解释&#xff1a; 6.2.3 例子&#xff1a; 6.2.3.1 若隔离级别是“读未提交” 6.2.3.2 若隔离级别是“…

无涯教程-JavaScript - BIN2DEC函数

描述 BIN2DEC函数将二进制数字转换为十进制。 语法 BIN2DEC (number)争论 Argument描述Required/Optionalnumber 您要转换的二进制数。 Number cannot contain more than 10 characters (10 bits). 数字的最高有效位是符号位。其余的9位是幅度位。 负数使用二进制补码表示。…

c++(c语言)通用版本的单链表的头插法创建

我们创建一个长度为n的链表时&#xff0c;可以采取头插法创建或者尾插法创建&#xff0c;本篇博客我们采取头插法来创建&#xff0c;&#xff08;作者只学了头插&#xff0c;尾插等以后来补qwq)。 我们先来画图来看看头插的创建形式把&#xff0c;会了原理再写代码。 首先是我…

选择IT行业真的无路可走了吗?

虽说如今IT行业的市场上求职者众多&#xff0c;现在找工作难度也比之前大很多&#xff0c;但这个是大环境趋势&#xff0c;每个行业其实都存在这种情况&#xff0c;而且失业率也高达30%。现在企业一般招聘要求越来越高&#xff0c;各种行业都有劝退人士&#xff0c;劝退不要转行…

文献关系的可视化工具

文章目录 简介网站链接Demo说明数据库 简介 One minute to find a hundred related papers 网站链接 https://www.connectedpapers.com/ Demo 说明 You can use Connected Papers to: Get a visual overview of a new academic field Enter a typical paper and we’ll …

MySQL事务日志--redo, undo详解

事务有 4 种特性&#xff1a;原子性、一致性、隔离性和持久性。那么事务的四种特性到底是基于什么机制实现呢&#xff1f; 事务的隔离性由 锁机制 实现。 而事务的原子性、一致性和持久性由事务的 redo 日志和 undo 日志来保证。 REDO LOG 称为 重做日志 &#xff0c…

亚马逊下架电池,家用及商用电池UL2054检测报告介绍|亚马逊UL2054报告

UL2054是针对可充电电池和电池包的测试和认证项目。该测试项目由美国安全实验室&#xff08;Underwriters Laboratories&#xff09;执行&#xff0c;主要评估电池产品的安全性、性能和符合性。 适用家用及商用电池UL2054检测报告介绍|亚马逊UL2054报告 美国UL电池认证对电池标…

027:vue中两列表数据联动,购物车添加、删除和状态更改

第027个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

敦煌https证书能做些什么

随着互联网技术的不断发展&#xff0c;人们的生活方式和社交方式也发生了巨大的变化。互联网已经成为人们生活中不可或缺的一部分&#xff0c;它不仅提供了方便快捷的信息获取方式&#xff0c;还为人们提供了一个全新的社交平台。 然而&#xff0c;随着互联网的不断发展&#x…

工业设备状态监测中的声发射技术应用

工业设备状态监测是现代制造业和工业领域的重要一环&#xff0c;它能够帮助企业实时追踪设备的运行状况&#xff0c;及早发现潜在问题&#xff0c;采取预防性维护措施&#xff0c;以提高生产效率、降低维修成本&#xff0c;并确保工作场所的安全性。在这个领域&#xff0c;声发…

IT运维:使用数据分析平台监控H3C交换机

概述 在企业日常运维中&#xff0c;设备种类繁多&#xff0c;日志格式各异&#xff0c;日志量巨大&#xff0c;大量的告警&#xff0c;我们面临着如何统一的存放这些日志&#xff1f;如何对海量的日志进行查看&#xff0c;分析&#xff1f;传统的日志设备无法满足日志格式各异的…

lv3 嵌入式开发-10 NFS服务器搭建及使用

目录 1 NFS服务器介绍 1.1 NFS服务器的介绍 1.2 NFS服务器的特点 1.3 NFS服务器的适用场景 2 NFS服务器搭建 2.1 配置介绍 2.2 常见错误 3 WINDOWS下NFS服务器搭建&#xff08;扩展&#xff09; 1 NFS服务器介绍 1.1 NFS服务器的介绍 nfs&#xff08;Network File Sys…

一道面试题:介绍一下 Fragment 间的通信方式?

Fragment 间的通信可以借助以下几种方式实现&#xff1a; EventBusActivity&#xff08;or Parent Fragment&#xff09;ViewModelResult API 1. 基于 EventBus 通信 EventBus 的优缺点都很突出。 优点是限制少可随意使用&#xff0c;缺点是限制太少使用太随意。 因为 Even…