EasyExcel动态复杂表头导出方法

目录

    • 需求分析
    • 解决方案
    • 数据问题
    • 数据导入

需求分析

公司数据比较特殊有一部分数据需要动态修改导致信息导入时表头是不确定的,但其中又有一部分表头是固定的,如下图所示,如果表头全部是固定的话可以通过EasyExcel实体类的注解很轻松的解决,但由于部分数据动态改变,所以无法完全依靠注解实现。

在这里插入图片描述

解决方案

自定义方法通过反射获取实体类@ExcelProperty注解的值,同时在方法中获取动态表头信息共同组合成表头List数据。

	//模板下载接口实现
    public void downloadExcelTemplate(HttpServletResponse response) throws IOException {
        String filename = URLEncoder.encode("物料信息导入模板"+System.currentTimeMillis(),"utf-8");
        //设置响应头信息:将响应内容类型设置为 Excel 文件,并指定文件名和编码方式
        response.setHeader("Content-Disposition","attachment;filename=" + filename + ".xlsx");
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        //获取响应的输出流,用于将数据写入响应。
        OutputStream outputStream = response.getOutputStream();
        //创建一个 ExcelWriter 对象,用于写入 Excel 文件。
        ExcelWriter excelWriter = EasyExcel.write(outputStream).build();
        //gaugeOutfit.getItemHead()返回了表头List数据,也是动态表头的核心
        WriteSheet sheet = EasyExcel.writerSheet("sheet1").head(gaugeOutfit.getItemHead()).build();
        //向数据表中写入空数据
        excelWriter.write((Collection<?>) null, sheet);
        excelWriter.finish();
    }
//实体类
@TableName(value = "import_item",autoResultMap = true)
@Data
public class ImportItem implements Serializable {
    private static final long serialVersionUID = 1L;
    @TableId
    @ExcelIgnore
    private Long id;
    
    /**
     * 域动态信息,用于导入时集合所有的动态表头的信息,导入时使用
     */
    @TableField(typeHandler = JacksonTypeHandler.class , value = "dynamic_information")
    @ExcelIgnore
    private JSONObject dynamicInformation;
   
    @TableField("code")
    @ExcelProperty("物料编码")
    private String code;

    @TableField("name")
    @ExcelProperty("产品名称")
    @NotBlank(message = "产品名称字段不能为空")
    private String name;
  
    @TableField("category")
    @ExcelProperty("产品分类")
    private String category;
 
    @TableField("format")
    @ExcelProperty("产品规格")
    private String format;
    
    @TableField("life_cycle")
    @ExcelProperty("生命周期")
    private Integer lifeCycle;

    @TableField("brand")
    @ExcelProperty("品牌")
    private String brand;
   
    @TableField("sort")
    @ExcelProperty("排序")
    private Integer sort;
    
    @TableField("price_cost")
    @ExcelProperty("成本价")
    private BigDecimal priceCost;
  
    @TableField("price_line")
    @ExcelProperty("划线价")
    private BigDecimal priceLine;
    
    @TableField("length")
    @ExcelProperty("长度")
    private BigDecimal length;
    
    @TableField("width")
    @ExcelProperty("宽度")
    private BigDecimal width;
  
    @TableField("height")
    @ExcelProperty("高度")
    private BigDecimal height;
    
    @TableField("create_time")
    @ExcelIgnore
    private Date createTime;
    
    @ExcelIgnore
    private Date updateTime;
}

package com.ruoyi.plm.util;

import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.plm.mapper.AttributeKeyMapper;
import com.ruoyi.plm.mapper.DomainMapper;
import com.ruoyi.plm.model.entity.AttributeKey;
import com.ruoyi.plm.model.entity.Domain;
import com.ruoyi.plm.model.entity.ImportItem;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.*;

/**
 * @Author weijunliang
 * @CreateTime 2023/10/16 8:43
 * @Description TODO
 */
@Component
public class ExportExcelGaugeOutfit {
    @Resource
    private DomainMapper domainMapper;

    @Resource
    private AttributeKeyMapper keyMapper;

    public List<List<String>> getItemHead(){
        List<List<String>> list = new ArrayList<>();
        //反射获取@ExcelProperty注解字段
        Class<ImportItem> importItemClass = ImportItem.class;
        Field[] fields = importItemClass.getDeclaredFields();
        for(Field field :fields){
            if(field.isAnnotationPresent(ExcelProperty.class)){
                ExcelProperty fieldAnnotation = field.getAnnotation(ExcelProperty.class);
                String headName = Arrays.toString(fieldAnnotation.value()).replace("[", "").replace("]", "");
                List<String> head0 = new ArrayList<String>();
                //之所以加固定数据是为了后续导出数据时方便
                head0.add("固定数据");
                head0.add(headName);
                list.add(head0);
            }
        }
        //动态数据
        List<Domain> domainList = domainMapper.selectList(null);
        for (Domain domain : domainList){
            String domainName = domain.getName();
            QueryWrapper<AttributeKey> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("domain_id",domain.getId());
            List<AttributeKey> keyList = keyMapper.selectList(queryWrapper);
            for (AttributeKey key : keyList){
                ArrayList<String> head1 = new ArrayList<>();
                head1.add(domainName);
                head1.add(key.getName());
                list.add(head1);
            }
        }
        return list;
    }
}

数据问题

虽然上述方法解决了动态表头的问题,但当需要导出数据时把动态数据对应到表中的动态表头也需要把所有数据转换为相同List才行,这也就使得导出数据时需要手动进行处理而无法完全依靠EasyExcel的注解实现,颇费一番手脚。

	//获取所有数据
    private ArrayList<List<Object>> getAllData() throws IllegalAccessException {
        List<Item> items = itemMapper.selectList(null);
        ArrayList<List<Object>> importItemArrayList = new ArrayList<>();
        importItemArrayList.addAll(itemTransferList(items));
        return importItemArrayList;
    }
    //物料信息转换为List
    private List<List<Object>> itemTransferList(List<Item> itemList) throws IllegalAccessException {
        ArrayList<List<Object>> lists = new ArrayList<>();
        for (Item item : itemList){
            ImportItem importItem = new ImportItem();
            BeanUtils.copyProperties(item,importItem);
            //处理其它数据
            //通过反射在hashMap中添加固定字段信息
            HashMap<String, Object> hashMap = new HashMap<>();
            Class<ImportItem> importItemClass = ImportItem.class;
            Field[] fields = importItemClass.getDeclaredFields();
            for(Field field :fields){
                if(field.isAnnotationPresent(ExcelProperty.class)){
                    field.setAccessible(true);
                    ExcelProperty fieldAnnotation = field.getAnnotation(ExcelProperty.class);
                    String headName = Arrays.toString(fieldAnnotation.value()).replace("[", "").replace("]", "");
                    hashMap.put(headName, field.get(importItem));
                }
            }
            //hashMap添加动态字段信息,根据自己的业务逻辑修改
            List<Domain> domainList = domainMapper.selectList(null);
            for (Domain domain : domainList){
                /**
                ******
                **/
                hashMap.put(headName,headValue);
            }
            //hashMap对应表头数据并转换为list
            List<List<String>> itemHead = gaugeOutfit.getItemHead();
            ArrayList<Object> list = new ArrayList<>();
            for (List<String> head : itemHead){
                Object o = hashMap.get(head.get(1));
                list.add(o);
            }
            lists.add(list);
        }
        return lists;
    }

数据导入

参考文章:EasyExcel复杂表头数据导入

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java自学第3课:Java语言流程控制和字符串

1 复合语句 复合语句是以区块为单位的语句&#xff0c;也就是{}内的内容。 2 条件语句 if (布尔表达式){语句序列}else{语句序列} 有个好玩的是&#xff0c;对年龄段的分段&#xff0c;其实以前的思维是有点冗余的&#xff0c;比如a<100 & a>90&#xff0c;在复合…

文本内容转换成语音播放的工具:Speech Mac

Speech Mac版是一款适用于Mac电脑的语音合成工具。它将macOS语音合成器的所有功能整合到一个易于使用的界面中。通过Speech Mac版&#xff0c;用户可以选择40多种声音和语言&#xff0c;方便地将文本转换为语音。用户可以将文本拖放或粘贴到Speech中&#xff0c;并随时更改语音…

巴黎奥运会将基于阿里云实现云上转播

10月31日&#xff0c;2023杭州云栖大会&#xff0c;奥林匹克广播服务公司与奥林匹克频道服务公司首席技术官索蒂里斯萨拉穆里斯&#xff08;Sotiris SALAMOURIS&#xff09;表示&#xff0c;过去5年阿里云作为奥运会转播的基础设施&#xff0c;让奥运故事触达了更多全球观众。 …

mybatis-plus技巧--动态表名-多语句-拼接sql--关于mybatis的mysql分页查询总数的优化思考

文章目录 动态表名xml表名填充表名拦截器每天按统计每次设置 多语句操作forEach动态拼接 参数构建java进行拼接sqlmysql分页查询总数count不要使用count&#xff08;常数&#xff09;&#xff0c;count&#xff08;列名&#xff09;代替count(*)自己计数 SQL_CALC_FOUND_ROWSxm…

性能优化之懒加载 - 基于观察者模式和单例模式的实现

一、引入 在前端性能优化中&#xff0c;关于图片/视频等内容的懒加载一直都是优化利器。当用户看到对应的视图模块时&#xff0c;才去请求加载对应的图像。 原理也很简单&#xff0c;通过浏览器提供的 IntersectionObserver - Web API 接口参考 | MDN (mozilla.org)&#xff0c…

JavaScript设计模式之责任链模式

适用场景&#xff1a;一个完整的流程&#xff0c;中间分成多个环节&#xff0c;各个环节之间存在一定的顺序关系&#xff0c;同时中间的环节的个数不一定&#xff0c;可能添加环节&#xff0c;也可能减少环节&#xff0c;只要保证顺序关系就可以。 如下图&#xff1a; ES5写法…

flutter之bloc使用详解

flutter中一切皆为Widget&#xff0c;因此在我们开发中&#xff0c;往往业务和UI逻辑写在一起&#xff0c;这样不利于代码维护&#xff0c;因此状态管理框架久诞生了&#xff0c;这篇就开始讲一讲Bloc。 对于Bloc库有两个&#xff0c;如下图&#xff1a; flutter_bloc其实是对…

进程控制(三):进程替换

文章目录 进程控制&#xff08;三&#xff09;进程替换进程替换函数进程中的环境变量 总结 进程控制&#xff08;三&#xff09; 进程控制中的进程替换&#xff0c;下文我们学习进程替换的意义&#xff0c;以及进程替换的方式 进程替换 初步认识进程替换&#xff0c;我们先使…

Spring Cloud应用- Eureka原理、搭建

初期对Spring Cloud的学习以应用搭建为主&#xff0c;所以内容不会太枯燥。 一直以来&#xff0c;自以为Spring全家桶的学习中&#xff0c;Spring framework是基础中的基础&#xff0c;部分内容也还是必须要读源码去理解底层原理&#xff0c;SpringMVC、SpringBoot&#xff0c…

【ElasticSearch系列-03】ElasticSearch的高级句法查询Query DSL

ElasticSearch系列整体栏目 内容链接地址【一】ElasticSearch下载和安装https://zhenghuisheng.blog.csdn.net/article/details/129260827【二】ElasticSearch概念和基本操作https://blog.csdn.net/zhenghuishengq/article/details/134121631【二】ElasticSearch的高级查询Quer…

Linux上编译sqlite3库出现undefined reference to `sqlite3_column_table_name‘

作者&#xff1a;朱金灿 来源&#xff1a;clever101的专栏 为什么大多数人学不会人工智能编程&#xff1f;>>> 在Ubuntu 18上编译sqlite3库后在运行程序时出现undefined reference to sqlite3_column_table_name’的错误。网上的说法是说缺少SQLITE_ENABLE_COLUMN_M…

解决ModuleNotFoundError: No module named ‘yaml‘

报错&#xff1a;ModuleNotFoundError: No module named yaml 使用&#xff1a; pip install yaml 仍然报错&#xff1a; 最终解决方案&#xff1a; pip install pyyaml 或者 conda install pyyaml

百度竞价排名推广对比自然排名哪一个更具优势-华媒舍

在搜索引擎结论网页页面&#xff08;SERP&#xff09;中&#xff0c;我们经常会看到一些网站链接及其广告栏。这种连接一般分为两种类型&#xff1a;百度竞价推广排名推广与自然排名。究竟哪个更有优势&#xff1f;本文将对这几种排名形式进行科谱详细介绍。 什么叫百度竞价推广…

右击显示Pycharm打开教程

效果图 操作流程 win r 输入 regedit 回车打开注册表编辑器 2.找到 shell 路径 计算机\HKEY_CLASSES_ROOT\Directory\shell3.在 shell 下新建项&#xff0c;名称为 Pycharm 单击Pycharm文件夹&#xff0c;双击默认项&#xff0c;修改默认值&#xff0c;这个数值就是你右击后…

KaiwuDB 内核解析 - SQL 查询的生命周期

一、概述 KaiwuDB 内核解析系列共分上下两部分&#xff0c;本文是该系列的第一部分&#xff0c;主要涵盖了网络协议到 SQL 执行器&#xff0c;解释 KaiwuDB 如何执行 SQL 查询&#xff0c;包括系统各个组件的执行路径&#xff08;网络协议、SQL 会话管理、解析器、执行计划及优…

ucos_conf、ucos_src和ucos_port

目录 ucos_conf 文件夹ucos_src 文件夹ucos_port 文件夹 在 uC/OS-II 中&#xff0c;ucos_conf、ucos_src 和 ucos_port 是三个不同的文件夹&#xff0c;它们的作用和功能有所不同&#xff1a; ucos_conf 文件夹 ucos_conf 文件夹&#xff1a;ucos_conf 文件夹包含了 uC/OS-II…

CSGO游戏里的饰品是如何被炒作起来的?

csgo倒狗们是如何操盘csgo饰品市场的&#xff1f; CSGO游戏里的饰品是如何被炒作起来的&#xff1f; 随着近几年csgo玩家数量急剧上升&#xff0c;倒狗在市场中的比例也在上升&#xff0c;之前的csgo饰品市场以散户居多&#xff0c;价格波动不大&#xff0c;现在倒狗大量涌入&a…

Docker学习——①

文章目录 1、什么是虚拟化、容器化&#xff1f;2、为什么要虚拟化、容器化&#xff1f;3、虚拟化实现方式3.1 应用程序执行环境分层3.2 虚拟化常见类别3.3 常见虚拟化实现3.3.1 主机虚拟化(虚拟机)实现3.3.2 容器虚拟化实现3.3.3 空间隔离实战--基础知识3.3.4 PID 隔离3.3.5 Mo…

【优选算法系列】【专题九链表】第一节.链表常用技巧和操作总结(2. 两数相加)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、链表常用技巧和操作总结二、两数相加 2.1 题目描述 2.2 题目解析 2.2.1 算法原理 2.2.2 代码编写总结 前言 一、链表常…

uniapp自定义权限菜单,动态tabbar

已封装为组件&#xff0c;亲测4个菜单项目可以切换&#xff0c; 以下为示例&#xff0c;根据Storage 中 userType 的 值&#xff0c;判断权限菜单 <template><view class"tab-bar pb10"><view class"tabli" v-for"(tab, index) in ta…