java 基于cglib、commons-beanutils库实现给前端返回动态列的集合

项目场景:

提示:这里简述项目相关背景:

项目场景:对用户选择的日期区间内,每周 bug数的不同状态的数量统计(如下图)
在这里插入图片描述


问题描述

通常我们创建返回对象的类的时候都是提前预设好的固定字段,针对列的数量不固定且字段名不固定该如何处理?

思路

基于cglib、commons-beanutils库实现

  • 将原对象和扩展字段封装为字段map
  • 基于字段map和原对象创建其子类对象
  • 重新将原字段值和扩展字段值赋给子类对象
  • 返回子类对象

方案:

  1. maven依赖
<dependency>
 <groupId>commons-beanutils</groupId>
 <artifactId>commons-beanutils</artifactId>
 <version>1.9.3</version>
</dependency>
<dependency>
 <groupId>cglib</groupId>
 <artifactId>cglib-nodep</artifactId>
 <version>3.2.4</version>
</dependency>

  1. 代码实现
  • 原始返回对象类
public class BugListVo {

    private String projectName;
    
    public String getProjectName() {
        return projectName;
    }

    public void setProjectName(String projectName) {
        this.projectName = projectName;
    }
}
  • 工具类
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.springframework.cglib.beans.BeanGenerator;
import org.springframework.cglib.beans.BeanMap;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

/**
 * @description: 工具类
 */
@Slf4j
public final class PropertyAppender {

    private static final class DynamicBean {

        private Object target;

        private BeanMap beanMap;

        private DynamicBean(Class superclass, Map<String, Class> propertyMap) {
            this.target = generateBean(superclass, propertyMap);
            this.beanMap = BeanMap.create(this.target);
        }

        private void setValue(String property, Object value) {
            beanMap.put(property, value);
        }

        private Object getValue(String property) {
            return beanMap.get(property);
        }

        private Object getTarget() {
            return this.target;
        }

        /**
         * 根据属性生成对象
         */
        private Object generateBean(Class superclass, Map<String, Class> propertyMap) {
            BeanGenerator generator = new BeanGenerator();
            if (null != superclass) {
                generator.setSuperclass(superclass);
            }
            BeanGenerator.addProperties(generator, propertyMap);
            return generator.create();
        }
    }

    public static Object generate(Object dest, Map<String, Object> newValueMap)
            throws InvocationTargetException, IllegalAccessException {
        PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();

        // 1.获取原对象的字段数组
        PropertyDescriptor[] descriptorArr = propertyUtilsBean.getPropertyDescriptors(dest);

        // 2.遍历原对象的字段数组,并将其封装到Map
        Map<String, Class> oldKeyMap = new HashMap<>(4);
        for (PropertyDescriptor it : descriptorArr) {
            if (!"class".equalsIgnoreCase(it.getName())) {
                oldKeyMap.put(it.getName(), it.getPropertyType());
                newValueMap.put(it.getName(), it.getReadMethod().invoke(dest));
            }
        }

        // 3.将扩展字段Map合并到原字段Map中
        newValueMap.forEach((k, v) -> oldKeyMap.put(k, v.getClass()));

        // 4.根据新的字段组合生成子类对象
        DynamicBean dynamicBean = new DynamicBean(dest.getClass(), oldKeyMap);

        // 5.放回合并后的属性集合
        newValueMap.forEach((k, v) -> {
            try {
                dynamicBean.setValue(k, v);
            } catch (Exception e) {
                log.error("动态添加字段【值】出错", e);
            }
        });
        return dynamicBean.getTarget();
    }
}
  • 测试
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Test {

    private static final ObjectMapper MAPPER = new ObjectMapper();

    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, JsonProcessingException {
        BugListVo bug = new BugListVo();
        bug.setProjectName("project_1");
        String jsonStr = MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(bug);
        System.out.println("BugListVo:" + jsonStr);
        Map<String, Object> propertiesMap = new HashMap<>(1);
        List<String> weeks = Arrays.asList("25年2周", "25年3周", "25年4周", "25年5周", "25年6周", "25年7周");
        for (int i = 0; i < weeks.size(); i++) {
            propertiesMap.put(weeks.get(i), i);
        }
        Object obj = PropertyAppender.generate(bug, propertiesMap);
        String jsonStr1 = MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        System.out.println("动态为BugListVo添加属性之后,bug:" + jsonStr1);
    }
}
  • 测试结果

BugListVo:{
“projectName” : “project_1”
}
动态为BugListVo添加属性之后,bug:{
“projectName” : “project_1”,
“25年6周” : 4,
“25年2周” : 0,
“25年3周” : 1,
“25年5周” : 3,
“25年4周” : 2,
“25年7周” : 5
}

安装Docker安装插件,可以按照以下步骤进行操作: 1. 首先,安装Docker。可以按照官方文档提供的步骤进行安装,或者使用适合您操作系统的包管理器进行安装。 2. 安装Docker Compose插件。可以使用以下方法安装: 2.1 下载指定版本的docker-compose文件: curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose 2.2 赋予docker-compose文件执行权限: chmod +x /usr/local/bin/docker-compose 2.3 验证安装是否成功: docker-compose --version 3. 在安装插件之前,可以测试端口是否已被占用,以避免编排过程中出错。可以使用以下命令安装netstat并查看端口号是否被占用: yum -y install net-tools netstat -npl | grep 3306 现在,您已经安装Docker安装Docker Compose插件,可以继续进行其他操作,例如上传docker-compose.yml文件到服务器,并在服务器上安装MySQL容器。可以参考Docker的官方文档或其他资源来了解如何使用DockerDocker Compose进行容器的安装和配置。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Docker安装docker-compose插件](https://blog.youkuaiyun.com/qq_50661854/article/details/124453329)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [Docker安装MySQL docker安装mysql 完整详细教程](https://blog.youkuaiyun.com/qq_40739917/article/details/130891879)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值