riku
2025-08-28 3bb4fb15c664d29d179083698fdad35a661b1d7f
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package com.flightfeather.uav.common.file
 
import freemarker.template.Configuration
import freemarker.template.Template
 
import org.docx4j.openpackaging.packages.WordprocessingMLPackage
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.OutputStreamWriter
import java.nio.charset.StandardCharsets
 
/**
 * Word文件生成器(基于Docx4j + FreeMarker)
 * @date 2025/8/28 09:29
 * @author feiyu
 */
class Docx4jGenerator(
    private val templatePath: String,
    private val freemarkerConfig: Configuration = defaultFreemarkerConfig()
) {
    private var wordMLPackage: WordprocessingMLPackage? = null
    private var mainDocumentPart: MainDocumentPart? = null
 
    /**
     * 创建Word文档包
     */
    fun loadTemplate(): Docx4jGenerator {
        wordMLPackage = WordprocessingMLPackage.createPackage()
        mainDocumentPart = wordMLPackage?.mainDocumentPart
 
        return this
    }
 
    /**
     * 使用FreeMarker填充模板数据
     */
    fun fillData(dataModel: Map<String, Any>): Docx4jGenerator {
        val template = freemarkerConfig.getTemplate(templatePath.substringAfterLast("/"))
        val xmlContent = renderTemplate(template, dataModel)
 
        mainDocumentPart?.unmarshal(ByteArrayInputStream(xmlContent.toByteArray(StandardCharsets.UTF_8)))
        return this
    }
 
    /**
     * 添加图片到Word文档
     * @param imagePath 图片路径
     * @param width 宽度(像素)
     * @param height 高度(像素)
     * @param paragraphId 段落ID,指定图片插入位置
     */
    fun addImage(imagePath: String, width: Int, height: Int, paragraphId: String): Docx4jGenerator {
        // 实现图片添加逻辑
        return this
    }
 
    /**
     * 添加表格到Word文档
     * @param data 表格数据
     * @param paragraphId 段落ID,指定表格插入位置
     */
    fun addTable(data: List<List<String>>, paragraphId: String): Docx4jGenerator {
        // 实现表格添加逻辑
        return this
    }
 
    /**
     * 保存生成的Word文件
     * @param outputPath 输出文件路径
     */
    fun save(outputPath: String) {
        wordMLPackage?.save(File(outputPath))
    }
 
    /**
     * 使用FreeMarker渲染模板
     */
    private fun renderTemplate(template: Template, dataModel: Map<String, Any>): String {
        val outputStream = ByteArrayOutputStream()
        val writer = OutputStreamWriter(outputStream, StandardCharsets.UTF_8)
        template.process(dataModel, writer)
        writer.flush()
        return outputStream.toString(StandardCharsets.UTF_8.name())
    }
 
    companion object {
        /**
         * 默认FreeMarker配置
         */
        fun defaultFreemarkerConfig(): Configuration {
            val config = Configuration(Configuration.VERSION_2_3_31)
            config.defaultEncoding = "UTF-8"
            config.setClassForTemplateLoading(Docx4jGenerator::class.java, "/templates")
            return config
        }
 
        /**
         * 简化调用的静态方法
         */
        fun generate(
            templatePath: String,
            outputPath: String,
            dataModel: Map<String, Any>,
            config: Configuration = defaultFreemarkerConfig()
        ) {
            Docx4jGenerator(templatePath, config)
                .loadTemplate()
                .fillData(dataModel)
                .save(outputPath)
        }
    }
}