EasyExcel合并相同内容单元格及动态标题功能的实现

一、最初版本
导出的结果:
在这里插入图片描述
对应实体类代码:

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentLoopMerge;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import lombok.*;import java.io.Serializable;@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Data
@ContentRowHeight(30)
@HeadRowHeight(40)
@ColumnWidth(25)
public class StudentExportVo implements Serializable {private static final long serialVersionUID = -5809782578272943999L;@ExcelProperty(value = "学校", order = 1)@ContentLoopMerge(eachRow = 3)private String school;@ExcelProperty(value = "姓名", order = 2)private String name;@ExcelProperty(value = "性别", order = 3)private String sex;@ExcelProperty(value = "年龄", order = 4)private String age;@ExcelProperty(value = "城市", order = 5)private String city;@ExcelProperty(value = "备注", order = 6)private String remarks;}

对应业务代码:

@ApiOperation(value = "导出学生信息", notes = "导出学生信息")
@PostMapping("/exportStudent")
public void exportStudent(@RequestBody String str, HttpServletResponse response) {List<StudentExportVo> list = this.getStudentExportVos();ExcelUtils.writeExcel(response, StudentExportVo.class, list, "导出学生信息", "sheet1");
}
//数据制造
private List<StudentExportVo> getStudentExportVos() {List<StudentExportVo> list = new ArrayList<>();StudentExportVo v1 = new StudentExportVo();v1.setSchool("北京大学");v1.setName("张三");v1.setSex("男");v1.setAge("20");v1.setCity("北京");v1.setRemarks("无");list.add(v1);StudentExportVo v2 = new StudentExportVo();v2.setSchool("北京大学");v2.setName("李四");v2.setSex("男");v2.setAge("22");v2.setCity("上海");v2.setRemarks("无");list.add(v2);StudentExportVo v3 = new StudentExportVo();v3.setSchool("北京大学");v3.setName("王五");v3.setSex("女");v3.setAge("22");v3.setCity("青岛");v3.setRemarks("无");list.add(v3);StudentExportVo v4 = new StudentExportVo();v4.setSchool("清华大学");v4.setName("赵六");v4.setSex("女");v4.setAge("21");v4.setCity("重庆");v4.setRemarks("无");list.add(v4);StudentExportVo v5 = new StudentExportVo();v5.setSchool("武汉大学");v5.setName("王强");v5.setSex("男");v5.setAge("24");v5.setCity("长沙");v5.setRemarks("无");list.add(v5);StudentExportVo v6 = new StudentExportVo();v6.setSchool("武汉大学");v6.setName("赵燕");v6.setSex("女");v6.setAge("21");v6.setCity("深圳");v6.setRemarks("无");list.add(v6);StudentExportVo v7 = new StudentExportVo();v7.setSchool("厦门大学");v7.setName("陆仟");v7.setSex("女");v7.setAge("21");v7.setCity("广州");v7.setRemarks("无");list.add(v7);return list;
}

二、使用注解的版本
导出的结果:
在这里插入图片描述
对应实体类代码:

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Data
@ContentRowHeight(30)
@HeadRowHeight(40)
@ColumnWidth(25)
public class StudentExportVo implements Serializable {private static final long serialVersionUID = -5809782578272943999L;@ExcelProperty(value = {"学生信息","学校"}, order = 1)@ContentLoopMerge(eachRow = 3)private String school;@ExcelProperty(value = {"学生信息","姓名"}, order = 2)private String name;@ExcelProperty(value = {"学生信息","性别"}, order = 3)private String sex;@ExcelProperty(value = {"学生信息","年龄"}, order = 4)private String age;@ExcelProperty(value = {"学生信息","城市"}, order = 5)private String city;@ExcelProperty(value = {"学生信息","备注"}, order = 6)private String remarks;}

对应业务代码:同上

@ContentLoopMerge(eachRow = 3) 可以合并单元格,但是他是按指定行数合并,并不能实现内容相同的合并

@ExcelProperty(value = {“学生信息”,“备注”},能实现多个标题,但标题是固定的,不是动态的

三、自定义改造
导出的结果:
在这里插入图片描述

对应实体类代码:

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Data
@ContentRowHeight(30)
@HeadRowHeight(40)
@ColumnWidth(25)
public class StudentExportVo implements Serializable {private static final long serialVersionUID = -5809782578272943999L;@ExcelProperty(value = {"学生信息","学校"}, order = 1)//@ContentLoopMerge(eachRow = 3)private String school;@ExcelProperty(value = {"学生信息","姓名"}, order = 2)private String name;@ExcelProperty(value = {"学生信息","性别"}, order = 3)private String sex;@ExcelProperty(value = {"学生信息","年龄"}, order = 4)private String age;@ExcelProperty(value = {"学生信息","城市"}, order = 5)private String city;@ExcelProperty(value = {"学生信息","备注"}, order = 6)private String remarks;}

对应业务代码:

@ApiOperation(value = "导出学生信息", notes = "导出学生信息")@PostMapping("/exportStudent")public void exportStudent(@RequestBody String dynamicTitle, HttpServletResponse response) {List<StudentExportVo> list = this.getStudentExportVos();try {String fileName = "学生信息";fileName = URLEncoder.encode(fileName, "UTF-8");response.setContentType("application/json;charset=utf-8");response.setCharacterEncoding("utf-8");response.addHeader("Pargam", "no-cache");response.addHeader("Cache-Control", "no-cache");response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");ServletOutputStream output = response.getOutputStream();//需要合并的列int[] mergeColumeIndex = {0};// 从第二行后开始合并int mergeRowIndex = 2;//设置动态标题List<List<String>> headers = this.getHeaders("学生信息" + dynamicTitle);// 头的策略WriteCellStyle headWriteCellStyle = new WriteCellStyle();// 背景设置为白色headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);/*WriteFont headWriteFont = new WriteFont();headWriteFont.setFontHeightInPoints((short)20);headWriteCellStyle.setWriteFont(headWriteFont);*/// 内容的策略WriteCellStyle contentWriteCellStyle = new WriteCellStyle();// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定//contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);// 背景绿色//contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());//设置 自动换行contentWriteCellStyle.setWrapped(true);//设置 垂直居中contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);//设置 水平居中contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);/*WriteFont contentWriteFont = new WriteFont();// 字体大小contentWriteFont.setFontHeightInPoints((short)20);contentWriteCellStyle.setWriteFont(contentWriteFont);*/// 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现HorizontalCellStyleStrategy horizontalCellStyleStrategy =new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);EasyExcel.write(output, StudentExportVo.class).sheet("学生信息").head(headers).registerWriteHandler(new ExcelMergeHandler(mergeRowIndex, mergeColumeIndex)).registerWriteHandler(horizontalCellStyleStrategy)
//                    .registerWriteHandler(new SimpleColumnWidthStyleStrategy(30)).registerWriteHandler(new AbstractColumnWidthStyleStrategy() {@Overrideprotected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {Sheet sheet = writeSheetHolder.getSheet();int columnIndex = cell.getColumnIndex();if(columnIndex == 5){// 列宽100sheet.setColumnWidth(columnIndex, 10000);}else {// 列宽50sheet.setColumnWidth(columnIndex, 5000);}// 行高40sheet.setDefaultRowHeight((short) 4000);}}).doWrite(list);output.flush();} catch (IOException e) {log.error(e.getMessage(), e);}}private List<List<String>> getHeaders(String dynamicTitle) {List<List<String>> headers=new ArrayList<>();List<String> schoolHead=new ArrayList<>();schoolHead.add(dynamicTitle);schoolHead.add("学校");List<String> nameHead=new ArrayList<>();nameHead.add(dynamicTitle);nameHead.add("姓名");List<String> sexHead=new ArrayList<>();sexHead.add(dynamicTitle);sexHead.add("性别");List<String> ageHead=new ArrayList<>();ageHead.add(dynamicTitle);ageHead.add("年龄");List<String> cityHead=new ArrayList<>();cityHead.add(dynamicTitle);cityHead.add("城市");List<String> remarksHead=new ArrayList<>();remarksHead.add(dynamicTitle);remarksHead.add("备注");headers.add(schoolHead);headers.add(nameHead);headers.add(sexHead);headers.add(ageHead);headers.add(cityHead);headers.add(remarksHead);return headers;}//数据制造private List<StudentExportVo> getStudentExportVos() {List<StudentExportVo> list = new ArrayList<>();StudentExportVo v1 = new StudentExportVo();v1.setSchool("北京大学");v1.setName("张三");v1.setSex("男");v1.setAge("20");v1.setCity("北京");v1.setRemarks("无");list.add(v1);StudentExportVo v2 = new StudentExportVo();v2.setSchool("北京大学");v2.setName("李四");v2.setSex("男");v2.setAge("22");v2.setCity("上海");v2.setRemarks("无");list.add(v2);StudentExportVo v3 = new StudentExportVo();v3.setSchool("北京大学");v3.setName("王五");v3.setSex("女");v3.setAge("22");v3.setCity("青岛");v3.setRemarks("无");list.add(v3);StudentExportVo v4 = new StudentExportVo();v4.setSchool("清华大学");v4.setName("赵六");v4.setSex("女");v4.setAge("21");v4.setCity("重庆");v4.setRemarks("无");list.add(v4);StudentExportVo v5 = new StudentExportVo();v5.setSchool("武汉大学");v5.setName("王强");v5.setSex("男");v5.setAge("24");v5.setCity("长沙");v5.setRemarks("无");list.add(v5);StudentExportVo v6 = new StudentExportVo();v6.setSchool("武汉大学");v6.setName("赵燕");v6.setSex("女");v6.setAge("21");v6.setCity("深圳");v6.setRemarks("无");list.add(v6);StudentExportVo v7 = new StudentExportVo();v7.setSchool("厦门大学");v7.setName("陆仟");v7.setSex("女");v7.setAge("21");v7.setCity("广州");v7.setRemarks("无");list.add(v7);return list;}

合并单元格相同内容处理类:ExcelMergeHandler

import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;import java.util.List;
public class ExcelMergeHandler implements CellWriteHandler {private int[] mergeColumnIndex;private int mergeRowIndex;public ExcelMergeHandler() {}public ExcelMergeHandler(int mergeRowIndex, int[] mergeColumnIndex) {this.mergeRowIndex = mergeRowIndex;this.mergeColumnIndex = mergeColumnIndex;}@Overridepublic void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {}@Overridepublic void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {}@Overridepublic void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {}@Overridepublic void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {//当前行int curRowIndex = cell.getRowIndex();//当前列int curColIndex = cell.getColumnIndex();if (curRowIndex > mergeRowIndex) {for (int i = 0; i < mergeColumnIndex.length; i++) {if (curColIndex == mergeColumnIndex[i]) {mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);break;}}}}/*** 当前单元格向上合并** @param writeSheetHolder* @param cell             当前单元格* @param curRowIndex      当前行* @param curColIndex      当前列*/private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();// 将当前单元格数据与上一个单元格数据比较Boolean dataBool = preData.equals(curData);//此处需要注意:因为我是按照工程名称确定是否需要合并的,所以获取每一行第二列数据和上一行第一列数据进行比较,如果相等合并,getCell里面的值,是工程名称所在列的下标String s1 = cell.getRow().getCell(0).getStringCellValue();String s2 = cell.getSheet().getRow(curRowIndex - 1).getCell(0).getStringCellValue();/*BigDecimal d1 = new BigDecimal(cell.getRow().getCell(0).getNumericCellValue());BigDecimal d2 = new BigDecimal(cell.getSheet().getRow(curRowIndex - 1).getCell(0).getNumericCellValue());*/Boolean bool = s1.compareTo(s2) == 0 ? true:false;// 原始的// Boolean bool =  cell.getRow().getCell(1).getStringCellValue().equals(cell.getSheet().getRow(curRowIndex - 1).getCell(1).getStringCellValue());if (dataBool && bool) {Sheet sheet = writeSheetHolder.getSheet();List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();boolean isMerged = false;for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {CellRangeAddress cellRangeAddr = mergeRegions.get(i);// 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {sheet.removeMergedRegion(i);cellRangeAddr.setLastRow(curRowIndex);sheet.addMergedRegion(cellRangeAddr);isMerged = true;}}// 若上一个单元格未被合并,则新增合并单元if (!isMerged) {CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);sheet.addMergedRegion(cellRangeAddress);}}}
}

总结:

1、使用自定义合并相同内容单元格时,实体类中的注解@ContentLoopMerge需要去掉,要不然会受到影响

2、该段自定义代码中如内容合并、设置动态标题、内容、以及每个列的宽度及字体都是可以根据自定义策略来进行设置的,具体用法可以参考代码注释说明,根据需要进行使用

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

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

相关文章

全链路压力测试:解析其主要特点

随着信息技术的飞速发展和云计算的普及&#xff0c;全链路压力测试作为一种关键的质量保障手段&#xff0c;在软件开发和系统部署中扮演着至关重要的角色。全链路压力测试以模拟真实生产环境的压力和负载&#xff0c;对整个业务流程进行全面测试&#xff0c;具有以下主要特点&a…

Nginx网站服务详解(Nginx服务的主配置文件 ——nginx.conf)

目录 一、全局配置的六个模块简介 二、Nginx配置文件的详解 1&#xff09;全局配置模块 2&#xff09;I/O 事件配置 3&#xff09;HTTP 配置 4&#xff09;web服务监听设置 5&#xff09;其他设置 location常见配置指令&#xff1a;“root、alias、proxy_pass 对比&a…

【数据分享】2019-2023年我国地级市逐年新房房价数据(免费获取/Excel/Shp格式)

房价是一个城市发展程度的重要体现&#xff0c;一个城市的房价越高通常代表这个城市越发达&#xff0c;对于人口的吸引力越大&#xff01;因此&#xff0c;房价数据是我们在各项城市研究中都非常常用的数据&#xff01;之前我们分享了2019—2023年我国地级市逐月的新房房价数据…

揭秘`v-if`和`v-show`的区别:选择正确指令的技巧(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

EasyExcel模板导出(行和列自动合并)

1.需求背景: ①需要从第三方获取数据,第三方接口有两个参数,开始时间和结束时间 ②获取回来的数据并没有入库,所以不能通过数据库将数据归类统计,excel合并大概的流程是判断上一行或者左右相邻列是否相同,然后进行合并,所以不能是零散的数据且客户要求每一个自治区和每一个航站…

系统分析师(软考)知识点整理(一)

第一章 信息 信息是不确定性的减少 xi: n个状态中的第i个状态p(xi):出现第i个状态的概率b: b一般取值为2 特征 #mermaid-svg-pvPkY9RE5GZIIIxl {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-pvPkY9RE5GZIIIxl…

一篇文章带你了解各个程序员接单平台,让你选择不再迷茫!!!

相信现在很多程序员都已经走上了或者准备走上网上接单这条路&#xff0c;但是目前市面上的接单平台可谓五花八门&#xff0c;对于各个平台的优缺点&#xff0c;不同的程序员该如何选择适合自己的接单平台&#xff0c;你又是否了解呢&#xff1f; 接下来就让小编用一篇文章来为…

Gemini自曝中文用百度文心一言训练,网友看呆:大公司互薅羊毛??

谷歌Gemini中文语料疑似来自文心一言&#xff1f;&#xff1f;&#xff1f; 先是有读者向我们爆料&#xff1a; 在谷歌Vertex AI平台使用该模型进行中文对话时&#xff0c;Gemini-Pro直接表示自己是百度语言大模型。 很快&#xff0c;有微博大V阑夕夜也发博称&#xff1a; 在…

超实用的Web兼容性测试经验总结,建议Mark

在日常工作中&#xff0c;我们经常碰到网页不兼容的问题。我们之所以要做兼容性测试&#xff0c;目的在于保证待测试项目在不同的操作系统平台上正常运行。 主要包括待测试项目能在同一操作系统平台的不同版本上正常运行&#xff1b;待测试项目能与相关的其他软件或系统的“和…

手撕HashMap源码2

目录 引言 putTreeVal红黑树添加结点方法讲解 treeifyBin进行树化的方法&#xff08;虚假的树化&#xff09; treeify真正的树化操作 从扩容的部分来分析红黑树的代码 split红黑树扩容迁移的方法 untreeify链化&#xff08;退树成链&#xff09; 红黑树代码分析 rota…

FO with Prefix Hashing KEM Generalizations

参考文献&#xff1a; [Has88] Hastad J. Solving simultaneous modular equations of low degree[J]. siam Journal on Computing, 1988, 17(2): 336-341.[BBM00] Bellare M, Boldyreva A, Micali S. Public-key encryption in a multi-user setting: Security proofs and im…

2023 英特尔On技术创新大会直播 | AI 融合发展之旅

前言 2023 年的英特尔 On 技术创新大会中国站&#xff0c;主要聚焦最新一代增强 AI 能力的计算平台&#xff0c;深度讲解如何支持开放、多架构的软件方案&#xff0c;以赋能人工智能并推动其持续发展。 大会的目标之一是优化系统并赋能开发者&#xff0c;特别注重芯片增强技术…

国产划片机品牌众多,如何选择优质的供应商?

在半导体行业的发展浪潮中&#xff0c;划片机作为关键设备之一&#xff0c;其性能和质量对于生产过程的高效性和产品的质量具有至关重要的影响。近年来&#xff0c;国产划片机的品牌数量不断增多&#xff0c;为半导体行业提供了更多的选择。然而&#xff0c;如何从众多的品牌中…

【Python炫酷系列】一闪一闪亮星星,漫天都是小星星(完整代码)

文章目录 环境需求完整代码详细分析系列文章环境需求 python3.11.4及以上版本PyCharm Community Edition 2023.2.5pyinstaller6.2.0(可选,这个库用于打包,使程序没有python环境也可以运行,如果想发给好朋友的话需要这个库哦~)【注】 python环境搭建请见:https://want595.…

Python 爬虫之简单的爬虫(四)

爬取动态网页&#xff08;下&#xff09; 文章目录 爬取动态网页&#xff08;下&#xff09;前言一、大致内容二、基本思路三、代码编写1.引入库2.加载网页数据3.获取并保存4.保存文档 总结 前言 上篇主要讲了如何去爬取数据&#xff0c;这篇来讲一下如何在获取的同时将数据整…

每个开发人员都应该知道的六个生成式 AI 框架和工具

在快速发展的技术环境中&#xff0c;生成式人工智能是一股革命性的力量&#xff0c;它改变了开发人员处理复杂问题和创新的方式。本文深入探讨了生成式 AI 的世界&#xff0c;揭示了对每个开发人员都至关重要的框架和工具。 1. LangChain LangChain 由 Harrison Chase 开发并于…

Ansible自动化运维以及模块使用

ansible的作用&#xff1a; 远程操作主机功能 自动化运维(playbook剧本基于yaml格式书写) ansible是基于python开发的配置管理和应用部署工具。在自动化运维中&#xff0c;现在是异军突起 ansible能够批量配置、部署、管理上千台主机。类似于Xshell的一键输入工具。不需要每…

通过层进行高效学习:探索深度神经网络中的层次稀疏表示

一、介绍 深度学习中的层次稀疏表示是人工智能领域日益重要的研究领域。本文将探讨分层稀疏表示的概念、它们在深度学习中的意义、应用、挑战和未来方向。 最大限度地提高人工智能的效率和性能&#xff1a;深度学习系统中分层稀疏表示的力量。 二、理解层次稀疏表示 分层稀疏表…

JDK各个版本特性讲解-JDK19特性

JDK各个版本特性讲解-JDK19特性 一、JAVA19概述二、新特性介绍1. 记录模式(预览版本)2.Linux/RISC-V 移植3.外部函数和内存 API &#xff08;预览版&#xff09;4.虚拟线程(预览版)5.Vector API &#xff08;第四次孵化&#xff09;6.Switch 模式匹配&#xff08;第三预览版&am…

从C代码制作chm开发文档【doxygen + graphviz+winChm】

需要的工具&#xff1a; 1. doxygen 最新版本 2. graphviz 最新版本 3. winChm破解版本 1. 最后制作的效果 2. 生成HTML文档 生成hmtl文档是勾选如下2项&#xff0c;为生成chm准备&#xff1a; 需要选择如下2项&#xff1a; generate HTMLHELP 生…