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…

基本数据类型与 字符串相加的 知识点

在Java中&#xff0c;基本数据类型和字符串的相加操作会触发字符串连接&#xff08;concatenation&#xff09;操作。这是因为Java中的字符串是不可变的&#xff0c;即一旦创建&#xff0c;就不能修改。因此&#xff0c;当你将一个基本数据类型的值与字符串相加时&#xff0c;J…

系统学习Python——装饰器:基础知识-[函数装饰器:使用方法]

分类目录&#xff1a;《系统学习Python》总目录 函数装饰器已经从Python2.4开始可用。正如我们在前文所见到的&#xff0c;它们大体上是一种语法糖&#xff1a;在def语句结束时通过另一个函数来运行这个函数&#xff0c;把最初的函数名重新绑定到返回的结果。 函数装饰器是一种…

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

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

js对象转换为excel,excel转换为js对象

文章目录 前言js转excelexcel转js对象总结 前言 使用module.exports导出&#xff0c;require导入 修改后缀为mjs,可使用importd导入 &#xff0c;export default \export导出&#xff08;自用过一次&#xff0c;后面忘记怎么改的了&#xff09; js转excel 需要安装nodejs node …

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

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

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

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

pip install xxx时候遇到Read timed out的问题

我们在安装一些包的时候&#xff0c;比如TensorFlow等等&#xff0c;如果直接使用: pip install tensorflow 这句命令来进行安装的时候&#xff0c;我们会发现此时安装的速度不仅非常慢&#xff0c;而且还有可能出现网络超时的情况&#xff0c;比如如下问题&#xff1a; Trac…

手撕HashMap源码2

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

JS实现简单的gpt打字机效果

功能要求 在后台传输得到的数据在展示时候进行打字机效果一个字一个字进行展示 实现想法 1、在一个滚动容器中展示一个个文字&#xff0c;也就是将全部数据截取出来添加到一个新数组中 2、采用循环或者定时器进行编写 注意&#xff1a;前提条件是需要后端传值提供 换行符号…

Pytorch读写张量文件

目录 一、加载和保存张量 1、直接读写张量 2、读写张量列表 3、读写张量字典 二、加载和保存模型参数 一、加载和保存张量 1、直接读写张量 对于单个张量&#xff0c;我们可以直接调用load和save函数分别读写它们。这两个函数都要求我们提供一个名称&#xff0c;save要求将…

C++11 shared_ptr智能指针

转载自c语言中文网 在实际的 C 开发中&#xff0c;我们经常会遇到诸如程序运行中突然崩溃、程序运行所用内存越来越多最终不得不重启等问题&#xff0c;这些问题往往都是内存资源管理不当造成的。比如&#xff1a; 有些内存资源已经被释放&#xff0c;但指向它的指针并没有改…

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;如何从众多的品牌中…