芮梦月 发表于 2025-9-30 18:09:57

java从word模板生成.doc和.wps文件

当遇到要生成一个word文档(证明文件等)的需求时,就可以考虑使用word模板生成.doc和.wps文件
一、需求
1、生成如下这样的订单数据.doc文件,红框部分是变化的,其余部分是固定的

2、生成如下这样的书籍列表,书的个数不固定是动态的。

二、使用Docx4j实现 
1、引入依赖
<dependency>
    <groupId>org.docx4j</groupId>
    docx4j-core</artifactId>
    <version>8.3.0</version>
</dependency>


<dependency>
    <groupId>org.docx4j</groupId>
    docx4j-JAXB-ReferenceImpl</artifactId>
    <version>8.3.0</version>
</dependency>



<dependency>
    <groupId>org.apache.velocity</groupId>
    velocity-engine-core</artifactId>
    <version>2.3</version>
</dependency>

<dependency>
    <groupId>org.docx4j</groupId>
    docx4j-JAXB-Internal</artifactId>
    <version>8.3.0</version>
</dependency>注: 前两个完成第一个需求就够了,后两个使用模板完成后一个需求
 2、制作模板
变量的地方用${}
模板contract_template.docx内容如下:

 
模板book_template.docx内容如下:
使用foreach进行循环

3、代码
Docx4jService类package com.example.demo.demos;

import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.Document;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;

import javax.xml.bind.JAXBElement;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.Map;

@Service
public class Docx4jService {

    /**
   * 根据模板生成Word文档(修复没有write方法的问题)
   */
    public byte[] generateWord(String templatePath, Map<String, String> data) throws Exception {
      // 1. 加载模板
      ClassPathResource resource = new ClassPathResource(templatePath);
      WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(resource.getInputStream());
      MainDocumentPart mainDocumentPart = wordMLPackage.getMainDocumentPart();

      // 2. 获取文档XML内容
      Document document = mainDocumentPart.getJaxbElement();
      List<Object> content = document.getBody().getContent();

      // 3. 手动替换变量
      replaceVariables(content, data);

      // 4. 写回并生成字节数组(使用save方法替代write方法)
      try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            // 关键修复:用save方法替代write方法
            wordMLPackage.save(out);
            return out.toByteArray();
      }
    }

    /**
   * 递归替换文档中的变量(修复Text节点无法识别问题)
   */
    @SuppressWarnings("unchecked")
    private void replaceVariables(List<Object> content, Map<String, String> data) {
      for (int i = 0; i < content.size(); i++) {
            Object obj = content.get(i);

            // 处理JAXB包装的元素(解开外层包装)
            if (obj instanceof JAXBElement) {
                obj = ((JAXBElement<?>) obj).getValue();
            }

            // 关键修复:处理运行元素(R),Text节点一定在R里面
            if (obj instanceof org.docx4j.wml.R) {
                org.docx4j.wml.R run = (org.docx4j.wml.R) obj;
                // 遍历R元素中的内容,寻找Text节点
                replaceVariables(run.getContent(), data);
            }
            // 现在可以找到Text节点了
            else if (obj instanceof org.docx4j.wml.Text) {
                org.docx4j.wml.Text text = (org.docx4j.wml.Text) obj;
                String value = text.getValue();

                // 遍历所有变量进行替换
                for (Map.Entry<String, String> entry : data.entrySet()) {
                  String key = "${" + entry.getKey() + "}";
                  if (value.contains(key)) {
                        value = value.replace(key, entry.getValue());
                        text.setValue(value);
                  }
                }
            }
            // 处理段落(P):继续遍历段落中的内容(会包含R元素)
            else if (obj instanceof org.docx4j.wml.P) {
                org.docx4j.wml.P p = (org.docx4j.wml.P) obj;
                replaceVariables(p.getContent(), data);
            }
            // 处理表格(Tbl):继续遍历表格中的内容
            else if (obj instanceof org.docx4j.wml.Tbl) {
                org.docx4j.wml.Tbl tbl = (org.docx4j.wml.Tbl) obj;
                replaceVariables(tbl.getContent(), data);
            }
      }
    }


Book类<br>package com.example.demo.demos;

public class Book {
    private String name;
    private String author;


    public String getName() {
      return name;
    }

    public void setName(String name) {
      this.name = name;
    }

    public String getAuthor() {
      return author;
    }

    public void setAuthor(String author) {
      this.author = author;
    }


    public Book(String name, String author) {
      this.name = name;
      this.author = author;
    }
} WordController类
 
package com.example.demo.demos;import org.docx4j.jaxb.Context;import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.io.ClassPathResource;import org.springframework.http.HttpHeaders;import org.springframework.http.HttpStatus;import org.springframework.http.ResponseEntity;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletResponse;import javax.xml.bind.JAXBException;import javax.xml.bind.Unmarshaller;import javax.xml.stream.XMLInputFactory;import javax.xml.stream.XMLStreamException;import javax.xml.stream.XMLStreamReader;import javax.xml.transform.stream.StreamSource;import java.io.*;import java.net.URLEncoder;import java.util.*;import org.apache.velocity.VelocityContext;import org.apache.velocity.app.Velocity;import org.docx4j.Docx4J;import org.docx4j.openpackaging.packages.WordprocessingMLPackage;import org.docx4j.wml.Document;@RestController@RequestMapping("/word")public class WordController {    @Autowired    private Docx4jService docx4jService;    /**   * 生成并下载 Word 文档   */    @GetMapping("/generate")    public ResponseEntity generateWord() throws Exception {      // 1. 准备模板变量数据      Map data = new HashMap();      data.put("username", "张三");      data.put("orderNo", "ORD20250911001");      data.put("amount", "1000.00");      data.put("date", "2025-09-11");      // 2. 调用服务生成 Word 字节数组      byte[] wordBytes = docx4jService.generateWord("templates/contract_template.docx", data);      // 3. 配置响应头,实现文件下载      String fileName = URLEncoder.encode("订单详情.docx", "UTF-8");      HttpHeaders headers = new HttpHeaders();      headers.add("Content-Disposition", "attachment; filename=" + fileName);      headers.add("Content-Type", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");      return new ResponseEntity(wordBytes, headers, HttpStatus.OK);    }    static {      try {            Properties props = new Properties();            props.setProperty("resource.loader", "class");            props.setProperty("class.resource.loader.class",                  "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");            Velocity.init(props);      } catch (Exception e) {            throw new RuntimeException("Velocity引擎初始化失败", e);      }    }    @GetMapping("/export")    public void exportBooks(HttpServletResponse response) {      try (InputStream templateStream = new ClassPathResource("templates/book_template.docx").getInputStream()) {            WordprocessingMLPackage template = WordprocessingMLPackage.load(templateStream);            MainDocumentPart mainPart = template.getMainDocumentPart();            //生成books内容            List books = new ArrayList();            for (int i = 1; i
页: [1]
查看完整版本: java从word模板生成.doc和.wps文件