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

EasyExcel中自定义拦截器的运用

在EasyExcel中自定义拦截器不仅可以帮助我们不止步于数据的填充,而且可以对样式、单元格合并等带来便捷的功能。下面直接开始

我们定义一个MergeWriteHandler的类继承AbstractMergeStrategy实现CellWriteHandler

public class MergeLastWriteHandler extends AbstractMergeStrategy implements CellWriteHandler 

当中我们重写merge方法

@Overrideprotected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {}

我们可以在重写的方法中得到形参中的Cel,那我们可以通过调用cell.getStringCellValue()得到当前单元格的内容,判断当前单元格的内容是否是目标单元格,例如下面代码

if (cell.getStringCellValue().equals("说明")) {cell.setCellValue("说明:这是一条说明");//获取表格最后一行int lastRowNum = sheet.getLastRowNum();CellRangeAddress region = new CellRangeAddress(lastRowNum, lastRowNum, 0, 5);sheet.addMergedRegionUnsafe(region);}

并且这里我们通过sheet中的 getLastRowNum()获取最后一行,最终通过CellRangeAddress来进行单元格合并,从下面源码我们可以了解到合并的规则是什么(通过int firstRow, int lastRow, int firstCol, int lastCol)

/*** Creates new cell range. Indexes are zero-based.** @param firstRow Index of first row* @param lastRow Index of last row (inclusive), must be equal to or larger than {@code firstRow}* @param firstCol Index of first column* @param lastCol Index of last column (inclusive), must be equal to or larger than {@code firstCol}*/public CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol) {super(firstRow, lastRow, firstCol, lastCol);if (lastRow < firstRow || lastCol < firstCol) {throw new IllegalArgumentException("Invalid cell range, having lastRow < firstRow || lastCol < firstCol, " +"had rows " + lastRow + " >= " + firstRow + " or cells " + lastCol + " >= " + firstCol);}}

这样就可以实现合并单元格,不过这里可能会出现一个问题

java.lang.IllegalStateException: Cannot get a STRING value from a NUMERIC cellat org.apache.poi.xssf.streaming.SXSSFCell.typeMismatch(SXSSFCell.java:943)at org.apache.poi.xssf.streaming.SXSSFCell.getStringCellValue(SXSSFCell.java:460)

因为会访问所有的单元格,有可能会出现是不是字符串类型的单元格,所以我们最好在开始的时候对其进行处理一次

if (cell.getCellType().equals(CellType.NUMERIC)){double numericCellValue = cell.getNumericCellValue();String s = Double.toString(numericCellValue);String substring = s.substring(0, s.indexOf("."));cell.setCellValue(substring);}

但这里可能我们还需要一个操作,例如如果我们全局配置了表框线条,但是不想当前的单元格有线条,如何处理呢,定义CustomCellWriteHandler拦截器继承AbstractCellWriteHandler

public class CustomCellWriteHandler extends AbstractCellWriteHandler{}

重写当中的afterCellDispose方法,得到

 @Overridepublic void afterCellDispose(CellWriteHandlerContext context) {super.afterCellDispose(context);}

现在我们对其进行操作

  Cell cell = context.getCell();if(BooleanUtils.isNotTrue(context.getHead())){if(cell.getStringCellValue().contains("说明"))){Workbook workbook = context.getWriteWorkbookHolder().getWorkbook();CellStyle cellStyle = workbook.createCellStyle();cellStyle.setBorderTop(BorderStyle.THIN);cellStyle.setBorderBottom(BorderStyle.THIN);cellStyle.setAlignment(HorizontalAlignment.LEFT);cell.setCellStyle(cellStyle);context.getFirstCellData().setWriteCellStyle(null); //关键代码,不设置不生效}
}

最后只需要在写入的时候,把拦截器放进去就可以了,看完整代码

public class CustomCellWriteHandler extends AbstractCellWriteHandler {@Overridepublic void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {short height = 600;row.setHeight(height);}@Overridepublic void afterCellDispose(CellWriteHandlerContext context) {Cell cell = context.getCell();if(BooleanUtils.isNotTrue(context.getHead())){if(cell.getStringCellValue().contains("说明"))){Workbook workbook = context.getWriteWorkbookHolder().getWorkbook();CellStyle cellStyle = workbook.createCellStyle();cellStyle.setBorderTop(BorderStyle.THIN);cellStyle.setBorderBottom(BorderStyle.THIN);cellStyle.setAlignment(HorizontalAlignment.LEFT);cell.setCellStyle(cellStyle);context.getFirstCellData().setWriteCellStyle(null);}}super.afterCellDispose(context);}
}

合并单元格的拦截器

public class MergeLastWriteHandler extends AbstractMergeStrategy implements CellWriteHandler {public static HorizontalCellStyleStrategy getStyleStrategy() {// 头的策略WriteCellStyle headWriteCellStyle = new WriteCellStyle();// 设置对齐//headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);// 背景色, 设置为绿色,也是默认颜色headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());// 字体//WriteFont headWriteFont = new WriteFont();//headWriteFont.setFontHeightInPoints((short) 12);//headWriteCellStyle.setWriteFont(headWriteFont);// 内容的策略WriteCellStyle contentWriteCellStyle = new WriteCellStyle();// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定// contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);// 字体策略WriteFont contentWriteFont = new WriteFont();//contentWriteFont.setFontHeightInPoints((short) 12);contentWriteCellStyle.setWriteFont(contentWriteFont);//设置 自动换行contentWriteCellStyle.setWrapped(true);//设置 垂直居中contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);//设置 水平居中contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);//设置边框样式contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);contentWriteCellStyle.setBorderTop(BorderStyle.THIN);contentWriteCellStyle.setBorderRight(BorderStyle.THIN);contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);// 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);return horizontalCellStyleStrategy;}@Overrideprotected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {if (cell.getCellType() == CellType.NUMERIC) {double numericCellValue = cell.getNumericCellValue();String s = Double.toString(numericCellValue);String substring = s.substring(0, s.indexOf("."));cell.setCellValue(substring);}if (cell.getStringCellValue().equals("说明")) {cell.setCellValue("说明:这是一条说明");//获取表格最后一行int lastRowNum = sheet.getLastRowNum();CellRangeAddress region = new CellRangeAddress(lastRowNum, lastRowNum, 0, 5);sheet.addMergedRegionUnsafe(region);}}
}

看一下Controller层

@GetMapping("/excelWrapper")public void excelWrapper(HttpServletResponse response) throws IOException {try {List<User> userList =  DataByExcel();  //获取数据的列表List<BudgetForm> budgetForm = BeanUtil.copyToList(userList,BudgetForm.class);String fileName = one.getProjectName() + ".xlsx";response.setContentType("application/vnd.openxmlformatsofficedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");response.setHeader("Content-disposition", "attachment;filename=" + fileName );// 创建ExcelWriter对象WriteSheet writeSheet = EasyExcel.writerSheet("表格sheet").registerWriteHandler(new MergeLastWriteHandler()).registerWriteHandler(new CustomCellWriteHandler()).build();// 向Excel中写入数据ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), BudgetForm.class).build();excelWriter.write(userList , writeSheet);// 关闭流excelWriter.finish();} catch (Exception e) {e.printStackTrace();}}

对表头设置(自己对应表格设置对应字段)

@Data
@ContentRowHeight(47) //内容行高
@HeadRowHeight(35)//表头行高
public class BudgetForm implements Serializable  {@ColumnWidth(6)@ExcelProperty(value ={"表格","序号"} ,index = 0)@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)private Integer serialNumber;@ColumnWidth(15)@ExcelProperty(value ={"表格","名称"} ,index = 1)@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)private String name;@ColumnWidth(26)@ExcelProperty(value = {"表格","备注"},index = 2)@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)private String remark;@ColumnWidth(26)@ExcelProperty(value = {"表格","其他"},index = 3)@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)private String budgetary;@ExcelIgnore@ApiModelProperty("合计")private String total;}

相关文章:

EasyExcel中自定义拦截器的运用

在EasyExcel中自定义拦截器不仅可以帮助我们不止步于数据的填充&#xff0c;而且可以对样式、单元格合并等带来便捷的功能。下面直接开始 我们定义一个MergeWriteHandler的类继承AbstractMergeStrategy实现CellWriteHandler public class MergeLastWriteHandler extends Abst…...

shell编程-7

shell学习第7天 sed的学习1.sed是什么2.sed有两个空间pattern hold3.sed的语法4. sed里单引号和双引号的区别:5.sed的查找方式6.sed的命令sed的标签用法sed的a命令:追加sed的i命令:根据行号插入sed的c命令:整行替换sed的r命令sed的s命令:替换sed的d命令:删除sed中的&符号 7…...

工业智能网关储能物联网应用实现能源的高效利用及远程管理

储能电力物联网是指利用物联网技术和储能技术相结合&#xff0c;实现对电力系统中各种储能设备的智能管理和优化控制。随着可再生能源的不断发展和应用&#xff0c;电力系统面临着越来越大的电力调度和储能需求而储能电力物联网的出现可以有效解决这一问题&#xff0c;提高电力…...

虹科数字化与AR部门升级为安宝特AR子公司

致关心虹科AR的朋友们&#xff1a; 感谢您一直以来对虹科数字化与AR的支持和信任&#xff0c;为了更好地满足市场需求和公司发展的需要&#xff0c;虹科数字化与AR部门现已升级为虹科旗下独立子公司&#xff0c;并正式更名为“安宝特AR”。 ”虹科数字化与AR“自成立以来&…...

服务器是什么?(四种服务器类型)

服务器 服务器定义广义: 专门给其他机器提供服务的计算机。狭义:一台高性能的计算机&#xff0c;通过网络提供外部计算机一些业务服务 个人PC内存大概8G&#xff0c;服务器内存128G起步 服务器是什么 服务器指的是 网络中能对其他机器提供某些服务的计算机系统 &#xff0c;相对…...

09-微服务Sentinel整合GateWay

一、概述 在微服务系统中&#xff0c;网关提供了微服务系统的统一入口&#xff0c;所以我们在做限流的时候&#xff0c;肯定是要在网关层面做一个流量的控制&#xff0c;Sentinel 支持对 Spring Cloud Gateway、Zuul 等主流的 API Gateway 进行限流。 1.1 总览 Sentinel 1.6.…...

python基础学习-03 安装

python3 可应用于多平台包括 Windows、Linux 和 Mac OS X。 Unix (Solaris, Linux, FreeBSD, AIX, HP/UX, SunOS, IRIX, 等等。)Win 9x/NT/2000Macintosh (Intel, PPC, 68K)OS/2DOS (多个DOS版本)PalmOSNokia 移动手机Windows CEAcorn/RISC OSBeOSAmigaVMS/OpenVMSQNXVxWorksP…...

HTML — 区块元素

HTML 通过各种标签将元素组合起来。 一. 区块元素 大多数 HTML 元素被定义为块级元素或内联元素。块级元素在浏览器显示时&#xff0c;通常会以新的行开始。例如&#xff1a;<div>、<h1>、<p>、<ul>等。 它们在使用时会独自占据一行&#xff0c;称为块…...

《PCI Express体系结构导读》随记 —— 第I篇 第3章 PCI总线的数据交换(4)

接前一篇文章&#xff1a;《PCI Express体系结构导读》随记 —— 第I篇 第3章 PCI总线的数据交换&#xff08;3&#xff09; 3.2 PCI设备的数据传递 PCI设备的数据传递使用地址译码方式&#xff0c;当一个存储器读写总线事务到达PCI总线时&#xff0c;在这条总线上的所有PCI设…...

力扣0083——删除排序链表中的重复元素

删除排序链表中的重复元素 难度&#xff1a;简单 题目描述 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。 示例1 输入&#xff1a;head [1,1,2] 输出&#xff1a;[1,2]示例2 输入&#xff1a…...

MySQL数据库的一些缩写含义

DDL Data Definition Language&#xff0c;数据定义语言&#xff0c;用来定义数据库对象(数据库&#xff0c;表&#xff0c;字段) DML DML英文全称是Data Manipulation Language(数据操作语言)&#xff0c;用来对数据库中表的数据记录进 行增、删、改操作。 添加数据&#x…...

解决 ssh: connect to host github.com port 22: Connection timed out

问题 今天使用git克隆github上的代码时&#xff0c;一直报错 原以为是公钥过期了&#xff0c;就尝试修改配置公钥&#xff0c;但是尝试了几次都不行&#xff0c;最终在博客上找到了解决方案&#xff0c;在次记录一下&#xff0c;以备不时之需 解决ssh-connect-to-host-github…...

【iOS ARKit】同时开启前后摄像头BlendShapes

在上一节中已经了解了 iOS ARkit 进行BlendShapes的基本操作&#xff0c;这一小节继续实践同时开启前后摄像头进行人脸捕捉和世界追踪。 iOS设备配备了前后两个摄像头&#xff0c;在运行AR 应用时&#xff0c;需要选择使用哪个摄像头作为图像输人。最常见的AR 体验使用设备后置…...

Vue3动态插入组件

一、使用<component>is实现动态组件插入 <component>&#xff1a;一个用于渲染动态组件或元素的“元组件”。 :is : 要渲染的实际组件&#xff0c;当 is 是字符串&#xff0c;它既可以是 HTML 标签名也可以是组件的注册名。 <script> import Foo from ./F…...

介绍一下OpenCV中常用的图像处理函数

OpenCV中常用的图像处理函数有很多&#xff0c;以下是其中一些函数的介绍&#xff1a; - cvLoadImage()&#xff1a;读入图像函数。 - imshow()&#xff1a;显示图像函数。 - imwrite()&#xff1a;保存图像函数。 - Mat srcImage imread()&#xff1a;读入图像函数。 - …...

vscode vim 快捷键汇总

需满足操作&#xff1a; 上下移动按照 word 移动选中增删改查找字符/变量移动、增加、复制、删除 行选中多个相同的变量/字符屏幕移动增加多个光标快速注释 上下左右移动 CommandDescription&#x1f522; hleft (also: CTRL-H, BS, or Left key)&#x1f522; lright (also…...

npm官方注册表和淘宝镜像切换

1.切换到淘宝镜像 加快npm包的下载速度&#xff0c; //已失效 //npm config set registry https://registry.npm.taobao.org/ npm config set registry https://registry.npmmirror.com这会将npm的注册表设置为淘宝镜像 查看&#xff1a; npm config get registry如果返回的…...

LFU算法

LFU算法 Least Frequently Used&#xff08;最不频繁使用&#xff09; Leetcode有原题&#xff0c;之前手写过LRU&#xff0c;数据结构还是习惯于用java实现&#xff0c;实现是copy的评论题解。 题解注释写的很清楚 大致就是说LFUCache类维护一个存放node的map&#xff0c;同…...

JVM系列-7内存调优

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring原理、JUC原理、Kafka原理、分布式技术原理、数据库技术、JVM原理&#x1f525;如果感觉博主的文…...

[UI5 常用控件] 01.Text

文章目录 前言1. 普通文本2. 长文本&#xff1a;3. 设置最大显示行数 ( maxLines3 )4. 单行显示 ( wrappingfalse )5. 显示空白符 ( renderWhitespacetrue )6. 使用 - 连接单词:只适用于英文 ( wrappingTypeHyphenated )7. 空白时使用 - 代替 ( emptyIndicatorModeOn )8. JSON数…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...

【HarmonyOS 5】鸿蒙中Stage模型与FA模型详解

一、前言 在HarmonyOS 5的应用开发模型中&#xff0c;featureAbility是旧版FA模型&#xff08;Feature Ability&#xff09;的用法&#xff0c;Stage模型已采用全新的应用架构&#xff0c;推荐使用组件化的上下文获取方式&#xff0c;而非依赖featureAbility。 FA大概是API7之…...

Python学习(8) ----- Python的类与对象

Python 中的类&#xff08;Class&#xff09;与对象&#xff08;Object&#xff09;是面向对象编程&#xff08;OOP&#xff09;的核心。我们可以通过“类是模板&#xff0c;对象是实例”来理解它们的关系。 &#x1f9f1; 一句话理解&#xff1a; 类就像“图纸”&#xff0c;对…...

python打卡第47天

昨天代码中注意力热图的部分顺移至今天 知识点回顾&#xff1a; 热力图 作业&#xff1a;对比不同卷积层热图可视化的结果 def visualize_attention_map(model, test_loader, device, class_names, num_samples3):"""可视化模型的注意力热力图&#xff0c;展示模…...

FTXUI::Dom 模块

DOM 模块定义了分层的 FTXUI::Element 树&#xff0c;可用于构建复杂的终端界面&#xff0c;支持响应终端尺寸变化。 namespace ftxui {...// 定义文档 定义布局盒子 Element document vbox({// 设置文本 设置加粗 设置文本颜色text("The window") | bold | color(…...

react-pdf(pdfjs-dist)如何兼容老浏览器(chrome 49)

之前都是使用react-pdf来渲染pdf文件&#xff0c;这次有个需求是要兼容xp环境&#xff0c;xp上chrome最高支持到49&#xff0c;虽然说iframe或者embed都可以实现预览pdf&#xff0c;但为了后续的定制化需求&#xff0c;还是需要使用js库来渲染。 chrome 49测试环境 能用的测试…...