news 2026/6/14 10:55:56

别再手动插图片了!用EasyExcel 3.x + POI动态生成带照片的Excel报表(附完整代码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
别再手动插图片了!用EasyExcel 3.x + POI动态生成带照片的Excel报表(附完整代码)

动态生成带图片的Excel报表:EasyExcel 3.x实战指南

每次手动在Excel里调整图片位置时,我都忍不住想摔键盘——直到发现EasyExcel的模板填充功能。上周公司HR部门提出新需求:要为300名新员工批量生成带照片的工牌Excel,如果手动操作至少需要两天。而用下面这个方法,我们只用了20分钟就完成了全部报表生成。

1. 环境准备与模板设计

1.1 依赖配置要点

在Spring Boot项目中引入关键依赖时,版本兼容性是个隐形杀手。推荐使用以下组合:

<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.1.1</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>5.2.3</version> </dependency>

注意:POI 4.x以上版本与EasyExcel 3.x存在图片写入兼容性问题,实测5.2.3版本最稳定

1.2 智能模板设计技巧

设计模板时,这些细节能让后续开发事半功倍:

  • 使用${variable}作为文本占位符
  • 图片位置预留空白单元格并添加批注<!-- image:fieldName -->
  • 固定行高列宽避免图片挤压变形

推荐尺寸参数

内容类型行高(px)列宽(字符)
证件照12015
产品图20025
二维码6010

2. 动态图片写入核心逻辑

2.1 图片定位算法解析

通过相对位置计算实现智能排版,这段代码可处理多图片自动排列:

public WriteCellData<Void> calculateImagePosition(List<ImageData> images, int columns) { WriteCellData<Void> cellData = new WriteCellData<>(); for (int i = 0; i < images.size(); i++) { ImageData image = images.get(i); int rowGroup = i / columns; int colIndex = i % columns; // 动态计算位置 image.setRelativeFirstRowIndex(rowGroup * 6); image.setRelativeLastRowIndex(rowGroup * 6 + 5); image.setRelativeFirstColumnIndex(colIndex * 4); image.setRelativeLastColumnIndex(colIndex * 4 + 3); } return cellData; }

2.2 性能优化实践

处理大批量图片时,这三个技巧将执行时间缩短70%:

  1. 内存优化:使用ByteArrayOutputStream缓冲图片数据
  2. 并行处理:对图片分组后使用并行流处理
  3. 缓存机制:重复图片只读取一次
// 并行处理示例 List<CompletableFuture<ImageData>> futures = imagePaths.stream() .parallel() .map(path -> CompletableFuture.supplyAsync(() -> loadImage(path))) .collect(Collectors.toList()); List<ImageData> images = futures.stream() .map(CompletableFuture::join) .collect(Collectors.toList());

3. Spring Boot集成方案

3.1 控制器层最佳实践

这个RESTful接口可直接生成并返回Excel流:

@GetMapping("/export/employee-cards") public void exportEmployeeCards(HttpServletResponse response) throws IOException { response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setHeader("Content-Disposition", "attachment; filename=employee_cards.xlsx"); List<Employee> employees = employeeService.listWithPhotos(); ExcelWriter writer = EasyExcel.write(response.getOutputStream()) .withTemplate(ResourceUtils.getFile("classpath:templates/employee_card.xlsx")) .build(); employees.forEach(emp -> { WriteSheet sheet = EasyExcel.writerSheet("Page " + emp.getDept()).build(); writer.fill(convertToMap(emp), sheet); }); writer.finish(); }

3.2 常见坑点解决方案

这些报错你肯定遇到过:

  • 图片变形:设置固定宽高比
    imageData.setAnchor(new ClientAnchor(0, 0, 0, 0, col, row, col+2, row+4));
  • 内存溢出:分批次写入并及时清理缓存
  • 格式错乱:统一使用PNG格式图片

4. 高级应用场景拓展

4.1 混合内容报表生成

结合文本、图片、条形码的复合报表解决方案:

  1. 使用Map<String, Object>混合不同类型数据
  2. 分层填充策略:先文本后图片
  3. 动态调整模板样式
Map<String, Object> data = new HashMap<>(); data.put("title", "产品质检报告"); data.put("items", productList); // 文本列表 data.put("signature", getSignatureImage()); // 签名图片 data.put("barcode", generateBarcode()); // 条形码

4.2 云端文件处理方案

当图片存储在OSS等云端服务时,这样处理最优雅:

public ImageData loadFromOSS(String ossUrl) { OSS ossClient = new OSSClientBuilder().build(endpoint, accessKey, secretKey); try (InputStream stream = ossClient.getObject(bucketName, objectName).getObjectContent()) { ImageData image = new ImageData(); image.setImage(IOUtils.toByteArray(stream)); return image; } finally { ossClient.shutdown(); } }

报表生成后自动上传到云存储的完整流程:

  1. 本地生成临时文件
  2. 使用断点续传分片上传
  3. 清理本地临时文件
  4. 返回下载链接
String uploadId = ossClient.initiateMultipartUpload(bucketName, objectName).getUploadId(); List<PartETag> partETags = new ArrayList<>(); // 分片上传逻辑... ossClient.completeMultipartUpload(new CompleteMultipartUploadRequest( bucketName, objectName, uploadId, partETags));
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/14 10:55:51

用Python给妈妈一个惊喜:手把手教你用Turtle和Matplotlib画动态爱心贺卡

用Python给妈妈一个惊喜&#xff1a;手把手教你用Turtle和Matplotlib画动态爱心贺卡在数字时代&#xff0c;亲手制作的礼物往往比千篇一律的商店商品更能打动人心。想象一下&#xff0c;当妈妈收到一张由你编写的代码生成的动态爱心贺卡时&#xff0c;她脸上会露出怎样的惊喜表…

作者头像 李华
网站建设 2026/6/14 10:55:50

竞品在AI搜索里“偷跑”?7款GEO监测工具实测横评

一、AI搜索时代&#xff0c;不看竞品等于闭着眼睛打仗 2026年&#xff0c;下面的情况在市场行业不断发生&#xff1a; 你花了半年优化内容、铺了几十篇媒体稿&#xff0c;结果打开豆包问“这个行业有哪些推荐品牌”&#xff0c;AI第一个推荐的是竞品——还附了一句“该品牌在该…

作者头像 李华
网站建设 2026/6/14 10:54:20

Ajax — 异步数据交互

Ajax&#xff08;Asynchronous JavaScript and XML&#xff09;是 Web 2.0 时代的核心技术。它让 JS 可以在不刷新页面的情况下&#xff0c;主动向服务器发起 HTTP 请求、获取数据、动态更新页面。没有 Ajax 之前&#xff0c;任何数据更新都要整页刷新 —— 体验极差。Ajax 让 …

作者头像 李华
网站建设 2026/6/14 10:51:14

解锁iPhone隐藏力量:2026年iOS越狱完全指南

解锁iPhone隐藏力量&#xff1a;2026年iOS越狱完全指南 【免费下载链接】Jailbreak iOS 26.4 - 26, 17 - 17.7.5 & iOS 18 - 18.7.3 Jailbreak Tools, Cydia/Sileo/Zebra Tweaks & Jailbreak News Updates || AI Jailbreak Finder &#x1f447; 项目地址: https://g…

作者头像 李华
网站建设 2026/6/14 10:51:04

DeepSeek模型本地部署实战:轻量高保真AI的民主化落地

1. 项目概述&#xff1a;这不是又一个“大模型发布”&#xff0c;而是一次技术权力的重新分配 “DeepSeek’s AI Breakthrough: The Democratisation of Artificial Intelligence”——这个标题里没有堆砌参数&#xff0c;没提多少Billion Tokens&#xff0c;也没用“SOTA”“S…

作者头像 李华