前言 在后端开发中,生成和导出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}}
, `