找回密码
 立即注册
首页 业界区 业界 java从word模板生成.doc和.wps文件

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

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

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

二、使用Docx4j实现 
1、引入依赖
  1. <dependency>
  2.     <groupId>org.docx4j</groupId>
  3.     docx4j-core</artifactId>
  4.     <version>8.3.0</version>
  5. </dependency>
  6. <dependency>
  7.     <groupId>org.docx4j</groupId>
  8.     docx4j-JAXB-ReferenceImpl</artifactId>
  9.     <version>8.3.0</version>
  10. </dependency>
  11. <dependency>
  12.     <groupId>org.apache.velocity</groupId>
  13.     velocity-engine-core</artifactId>
  14.     <version>2.3</version>
  15. </dependency>
  16. <dependency>
  17.     <groupId>org.docx4j</groupId>
  18.     docx4j-JAXB-Internal</artifactId>
  19.     <version>8.3.0</version>
  20. </dependency>
复制代码
注: 前两个完成第一个需求就够了,后两个使用模板完成后一个需求
 2、制作模板
变量的地方用${}
模板contract_template.docx内容如下:
3.png

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

3、代码
  1. Docx4jService类
复制代码
  1. package com.example.demo.demos;
  2. import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
  3. import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
  4. import org.docx4j.wml.Document;
  5. import org.springframework.core.io.ClassPathResource;
  6. import org.springframework.stereotype.Service;
  7. import javax.xml.bind.JAXBElement;
  8. import java.io.ByteArrayOutputStream;
  9. import java.util.List;
  10. import java.util.Map;
  11. @Service
  12. public class Docx4jService {
  13.     /**
  14.      * 根据模板生成Word文档(修复没有write方法的问题)
  15.      */
  16.     public byte[] generateWord(String templatePath, Map<String, String> data) throws Exception {
  17.         // 1. 加载模板
  18.         ClassPathResource resource = new ClassPathResource(templatePath);
  19.         WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(resource.getInputStream());
  20.         MainDocumentPart mainDocumentPart = wordMLPackage.getMainDocumentPart();
  21.         // 2. 获取文档XML内容
  22.         Document document = mainDocumentPart.getJaxbElement();
  23.         List<Object> content = document.getBody().getContent();
  24.         // 3. 手动替换变量
  25.         replaceVariables(content, data);
  26.         // 4. 写回并生成字节数组(使用save方法替代write方法)
  27.         try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
  28.             // 关键修复:用save方法替代write方法
  29.             wordMLPackage.save(out);
  30.             return out.toByteArray();
  31.         }
  32.     }
  33.     /**
  34.      * 递归替换文档中的变量(修复Text节点无法识别问题)
  35.      */
  36.     @SuppressWarnings("unchecked")
  37.     private void replaceVariables(List<Object> content, Map<String, String> data) {
  38.         for (int i = 0; i < content.size(); i++) {
  39.             Object obj = content.get(i);
  40.             // 处理JAXB包装的元素(解开外层包装)
  41.             if (obj instanceof JAXBElement) {
  42.                 obj = ((JAXBElement<?>) obj).getValue();
  43.             }
  44.             // 关键修复:处理运行元素(R),Text节点一定在R里面
  45.             if (obj instanceof org.docx4j.wml.R) {
  46.                 org.docx4j.wml.R run = (org.docx4j.wml.R) obj;
  47.                 // 遍历R元素中的内容,寻找Text节点
  48.                 replaceVariables(run.getContent(), data);
  49.             }
  50.             // 现在可以找到Text节点了
  51.             else if (obj instanceof org.docx4j.wml.Text) {
  52.                 org.docx4j.wml.Text text = (org.docx4j.wml.Text) obj;
  53.                 String value = text.getValue();
  54.                 // 遍历所有变量进行替换
  55.                 for (Map.Entry<String, String> entry : data.entrySet()) {
  56.                     String key = "${" + entry.getKey() + "}";
  57.                     if (value.contains(key)) {
  58.                         value = value.replace(key, entry.getValue());
  59.                         text.setValue(value);
  60.                     }
  61.                 }
  62.             }
  63.             // 处理段落(P):继续遍历段落中的内容(会包含R元素)
  64.             else if (obj instanceof org.docx4j.wml.P) {
  65.                 org.docx4j.wml.P p = (org.docx4j.wml.P) obj;
  66.                 replaceVariables(p.getContent(), data);
  67.             }
  68.             // 处理表格(Tbl):继续遍历表格中的内容
  69.             else if (obj instanceof org.docx4j.wml.Tbl) {
  70.                 org.docx4j.wml.Tbl tbl = (org.docx4j.wml.Tbl) obj;
  71.                 replaceVariables(tbl.getContent(), data);
  72.             }
  73.         }
  74.     }
  75. }
复制代码
 
  1. Book类<br>
复制代码
  1. package com.example.demo.demos;
  2. public class Book {
  3.     private String name;
  4.     private String author;
  5.     public String getName() {
  6.         return name;
  7.     }
  8.     public void setName(String name) {
  9.         this.name = name;
  10.     }
  11.     public String getAuthor() {
  12.         return author;
  13.     }
  14.     public void setAuthor(String author) {
  15.         this.author = author;
  16.     }
  17.     public Book(String name, String author) {
  18.         this.name = name;
  19.         this.author = author;
  20.     }
  21. }
复制代码
[code][/code] WordController类
 
[code]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

相关推荐

您需要登录后才可以回帖 登录 | 立即注册