java 使用 docx4j 将xmldocx 生成为真正的word文档,将FreeMarker导出的word转换为真正的word,解决word不能在线预览问题

问题描述

遇到的问题,使用FreeMarker导出Word后本地打开正常,但上传后在浏览器预览显示的是一个xml。

问题原因

使用FreeMarker模板导出的Word实际上是一个xml文件,Word和WPS支持这种格式,但是网页预览不支持。可以通过修改导出后的.doc文件的后缀验证,修改为.xml后导出的文件可以打开,但本地创建的.doc文件不能打开。

解决方法

将xml文件转换成真正的word文件。
docx4j是一个用于创建和操作Microsoft Open XML (Word docx, PowerPoint pptx, 和 Excel xlsx)文件的Java类库。

引入依赖
        <dependency>
			<groupId>org.docx4j</groupId>
			<artifactId>docx4j-JAXB-ReferenceImpl</artifactId>
			<version>8.3.3</version>
		</dependency>
转换工具类代码
public class FreeMarkerGenWordUtil {


    /**
     * @description 根据模版+数据生成Word文档 字节流
     * @author luxinting email:luxinting@caseeder.com
     * @date 2023/10/19 10:23
     * @param[1] dataMap 模版动态数据
     * @param[2] template 模版
     * @return ByteArrayInputStream
     * @throws
     */
    public static ByteArrayInputStream createWord(Map<String, Object> dataMap, Template template) {
        ByteArrayOutputStream byteArrayOutputStream = null;
        Writer writer = null;
        ByteArrayInputStream inputStream = null;
        ByteArrayOutputStream osAfterConvert = null;
        try {
            byteArrayOutputStream = new ByteArrayOutputStream();
            writer = new OutputStreamWriter(byteArrayOutputStream, "utf-8");
            template.process(dataMap, writer);
            inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            //兼容微软Office Word
            WordprocessingMLPackage word = Docx4J.load(inputStream);
            osAfterConvert = new ByteArrayOutputStream();
            Docx4J.save(word, osAfterConvert);
            return new ByteArrayInputStream(osAfterConvert.toByteArray());
        } catch (IOException | TemplateException | Docx4JException e) {
            e.printStackTrace();
            return null;
        } finally {
            if (byteArrayOutputStream != null) {
                try {
                    byteArrayOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (osAfterConvert != null) {
                try {
                    osAfterConvert.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


}
将生成的.docx文件导出的方法
public Result exportForceNoticeWordFile(HttpServletResponse response, Long reportId) {
        if (reportId == null) {
            return DataResultUtil.fail("报告ID不能为空");
        }

        //获取数据
        Map<String, Object> dataMap = buildExportDataMap(reportId);
        if (dataMap == null) {
            return DataResultUtil.fail("报告ID不正确");
        }

        Configuration configuration = new Configuration(Configuration.VERSION_2_3_31);
        ServletOutputStream sos = null;
        ByteArrayInputStream inputStream = null;
        try {
            // 加载文档模板FTL文件所存在的位置
            configuration.setTemplateLoader(new ClassTemplateLoader(this.getClass(), "/templates/"));
            configuration.setDefaultEncoding("UTF-8");
            Template template = configuration.getTemplate("RecallDeviceForce.ftl");
            inputStream = FreeMarkerGenWordUtil.createWord(dataMap, template);
            if (inputStream==null) {
                return DataResultUtil.fail("导出失败,导出模板处理异常");
            }
            response.setContentType("multipart/form-data");
            //为文件重新设置名字
            String fileName = "通知书.docx";
            response.addHeader("Content-Disposition", "attachment; filename=\"" + new String((fileName).getBytes("UTF-8"), "ISO8859-1") + "\"");

            sos = response.getOutputStream();
            //读取文件流
            int len = 0;
            byte[] buffer = new byte[1024 * 10];
            while ((len = inputStream.read(buffer)) != -1) {
                sos.write(buffer, 0, len);
            }
            sos.flush();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    LogUtil.error("导出异常:" + e.getMessage());
                    e.printStackTrace();
                }
            }
            if (sos != null) {
                try {
                    sos.close();
                } catch (IOException e) {
                    LogUtil.error("导出异常:" + e.getMessage());
                    e.printStackTrace();
                }
            }

        }
        return DataResultUtil.success();
    }
Docx4j是一个用于处理Word文档Java库,它提供了丰富的功能,包括创建、修改和转换Word文档等。要将Word文档转换为PDF,可以使用Docx4j提供的功能。 首先,你需要在项目中引入Docx4j库的依赖。你可以在Maven或Gradle中添加以下依赖: Maven: ```xml <dependency> <groupId>org.docx4j</groupId> <artifactId>docx4j</artifactId> <version>8.2.9</version> </dependency> ``` Gradle: ```groovy implementation 'org.docx4j:docx4j:8.2.9' ``` 接下来,你可以使用以下代码将Word文档转换为PDF: ```java import org.docx4j.Docx4J; import org.docx4j.convert.out.FOSettings; public class WordToPdfConverter { public static void main(String[] args) throws Exception { // 加载Word文档 String inputFilePath = "path/to/input.docx"; org.docx4j.openpackaging.packages.WordprocessingMLPackage wordMLPackage = Docx4J.load(new java.io.File(inputFilePath)); // 创建FOSettings对象,并设置输出格式为PDF FOSettings foSettings = Docx4J.createFOSettings(); foSettings.setWmlPackage(wordMLPackage); foSettings.setApacheFopMime("application/pdf"); // 设置输出路径 String outputFilePath = "path/to/output.pdf"; java.io.OutputStream outputStream = new java.io.FileOutputStream(outputFilePath); // 执行转换 Docx4J.toFO(foSettings, outputStream, Docx4J.FLAG_EXPORT_PREFER_XSL); // 关闭输出流 outputStream.close(); System.out.println("Word文档转换为PDF成功!"); } } ``` 以上代码中,你需要将`inputFilePath`替换为要转换Word文档的路径,将`outputFilePath`替换为要保存的PDF文件的路径。执行代码后,将会成对应的PDF文件。 希望以上信息对你有所帮助!如果你有任何其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值