基于FreeMarker模板引擎生成Word并导出PDF

基于FreeMarker模板引擎生成Word并导出PDF

1.导入相关maven

xml 复制代码
     <!-- FreeMarker模板引擎 -->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.31</version>
        </dependency>
        <dependency>
            <groupId>aspose</groupId>
            <artifactId>aspose-words</artifactId>
            <version>19.5</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>html2pdf</artifactId>
            <version>4.0.5</version>
        </dependency>

2.FreeMarker渲染数据导出word

java 复制代码
/**
 * Word文档生成工具类
 */
public class WordDocumentGenerator {

    /**
     * 使用FreeMarker生成Word文档
     */
    public static byte[] generateWordDocumentAsBytes(String templatePath, Map<String, Object> root)
            throws IOException, TemplateException {

        // 创建FreeMarker配置
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
        cfg.setDefaultEncoding("UTF-8");

        // 设置模板加载路径
        ClassPathResource resource = new ClassPathResource(templatePath);
        File templateFile = resource.getFile();
        String templateDir = templateFile.getParent();
        String templateName = templateFile.getName();

        cfg.setDirectoryForTemplateLoading(new File(templateDir));

        // 加载模板
        Template template = cfg.getTemplate(templateName, "UTF-8");

        // 使用ByteArrayOutputStream获取字节流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        Writer out = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
        template.process(root, out);
        out.close();

        return outputStream.toByteArray();
    }

    public static InputStream generateWordDocumentAsStream(String templatePath, Map<String, Object> root)
            throws IOException, TemplateException {

        byte[] bytes = generateWordDocumentAsBytes(templatePath, root);
        return new ByteArrayInputStream(bytes);
    }

    /**
     * 使用FreeMarker生成Word文档并返回Base64编码的字符串
     */
    public static String generateWordDocumentAsBase64(String templatePath, Map<String, Object> root)
            throws IOException, TemplateException {

        byte[] bytes = generateWordDocumentAsBytes(templatePath, root);
        return Base64.getEncoder().encodeToString(bytes);
    }


    /**
     * 使用FreeMarker生成Word文档并保存到指定路径
     */
    public static void generateWordDocument(String templatePath, String outputPath, Map<String, Object> root)
            throws IOException, TemplateException {

        // 创建FreeMarker配置
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
        cfg.setDefaultEncoding("UTF-8");

        // 设置模板加载路径
        File templateFile = new File(templatePath);
        String templateDir = templateFile.getParent();
        String templateName = templateFile.getName();

        cfg.setDirectoryForTemplateLoading(new File(templateDir));

        // 加载模板
        Template template = cfg.getTemplate(templateName, "UTF-8");

        // 创建输出目录(如果不存在)
        File outputFile = new File(outputPath);
        outputFile.getParentFile().mkdirs();

        // 写入文件
        try (Writer fileWriter = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream(outputFile), "UTF-8"))) {
            template.process(root, fileWriter);
        }
    }

3.导出PDF

说明:因为FreeMarker导出的word文档,本质还是xml文件,所以这里要用到aspose工具,支持xml文件 转化为pdf.

1.安装许可证,不然会出现导出会有水印。

license.xml

xml 复制代码
<License>
    <Data>
        <Products>
            <Product>Aspose.Total for Java</Product>
            <Product>Aspose.Words for Java</Product>
        </Products>
        <EditionType>Enterprise</EditionType>
        <SubscriptionExpiry>20991231</SubscriptionExpiry>
        <LicenseExpiry>20991231</LicenseExpiry>
        <SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber>
    </Data>
    <Signature>sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=</Signature>
</License>

AsposeWordToPDFGenerator.java

java 复制代码
public class AsposeWordToPDFGenerator {

    public static boolean getLicense() {
        boolean result = false;
        try {
            // license.xml应放在..\WebRoot\WEB-INF\classes路径下
            InputStream is = WordDocumentGenerator.class.getClassLoader().getResourceAsStream("license.xml");
            License aposeLic = new License();
            aposeLic.setLicense(is);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     WordDocumentGenerator     *
     * @param inputStream
     * @param outputStream
     * @param saveTo       SaveFormat {@link SaveFormat }
     */
    public static void conversion(InputStream inputStream, OutputStream outputStream, int saveTo) {
        // 验证License 若不验证则转化出的pdf文档会有水印产生
        if (!getLicense()) {
            return;
        }
        try {
            // Address是将要被转化的word文档
            Document document = new Document(inputStream);

            // 设置字体文件夹路径(根据实际字体存放位置修改)
            String fontPath = AsposeWordToPDFGenerator.class.getClassLoader().getResource("Fonts").getPath();
            FontSettings fontSettings = new FontSettings();
            fontSettings.setFontsFolder(fontPath,true);
            document.setFontSettings(fontSettings);
            for (Section section : document.getSections()) {
                PageSetup pageSetup = section.getPageSetup();
                pageSetup.setTopMargin(20);   // 上边距
                pageSetup.setPaperSize(PaperSize.A4);
                TableCollection tables = section.getBody().getTables();
                for (Table table : tables) {
                    table.setAllowAutoFit(false);
                    RowCollection rows = table.getRows();
                    for (Row row : rows) {
                        CellCollection cells = row.getCells();
                        for (Cell cell : cells) {
                            CellFormat cellFormat = cell.getCellFormat();
                            cellFormat.setFitText(false);
                            cellFormat.setWrapText(true);
                        }
                    }
                }
            }
            // 全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF, EPUB, XPS, SWF 相互转换
            document.save(outputStream, saveTo);
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("word转pdf失败");
        }
    }
    /**
     * Word 转 PDF 并返回 base64 编码
     * @param inputStream Word 文档输入流
     * @return PDF 文件的 base64 编码字符串,转换失败返回 null
     */
    public static String convertToBase64(InputStream inputStream) {
        if (!getLicense()) {
            return null;
        }
        try (java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream()) {
            Document document = new Document(inputStream);
            // 设置字体路径(使用类路径)
            String fontPath = AsposeWordToPDFGenerator.class.getClassLoader().getResource("Fonts").getPath();
            FontSettings fontSettings = new FontSettings();
            fontSettings.setFontsFolder(fontPath, true);
            document.setFontSettings(fontSettings);

            for (Section section : document.getSections()) {
                PageSetup pageSetup = section.getPageSetup();
                pageSetup.setTopMargin(20);
                pageSetup.setPaperSize(PaperSize.A4);
                TableCollection tables = section.getBody().getTables();
                for (Table table : tables) {
                    table.setAllowAutoFit(false);
                    RowCollection rows = table.getRows();
                    for (Row row : rows) {
                        CellCollection cells = row.getCells();
                        for (Cell cell : cells) {
                            CellFormat cellFormat = cell.getCellFormat();
                            cellFormat.setFitText(false);
                            cellFormat.setWrapText(true);
                        }
                    }
                }
            }
            document.save(outputStream, SaveFormat.PDF);
            return Base64.getEncoder().encodeToString(outputStream.toByteArray());
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("word 转 pdf 失败");
        }
    }

}
相关推荐
轻刀快马20 分钟前
跨越软硬件的共鸣(二):从 Cache 写策略看 Redis 与 DB 的一致性博弈
java·开发语言·redis·计算机组成原理
折哥的程序人生 · 物流技术专研20 分钟前
Java 23 种设计模式:从踩坑到精通 | 装饰器模式 —— 比继承更灵活的扩展方式,你用过吗?
java·装饰器模式·java面试·结构型模式·java设计模式·javaio·从踩坑到精通
lili001227 分钟前
2026 企业 AI 选型新范式:OpenRouter Fusion 证明多模型融合性价比远超单模型,企业该如何重构技术栈? - 微元算力(weytoken)
java·人工智能·python·重构·ai编程
shushangyun_30 分钟前
汽车服务行业B2B平台+AI解决方案哪家专业:2026年最新测评
java·运维·网络·数据库·人工智能·汽车
gCode Teacher 格码致知30 分钟前
Javascript技术:CSS 中rem、vh 和 px各有其最佳适用场景-由Deepseek产生
开发语言·javascript·css
A.说学逗唱的Coke33 分钟前
【大模型专题】Spring AI Alibaba × Skill 整合实战:让 AI 真正“会干活
java·人工智能·spring
大黄说说1 小时前
深入理解 Go 协程 Goroutine:并发编程的核心精髓
java·数据库·python
超皮小龙猫1 小时前
c语言-1
c语言·开发语言
许彰午1 小时前
38_Java设计模式之装饰器模式
java·设计模式·装饰器模式
折哥的程序人生 · 物流技术专研1 小时前
Java 23 种设计模式:从踩坑到精通 | 组合模式 —— 树形结构处理,部分与整体一视同仁
java·组合模式·java面试·springsecurity·结构型模式·java设计模式·从踩坑到精通