前言 在后端开发中,生成和导出Excel、Word等办公文档是一项常见的需求,例如报表导出、数据汇总、合同生成等。Java生态系统提供了多种强大的库来帮助我们完成这些任务。本文将重点介绍使用Apache POI、EasyExcel导出Excel文件,以及使用Apache POI (XWPF)和poi-tl导出Word文件的方法。
一、导出Excel文件 Excel文件因其强大的数据组织和分析能力,在企业应用中广泛使用。下面介绍两种主流的Java库进行Excel导出的方法。
(一)使用 Apache POI 导出 Excel Apache POI 是一个非常成熟和功能强大的库,可以操作Microsoft Office格式的文件,包括Excel (.xls 和 .xlsx)。
1. 添加依赖 (Maven) 1 2 3 4 5 6 7 8 9 10 <dependency > <groupId > org.apache.poi</groupId > <artifactId > poi</artifactId > <version > 5.2.5</version > </dependency > <dependency > <groupId > org.apache.poi</groupId > <artifactId > poi-ooxml</artifactId > <version > 5.2.5</version > </dependency >
poi: 核心API,支持老的 .xls 格式 (HSSF)。
poi-ooxml: 支持新的 .xlsx 格式 (XSSF),推荐使用。
2. 导出步骤 导出Excel的基本步骤如下:
a. 创建工作簿 (Workbook)
HSSFWorkbook 用于 .xls 文件。
XSSFWorkbook 用于 .xlsx 文件。
SXSSFWorkbook 用于大数据量的 .xlsx 文件,它是一种流式API,可以有效减少内存占用。
b. 创建工作表 (Sheet)
c. 创建行 (Row)
d. 创建单元格 (Cell)
e. 设置单元格内容和样式 (可选)
f. 将工作簿写入输出流 (例如 HttpServletResponse.getOutputStream())
3. 示例代码 (导出 .xlsx) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 import org.apache.poi.ss.usermodel.*;import org.apache.poi.xssf.usermodel.XSSFWorkbook;import org.apache.poi.xssf.streaming.SXSSFWorkbook;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.OutputStream;import java.util.List;class UserDto { private Long id; private String username; private String email; public UserDto (Long id, String username, String email) { this .id = id; this .username = username; this .email = email; } public Long getId () { return id; } public String getUsername () { return username; } public String getEmail () { return email; } } public class ExcelExportService { public void exportUsersToExcel (List<UserDto> users, HttpServletResponse response) throws IOException { SXSSFWorkbook workbook = new SXSSFWorkbook (100 ); workbook.setCompressTempFiles(true ); Sheet sheet = workbook.createSheet("用户信息" ); Row headerRow = sheet.createRow(0 ); String[] headers = {"ID" , "用户名" , "邮箱" }; CellStyle headerStyle = workbook.createCellStyle(); Font headerFont = workbook.createFont(); headerFont.setBold(true ); headerStyle.setFont(headerFont); for (int i = 0 ; i < headers.length; i++) { Cell cell = headerRow.createCell(i); cell.setCellValue(headers[i]); cell.setCellStyle(headerStyle); } int rowNum = 1 ; for (UserDto user : users) { Row row = sheet.createRow(rowNum++); row.createCell(0 ).setCellValue(user.getId()); row.createCell(1 ).setCellValue(user.getUsername()); row.createCell(2 ).setCellValue(user.getEmail()); } for (int i = 0 ; i < headers.length; i++) { sheet.autoSizeColumn(i); } response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ); response.setHeader("Content-Disposition" , "attachment; filename=\"users.xlsx\"" ); OutputStream outputStream = response.getOutputStream(); workbook.write(outputStream); outputStream.close(); workbook.close(); if (workbook instanceof SXSSFWorkbook) { ((SXSSFWorkbook) workbook).dispose(); } } }
4. 注意事项
内存管理 : 对于大量数据,务必使用 SXSSFWorkbook 来避免内存溢出。
样式 : 过多的不同样式对象会增加内存消耗和文件大小。尽量复用 CellStyle 对象。
错误处理 : 确保在 finally 块中关闭流和工作簿。
并发 : 如果多个用户同时请求导出,确保导出逻辑是线程安全的,或者为每个请求创建独立的 Workbook 实例。
(二)使用 EasyExcel (Alibaba) 导出 Excel EasyExcel 是阿里巴巴开源的一个Java库,它在Apache POI的基础上进行了封装,旨在简化Excel的读写操作,并着重解决了内存消耗大的问题。
1. 添加依赖 (Maven) 1 2 3 4 5 <dependency > <groupId > com.alibaba</groupId > <artifactId > easyexcel</artifactId > <version > 3.3.3</version > </dependency >
EasyExcel 会自动传递依赖 Apache POI 相关的包。
2. 导出步骤 EasyExcel 的导出通常更加简洁:
a. 定义数据模型 (一个Java类),并使用注解 (如 @ExcelProperty) 映射到Excel列。 b. 调用 EasyExcel.write() 方法指定输出流和数据模型类。 c. 通过 .sheet() 指定工作表名称。 d. 调用 .doWrite() 执行写入操作,传入数据列表。
3. 示例代码 首先,定义数据模型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import com.alibaba.excel.annotation.ExcelProperty;import com.alibaba.excel.annotation.write.style.ColumnWidth;import com.alibaba.excel.annotation.write.style.HeadFontStyle;import com.alibaba.excel.annotation.write.style.HeadRowHeight;@HeadRowHeight(20) @ColumnWidth(25) @HeadFontStyle(fontHeightInPoints = 12, bold = true) public class UserExcelDto { @ExcelProperty("用户ID") @ColumnWidth(15) private Long id; @ExcelProperty("登录名") private String username; @ExcelProperty("电子邮箱") @ColumnWidth(30) private String email; public UserExcelDto (Long id, String username, String email) { this .id = id; this .username = username; this .email = email; } public Long getId () { return id; } public void setId (Long id) { this .id = id; } public String getUsername () { return username; } public void setUsername (String username) { this .username = username; } public String getEmail () { return email; } public void setEmail (String email) { this .email = email; } }
然后是导出服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import com.alibaba.excel.EasyExcel;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.net.URLEncoder;import java.util.List;import java.util.stream.Collectors;public class EasyExcelExportService { public void exportUsersWithEasyExcel (List<UserDto> users, HttpServletResponse response) throws IOException { List<UserExcelDto> excelUsers = users.stream() .map(user -> new UserExcelDto (user.getId(), user.getUsername(), user.getEmail())) .collect(Collectors.toList()); response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ); response.setCharacterEncoding("utf-8" ); String fileName = URLEncoder.encode("用户信息" , "UTF-8" ).replaceAll("\\+" , "%20" ); response.setHeader("Content-disposition" , "attachment;filename*=" + "UTF-8''" + fileName + ".xlsx" ); EasyExcel.write(response.getOutputStream(), UserExcelDto.class) .sheet("用户列表" ) .doWrite(excelUsers); } }
4. 优势与特点
简洁API : 相较于POI,API更加简单易用,上手快。
低内存消耗 : 内部优化了内存使用,特别适合大数据量导出,不易OOM。
注解驱动 : 通过注解定义Excel的列名、宽度、样式等,代码更清晰。
灵活的拦截器/处理器 : 支持通过 WriteHandler 自定义样式、合并单元格等复杂操作。
二、导出Word文件 Word文档通常用于生成格式化的报告、合同、通知等。Java中操作Word文档也主要依赖Apache POI,或者使用基于POI的模板引擎。
(一)使用 Apache POI (XWPF) 导出 Word (.docx) Apache POI的 XWPF 组件用于处理 .docx 格式的Word文档。
1. 添加依赖 (Maven) (同Excel的 poi-ooxml 依赖,它已包含操作Word所需的基本组件)
1 2 3 4 5 <dependency > <groupId > org.apache.poi</groupId > <artifactId > poi-ooxml</artifactId > <version > 5.2.5</version > </dependency >
2. 导出步骤 a. 创建文档对象 (XWPFDocument) b. 创建段落 (XWPFParagraph) c. 创建文本运行 (XWPFRun) 并设置内容和样式 d. 创建表格 (XWPFTable)、图片等 (可选) e. 将文档写入输出流
3. 示例代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 import org.apache.poi.xwpf.usermodel.*;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.OutputStream;import java.math.BigInteger;public class WordExportService { public void exportSimpleWord (HttpServletResponse response) throws IOException { XWPFDocument document = new XWPFDocument (); XWPFParagraph titleParagraph = document.createParagraph(); titleParagraph.setAlignment(ParagraphAlignment.CENTER); XWPFRun titleRun = titleParagraph.createRun(); titleRun.setText("这是一个示例Word文档标题" ); titleRun.setBold(true ); titleRun.setFontSize(20 ); titleRun.addBreak(); XWPFParagraph contentParagraph = document.createParagraph(); XWPFRun contentRun = contentParagraph.createRun(); contentRun.setText("这是第一段内容。Apache POI 提供了丰富的API来操作Word文档,包括设置字体、颜色、对齐方式等。" ); contentRun.addBreak(); XWPFRun contentRun2 = contentParagraph.createRun(); contentRun2.setText("这是同一段落的第二句话,可以设置不同样式。" ); contentRun2.setItalic(true ); contentRun2.setColor("0070C0" ); XWPFTable table = document.createTable(3 , 3 ); table.getRow(0 ).getCell(0 ).setText("表头1" ); table.getRow(0 ).getCell(1 ).setText("表头2" ); table.getRow(0 ).getCell(2 ).setText("表头3" ); table.getRow(1 ).getCell(0 ).setText("数据A1" ); table.getRow(1 ).getCell(1 ).setText("数据B1" ); table.getRow(1 ).getCell(2 ).setText("数据C1" ); table.getRow(2 ).getCell(0 ).setText("数据A2" ); table.getRow(2 ).getCell(1 ).setText("数据B2" ); table.getRow(2 ).getCell(2 ).setText("数据C2" ); response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document" ); response.setHeader("Content-Disposition" , "attachment; filename=\"sample.docx\"" ); OutputStream outputStream = response.getOutputStream(); document.write(outputStream); outputStream.close(); document.close(); } }
4. 注意事项
API复杂度 : POI XWPF的API相对底层,生成复杂格式的文档可能需要较多代码。
样式控制 : 字体、段落格式、表格样式等都需要通过API精细控制。
性能 : 对于非常复杂的文档或大量文档生成,性能可能需要关注。
(二)使用 poi-tl (Poi-template-language) 导出 Word poi-tl 是一个基于Apache POI的Word模板引擎,它允许你创建Word模板 (.docx格式),在模板中使用特定的标签语法 (如 {{name}}, `