使用 Spring Boot + POI 实现动态 DOCX 模版导出

使用 Spring Boot + POI 实现动态 DOCX 模版导出

在企业级应用开发中,根据业务逻辑动态生成Word文档(如报告、合同、通知等)的需求十分常见。Apache POI 是一个强大的 Java 库,能读写 Microsoft Office 格式的文件,包括 DOCX。结合 Spring Boot 的特性,可以轻松实现基于模板的动态文档生成。下面是如何使用 Spring Boot 和 Apache POI 创建一个简单的动态 DOCX 模版导出应用的指南。

环境准备

  • Java 11+
  • Spring Boot 2.7.0 或更高版本
  • Maven 或 Gradle 构建工具
  • Apache POI 库

添加依赖

在你的 pom.xml 文件中添加以下依赖:

xml 复制代码
<dependencies> 
  <!-- Spring Boot Web Starter --> 
  <dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-web</artifactId> 
  </dependency> <!-- Apache POI for handling DOCX files --> 
  <dependency> <groupId>org.apache.poi</groupId> 
    <artifactId>poi-ooxml</artifactId> 
    <version>5.2.2</version> 
  </dependency>
</dependencies>

创建模版

在项目的资源目录下创建一个 .docx 文件作为模版。例如,创建一个名为 reportTemplate.docx 的文件,其中包含占位符,如 ${name}${date} 等。

编写控制器

创建一个控制器类,用于处理 HTTP 请求并生成动态文档。

java 复制代码
import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.HashMap; import java.util.Map;

@GetMapping(value = "/generateReport", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@RestController public class ReportController {
  public void generateReport(HttpServletResponse response) throws IOException {
      // Load the template document
      XWPFDocument doc = new XWPFDocument(getClass().getResourceAsStream("/templates/reportTemplate.docx"));

      // Prepare data
      Map<String, String> data = new HashMap<>();
      data.put("name", "John Doe");
      data.put("date", "2023-04-01");

      // Replace placeholders with actual data
      for (XWPFParagraph paragraph : doc.getParagraphs()) {
          for (String key : data.keySet()) {
              String text = paragraph.getText();
              if (text.contains(key)) {
                  paragraph.setText(text.replace(key, data.get(key)), 0);
              }
          }
      }

      // Set response headers
      response.setHeader("Content-Disposition", "attachment; filename=generatedReport.docx");
      response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);

      // Write the document to the response output stream
      doc.write(response.getOutputStream());
      doc.close();
  }
}

替换模版中的占位符

在上面的控制器代码中,我们加载了模版文档,准备了一些数据,然后遍历文档中的每个段落,查找并替换占位符。

我是失忆,继续在代码江湖中书写属于自己的平凡传奇,更多精彩,敬请关注!
相关推荐
optimistic_chen20 小时前
【AI Agent 全栈开发】MCP
java·linux·运维·人工智能·ai编程·mcp
Lee川1 天前
从零解剖一个 AI Agent Tool是如何实现的
前端·人工智能·后端
2401_833269301 天前
Java网络编程入门
java·开发语言
金銀銅鐵1 天前
[Java] 如何将 Lambda 表达式对应的类保存到 class 文件中?
java·后端
五月君_1 天前
Bun v1.3.14 发布,Rust 版即将进 Claude Code 内测,下一版可能就告别 Zig
开发语言·后端·rust
明月_清风1 天前
🍃 MongoDB 从入门到上手:一篇写给新手的科普指南
后端·mongodb
それども1 天前
Gradle 构建疑难杂症 Could not find netty-transport-native-epoll-linux-aarch_64.ja
java·服务器·gradle·maven
正儿八经的少年1 天前
application.yml 系列配置文件作用与区别
java·配置文件
鱼很腾apoc1 天前
【学习篇】第20期 超详解 C++ 多态:从语法规则到底层原理
java·c语言·开发语言·c++·学习·算法·青少年编程
cheems95271 天前
[Spring MVC] 统一功能与拦截器实践总结
java·spring·mvc