【EasyExcel】EasyExcel导出表格包含合计行、自定义样式、自适应列宽
目录
- 0 EasyExcel简介
- 1 Excel导出工具类
- 设置自定义表头样式
- 设置自适应列宽
- 添加合计行
- 2 调用导出工具类导出Excel表
- 3 测试结果
0 EasyExcel简介
在数据处理和报表生成的过程中,Excel是一个非常常用的工具。特别是在Java开发中,EasyExcel库因其简单高效而备受欢迎。
EasyExcel是阿里巴巴开源的一个Excel处理库,特别适用于大数据量的Excel文件的读写。它的优点在于使用简单、性能高效,特别适合在Java项目中处理Excel文件。
1 Excel导出工具类
Excel导出工具类ExcelUtil类代码如下:
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import lombok.Data;
import org.apache.poi.ss.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;@Data
public class ExcelUtil{public static void downloadExcelWithHead(HttpServletResponse response, List<?> list, String sheetName, List<List<String>> rowHead) throws IOException {if (list.isEmpty()) {throw new IllegalArgumentException("列表不能为空!");}Class<?> clazz = list.get(0).getClass();response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");String fileName = URLEncoder.encode(sheetName, "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), clazz).excelType(ExcelTypeEnum.XLSX).build();// 创建 ExcelWriterBuilderExcelWriterBuilder excelWriterBuilder = EasyExcel.write(response.getOutputStream(), clazz).autoCloseStream(true).needHead(true);excelWriterBuilder.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy());excelWriterBuilder.useDefaultStyle(false);// 创建 WriteSheet 并设置动态标题行WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).head(rowHead) // 设置标题行.registerWriteHandler(setCellStyle()) // 设置表头样式.registerWriteHandler(new CustomCellWriteUtil()) // 设置列宽自适应.build();// 写入数据excelWriter.write(list, writeSheet);excelWriter.finish();}}
设置自定义表头样式
其中,downloadExcelWithHead()中调用setCellStyle()方法用于设置表头样式。setCellStyle()方法的代码如下:
public static HorizontalCellStyleStrategy setCellStyle() {// 表头策略WriteCellStyle headWriteCellStyle = new WriteCellStyle();// 背景设置为白色headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.index);headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);headWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);//边框headWriteCellStyle.setBorderBottom(BorderStyle.THIN);headWriteCellStyle.setBorderLeft(BorderStyle.THIN);headWriteCellStyle.setBorderRight(BorderStyle.THIN);headWriteCellStyle.setBorderTop(BorderStyle.THIN);//自动换行headWriteCellStyle.setWrapped(true);WriteFont headWriteFont = new WriteFont();headWriteFont.setBold(true);headWriteFont.setFontName("宋体");headWriteFont.setFontHeightInPoints((short)12);headWriteCellStyle.setWriteFont(headWriteFont);// 内容的策略WriteCellStyle contentWriteCellStyle = new WriteCellStyle();// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);// 背景白色contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);//边框contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);contentWriteCellStyle.setBorderRight(BorderStyle.THIN);contentWriteCellStyle.setBorderTop(BorderStyle.THIN);//自动换行contentWriteCellStyle.setWrapped(true);//文字WriteFont contentWriteFont = new WriteFont();// 字体大小contentWriteFont.setFontHeightInPoints((short)12);contentWriteFont.setFontName("宋体");contentWriteCellStyle.setWriteFont(contentWriteFont);return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);}
设置自适应列宽
自适应列宽通过CustomCellWriteUtil类设置,CustomCellWriteUtil类的代码如下:
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.CellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.Cell;import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** excel自适应列宽*/
public class CustomCellWriteUtil extends AbstractColumnWidthStyleStrategy {private static final int MAX_COLUMN_WIDTH = 255;private Map<Integer, Map<Integer, Integer>> CACHE = new HashMap(8);public CustomCellWriteUtil() {}protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);if (needSetWidth) {Map<Integer, Integer> maxColumnWidthMap = (Map) CACHE.get(writeSheetHolder.getSheetNo());if (maxColumnWidthMap == null) {maxColumnWidthMap = new HashMap(16);CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);}Integer columnWidth = this.dataLength(cellDataList, cell, isHead);if (columnWidth >= 0) {if (columnWidth > 255) {columnWidth = 255;}Integer maxColumnWidth = (Integer) ((Map) maxColumnWidthMap).get(cell.getColumnIndex());if (maxColumnWidth == null || columnWidth > maxColumnWidth) {((Map) maxColumnWidthMap).put(cell.getColumnIndex(), columnWidth);writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), 7250);}}}}private Integer dataLength(List<WriteCellData<?>> cellDataList, Cell cell, Boolean isHead) {if (isHead) {return cell.getStringCellValue().getBytes().length;} else {CellData cellData = (CellData) cellDataList.get(0);CellDataTypeEnum type = cellData.getType();if (type == null) {return -1;} else {switch (type) {case STRING:return cellData.getStringValue().getBytes().length;case BOOLEAN:return cellData.getBooleanValue().toString().getBytes().length;case NUMBER:return cellData.getNumberValue().toString().getBytes().length;default:return -1;}}}}
}
添加合计行
合计行用于展示数据的总和或其他统计信息。在Controller中调用downloadExcelWithHead()方法导出Excel时,添加合计行和自定义表头形式。
2 调用导出工具类导出Excel表
此处以导出产品明细表为例,新建产品表如下:

entity、mapper、service层省略,在Controller层中添加一个导出产品明细表接口,代码如下:
import com.z.entity.Product;
import com.z.service.ProductService;
import com.z.util.ConvertUtil;
import com.z.util.ExcelUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;@RestController
@RequestMapping("/product")
public class ProductController {@Autowiredprivate ProductService productService;@PostMapping("/export")public void export(HttpServletResponse response) throws IOException {List<Product> dataList = productService.list();if(null == dataList || dataList.isEmpty()){throw new RuntimeException("数据为空,导出失败!");}// 计算合计double totalProductCost = dataList.stream().mapToDouble(data -> data.getProductCost() != null ? data.getProductCost() : 0.0).sum();int totalProductNum = dataList.stream().mapToInt(data -> data.getProductNum() != null ? data.getProductNum() : 0).sum();// 创建合计行Product totalRow = new Product();totalRow.setId("合计");totalRow.setProductCost(totalProductCost);totalRow.setProductNum(totalProductNum);// 添加合计行到列表dataList.add(totalRow);// 创建自定义表头List<List<String>> rowHead = createHead();// 导出 Excel(带标题列,带合计列)ExcelUtil.downloadExcelWithHead(response, dataList, "产品明细表", rowHead);}/*** 设置Excel头* @return*/private List<List<String>> createHead() {List<List<String>> list = new ArrayList<>();// 第一列表头List<String> headRow1 = new ArrayList<>();headRow1.add("产品明细表报表");headRow1.add("test");headRow1.add("产品序号");list.add(headRow1);// 第二列表头List<String> headRow2 = new ArrayList<>();headRow2.add("产品明细表报表");headRow2.add("备注:"+"此处可调用方法取值");headRow2.add("产品编号");list.add(headRow2);// 第三列表头List<String> headRow3 = new ArrayList<>();headRow3.add("产品明细表报表");headRow3.add("备注:"+"此处可调用方法取值");headRow3.add("产品名称");list.add(headRow3);// 第四列表头List<String> headRow4 = new ArrayList<>();headRow4.add("产品明细表报表");headRow4.add("无");headRow4.add("产品进价");list.add(headRow4);// 第五列表头List<String> headRow5 = new ArrayList<>();headRow5.add("产品明细表报表");headRow5.add("测试");headRow5.add("产品库存");list.add(headRow5);return list;}
其中,在使用createHead()方法设置Excel头时,可以调用service层中的方法,自定义显示特定值。
3 测试结果
最终使用postman调用该导出接口,导出的表格结果如下:

相关文章:
【EasyExcel】EasyExcel导出表格包含合计行、自定义样式、自适应列宽
目录 0 EasyExcel简介1 Excel导出工具类设置自定义表头样式设置自适应列宽添加合计行 2 调用导出工具类导出Excel表3 测试结果 0 EasyExcel简介 在数据处理和报表生成的过程中,Excel是一个非常常用的工具。特别是在Java开发中,EasyExcel库因其简单高效而…...
es数据同步(仅供自己参考)
数据同步的问题分析: 当MySQL进行增删改查的时候,数据库的数据有所改变,这个时候需要修改es中的索引库的值,这个时候就涉及到了数据同步的问题 解决方法: 1、同步方法: 当服务对MySQL进行增删改的时候&…...
apt镜像源制作-ubuntu22.04
# 安装必要的软件 sudo apt-get install -y apt-mirror # 编辑/etc/apt/mirror.list,添加以下内容 set base_path /var/spool/apt-mirror # 指定要镜像的Ubuntu发布和组件-null dir jammy-updates main restricted universe multiverse # 镜像的Ubuntu发布和组件的URL-n…...
libaom 源码分析: 预测编码过程梳理
AV1 预测编码中核心技术 AV1(AOMedia Video 1)作为一种开源的视频编码格式,其预测编码核心技术主要包括以下几个方面: 分区树分割模块: AV1利用多类型分割模式,递归地对图像/视频序列进行分区,以捕捉更丰富的空间信息,从而提升编码效率。这包括新的方向预测分割模式及…...
从0开始学习Linux——Yum工具
往期目录: 从0开始学习Linux——简介&安装 从0开始学习Linux——搭建属于自己的Linux虚拟机 从0开始学习Linux——文本编辑器 上一个章节我们简单了解了Linux中常用的一些文本编辑器,本次教程我们将学习yum工具。 一、Yum简介 Yum(全名…...
【Linux】Linux管道揭秘:匿名管道如何连接进程世界
🌈个人主页:Yui_ 🌈Linux专栏:Linux 🌈C语言笔记专栏:C语言笔记 🌈数据结构专栏:数据结构 🌈C专栏:C 文章目录 1.什么是管道 ?2. 管道的类型2.1 匿…...
【LeetCode】【算法】155. 最小栈
LeetCode 155. 最小栈 题目描述 设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。 void push(int val) 将元素val推入堆栈。 void pop() 删除堆栈顶部的元素。 int …...
3.3 windows,ReactOS系统中页面的换出----1
系列文章目录 文章目录 系列文章目录3.3 页面的换出MiBalancerThread()MmTrimUserMemory()MmPageOutVirtualMemory() 3.3 页面的换出 在前一节中我们看到,如果有映射的页面已经被倒换到磁盘上即倒换文件中,…...
QCustomPlot添加自定义的图例,实现隐藏、删除功能(二)
文章目录 实现步骤:详细代码示例:实现原理和解释:使用方法:其他参考要实现一个支持复选框来控制曲线显示和隐藏的自定义 QCPLegend 类,可以通过继承 QCPLegend 并重写绘制和事件处理方法来实现,同时发出信号通知曲线的状态变更。 实现步骤: 继承 QCPLegend 类,添加绘…...
Linux云计算 |【第五阶段】CLOUD-DAY8
主要内容: 掌握DaemonSet控制器、污点策略(NoSchedule、Noexecute)、Job / CronJob资源对象、掌握Service服务、服务名解析CluterIP(服务名自动发现)、(Nodeport、Headless)、Ingress控制器 一…...
岛屿数量 广搜版BFS C#
和之前的卡码网深搜版是一道题 力扣第200题 99. 岛屿数量 题目描述 给定一个由 1(陆地)和 0(水)组成的矩阵,你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。…...
hive切换表底层文件类型以及分隔符
1、改底层文件存储类型,但是一般只会在数据文件与期望类型一致的时候使用,比如load等方式时发现建表时没指定对这样的,因为这个语句不会更改具体的底层文件内容,只改元数据 ALTER TABLE 表名 SET FILEFORMAT 希望类型;2、更改数据…...
ChatGPT o1与GPT-4o、Claude 3.5 Sonnet和Gemini 1.5 Pro的比较
全新的ChatGPT o1模型(代号“Strawberry”)是OpenAI的最新进展,专注于以前的AI模型难以应对的领域:高层次推理、数学和复杂编程。OpenAI设计o1模型以花费更多时间思考问题,使其在需要逐层推理的任务中提高准确性。本文…...
asp.net文件防盗链
URLRewriter实现 可以参考下面的文章 代码 .net framework 新建asp.net framework的web项目,新建AntiTheftChainHandler using System.Web;namespace AntiTheftChainStu01.Handler {public class AntiTheftChainHandler : IHttpHandler{public bool IsReusable…...
【日志】力扣58.最后一个单词的长度//14.最长公共前缀//28. 找出字符串中第一个匹配项的下标
2024.11.6 【力扣刷题】 58. 最后一个单词的长度 - 力扣(LeetCode)https://leetcode.cn/problems/length-of-last-word/?envTypestudy-plan-v2&envIdtop-interview-150 int lengthOfLastWord(char* s) {int count 0;for (int i strlen(s) - 1; i…...
华为杯”第十五届中国研究生数学建模竞赛-B题:光传送网建模与价值评估(续)
目录 4. 问题二 光传送网规划 4.1 基本假设 4.2 模型建立 4.3 子问题一 4.2 子问题二 4.5 子问题三 5. 问题三 改善星座图 5.1 问题简述 5.2 问题分析 5.3 建模与问题求解 5.3.1 方案一 5.3.2 方案二 6. 模型评价 6.1 模型的优点 6.2 模型的缺点 参考文献 本文篇幅较长,分为上…...
android 使用xml设置背景图片和圆角
使用xml设置背景图片和圆角 <?xml version"1.0" encoding"utf-8"?> <layer-list xmlns:android"http://schemas.android.com/apk/res/android"><item><shape><solid android:color"android:color/transparen…...
数据结构,问题 E: 表达式括号匹配
题目描述 假设一个表达式有英文字母(小写)和数字、运算符(,—,*,/)和左右小(圆)括号构成,以“”作为表达式的结束符。请编写一个程序检查表达式中的左右圆括号…...
国家宠物美容师职业技能等级评价(高级)理论考试题
国家宠物美容师职业技能等级评价 理论考试复习参考范围 高级/三级 宠物美容师(高级)理论考试题 一 判断题 犬只的世界只有黑白灰三种,通过颜色呈现的深浅度进行辨识(A ) A 对 B 错 美国养犬俱乐部简称AKC…...
Spring挖掘:(AOP篇)
学习AOP时,我们首先来了解一下何为AOP 一. 概念 AOP(面向切面编程,Aspect Oriented Programming)是一种编程技术,旨在通过预编译方式或运行期动态代理实现程序功能的统一管理和增强。AOP的主要目标是在不改变原有业务逻辑代码的…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】,分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...
Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...
DBLP数据库是什么?
DBLP(Digital Bibliography & Library Project)Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高,数据库文献更新速度很快,很好地反映了国际计算机科学学术研…...
Python竞赛环境搭建全攻略
Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型(算法、数据分析、机器学习等)不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...
Ubuntu系统多网卡多相机IP设置方法
目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机,交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息,系统版本:Ubuntu22.04.5 LTS;内核版本…...
Unity VR/MR开发-VR开发与传统3D开发的差异
视频讲解链接:【XR马斯维】VR/MR开发与传统3D开发的差异【UnityVR/MR开发教程--入门】_哔哩哔哩_bilibili...
