重阳,需求很常见:根据一个已设计好的 Excel 模板(含样式、公式、合并单元格、表头、页眉页脚等),往里面填充动态数据,然后生成新的 Excel 文件。
2026 年主流的三种方案对比(基于当前社区使用情况):
| 方案 | 推荐指数 (2026) | 内存占用 | 模板支持度(样式/合并/公式/图片) | 学习曲线 | 大文件友好度 | Maven 依赖大小 |
|---|---|---|---|---|---|---|
| EasyExcel (阿里) | ★★★★★ | 极低 | 优秀(支持复杂模板填充) | 低 | ★★★★★ | 小 |
| Apache POI | ★★★★☆ | 高 | 最好(几乎全能) | 中 | ★★☆☆☆ | 大 |
| JXLS (基于 POI) | ★★★☆☆ | 中 | 很好(Jxls 模板语法) | 中 | ★★★☆☆ | 中 |
| Fastexcel / Spire.XLS | ★★☆☆☆ | 低/中 | 中等 | 低/高 | ★★★★☆ | 小/商业 |
2026 年最推荐:EasyExcel
理由:内存友好、API 简洁、模板填充功能成熟、社区活跃、Spring Boot 集成极好。
下面直接给你 三种主流实现方式的完整代码示例(都基于 Spring Boot 项目场景)。
方案一:EasyExcel 模板填充(最推荐)
Maven 依赖(最新稳定版 3.x 或 4.x 系列,根据 2026 年情况用最新)
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.4</version> <!-- 或更高版本 -->
</dependency>
模板准备(excel 模板文件 template.xlsx)
在模板中用 {} 或自定义占位符,例如:
- 单值:
{date}、{totalAmount} - 列表竖向填充:
{.list}或用{{.开头(EasyExcel 推荐语法)
示例模板内容(A1 放标题,A2 开始表头,B3 开始放 {name}、{age} 等):
| A | B | C |
|---|---|---|
| 报表标题 | {title} | |
| 姓名 | 年龄 | 得分 |
| {.students} |
代码实现(Controller 或 Service 中)
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.enums.poi.HorizontalAlignment;
import com.alibaba.excel.write.enums.poi.VerticalAlignment;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
@RestController
@RequestMapping("/excel")
public class ExcelController {
@GetMapping("/export-template-fill")
public void exportWithTemplate(HttpServletResponse response) throws Exception {
// 1. 准备数据(可以从数据库查)
Map<String, Object> data = new HashMap<>();
data.put("title", "2026年班级成绩汇总");
data.put("date", "2026-02-03");
data.put("total", 88);
List<Map<String, Object>> students = new ArrayList<>();
students.add(Map.of("name", "张三", "age", 18, "score", 95));
students.add(Map.of("name", "李四", "age", 19, "score", 88));
students.add(Map.of("name", "王五", "age", 17, "score", 92));
data.put("students", students);
// 2. 设置响应头(浏览器下载)
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("成绩报表.xlsx", StandardCharsets.UTF_8.toString()).replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName);
// 3. 模板路径(放在 resources/templates/ 下)
String templateFileName = "templates/成绩模板.xlsx";
// 4. 核心:模板填充写出
EasyExcel.write(response.getOutputStream())
.withTemplate(templateFileName)
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 自适应列宽,可选
.sheet()
.doFill(data); // ← 核心方法!传入 map 或对象
}
}
高级用法提示(EasyExcel 模板填充常见技巧):
- 列表横向填充:用
{{.或指定方向 - 多列表:多个
.list占位符 - 复杂对象:
{.user.name}点语法 - 保留样式/公式/合并单元格:EasyExcel 会尽量保留
- 图片填充:支持
FillWrapper+Image对象
方案二:Apache POI 基于模板填充(最灵活,但内存高)
依赖:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.3.0</version> <!-- 或更高 -->
</dependency>
核心代码片段:
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileInputStream;
import java.io.OutputStream;
// 加载模板
try (FileInputStream fis = new FileInputStream("template.xlsx");
XSSFWorkbook workbook = new XSSFWorkbook(fis)) {
var sheet = workbook.getSheetAt(0);
// 填充单值
sheet.getRow(1).getCell(1).setCellValue("2026-02-03 重阳");
// 填充列表(从第3行开始)
int rowIndex = 3;
for (var student : students) {
var row = sheet.getRow(rowIndex) != null ? sheet.getRow(rowIndex) : sheet.createRow(rowIndex);
row.createCell(0).setCellValue(student.getName());
row.createCell(1).setCellValue(student.getAge());
rowIndex++;
}
// 输出到 response 或文件
workbook.write(response.getOutputStream());
}
优点:可以精确控制每个单元格的样式、公式、批注、条件格式等。
缺点:代码量大,内存占用高(大文件容易 OOM)。
方案三:快速选择建议
| 场景 | 首选方案 |
|---|---|
| 大数据量(万行+) | EasyExcel |
| 复杂样式/公式/图表保留 | Apache POI |
| 需要极致灵活控制单元格 | Apache POI |
| 快速上手、内存敏感 | EasyExcel |
| 想用模板语法(如 {var}) | EasyExcel / JXLS |
小建议:
- 先准备好模板文件,占位符用
{}或{{}}(EasyExcel 推荐) - 测试时把模板放 resources/templates/ 下,用 classpath 加载
- 生产环境建议把模板上传到文件服务器或放在 jar 外
重阳,你现在是想:
- 用 EasyExcel 做列表多sheet 填充?
- 处理合并单元格 / 图片 / 下拉框?
- 导出后自动调整列宽 / 加水印?
- 还是遇到具体报错想 debug?
告诉我你的具体需求或模板样子,我可以给你更精确的代码~