当前位置: 首页 > news >正文

【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简介 在数据处理和报表生成的过程中&#xff0c;Excel是一个非常常用的工具。特别是在Java开发中&#xff0c;EasyExcel库因其简单高效而…...

es数据同步(仅供自己参考)

数据同步的问题分析&#xff1a; 当MySQL进行增删改查的时候&#xff0c;数据库的数据有所改变&#xff0c;这个时候需要修改es中的索引库的值&#xff0c;这个时候就涉及到了数据同步的问题 解决方法&#xff1a; 1、同步方法&#xff1a; 当服务对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工具

往期目录&#xff1a; 从0开始学习Linux——简介&安装 从0开始学习Linux——搭建属于自己的Linux虚拟机 从0开始学习Linux——文本编辑器 上一个章节我们简单了解了Linux中常用的一些文本编辑器&#xff0c;本次教程我们将学习yum工具。 一、Yum简介 Yum&#xff08;全名…...

【Linux】Linux管道揭秘:匿名管道如何连接进程世界

&#x1f308;个人主页&#xff1a;Yui_ &#x1f308;Linux专栏&#xff1a;Linux &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;数据结构专栏&#xff1a;数据结构 &#x1f308;C专栏&#xff1a;C 文章目录 1.什么是管道 &#xff1f;2. 管道的类型2.1 匿…...

【LeetCode】【算法】155. 最小栈

LeetCode 155. 最小栈 题目描述 设计一个支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。 void push(int val) 将元素val推入堆栈。 void pop() 删除堆栈顶部的元素。 int …...

3.3 windows,ReactOS系统中页面的换出----1

系列文章目录 文章目录 系列文章目录3.3 页面的换出MiBalancerThread()MmTrimUserMemory&#xff08;&#xff09;MmPageOutVirtualMemory&#xff08;&#xff09; 3.3 页面的换出 在前一节中我们看到&#xff0c;如果有映射的页面已经被倒换到磁盘上即倒换文件中&#xff0c…...

QCustomPlot添加自定义的图例,实现隐藏、删除功能(二)

文章目录 实现步骤:详细代码示例:实现原理和解释:使用方法:其他参考要实现一个支持复选框来控制曲线显示和隐藏的自定义 QCPLegend 类,可以通过继承 QCPLegend 并重写绘制和事件处理方法来实现,同时发出信号通知曲线的状态变更。 实现步骤: 继承 QCPLegend 类,添加绘…...

Linux云计算 |【第五阶段】CLOUD-DAY8

主要内容&#xff1a; 掌握DaemonSet控制器、污点策略&#xff08;NoSchedule、Noexecute&#xff09;、Job / CronJob资源对象、掌握Service服务、服务名解析CluterIP&#xff08;服务名自动发现&#xff09;、&#xff08;Nodeport、Headless&#xff09;、Ingress控制器 一…...

岛屿数量 广搜版BFS C#

和之前的卡码网深搜版是一道题 力扣第200题 99. 岛屿数量 题目描述 给定一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的矩阵&#xff0c;你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成&#xff0c;并且四周都是水域。…...

hive切换表底层文件类型以及分隔符

1、改底层文件存储类型&#xff0c;但是一般只会在数据文件与期望类型一致的时候使用&#xff0c;比如load等方式时发现建表时没指定对这样的&#xff0c;因为这个语句不会更改具体的底层文件内容&#xff0c;只改元数据 ALTER TABLE 表名 SET FILEFORMAT 希望类型;2、更改数据…...

ChatGPT o1与GPT-4o、Claude 3.5 Sonnet和Gemini 1.5 Pro的比较

全新的ChatGPT o1模型&#xff08;代号“Strawberry”&#xff09;是OpenAI的最新进展&#xff0c;专注于以前的AI模型难以应对的领域&#xff1a;高层次推理、数学和复杂编程。OpenAI设计o1模型以花费更多时间思考问题&#xff0c;使其在需要逐层推理的任务中提高准确性。本文…...

asp.net文件防盗链

URLRewriter实现 可以参考下面的文章 代码 .net framework 新建asp.net framework的web项目&#xff0c;新建AntiTheftChainHandler using System.Web;namespace AntiTheftChainStu01.Handler {public class AntiTheftChainHandler : IHttpHandler{public bool IsReusable…...

【日志】力扣58.最后一个单词的长度//14.最长公共前缀//28. 找出字符串中第一个匹配项的下标

2024.11.6 【力扣刷题】 58. 最后一个单词的长度 - 力扣&#xff08;LeetCode&#xff09;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: 表达式括号匹配

题目描述 假设一个表达式有英文字母&#xff08;小写&#xff09;和数字、运算符&#xff08;&#xff0c;—&#xff0c;*&#xff0c;/&#xff09;和左右小&#xff08;圆&#xff09;括号构成&#xff0c;以“”作为表达式的结束符。请编写一个程序检查表达式中的左右圆括号…...

国家宠物美容师职业技能等级评价(高级)理论考试题

国家宠物美容师职业技能等级评价 理论考试复习参考范围 高级/三级 宠物美容师&#xff08;高级&#xff09;理论考试题 一 判断题 犬只的世界只有黑白灰三种&#xff0c;通过颜色呈现的深浅度进行辨识&#xff08;A &#xff09; A 对 B 错 美国养犬俱乐部简称AKC&#xf…...

Spring挖掘:(AOP篇)

学习AOP时,我们首先来了解一下何为AOP 一. 概念 AOP&#xff08;面向切面编程&#xff0c;Aspect Oriented Programming&#xff09;是一种编程技术&#xff0c;旨在通过预编译方式或运行期动态代理实现程序功能的统一管理和增强。AOP的主要目标是在不改变原有业务逻辑代码的…...

【杂谈】-递归进化:人工智能的自我改进与监管挑战

递归进化&#xff1a;人工智能的自我改进与监管挑战 文章目录 递归进化&#xff1a;人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管&#xff1f;3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

逻辑回归暴力训练预测金融欺诈

简述 「使用逻辑回归暴力预测金融欺诈&#xff0c;并不断增加特征维度持续测试」的做法&#xff0c;体现了一种逐步建模与迭代验证的实验思路&#xff0c;在金融欺诈检测中非常有价值&#xff0c;本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅

目录 前言 操作系统与驱动程序 是什么&#xff0c;为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中&#xff0c;我们在使用电子设备时&#xff0c;我们所输入执行的每一条指令最终大多都会作用到硬件上&#xff0c;比如下载一款软件最终会下载到硬盘上&am…...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态

前言 在人工智能技术飞速发展的今天&#xff0c;深度学习与大模型技术已成为推动行业变革的核心驱动力&#xff0c;而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心&#xff0c;系统性地呈现了两部深度技术著作的精华&#xff1a;…...

数据库正常,但后端收不到数据原因及解决

从代码和日志来看&#xff0c;后端SQL查询确实返回了数据&#xff0c;但最终user对象却为null。这表明查询结果没有正确映射到User对象上。 在前后端分离&#xff0c;并且ai辅助开发的时候&#xff0c;很容易出现前后端变量名不一致情况&#xff0c;还不报错&#xff0c;只是单…...