Java真的不难(五十一)SpringBoot使用EasyExcel实现导出

news2024/11/15 23:22:16

EasyExcel:

大家好久不见!

一、什么是EasyExcel?

EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。
github地址: https://github.com/alibaba/easyexcel
官方文档地址https://www.yuque.com/easyexcel/doc/easyexcel

当然还有一个POI也可以实现操作Excel,Apache POI提供API给Java程序对Microsoft Office格式档案读和写的功能,POI为“Poor Obfuscation Implementation”的首字母缩写,意为“简洁版的模糊实现”

EasyExcel和POI的区别:
在这里插入图片描述


二、EasyExcel的实际使用

首先导入依赖:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.2.4</version>
</dependency>

依赖版本按需使用即可,一些基本的操作大家看官方文档即可,在这里就记录一下自己通过EasyExcel导出的表格及过程

首先看一下需要导出的模板:

在这里插入图片描述
区域说明:
A:单个单元格填充
B:列表填充
C:列表填充(但单元格格式与B区域不同)
D:单个单元格填充

一、A区域的填充数据模板的设置:

这个区域填充还是很简单的,只要给每个表格取个参数名,用{}包裹,Java里面用Map来填充即可。Map的键对应{}里面的参数名,对应的值就是填充进去的值:
在这里插入图片描述
例如这样,以下数据都是从数据库查出后填入Map即可:

 HashMap<String, Object> workOrderFileData = new HashMap<>();
        for (ProjectWorkOrderFileData p : WorkOrderFileList) {
            workOrderFileData.put("projectCode", p.getProjectCode());
            workOrderFileData.put("projectName", p.getProjectName());
            workOrderFileData.put("inspectedEnt", p.getInspectedEnt());
            workOrderFileData.put("customerAddress", p.getCustomerAddress());
            workOrderFileData.put("linkMan", p.getLinkMan());
            workOrderFileData.put("linkPhone", p.getLinkPhone());
            workOrderFileData.put("bizCreateTime", p.getBizCreateTime().substring(0, 10));
            workOrderFileData.put("customerName", p.getCustomerName());
            workOrderFileData.put("prodCompany", p.getProdCompany());
            workOrderFileData.put("testCode", p.getTestCode());
            workOrderFileData.put("batchCode", p.getBatchCode());
            workOrderFileData.put("region", region);
 }

二、B和C区域的填充数据模板的设置:

因为B区域是有两个列表,所以我们一定在模板内区分开来,给每个列表取个参数名,然后给每个字段取个参数名,通过列表参数名点(.)字段参数名即可:
即:{} 代表普通变量, {.} 代表是list的变量 {前缀.} 前缀可以区分不同的list
注意: 用{} 来表示你要用的变量 如果本来就有"{“,”}" 特殊字符 用"{“,”}"代替
在这里插入图片描述
对于这两组数据,Java里面使用两个列表储存即可,列表内可以存一个对象:

ArrayList<SampleData> SampleDataList = service.selectSampleData(proId);
ArrayList<AnalysisMethodData> analysisMethodDataList = service.selectAnalysisMethodData(proId);

对象里面的字段名即是该列表所有字段名:

@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class SampleData {
    private int number;
    private String typeName;
    private String redFolderName;
    private String redAnalyzeItems;
    private int spotFrequency;
    private int frequency;
    private int day;
    private int cycleOrder;
    private int timesOrder;
    private int sampleOrder;
    private String remarks;
}

D区域的填充和A区域是一样的,通过Map来填充即可,因为是一对一的关系


三、两个列表之间单元格样式不一样的解决办法

通过模板可以看到BC两个列表之前的单元格样式不一样,如果不做处理,在填充的时候,C区域的样式会根据B区域的样式来填充,也就是C区域合并的单元格会被拆分,所以需要一个工具类:

public class MyHandler extends AbstractMergeStrategy {

    @Override
    protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
        if (relativeRowIndex == null || relativeRowIndex == 0) {
            return;
        }
        int rowIndex = cell.getRowIndex();
        int colIndex = cell.getColumnIndex();
        sheet = cell.getSheet();
        Row preRow = sheet.getRow(rowIndex - 1);
        Cell preCell = preRow.getCell(colIndex);//获取上一行的该格
        List<CellRangeAddress> list = sheet.getMergedRegions();
        CellStyle cs = cell.getCellStyle();
        cell.setCellStyle(cs);
        for (CellRangeAddress cellRangeAddress : list) {
            if (cellRangeAddress.containsRow(preCell.getRowIndex()) && cellRangeAddress.containsColumn(preCell.getColumnIndex())) {
                int lastColIndex = cellRangeAddress.getLastColumn();
                int firstColIndex = cellRangeAddress.getFirstColumn();
                CellRangeAddress cra = new CellRangeAddress(cell.getRowIndex(), cell.getRowIndex(), firstColIndex, lastColIndex);
                sheet.addMergedRegion(cra);
                RegionUtil.setBorderBottom(BorderStyle.THIN, cra, sheet);
                RegionUtil.setBorderLeft(BorderStyle.THIN, cra, sheet);
                RegionUtil.setBorderRight(BorderStyle.THIN, cra, sheet);
                RegionUtil.setBorderTop(BorderStyle.THIN, cra, sheet);
                return;
            }
        }
    }
}

直接复制当工具类就完事!


三、完成其他配置,开始填充

我们还要设置两个地址:模板的位置以及导出后文件的储存位置,以下是控制层完整代码

@GetMapping(path = "/generateProjectWorkOrder")
    public JsonResp<String> generateProjectWorkOrder(@RequestParam("proId") String proId) {
        //设置模板位置以及导出后储存位置
        String templateFile = "D:/WorkProject/ExcelTemplate/模板.xls";
        String resultFile = "D:/WorkProject/ExcelTemplate/WorkOrderFile/" +"导出结果.xls";
        FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();
        ExcelWriter excelWriter = EasyExcel.write(resultFile).withTemplate(templateFile).build();
        //使用让该组单元格格式不受影响的工具类
        WriteSheet sheet = EasyExcel.writerSheet(0).registerWriteHandler(new MyHandler()).build();
        //获取数据(分别是ABCD四组数据)
        HashMap<String, Object> workOrderFileData = service.selectWorkOrder(proId);
        ArrayList<SampleData> SampleDataList = service.selectSampleData(proId);
        ArrayList<AnalysisMethodData> analysisMethodDataList = service.selectAnalysisMethodData(proId);
        HashMap<String, String> reviewerData = service.selectReviewerData(proId);
        //单组填充(A区域)
        excelWriter.fill(workOrderFileData, sheet);
        //多个列表填充(B、C区域)
        // 如果有多个list 模板上必须有{前缀.} 这里的前缀就是 data1,然后多个list必须用 FillWrapper包裹
        excelWriter.fill(new FillWrapper("data1", SampleDataList), fillConfig, sheet);
        excelWriter.fill(new FillWrapper("data2", analysisMethodDataList), fillConfig, sheet);
        //单组填充(D区域)
        excelWriter.fill(reviewerData, sheet);
        //关闭流
        excelWriter.finish();
        //返回数据
        JsonResp<String> objectJsonResp = new JsonResp<>();
        //返回路径
        resultFile = "lims/downloadGenerateExcel?path=" + resultFile;
        objectJsonResp.setData(resultFile);
        return objectJsonResp;
    }

数据获取的方式按照自己的格式来即可,若完成以上编写,可以实现本地的导出与下载,若需要部署在服务器上,则还需要从服务器下载到本地


三、服务器项目导出后下载到本地

若把项目部署在服务器上,使用该功能首先是下载到服务器上,然后再从服务器上下载到本地电脑。
我们可以使用HttpServletResponse response 来操作:
代码如下:

    @GetMapping(path = "/downloadGenerateExcel")
    public void download(String path, HttpServletResponse response) {
        try {
            // path是指想要下载的文件的路径
            File file = new File(path);
            String filename = file.getName();
            // 将文件写入输入流
            FileInputStream fileInputStream = new FileInputStream(file);
            InputStream fis = new BufferedInputStream(fileInputStream);
            byte[] buffer = new byte[fis.available()];
            //noinspection ResultOfMethodCallIgnored
            fis.read(buffer);
            fis.close();
            response.reset();
            response.setCharacterEncoding("UTF-8");
            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
            // 告知浏览器文件的大小
            response.addHeader("Content-Length", "" + file.length());
            OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");
            outputStream.write(buffer);
            outputStream.flush();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

这个方法的参数就是上述方法最后的代码:

//返回数据
JsonResp<String> objectJsonResp = new JsonResp<>();
//返回路径
resultFile = "lims/downloadGenerateExcel?path=" + resultFile;
objectJsonResp.setData(resultFile);
return objectJsonResp;

也就是导出完成后返回的参数可以自动调用这个方法,把返回的参数自动传入该方法的Path,即可完成从服务器下载到本地。


四、使用效果

运行对应的接口,即可把数据导出并填充在指定的Excel模板内,并下载到指定位置,使用以上模板导出的结果如下:
在这里插入图片描述
以上均为模拟数据,大家根据实际情况来编写即可

在最后附上EasyExcel最新的文档地址https://easyexcel.opensource.alibaba.com/docs/current/quickstart/fill


在这里插入图片描述

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

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

相关文章

MAC安装redis的简单方法

使用mac的包管理工具brew一行命令搞定安装。若未安装brew&#xff0c;命令行先输入以下命令安装brew。 /bin/bash -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" brew install redis6.2 brew services restart redis6.2 一、安装…

三台服务器使用docker搭建redis一主二从三哨兵,概念-搭建-整合springboot【保姆级】

一、前言 redis在我们企业级开发中是很常见的&#xff0c;但是单个redis不能保证我们的稳定使用&#xff0c;所以我们要建立一个集群。 redis有两种高可用的方案&#xff1a; High availability with Redis Sentinel&#xff08;哨兵&#xff09;Scaling with Redis Cluster&…

FT 在图像处理中的应用

接上文&#xff1a;离散傅里叶变换(DFT) 四、二维傅里叶变换 在此之前&#xff0c;文章都是对 FT 的理论部分的科普推导&#xff0c;距离我们的实际应用还有一定距离 虽然之前提到函数时域时&#xff0c;都是默认我们以时间 t 作为自变量&#xff0c;但事实上自变量也可以是其…

小册上新 | 掌握 SpringBoot 场景整合,成为开发多面手!

只会 SpringBoot 还远远不够 SpringBoot 的强大不言而喻&#xff0c;其底层 SpringFramework 强大的 IOC 容器和 AOP 机制&#xff0c;加之 SpringBoot 的自动装配&#xff0c;使得 SpringBoot 成为当今 JavaEE 开发中最受欢迎&#xff0c;以及使用范围极其广泛的基本技术。 …

[附源码]计算机毕业设计JAVA领导干部听课评课管理系统

[附源码]计算机毕业设计JAVA领导干部听课评课管理系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM…

设计模式之美——DRY原则 和 迪米特法则

DRY原则 Don’t Repeat Yourself。中文直译为&#xff1a;不要重复自己。即&#xff0c;不要写重复的代码。 我们主要讲三种典型的代码重复情况&#xff1a;实现逻辑重复、功能语义重复和代码执行重复。 实现逻辑重复 public class UserAuthenticator {public void authenti…

Web(二)html5基础-表格高级样式的设置

第1关_表格高级样式设置相关概念 第2关_设置表格的外边框样式 编程要求 根据提示&#xff0c;在右侧编辑器补充代码&#xff0c;在右侧编辑器中的Begin - End区域内补充代码&#xff0c;具体要求是&#xff1a; 1.添加table标签及属性&#xff0c;使得表格的宽度为100&#x…

CAS号:81075-03-8,H2N-AYA-OH

血管紧张素-1转换酶抑制剂(IC₅₀14.2 μM)Ala-Tyr已作为酪氨酸源应用于大鼠静脉营养。二肽AY是肝衰竭患者肠外营养的有效Tyr来源。 Inhibitor of angiotensin-1 converting enzyme (ACE), IC₅₀ 14.2 μM. Ala-Tyr has been used as a tyrosine source in intravenous nutrit…

设置ZIP文件打开密码的两种方法

使用WinRAR缩包ZIP文件时&#xff0c;有两种方式来设置打开密码&#xff0c;我们可以根据不同需要选择不同的方法。 方法一&#xff1a; 在压缩文件的时候同时设置打开密码&#xff0c;只设置当下压缩的ZIP文件。 首先&#xff0c;鼠标选择需要压缩的文件&#xff0c;然后点…

推荐一个基于Springboot + Vue 开发的前后端分离博客

基于Springboot Vue 开发的前后端分离博客 博客介绍 本博客是参考 [风丶宇] 大佬的博客更新而成&#xff0c;感谢大佬提供的页面&#xff0c;然后定制新增部分功能&#xff0c;是个非常值得新手入门学习的Java规范化编程案例&#xff01; 在线地址 项目链接&#xff1a; h…

【附源码】计算机毕业设计JAVA忆居民宿管理

【附源码】计算机毕业设计JAVA忆居民宿管理 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JAVA mybati…

Yolov4 训练数据常见的问题

1.Failed to load module"canberra-gtk-module" 解决办法&#xff1a;安装对应的module sudo apt-get install libcanberra-gtk-module 2.Killed 注意&#xff1a;造成killed问题的可能性比较多&#xff0c;这里我只记录我是如何解决的 。 解决&#xff1a; 首先是…

膜拜,华为内部都在强推的783页大数据处理系统:Hadoop源代码pdf

前言 都说程序员工资高、待遇好&#xff0c; 2022 金九银十到了&#xff0c;你的小目标是 30K、40K&#xff0c;还是 16薪的 20K&#xff1f;作为一名 Java 开发工程师&#xff0c;当能力可以满足公司业务需求时&#xff0c;拿到超预期的 Offer 并不算难。然而&#xff0c;提升…

数据结构和常用排序算法复杂度

1.顺序表 插入操作时间复杂度 最好O(1)&#xff0c;最坏O(n)&#xff0c;平均O(n) 移动结点的平均次数n/2 删除操作时间复杂度 最好O(1)&#xff0c;最坏O(n)&#xff0c;平均O(n) 移动结点的平均次数(n-1)/2 按值查找时间复杂度 最好O(1)&#xff0c;最坏O(n)&#xff0c;平…

数据库DQL数据查询语言

文章目录DQL数据查询语言语法:基础查询语法:WHERE子句使用AND"与"和OR"或"来连接多个条件进行查询IN(列表):等于列表其中之一(在列表中)NOT IN(列表):不在列表中&#xff0c;不能等于列表中的所有项BETWEEN...AND...:在一个范围之内DISTINCT去重操作。在结…

01.一个页面为啥有四个进程

打开了1个页面&#xff0c;Chrome启动了4个进程 并行处理 计算机中的并行处理就是同一时刻处理多个任务&#xff0c;比如我们要计算下面这三个表达式的值&#xff0c;并显示出结果。 A 12 B 20/5 C 7*8在编写代码的时候&#xff0c;我们可以把这个过程拆分为四个任务&…

sqli-labs/Less-57

这一关还是有14次尝试机会的 而且还是以id作为注入点的 首先输入如下语句 id1 and 12 查看回显 属于字符型 接着判断一下属于单引号还是双引号 输入1 查看回显 正确回显 在尝试一下双引号 输入1" 回显如下 肯定存在双引号包裹 但是是否有括号呢 不得而知 接着佐证一…

大一学生HTML期末作业 【html体育羽毛球6页面带注册】学生网页设计作业源码

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 校园篮球网页设计 | 足球体育运动 | 体育游泳运动 | 兵乓球 | 网球 | 等网站的设计与制作 | HTML期末大学生网页设计作业 HTML&#xff1a;结构 CSS&…

【仿真建模】第五课:AnyLogic入门基础课程 - 地铁车站仿真讲解

文章目录一、新建模型二、修改相关属性三、OutPart 站外部分四、站内部分4.1 FirstFloor 第一层楼一、新建模型 新建模型&#xff0c;单位改为分钟 二、修改相关属性 修改比例尺 三、OutPart 站外部分 新建 OutPart 智能体类型 重命名为 OutPart 修改OutPart的比例尺为50&am…

【JVM】类加载机制:分析与验证

一、加载 将类的字节码载入方法区中&#xff0c;内部采用 C 的 instanceKlass 描述 java 类。它的重要 field 有&#xff1a; _java_mirror &#xff1a; java 的类镜像&#xff0c;例如对 String 来说&#xff0c;就是 String.class&#xff0c;作用是把 klass 暴露给 java 使…