概述
在企业级应用中,经常需要将数据导出为 Word 文档,以便用户可以方便地查看、编辑或打印这些数据。Spring Boot 以其简洁性和易用性著称,而 Freemarker 是一款强大的模板引擎,能够灵活地生成各种类型的文本输出。结合这两种技术,我们可以快速实现一个功能完备且易于维护的 Word 文档导出功能。
准备工作
技术栈
- Spring Boot: 用于构建应用和服务。
- Freemarker: 作为模板引擎来生成文档。
- Apache POI: 用于处理 Word 文件。
- Maven: 构建工具。
开发环境
- IDE: IntelliJ IDEA 或 Eclipse
- JDK: 1.8 或更高版本
- Maven: 3.6.0 或更高版本
创建项目
- 初始化项目:
- 使用 Spring Initializr 创建一个新的 Spring Boot 项目。
- 添加 spring-boot-starter-web 依赖项。
- 添加 spring-boot-starter-freemarker 依赖项。
- 添加依赖:
- 在 pom.xml 中添加 Apache POI 的相关依赖,以便能够处理 .docx 文件。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- Apache POI for Word document handling -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.2</version>
</dependency>
</dependencies>
设计模板
- 创建模板文件:
- 在 src/main/resources/templates 目录下创建一个 .ftl 文件,例如 report.ftl。
- 使用 Freemarker 的标签语法设计模板。
- 模板示例:
- 一个简单的报告模板可能包含一些文本和表格数据。
<!DOCTYPE document PUBLIC "-//OOXML//DTD Document//EN" "document.dtd">
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:body>
<w:p>
<w:r>
<w:t>Welcome, ${username}!</w:t>
</w:r>
</w:p>
<w:tbl>
<w:tr>
<w:tc>
<w:p>
<w:r>
<w:t>Data Label</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:p>
<w:r>
<w:t>Data Value</w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
<#list data as item>
<w:tr>
<w:tc>
<w:p>
<w:r>
<w:t>${item.label}</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:p>
<w:r>
<w:t>${item.value}</w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
</#list>
</w:tbl>
</w:body>
</w:document>
高级功能
处理样式和复杂布局
在实际应用中,Word 文档通常需要更加复杂的样式和布局。虽然 Freemarker 本身不直接支持 Word 的样式标签,但我们可以借助 Apache POI 库来处理样式和复杂布局。
- 创建样式:
- 使用 Apache POI 的 XWPFStyles API 来定义样式,并将其应用于文档中的元素。
- 插入图片:
- 使用 XWPFDocument 的 addPicture 方法来插入图片到文档中。
- 处理列表和表格:
- 使用 Freemarker 的循环标签来生成列表和表格,再通过 Apache POI 的 API 来控制表格的具体样式和结构。
示例代码
为了演示如何处理样式,我们将添加一些基本的样式到我们的 Word 文档中。
Java
深色版本
1import org.apache.poi.xwpf.usermodel.*;
2import org.springframework.beans.factory.annotation.Autowired;
3import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
4import org.springframework.web.bind.annotation.GetMapping;
5import org.springframework.web.bind.annotation.RequestMapping;
6import org.springframework.web.bind.annotation.RestController;
7import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
8
9import freemarker.template.Configuration;
10import freemarker.template.Template;
11import freemarker.template.TemplateException;
12
13import javax.servlet.http.HttpServletResponse;
14import java.io.IOException;
15import java.io.OutputStreamWriter;
16import java.nio.charset.StandardCharsets;
17import java.util.HashMap;
18import java.util.List;
19import java.util.Map;
20
21@RestController
22@RequestMapping("/export")
23public class ReportExportController {
24
25 @Autowired
26 private FreeMarkerConfigurer configurer;
27
28 @GetMapping("/word")
29 public void exportWord(HttpServletResponse response) throws IOException, TemplateException {
30 // 设置响应头
31 response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
32 response.setHeader("Content-Disposition", "attachment; filename=report.docx");
33
34 // 获取模板
35 Configuration cfg = configurer.getConfiguration();
36 Template template = cfg.getTemplate("report.ftl");
37
38 // 数据模型
39 Map<String, Object> model = new HashMap<>();
40 List<User> users = getUserData(); // 从数据库或其他来源获取数据
41 model.put("title", "User Report");
42 model.put("users", users);
43
44 // 渲染模板
45 String processedHtml = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
46
47 // 创建 Word 文档
48 XWPFDocument document = new XWPFDocument();
49
50 // 添加样式
51 XWPFStyles styles = document.createStyles();
52 XWPFStyle style = styles.createStyle("MyHeading");
53 style.setCustomStyle(true);
54 style.setStyleId("Heading1");
55 style.addBasedOnStyle("Heading1");
56 style.setFontFamily("Arial");
57 style.setFontSize(16);
58 style.setBold(true);
59 style.setUnderline(XWPFUnderlinePatterns.SINGLE);
60
61 // 将 HTML 转换为 XWPFParagraphs
62 XHTMLOptions options = XHTMLOptions.create()
63 .setIgnoreStylesIfUnused(false)
64 .setFragment(true)
65 .setUseXWPFTable(true)
66 .setDefaultStyles(styles)
67 .setInsertNewParagraphForBlockLevelTags(true);
68
69 XHTMLConverter.getInstance().convert(processedHtml, document, options);
70
71 // 写入响应流
72 try (OutputStreamWriter writer = new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8)) {
73 document.write(writer);
74 }
75 }
76
77 private List<User> getUserData() {
78 // 返回用户数据
79 return null;
80 }
81}
注意事项
- 兼容性:
- 确保生成的 Word 文档在不同的 Office 版本中都能正确显示。
- 性能考量:
- 如果要导出的数据量很大,考虑分批次处理或使用异步任务。
- 安全性:
- 在处理用户提交的数据时,确保对数据进行适当的验证和清理,防止潜在的安全问题。
总结
通过以上步骤,我们已经了解了如何利用 Spring Boot 和 Freemarker 生成带有样式的 Word 文档。这种方案既简单又高效,非常适合需要频繁生成报告的应用场景。如果需要更高级的功能,如图表生成或者复杂的页面布局,可以进一步探索 Apache POI 的其他功能