EasyExcel导出自定义表格

谈到新技术,每个人都会有点恐惧,怕处理不好。确实,第一次使用新技术会遇到很多坑,这次使用 EasyExcel 这个新技术去做 excel 导出,还要给表格加样式,遇到不同的版本问题,遇到颜色加错了地方,反正各种效果都打不到自己想要的那种,幸好最终看文档解决了,特此写下这篇博客。

EasyExcel导出自定义表格

  • 一、导入依赖
  • 二、原理分析
  • 三、上代码

一、导入依赖

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

二、原理分析

  1. 对于 read 函数主要通过流操作获取
    在这里插入图片描述
    对于 EasyExcel.read 方法中常用的一个 read 函数:

    java">EasyExcel.read(fileName, head, readListener).sheet().doRead();
    

    三个参数如下:

    • fileName:Excel 文件的路径或输入流。
    • head:Excel 表头对应的实体类,定义了 Excel 表的结构。
    • readListener:数据读取的监听器,定义了读取数据的逻辑。
  2. Excel 表头的实体类

    在读取 Excel 文件时,需要定义一个实体类来映射 Excel 表头,每个字段对应一个表头列。这个实体类用于指定数据在 Java 对象中的存储结构。

    java">public class ExcelData {private String name;private Integer age;// 其他字段...// 省略 getter 和 setter 方法
    }
    
  3. 数据读取监听器

    EasyExcel 提供了 AnalysisEventListener 类来处理 Excel 数据的读取。

    需要集成该类,并实现 invoke 方法来处理每一行数据的读取逻辑,以及 doAfterAllAnalysed 方法来处理所有数据解析完成后的逻辑。

    public class ExcelDataListener extends AnalysisEventListener<ExcelData> {@Overridepublic void invoke(ExcelData data, AnalysisContext context) {// 处理每一行数据的逻辑System.out.println("Read data: " + data);}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 所有数据解析完成后的逻辑}
    }
    
  4. Excel 写入

    EasyExcel 也提供了写入 Excel 文件的功能。可以使用 EasyExcel.write 方法来配置写入参数,然后调用 sheet 方法指定写入的 sheet,最后调用 doWrite 方法执行写入操作。

    EasyExcel.write(fileName, head).sheet("Sheet1").doWrite(dataList);
    

    三个参数如下:

    • fileName:写入的 Excel 文件路径。
    • head:Excel 表头对应的实体类。
    • dataList:要写入的数据列表。dataList 是一个 List 集合,其中的元素是实体类的对象。
  5. Excel 写入监听器

    写入 Excel 文件时进行一些额外的处理,可以使用写入的监听器 WritHandler。

    public class ExcelWriteHandler implements WriteHandler {@Overridepublic void sheet(int sheetNo, Sheet sheet) {// 对每个 sheet 进行处理的逻辑}@Overridepublic void row(int rowNum, Row row) {// 对每一行进行处理的逻辑}@Overridepublic void cell(int cellNum, Cell cell) {// 对每个单元格进行处理的逻辑}
    }
    

在写入 Excel 文件时,通过 excelWriter.registerWriterHandler( new ExcelWriterHandler() ) 注册写入监听器即可。

三、上代码

先看要求
在这里插入图片描述
其实这里的大部分样式,都可以参考 EasyExcel API 文档

导出

@Overridepublic void importUserSign(ImportUserSignReq req, HttpServletResponse response) {String projectName = req.getProjectName();String time = req.getTime();// 查询第一页数据List<SignTemplate1> data1 = new ArrayList<>();data1.add(new SignTemplate1().setE1("序号").setE2("成员姓名").setE3("签到次数").setE4("补签次数").setE5("签到总工时").setE6("最后签到时间"));data1.addAll(getData1(req));// 查询第二页数据List<SignTemplate2> data2 = getData2(req, getData1(req));Integer maxRow = data2.stream().map(SignTemplate2::getE2).max(Integer::compare).orElse(0); //获取最大行try {// 指定文件名
//            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
//            response.setCharacterEncoding("utf-8");
//            String fileName = URLEncoder.encode("签到模板导出.xlsx", "UTF-8");
//            response.setHeader("Content-disposition", "attachment;filename*=" + fileName);String fileName = "E:\\excel\\" + "签到模板导出" + System.currentTimeMillis() + ".xlsx";ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();// 第一页// 自定义头部样式WriteCellStyle headWriteCellStyle1 = new WriteCellStyle();headWriteCellStyle1.setFillForegroundColor(IndexedColors.GOLD.getIndex()); //背景颜色-黄色headWriteCellStyle1.setHorizontalAlignment(HorizontalAlignment.LEFT); //左对齐// 自定义内容样式WriteCellStyle contentWriteCellStyle1 = new WriteCellStyle();// 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现HorizontalCellStyleStrategy style1 = new HorizontalCellStyleStrategy(headWriteCellStyle1, contentWriteCellStyle1);// sheet命名WriteSheet writeSheet1 = EasyExcel.writerSheet(1, "项目名称").registerWriteHandler(style1) //自定义策略.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) //自动列宽.head(getHead("【"+projectName+"】", time, 6)) //动态表头.head(SignTemplate1.class).build();// 写入第一页excelWriter.write(data1, writeSheet1);// 第二页// 自定义头部样式WriteCellStyle headWriteCellStyle2 = new WriteCellStyle();headWriteCellStyle2.setFillForegroundColor(IndexedColors.GOLD.getIndex()); //背景颜色-黄色headWriteCellStyle2.setHorizontalAlignment(HorizontalAlignment.LEFT); //左对齐// 自定义内容样式WriteCellStyle contentWriteCellStyle2 = new WriteCellStyle();contentWriteCellStyle2.setHorizontalAlignment(HorizontalAlignment.RIGHT); //右对齐// 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现HorizontalCellStyleStrategy style2 = new HorizontalCellStyleStrategy(headWriteCellStyle2, contentWriteCellStyle2);// sheet命名WriteSheet writeSheet2 = EasyExcel.writerSheet(2, "签到明细").registerWriteHandler(style2) //自定义策略.registerWriteHandler(new CustomCellWriteHandler(maxRow, (data2.size()+1))) //自定义动态行/列背景颜色.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) //自动列宽.head(getHead("【"+projectName+"】", time, (data2.size()+1))) //动态表头.build();// 写入第二页excelWriter.write(dataList(data2, maxRow), writeSheet2).close();}catch (Exception e){e.printStackTrace();throw new CustomException("导出失败");}}

动态标题头

private List<List<String>> getHead(String projectName, String time, Integer num) {List<List<String>> list = new ArrayList<List<String>>();for (int i = 0; i < num; i++) {list.add(Arrays.asList(projectName, time));}return list;
}

动态填充数据

private List<List<Object>> dataList(List<SignTemplate2> data2, Integer maxRow) {List<List<Object>> list = new ArrayList<>();List<Object> row1 = ListUtils.newArrayList(); //第一行List<Object> row2 = ListUtils.newArrayList(); //第二行row1.add("成员名称");row2.add("签到次数");for (int i = 0; i <data2.size(); i++) { //行内每一列数据row1.add(data2.get(i).getE1());row2.add(data2.get(i).getE2());}list.add(row1);list.add(row2);for (int i = 0; i < maxRow; i++) {List<Object> row3 = ListUtils.newArrayList(); //第三行-多条List<Object> row4 = ListUtils.newArrayList(); //第四行-多条row3.add(null);row4.add(null);for (int j = 0; j <data2.size(); j++) { //行内每一列数据List<SignTemplate3> eList = data2.get(j).getEList();//当前列的签到集合if (i < eList.size()) {row3.add(eList.get(i).getE2()+"  "+eList.get(i).getE1());row4.add(ObjectUtil.isNotNull(eList.get(i).getE3())?eList.get(i).getE3():"暂无");}else {row3.add(null);row4.add(null);}}list.add(row3);list.add(row4);}return list;
}

自定义动态行/列背景颜色

package com.glbTech.business.dto.req.stat;import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.AbstractCellWriteHandler;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import lombok.Data;
import org.apache.commons.lang.BooleanUtils;
import org.apache.poi.hssf.usermodel.HSSFPalette;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;@Data
public class CustomCellWriteHandler extends AbstractCellWriteHandler {private Integer maxRow;private Integer maxCol;private final short colorL = IndexedColors.LIME.getIndex(); //绿色private final short colorH = IndexedColors.GREY_25_PERCENT.getIndex(); //灰色public CustomCellWriteHandler(Integer maxRow, Integer maxCol) {this.maxRow = maxRow;this.maxCol = maxCol;}@Overridepublic void afterCellDispose(CellWriteHandlerContext context) {// 自定义样式处理// 当前事件会在 数据设置到poi的cell里面才会回调int x = 1;for (int i = 4; i < (maxRow+2)*2; i=(x*2)) {Cell cell = context.getCell();int rowIndex = cell.getRowIndex(); //行int cellIndex = cell.getColumnIndex(); //行的列// 判断不是头的情况 如果是fill 的情况 这里会==null 所以用not trueif (BooleanUtils.isNotTrue(context.getHead())) {if (cellIndex > 0 && (rowIndex==i || rowIndex==i+1)) {// 拿到poi的workbookWorkbook workbook = context.getWriteWorkbookHolder().getWorkbook();// 这里千万记住 想办法能复用的地方把他缓存起来 一个表格最多创建6W个样式// 不同单元格尽量传同一个 cellStyleCellStyle cellStyle = workbook.createCellStyle();//设置颜色if (x%2==0) {cellStyle.setFillForegroundColor(colorL); //绿色}else {cellStyle.setFillForegroundColor(colorH); //灰色}cellStyle.setAlignment(HorizontalAlignment.RIGHT); //右对齐// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUNDcellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);cell.setCellStyle(cellStyle);// 由于这里没有指定dataformat 最后展示的数据 格式可能会不太正确// 这里要把 WriteCellData的样式清空, 不然后面还有一个拦截器 FillStyleCellWriteHandler 默认会将 WriteCellStyle 设置到// cell里面去 会导致自己设置的不一样(很关键)context.getFirstCellData().setWriteCellStyle(null);}}x++;}}
}

好事定律:每件事最后都会是好事,如果不是好事,说明还没到最后。

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

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

相关文章

pyside6 pytq PyDracula QVideoWidget视频只有声音没有画面

解决方案&#xff1a; 先不使用框架&#xff0c;纯pyside6代码&#xff0c;如果添加视频有画面有声音&#xff0c;那可以排除是硬件问题&#xff0c;如果没有画面只有声音&#xff0c;可能是视频解码器无法解码&#xff0c;换个格式的视频文件如果只有使用PyDracula 出问题&am…

web开发——前端html、css、JavaScript学习总结(持续更新中.......)

目录模版 1 html:结构标签/属性文本标记: mark文本设置:删除线del / 下划线ins/ 加粗b / 强调的文本em / 重要的文本 strong超链接: a联系信息: addressdiv 定义文档中的分区或节: div行元素:spanhtml结构: main / section / articlenav表格:table html中各种标签/属性的英文扩…

记一次寻找js来文件上传

edu教育证书站之路 0x01 信息收集 通过fofa&#xff0c;子域名收集等相关工具搜索域名 定位到站点&#xff1a;htps://xx..edu.cn/x/xx/ 0x02 寻找接口 通过f12寻找相关的js&#xff0c;发现有其他的页面 0x03 拼接路径 https://xx.xx.edu.cn/xx/xx/repairResgister 之后未授权…

主流接口测试框架对比

公司计划系统的开展接口自动化测试&#xff0c;需要我这边调研一下主流的接口测试框架给后端测试&#xff08;主要测试接口&#xff09;的同事介绍一下每个框架的特定和使用方式。后端同事根据他们接口的特点提出一下需求&#xff0c;看哪个框架更适合我们。 需求 1、接口编写…

亿道三防手持机丨安卓加固手持终端丨手持机PDA丨货物出入库

出入库管理是现代物流系统中的重要环节&#xff0c;涉及到货物的接收、分发、存储和追踪等方面。然而&#xff0c;在复杂的仓库环境中&#xff0c;传统的管理方法面临着很多困难和挑战&#xff0c;如手写记录容易出错、数据处理繁琐等。为了提高出入库管理的效率和准确性&#…

【新手适用】手把手教你从零开始实现一个基于Pytorch的卷积神经网络CNN一: 创建model模块和加载数据集

教程&#xff1a;j从零开始实现一个基于Pytorch的卷积神经网络 - 知乎 目录 网络结构 1 初始化 2 前向传播forward函数 2.1 forward函数定义 2.2 view函数和size函数 如何获取channels&#xff1f; 如何获取batchsize&#xff1f; 2.3 forward实现 2.4 main方法调用 模…

企业微信变更主体对用户有影响吗?

企业微信变更主体有什么作用&#xff1f;现在很多公司都用企业微信来加客户&#xff0c;有时候辛辛苦苦积累了很多客户&#xff0c;但是公司却因为各种各样的原因需要注销&#xff0c;那么就需要通过企业微信变更主体的方法&#xff0c;把企业微信绑定的公司更改为最新的。企业…

arduino 编程esp8266

概述&#xff1a; 1.wifi连接&#xff0c;扫描WiFi连接json序列化&#xff0c;http.get和http.post。 2.数据的存储和全局常量的flash定义。 3.文件的存储读写。 4.板子外设资源的访问&#xff1a;Libraries - Arduino Reference 注意&#xff1a;开发板未nodeMCU1.0(esp-12e)…

ISIS知识点【笔记】

isis配置 【Isis进程&#xff0c;Isis实体认证,Is-level&#xff0c;Isis接口开启功能&#xff1a;isis enable 1】 【Isis接口认证】 【49.0002.0000.0000.0004.00 前两段&#xff1a;区域ID。第三&#xff0c;四&#xff0c;五&#xff1a;主机ID。00&#xff…

Java后端八股------消息中间件篇

自动确认没收到&#xff0c;实现重复消费问题&#xff0c;可以用业务唯一标识来确定业务是否被消费。 TTL也就是超时时间&#xff0c;一般去dead letter的时间为min(消息的ttl,queue的ttl)。 acksall设置是最安全的&#xff0c;但是效率太低了&#xff0c;实际的生…

鲜花销售小程序|基于微信小程序的鲜花销售系统设计与实现(源码+数据库+文档)

鲜花销售小程序目录 目录 基于微信小程序的鲜花销售系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1前台功能模块 2、后台功能模块 1、管理员功能模块 四、数据库设计 1、实体ER图 2、具体的表设计如下所示&#xff1a; 五、核心代码 六、论文参考 七、…

Java开发从入门到精通(一):ZK 集群的部署

ZK 集群的部署 server.<节点ID>:<数据同步端口>:<选举端口> 节点 ID&#xff1a;为 1 到 125 之间的数字&#xff0c;写到对应服务节点的{dataDir}/myid 文件中。 IP 地址&#xff1a;节点的远程 IP 地址&#xff0c;可以相同&#xff0c;生产环境建议用不同…

突破编程_C++_设计模式(享元模式)

1 享元模式的基本概念 享元模式&#xff08;Flyweight Pattern&#xff09;是一种主要用于减少创建对象的数量&#xff0c;以减少内存占用和提高性能的设计模式。它通过使用共享对象来支持大量的细粒度对象&#xff0c;从而减少了内存占用。在享元模式中&#xff0c;有些对象可…

【io.net】问题汇总

【io.net】问题汇总 大家最近挖挖的如火如荼&#xff0c;可是不论是社区活动积分和参与挖矿积分&#xff0c;大家遇到了很多类似问题&#xff0c;重复解决。 因此我这里整理了一下常见的相关问题&#xff0c;大家可以一站式找到解决方案。解决方案主要分为运营和挖矿两个两面…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的障碍物检测系统(Python+PySide6界面+训练代码)

摘要&#xff1a;开发障碍物检测系统对于道路安全性具有关键作用。本篇博客详细介绍了如何运用深度学习构建一个障碍物检测系统&#xff0c;并提供了完整的实现代码。该系统基于强大的YOLOv8算法&#xff0c;并对比了YOLOv7、YOLOv6、YOLOv5&#xff0c;展示了不同模型间的性能…

如何解决由触发器导致 MySQL 内存溢出?

由触发器导致得 OOM 案例分析过程和解决方式。 作者&#xff1a;龚唐杰&#xff0c;爱可生 DBA 团队成员&#xff0c;主要负责 MySQL 技术支持&#xff0c;擅长 MySQL、PG、国产数据库。 爱可生开源社区出品&#xff0c;原创内容未经授权不得随意使用&#xff0c;转载请联系小编…

JavaScript 面试题

问题 1 // 请解释下面代码的输出结果 console.log(1 "2" "2"); console.log(1 "2" "2"); console.log(1 -"1" "2"); console.log("A" - "B" "2"); console.log(&qu…

零基础学习JS--基础篇--使用对象

JavaScript 的设计是一个简单的基于对象的范式。一个对象就是一系列属性的集合&#xff0c;一个属性包含一个名和一个值。一个属性的值可以是函数&#xff0c;这种情况下属性也被称为方法。除了浏览器里面预定义的那些对象之外&#xff0c;你也可以定义你自己的对象。本章节讲述…

苹果cms模板保护设置,防止被扒

苹果cms模板保护设置&#xff0c;防止被扒 如今互联网时代&#xff0c;网站模板前端被扒是常有的事&#xff0c;如何防止模板数据被扒&#xff1f; 保护设置方法&#xff1a; 登录宝塔 找到安装模板的网站 设置禁止访问文件 方法参考截图后缀填&#xff1a;php|html 目录填&a…

OA系统中的九大常用审批场景,你都晓得吗?

Hi&#xff0c;我是贝格前端工场&#xff0c;今天继续来剖析OA的功能&#xff0c;这次重点分析审批功能&#xff0c;欢迎老铁们点赞评论转发。 一、OA的审批功能和流程 OA的审批功能是指在办公自动化系统中&#xff0c;通过电子化的方式实现对各种申请、请求或业务流程的审批管…