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.rhkb.cn/news/220831.html

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

相关文章

【TB作品】51单片机,具有报时报温功能的电子钟

2.具有报时报温功能的电子钟 一、功能要求: 1.显示室温。 2.具有实时时间显示。 3.具有实时年月日显示和校对功能。 4.具有整点语音播报时间和温度功能。 5.定闹功能,闹钟音乐可选。 6.操作简单、界面友好。 二、设计建议: 1.单片机自选(C51、STM32或其他单片机)。 2.时钟日历芯…

第十七章 爬虫scrapy登录与中间件2

文章目录 数据盘区太快会报错&#xff0c;setting中配置延迟 连接提取器

深度学习记录--矩阵维数

如何识别矩阵的维数 如下图 矩阵的行列数容易在前向和后向传播过程中弄错&#xff0c;故写这篇文章来提醒易错点 顺便起到日后查表改错的作用 本文仅作本人查询参考(摘自吴恩达深度学习笔记)

线上环境如何正确配置 Django 的 DEBUG?

Author&#xff1a;rab Django Version&#xff1a;3.2 Python Version&#xff1a;3.9 目录 前言一、DEBUG True二、DEBUG False三、页面异常解决总结 前言 由于最近在学习 Django 的知识&#xff0c;于是尝试开发了一套 Blog 系统&#xff0c;在本地测试时是页面显示没问题…

Windows 10如何关闭系统自动更新(实用教程)

本章教程&#xff0c;用最简洁的方式介绍在windows10中如何关闭系统自动更新。 目录 一、关闭自动更新服务 二、关闭自动更新组策略 一、关闭自动更新服务 1、 winr 2、services.msc 3、找到并双击 Windows Update 修改启动类型为禁用 二、关闭自动更新组策略 1、winr 2、gp…

el-form与el-upload结合上传带附件的表单数据(前端篇)

1.写在之前 本文前端采用Vue element-plus技术栈&#xff0c;前端项目参考yudao-ui-admin-vue3项目与Geeker-Admin项目。 这篇文章是el-form与el-upload结合上传带附件的表单数据&#xff08;后端篇&#xff09;-CSDN博客姐妹篇&#xff0c;后端篇文章主要讲的是后端的实现逻…

JavaEE:线程池精讲

目录 一.什么是线程池 二.线程池的实现原理 &#x1f388;为什么要有工厂模式&#xff1f; 三.线程池的构造方法解读 &#x1f388;线程池的拒绝策略 四.自己实现一个线程池 一.什么是线程池 简单来说&#xff0c;线程池就好比一块鱼塘&#xff0c;鱼塘中的每条鱼就是一个线程…

SQL注入绕过正则及无列名注入

渗透测试 一、select\b[\s\S]*\bfrom正则二、科学计数法绕过三、过滤information四、无列名注入1、利用 join-using 注列名。2、无列名查询 五、报错注入7大常用函数1.ST_LatFromGeoHash()&#xff08;mysql>5.7.x&#xff09;payload 2.ST_LongFromGeoHash&#xff08;mysq…

针对这两个趋势,3.0全新新零售商业模式可以采取以下策略:

国内市场确实存在“消费升级”和“消费降级”两个趋势&#xff0c;这是由于不同消费者群体的需求和购买力存在差异。消费升级主要发生在高端市场&#xff0c;消费者愿意为高品质、高价值、高价格的商品和服务付出更多。而消费降级则主要发生在中低端市场&#xff0c;消费者更加…

学习k8s

学习k8s 我为什么要用k8s 和其他部署方式的区别是什么? 传统部署方式 java --> package --> 放到服务器上 --> Tomcat 如果是同时进行写操作,会存在并发问题. 用户 --网络带宽–> 服务器 -->服务 同一个服务器上,多个服务: 网络资源的占用 内存的占用 cpu的占…

《点云处理》 点云去噪

前言 通常从传感器&#xff08;3D相机、雷达&#xff09;中获取到的点云存在噪点&#xff08;杂点、离群点、孤岛点等各种叫法&#xff09;。噪点产生的原因有不同&#xff0c;可能是扫描到了不想要扫描的物体&#xff0c;可能是待测工件表面反光形成的&#xff0c;也可能是相…

c# OpenCV 基本绘画(直线、椭圆、矩形、圆、多边形、文本)(四)

我们将在这里演示如何使用几何形状和文本注释图像。 Cv2.Line() 绘制直线 Cv2.Ellipse() 绘制椭圆Cv2.Rectangle() 绘制矩形Cv2.Circle() 绘制圆Cv2.FillPoly() 绘制多边形Cv2.PutText() 绘制文本 一、绘制直线 Cv2.Line(image, start_point, end_point, color, thickness) …

IntelliJ IDE 插件开发 | (三)消息通知与事件监听

系列文章 IntelliJ IDE 插件开发 |&#xff08;一&#xff09;快速入门IntelliJ IDE 插件开发 |&#xff08;二&#xff09;UI 界面与数据持久化IntelliJ IDE 插件开发 |&#xff08;三&#xff09;消息通知与事件监听 前言 在前两篇文章中讲解了关于插件开发的基础知识&…

C语言:前缀和

【模板】前缀和_牛客题霸_牛客网 (nowcoder.com) 前缀和&#xff1a;将数组小于该前缀的数加起来的新数组。 例&#xff1a; 该数组为1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5。前缀和为1&#xff0c;3&#xff0c;6&#xff0c;10&#xff0c;15 。 如果要求…

1-完全理解以太坊智能合约

了解区块链 区块链技术的核心概念是分布式账本&#xff0c;它是许多参与者共享的特定类型的数据库。 这个特殊的数据库只是一个交易列表&#xff0c;记录着网络中发生的每笔交易。每个人都可以拥有自己的交易列表备份&#xff0c;再加上强有力的货币激励措施消除各方之间信任…

比 style gan 更好的 style gan2

上一篇博客介绍了style gan 原理&#xff0c;但是 style gan 的结果会有水珠伪影&#xff0c;作者实验后发现是 Adain 导致的&#xff0c;AdaIN对每一个feature map的通道进行归一化&#xff0c;这样可能破坏掉feature之间的信息。当然实验证明发现&#xff0c;去除AdaIN的归一…

广州华锐互动VRAR:利用VR开展新能源汽车触电安全演练,降低培训成本和风险

随着新能源汽车行业的快速发展&#xff0c;相关的安全培训也变得越来越重要。其中&#xff0c;触电急救培训对于保障驾驶员和乘客的安全具有重要意义。传统培训方式存在一些不足&#xff0c;而利用VR技术进行培训则具有很多优势。 利用VR技术开展新能源汽车触电安全演练可以在模…

2023 英特尔On技术创新大会直播 | 窥探未来科技的边界

2023 英特尔On技术创新大会直播 | 窥探未来科技的边界 写在最前面观后感其他有趣的专题课程 写在最前面 嘿&#xff0c;你是不是对科技和创新充满好奇&#xff1f;2023 英特尔 On 技术创新大会线上活动邀请你一起探索最前沿的科技世界&#xff01; 这不仅是一场普通的聚会&…

AWS Linux安装桌面并远程访问

文章目录 小结问题及解决参考 小结 在AWS Linux安装了桌面并进行远程访问。 问题及解决 需要使用过程桌面访问AWS Linux&#xff0c;这里在AWS服务器安装并使用Amazon Linux 2 MATE desktop。 检查OS版本&#xff1a; [ec2-userip-10-0-3-241 ~]$ grep PRETTY_NAME /etc/o…

WordCloud—— 词云

【说明】文章内容来自《机器学习入门——基于sklearn》&#xff0c;用于学习记录。若有争议联系删除。 wordcloud 是python的第三方库&#xff0c;称为词云&#xff0c;也成文字云&#xff0c;可以根据文本中的词频以直观和艺术化的形式展示文本中词语的重要性。 依赖于pillow …