100多张 Excel 报表需要导出,这样实现才足够优雅!

您所在的位置:网站首页 mysql导出数据到本地文件 100多张 Excel 报表需要导出,这样实现才足够优雅!

100多张 Excel 报表需要导出,这样实现才足够优雅!

2023-05-17 22:47| 来源: 网络整理| 查看: 265

点击上方“Java基基”,选择“设为星标”

做积极的人,而不是积极废人!

每天 14:00 更新文章,每天掉亿点点头发...

源码精品专栏

 

原创 | Java 2021 超神之路,很肝~

中文详细注释的开源项目

RPC 框架 Dubbo 源码解析

网络应用框架 Netty 源码解析

消息中间件 RocketMQ 源码解析

数据库中间件 Sharding-JDBC 和 MyCAT 源码解析

作业调度中间件 Elastic-Job 源码解析

分布式事务中间件 TCC-Transaction 源码解析

Eureka 和 Hystrix 源码解析

Java 并发源码

来源:juejin.im/post/

5c6b6b126fb9a04a0c2f024f

前言

实现的功能点

使用实例

实现效果

源码分析

成员变量

核心方法

多扯两点

1. 多线程查询数据

2. 如何解决接口超时

源码地址

源码服用姿势

拉票环节

前言

公司项目最近有一个需要:报表导出。整个系统下来,起码超过一百张报表需要导出。这个时候如何优雅的实现报表导出,释放生产力就显得很重要了。下面主要给大家分享一下该工具类的使用方法与实现思路。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

项目地址:https://github.com/YunaiV/ruoyi-vue-pro

视频教程:https://doc.iocoder.cn/video/

实现的功能点

对于每个报表都相同的操作,我们很自然的会抽离出来,这个很简单。而最重要的是:如何把那些每个报表不相同的操作进行良好的封装,尽可能的提高复用性;针对以上的原则,主要实现了一下关键功能点:

导出任意类型的数据

自由设置表头

自由设置字段的导出格式

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

项目地址:https://github.com/YunaiV/yudao-cloud

视频教程:https://doc.iocoder.cn/video/

使用实例

上面说到了本工具类实现了三个功能点,自然在使用的时候设置好这三个要点即可:

设置数据列表

设置表头

设置字段格式

下面的export函数可以直接向客户端返回一个excel数据,其中productInfoPos为待导出的数据列表,ExcelHeaderInfo用来保存表头信息,包括表头名称,表头的首列,尾列,首行,尾行。因为默认导出的数据格式都是字符串型,所以还需要一个Map参数用来指定某个字段的格式化类型(例如数字类型,小数类型、日期类型)。这里大家知道个大概怎么使用就好了,下面会对这些参数进行详细解释。

@Override     public void export(HttpServletResponse response, String fileName) {         // 待导出数据         List productInfoPos = this.multiThreadListProduct();         ExcelUtils excelUtils = new ExcelUtils(productInfoPos, getHeaderInfo(), getFormatInfo());         excelUtils.sendHttpResponse(response, fileName, excelUtils.getWorkbook());     }     // 获取表头信息     private List getHeaderInfo() {         return Arrays.asList(                 new ExcelHeaderInfo(1, 1, 0, 0, "id"),                 new ExcelHeaderInfo(1, 1, 1, 1, "商品名称"),                 new ExcelHeaderInfo(0, 0, 2, 3, "分类"),                 new ExcelHeaderInfo(1, 1, 2, 2, "类型ID"),                 new ExcelHeaderInfo(1, 1, 3, 3, "分类名称"),                 new ExcelHeaderInfo(0, 0, 4, 5, "品牌"),                 new ExcelHeaderInfo(1, 1, 4, 4, "品牌ID"),                 new ExcelHeaderInfo(1, 1, 5, 5, "品牌名称"),                 new ExcelHeaderInfo(0, 0, 6, 7, "商店"),                 new ExcelHeaderInfo(1, 1, 6, 6, "商店ID"),                 new ExcelHeaderInfo(1, 1, 7, 7, "商店名称"),                 new ExcelHeaderInfo(1, 1, 8, 8, "价格"),                 new ExcelHeaderInfo(1, 1, 9, 9, "库存"),                 new ExcelHeaderInfo(1, 1, 10, 10, "销量"),                 new ExcelHeaderInfo(1, 1, 11, 11, "插入时间"),                 new ExcelHeaderInfo(1, 1, 12, 12, "更新时间"),                 new ExcelHeaderInfo(1, 1, 13, 13, "记录是否已经删除")         );     }     // 获取格式化信息     private Map getFormatInfo() {         Map format = new HashMap();         format.put("id", ExcelFormat.FORMAT_INTEGER);         format.put("categoryId", ExcelFormat.FORMAT_INTEGER);         format.put("branchId", ExcelFormat.FORMAT_INTEGER);         format.put("shopId", ExcelFormat.FORMAT_INTEGER);         format.put("price", ExcelFormat.FORMAT_DOUBLE);         format.put("stock", ExcelFormat.FORMAT_INTEGER);         format.put("salesNum", ExcelFormat.FORMAT_INTEGER);         format.put("isDel", ExcelFormat.FORMAT_INTEGER);         return format;     } 实现效果 1953e74b13036c8eaccfe1a56ea9cb1c.jpeg 源码分析

哈哈,自己分析自己的代码,有点意思。由于不方便贴出太多的代码,大家可以先到github上clone源码,再回来阅读文章。✨源码地址✨LZ使用的poi 4.0.1版本的这个工具,想要实用海量数据的导出自然得使用SXSSFWorkbook这个组件。关于poi的具体用法在这里我就不多说了,这里主要是给大家讲解如何对poi进行封装使用。

成员变量

我们重点看ExcelUtils这个类,这个类是实现导出的核心,先来看一下三个成员变量。

private List list;     private List excelHeaderInfos;     private Map formatInfo; list

该成员变量用来保存待导出的数据。

ExcelHeaderInfo

该成员变量主要用来保存表头信息,因为我们需要定义多个表头信息,所以需要使用一个列表来保存,ExcelHeaderInfo构造函数如下ExcelHeaderInfo(int firstRow, int lastRow, int firstCol, int lastCol, String title)

firstRow:该表头所占位置的首行

lastRow:该表头所占位置的尾行

firstCol:该表头所占位置的首列

lastCol:该表头所占位置的尾行

title:该表头的名称

ExcelFormat

该参数主要用来格式化字段,我们需要预先约定好转换成那种格式,不能随用户自己定。所以我们定义了一个枚举类型的变量,该枚举类只有一个字符串类型成员变量,用来保存想要转换的格式,例如FORMAT_INTEGER就是转换成整型。因为我们需要接受多个字段的转换格式,所以定义了一个Map类型来接收,该参数可以省略(默认格式为字符串)。

public enum ExcelFormat {     FORMAT_INTEGER("INTEGER"),     FORMAT_DOUBLE("DOUBLE"),     FORMAT_PERCENT("PERCENT"),     FORMAT_DATE("DATE");     private String value;     ExcelFormat(String value) {         this.value = value;     }     public String getValue() {         return value;     } } 核心方法 1. 创建表头

该方法用来初始化表头,而创建表头最关键的就是poi中Sheet类的addMergedRegion(CellRangeAddress var1)方法,该方法用于单元格融合。我们会遍历ExcelHeaderInfo列表,按照每个ExcelHeaderInfo的坐标信息进行单元格融合,然后在融合之后的每个单元首行和首列的位置创建单元格,然后为单元格赋值即可,通过上面的步骤就完成了任意类型的表头设置。

// 创建表头     private void createHeader(Sheet sheet, CellStyle style) {         for (ExcelHeaderInfo excelHeaderInfo : excelHeaderInfos) {             Integer lastRow = excelHeaderInfo.getLastRow();             Integer firstRow = excelHeaderInfo.getFirstRow();             Integer lastCol = excelHeaderInfo.getLastCol();             Integer firstCol = excelHeaderInfo.getFirstCol();             // 行距或者列距大于0才进行单元格融合             if ((lastRow - firstRow) != 0 || (lastCol - firstCol) != 0) {                 sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol));             }             // 获取当前表头的首行位置             Row row = sheet.getRow(firstRow);             // 在表头的首行与首列位置创建一个新的单元格             Cell cell = row.createCell(firstCol);             // 赋值单元格             cell.setCellValue(excelHeaderInfo.getTitle());             cell.setCellStyle(style);             sheet.setColumnWidth(firstCol, sheet.getColumnWidth(firstCol) * 17 / 12);         }     } 2. 转换数据

在进行正文赋值之前,我们先要对原始数据列表转换成字符串的二维数组,之所以转成字符串格式是因为可以统一的处理各种类型,之后有需要我们再转换回来即可。

// 将原始数据转成二维数组     private String[][] transformData() {         int dataSize = this.list.size();         String[][] datas = new String[dataSize][];         // 获取报表的列数         Field[] fields = list.get(0).getClass().getDeclaredFields();         // 获取实体类的字段名称数组         List columnNames = this.getBeanProperty(fields);         for (int i = 0; i 


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3