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

JAVA - EasyExcel动态填充Excel模板与样式优化实战

1. 为什么选择EasyExcel处理Excel模板第一次接触Excel导出需求时我尝试过Apache POI。当时处理一个20MB的Excel文件直接让服务器内存飙到2GB差点引发生产事故。后来发现阿里开源的EasyExcel同样的文件内存占用不到100MB从此成为我的首选工具。EasyExcel特别适合处理模板导出场景它能直接读取现有Excel文件作为模板通过占位符实现动态数据填充保持原模板所有样式和格式支持百万级数据导出不卡顿最近做的消费帮扶系统需要导出带复杂格式的采购清单。产品经理给的模板包含合并单元格、条件格式、多级表头等复杂样式用EasyExcel只用了不到100行代码就完美实现。2. 快速搭建开发环境2.1 Maven依赖配置建议使用3.0版本老版本有些API不兼容。除了核心依赖还需要特别注意模板文件处理dependency groupIdcom.alibaba/groupId artifactIdeasyexcel/artifactId version3.1.1/version /dependency !-- 防止模板文件被过滤 -- plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-resources-plugin/artifactId configuration nonFilteredFileExtensions nonFilteredFileExtensionxlsx/nonFilteredFileExtension nonFilteredFileExtensionxls/nonFilteredFileExtension /nonFilteredFileExtensions /configuration /plugin2.2 模板设计规范在resources/template目录下创建assistance.xlsx模板文件时要注意这些坑占位符用{}包裹如{name}集合数据要加前缀如{.data}表示循环填充合并单元格的样式要完整否则填充后会丢失建议使用英文命名占位符避免编码问题我遇到过最头疼的问题是模板中的合并单元格。后来发现解决方案很简单在Excel里先取消合并设置好所有单元格样式后重新合并这样EasyExcel处理时就不会丢失样式。3. 动态数据填充实战3.1 基础数据绑定先看最简单的单数据填充。比如要导出用户信息public void exportUserInfo(HttpServletResponse response) { MapString, Object data new HashMap(); data.put(userName, 张三); data.put(age, 28); data.put(department, 技术部); InputStream template getClass().getResourceAsStream(/template/user.xlsx); ExcelWriter writer EasyExcel.write(response.getOutputStream()) .withTemplate(template) .build(); writer.fill(data, EasyExcel.writerSheet().build()); writer.finish(); }3.2 集合数据循环填充处理商品列表这种动态行数据时需要用FillWrapper包装ListProduct products productService.list(); MapString, Object data new HashMap(); data.put(reportDate, LocalDate.now()); ExcelWriter writer EasyExcel.write(outputStream) .withTemplate(template) .build(); // 单独填充普通数据 writer.fill(data, writeSheet); // 循环填充集合数据 FillConfig fillConfig FillConfig.builder().forceNewRow(true).build(); writer.fill(new FillWrapper(products, products), fillConfig, writeSheet);踩坑提醒集合占位符{.products}中的点不能省略否则会导致数据无法正常循环填充。我当初调试了2小时才发现这个细节。4. 样式深度定制技巧4.1 预定义样式策略通过RegisterWriteHandler可以全局控制样式// 标题样式 WriteCellStyle headStyle new WriteCellStyle(); headStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); WriteFont headFont new WriteFont(); headFont.setBold(true); headStyle.setWriteFont(headFont); // 内容样式 WriteCellStyle contentStyle new WriteCellStyle(); contentStyle.setWrapped(true); HorizontalCellStyleStrategy strategy new HorizontalCellStyleStrategy(headStyle, contentStyle); ExcelWriter writer EasyExcel.write(outputStream) .registerWriteHandler(strategy) .withTemplate(template) .build();4.2 动态样式调整有时需要根据数据值动态改变样式比如金额负数标红public class MoneyStyleHandler extends AbstractCellWriteHandler { Override public void afterCellDispose(WriteSheetHolder sheetHolder, WriteTableHolder tableHolder, ListCellData cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { if(!isHead amount.equals(head.getFieldName())) { Double value Double.parseDouble(cell.getStringValue()); if(value 0) { CellStyle style cell.getSheet().getWorkbook().createCellStyle(); style.setFillForegroundColor(IndexedColors.RED.getIndex()); cell.setCellStyle(style); } } } }在项目中实现导出功能时产品突然要求表头要有渐变底色。通过研究POI的API最终用这段代码实现WriteCellStyle headerStyle new WriteCellStyle(); GradientFillPattern gradientFill new GradientFillPattern(); gradientFill.setStartColor(IndexedColors.BLUE.getIndex()); gradientFill.setEndColor(IndexedColors.WHITE.getIndex()); headerStyle.setFillPatternType(gradientFill);5. 高级功能与性能优化5.1 图片导出方案导出带照片的员工信息表时需要特殊处理MapString, Object data new HashMap(); data.put(avatar, new WriteCellData(Files.readAllBytes(avatarPath))); // 设置图片位置 ImageData imageData new ImageData(); imageData.setImage(imageBytes); imageData.setRelativeFirstRowIndex(2); imageData.setRelativeFirstColumnIndex(1); imageData.setRelativeLastRowIndex(4); imageData.setRelativeLastColumnIndex(3);5.2 百万级数据导出处理大数据量导出时这三个参数很关键ExcelWriter writer EasyExcel.write(outputStream) .withTemplate(template) .autoCloseStream(false) .useDefaultStyle(false) .build(); // 分批次填充 for(int i0; i100; i) { ListProduct batch queryBatch(i, 10000); writer.fill(new FillWrapper(data, batch), writeSheet); }最近优化过一个导出慢的问题10万行数据导出要3分钟。通过以下调整降到30秒设置useDefaultStyle(false)禁用默认样式检查增加autoCloseStream(false)避免重复开闭流采用分页查询批量填充6. 常见问题排查指南6.1 乱码问题解决遇到导出文件乱码时按这个顺序检查确保模板文件本身无乱码检查HTTP响应头response.setContentType(application/vnd.ms-excel); response.setCharacterEncoding(UTF-8); response.setHeader(Content-Disposition, attachment;filename URLEncoder.encode(fileName, UTF-8));模板中的字体是否支持中文推荐使用宋体或微软雅黑6.2 样式丢失问题样式不生效时我的检查清单模板中的样式是否应用到了每个单元格合并单元格是否完整设置了所有区域的样式是否误用了useDefaultStyle(false)自定义样式处理器是否正确注册上周就遇到合并单元格边框丢失的问题最后发现是模板中只给左上角单元格设置了边框。解决方法是在Excel里全选合并区域统一设置样式。7. 项目实战案例最近完成的扶贫项目需要导出这样的报表带乡镇LOGO的页眉动态合并的农产品分类自动计算的金额汇总条件格式标记异常数据核心代码结构public void exportReport(HttpServletResponse response) { // 1. 准备数据 ReportData data prepareData(); // 2. 加载模板 InputStream template getTemplateStream(); // 3. 配置导出 ExcelWriter writer EasyExcel.write(response.getOutputStream()) .registerWriteHandler(new CustomMergeStrategy()) .registerWriteHandler(new SummaryHandler()) .withTemplate(template) .build(); // 4. 填充数据 writer.fill(data.getHeader(), writeSheet); writer.fill(new FillWrapper(items, data.getItems()), writeSheet); writer.fill(data.getSummary(), writeSheet); // 5. 处理图片 if(data.getLogo() ! null) { writer.fill(new WriteCellData(data.getLogo()), writeSheet); } writer.finish(); }这个案例中最大的挑战是动态合并单元格。最终通过自定义MergeStrategy实现public class CustomMergeStrategy extends AbstractMergeStrategy { Override protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { if(category.equals(head.getFieldName())) { // 实现合并逻辑 } } }实际开发中建议先用简单模板验证核心功能再逐步增加复杂度。我通常的调试流程是先确保基础数据能正常填充然后测试样式是否保留接着验证动态样式和特殊格式最后处理图片等复杂元素

相关文章:

JAVA - EasyExcel动态填充Excel模板与样式优化实战

1. 为什么选择EasyExcel处理Excel模板 第一次接触Excel导出需求时,我尝试过Apache POI。当时处理一个20MB的Excel文件,直接让服务器内存飙到2GB,差点引发生产事故。后来发现阿里开源的EasyExcel,同样的文件内存占用不到100MB&…...

单细胞UMAP图配色进阶:手把手教你用RColorBrewer和ggsci打造高级感图表

单细胞UMAP图配色进阶:手把手教你用RColorBrewer和ggsci打造高级感图表 在科研数据可视化领域,一张精心设计的图表往往能成为论文的点睛之笔。单细胞RNA测序分析中,UMAP图作为展示细胞异质性的核心工具,其配色方案直接影响着数据的…...

Lazarus实战:利用FpSpreadsheet控件打造高效电子表格数据处理工具

1. 认识Lazarus与FpSpreadsheet的黄金组合 第一次接触Lazarus开发环境时,我就被它的跨平台特性和类似Delphi的快速开发体验所吸引。作为一个长期从事单机程序开发的工程师,我一直在寻找能够快速处理电子表格数据的解决方案。直到发现了FpSpreadsheet这个…...

基于角谱传播的MATLAB仿真:从“相机人”到衍射光场的可视化探索

1. 从"相机人"到衍射光场:角谱传播的奇妙之旅 第一次看到"相机人"和Lena相位合成的复振幅场在MATLAB中传播时,那种震撼感至今难忘。就像看着一幅抽象画逐渐显露出隐藏的图案,光强分布中慢慢浮现出原本看不见的相位信息。…...

Realistic Vision V5.1 使用Linux命令管理生成任务:进程监控与日志分析

Realistic Vision V5.1 使用Linux命令管理生成任务:进程监控与日志分析 如果你已经成功部署了Realistic Vision V5.1,并且习惯了在命令行下工作,那么恭喜你,你已经站在了高效管理AI图像生成任务的门槛上。对于开发者来说&#xf…...

Qwen3.5-27B教育场景应用:学生作业图题自动解答+解题思路生成案例

Qwen3.5-27B教育场景应用:学生作业图题自动解答解题思路生成案例 1. 教育场景痛点分析 在传统教育场景中,学生遇到作业难题时往往面临以下困境: 解题资源有限:课后难以及时获得老师指导理解障碍:特别是图形类题目&a…...

Cursor 3 Agents Window 实操:IDE 退居二线,Agent 编排成了主角

Cursor 3 Agents Window 实操:IDE 退居二线,Agent 编排成了主角 4月2日,Cursor 发布了 3.0 版本(代号 Glass)。这次更新的核心变化只有一句话:编辑器不再是默认界面,Agents Window 是。 不是加了…...

通过EVE-NG模拟器快速搭建山石防火墙Web管理环境

1. 为什么选择EVE-NG搭建山石防火墙实验环境 对于网络工程师和安全运维人员来说,经常需要在实验环境中测试防火墙配置。传统方式需要购买物理设备,不仅成本高,而且部署周期长。EVE-NG模拟器的出现完美解决了这个问题,它就像是一个…...

CC-Link IE转Modbus TCP集成实战:耐达讯自动化网关在五星级酒店节能改造中的应用

在工业自动化系统集成领域,异构网络的数据交互始终是一个核心痛点。控制层普遍采用高性能的CC-Link IE工业以太网,以确保高速、确定的实时通信;而设备层往往存在大量基于Modbus TCP协议的通用设备,如变频器、智能仪表和传感器。这…...

如何通过平台架构实现15分钟养老服务圈的精准覆盖

居家养老服务的高效落地,离不开精准的机构定位与便捷的信息查询支撑。智慧养老系统居家养老地图模块,以数字化地图为核心载体,整合区域内养老机构资源与老人基础信息,破解传统居家养老中机构查找繁琐、信息脱节、对接低效等痛点&a…...

Debian 12 安装 Podman 5.7.1 最新版完整指南(含国内镜像加速配置)

Debian 12 容器化实践:Podman 5.7.1 高效部署与镜像加速全攻略 容器技术正在重塑现代应用交付的范式。作为Docker的替代方案,Podman以其无守护进程架构和原生rootless支持,正在成为开发者工具箱中的新宠。本文将带您深入探索在Debian 12上部…...

SPI vs I2C:OLED显示实战对比,哪种通信方式更适合你的项目?

SPI vs I2C:OLED显示实战对比与协议选型指南 在嵌入式系统设计中,选择合适的通信协议往往决定着项目的成败。当面对OLED显示模块时,SPI和I2C这两种主流串行通信协议的抉择常常让开发者陷入思考。我曾在一个智能家居控制面板项目中同时尝试了两…...

HDMI协议深度剖析:软硬件协同设计与信号完整性优化

1. HDMI协议基础与核心价值 第一次接触HDMI接口时,很多人会被它纤薄的体型迷惑——这根比USB还细的线缆,凭什么能传输4K高清画面和7.1声道音频?这要从HDMI协议的本质说起。作为音视频传输的"高速公路",HDMI(…...

SAP权限管理必知:5个关键Table详解与实战查询技巧

SAP权限管理必知:5个关键Table详解与实战查询技巧 在SAP系统的日常运维中,权限管理始终是系统管理员和开发人员面临的核心挑战之一。一个配置不当的权限体系不仅可能导致数据泄露风险,还可能引发业务流程混乱。与简单的权限表清单不同&#x…...

解密GPCRs二级结合口袋:从β2AR到5HT2BR的偏置信号传导机制

解密GPCRs二级结合口袋:从β2AR到5HT2BR的偏置信号传导机制 在结构药理学领域,G蛋白偶联受体(GPCRs)的配体结合机制研究一直是药物开发的核心课题。传统研究多聚焦于正位结合位点(Orthosteric Binding Site, OBS),而近年来,二级结…...

Drozer实战指南:从环境搭建到渗透测试全流程解析

1. 环境准备:搭建Drozer渗透测试基础平台 Drozer作为安卓安全测试的瑞士军刀,环境搭建是新手遇到的第一个门槛。我见过太多人卡在环境配置这一步就放弃了,其实只要掌握几个关键点就能轻松搞定。先说说我的环境选择:Windows 10系统…...

从微带到共面波导:WiFi射频传输线设计的PCB实战解析

1. WiFi射频传输线设计基础 刚接触射频PCB设计时,我最头疼的就是从芯片RF引脚到天线这段看似简单的走线。记得第一次做2.4GHz WiFi模块,信号强度总是不达标,后来才发现是传输线阻抗失配导致的。射频传输线就像高速公路,而我们的信…...

Unity中TextMeshPro (TMP) 中文项目字体优化

一、常用配置方案 A.静态主字体(Static Asset) 用途:储存游戏 95% 以上的文本配置内容:ASCII 字符(英文、数字、符号) 通用规范汉字一级字库(3500字) 配置操作步骤: Win…...

MICROCHIP微芯 AT24C32D-SSHM-T SOP8 EEPROM

特性 低压和标准电压操作-工作电压范围:1.7至5.5V 内部组织的4096x8,8192x82线串行接口 Schmitt触发器,带滤波输入以抑制噪声 双向数据传输协议 .1MHz(5.0V)和400KHz(1.8V兼容性) 写保护引脚用于硬件数据保护 .32字节页面写入模式(允许部分页面写入) .自动定时写周期…...

为什么AutoDL平台选择Ubuntu作为统一系统镜像?

1. 为什么AutoDL平台清一色选择Ubuntu? 第一次用AutoDL平台的朋友可能会发现一个有趣的现象:所有系统镜像清一色都是Ubuntu,从18.04到20.04再到22.04版本。这不禁让人好奇,为什么一个专业的AI计算平台会如此专一地选择Ubuntu&…...

【JVM级性能跃迁】:Java 25虚拟线程在实时风控系统的SLA突破——P99延迟从820ms降至43ms

第一章:Java 25虚拟线程在高并发架构下的实践企业级应用场景 Java 25正式将虚拟线程(Virtual Threads)从预览特性转为标准特性,标志着JVM在轻量级并发模型上的重大演进。相比传统平台线程,虚拟线程由JVM调度、在用户态…...

不止于安装:用Autopsy分析磁盘镜像(.E01)的完整入门流程与模块选择指南

不止于安装:用Autopsy分析磁盘镜像(.E01)的完整入门流程与模块选择指南 当你第一次打开Autopsy,面对满屏的专业术语和复杂选项时,那种手足无措的感觉我深有体会。三年前,我接手第一个数据泄露调查案时,就曾盯着那个空白…...

MARVELL迈威 88E1112-C2-NNC1C000 QFN 以太网收发器

功能特性 SGMII/SERDES MAC侧支持 支持与光纤应用相同的PHY的自动媒体支持 SFP模块支持-铜缆和光纤SFP模块-支持嵌入铜缆SFP模块 额外集成的SERDES可切换至1.25 GHz或125 MHz 高级诊断能力 -Marvell VCT 集成CRC错误检测器、数据包计数器和生成器 小型64引脚QFN封装 仅需两个电…...

圣女司幼幽-造相Z-Turbo快速部署:支持FP16精度的Z-Turbo LoRA推理优化

圣女司幼幽-造相Z-Turbo快速部署:支持FP16精度的Z-Turbo LoRA推理优化 本文介绍如何快速部署圣女司幼幽-造相Z-Turbo模型,这是一个基于Z-Image-Turbo LoRA版本的专业文生图模型,专注于生成《牧神记》中圣女司幼幽的高质量图像,并支…...

BMD58T280 TFT-LCD驱动库技术解析与嵌入式显示优化

1. BMD58T280 TFT-LCD显示库深度技术解析BMD58T280是Best Modules Corp推出的2.8英寸TFT-LCD显示扩展板专用Arduino驱动库,面向嵌入式开发者提供SPI与EBI双接口支持。该库并非通用型LCD驱动框架,而是针对BMD58T280硬件模块的定制化固件封装,其…...

【腾讯位置服务开发者征文大赛】用 AI 读懂城市情绪 —— 基于腾讯位置服务的反内卷散步助手

文章目录 前言一、问题背景1.1 传统地图方案的局限1.2 AI 地图的可能性 二、技术方案:四层架构,一张情绪地图2.1 整体架构2.2 腾讯位置服务能力使用清单2.3 AI 接入方案 三、项目实操3.1 下载 Skill3.2 创建 CodeBuddy 项目3.3 项目立项3.4 获取 API Ke…...

别只调库了!深入ESP32-CAM驱动层:手动配置OV2640传感器与帧缓冲区管理详解

深入ESP32-CAM驱动层:手动配置OV2640传感器与帧缓冲区管理实战指南 OV2640传感器作为ESP32-CAM模组的核心组件,其底层寄存器配置与帧缓冲区管理机制直接决定了图像采集的性能表现。本文将带您绕过esp_camera_init的封装层,从I2C寄存器操作、X…...

我用9个AI Agent,从0到1复刻了一个完整的Claude Code

起因4月初,Claude Code的源码泄露了。拿到源码之后通读了一遍,大概1,900个文件、512K行TypeScript代码。看完之后就有了一个想法:能不能用Go把它重写一遍?不是写个Demo玩玩,而是把所有功能都搬过来——CLI入口、LLM查询…...

告别网盘限速!八大平台直链解析工具终极指南

告别网盘限速!八大平台直链解析工具终极指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云盘 / 迅…...

别再只调参了!用PyTorch复现DCGAN人脸生成,我踩过的5个坑和3个调优技巧

别再只调参了!用PyTorch复现DCGAN人脸生成,我踩过的5个坑和3个调优技巧 当你在Colab上跑完最后一个epoch,看着生成器输出的那些扭曲五官,是否怀疑自己装了假的PyTorch?别急,这不过是DCGAN训练路上的常态。真…...