freemarker实现导出word docx格式

实现方法:

  1. 解析docx文件并填充word/document.xml文件(不兼容word2003)
  2. 使用freemarker填充 doc(doc另存为xml格式的文件)(手机端打不开)
  3. 使用poi方式构建文档(极其繁琐,不灵活)

方法2
docx压缩包格式:
目录结构定义自行搜索
在这里插入图片描述
word目录
在这里插入图片描述目录结构:

  • inspectReport.docx提供基本的压缩包格式,文档内容为编辑后的模板(为减少大小可清空word/document.xml的内容,media等资源文件保留)
  • inspectReport.ftl为docx压缩包中的word/document.xml文件,此文件为文档内容

在这里插入图片描述
代码实现:

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class FileUtil {
    private static Configuration FM_CONFIG;
    private static final Logger LOG = LoggerFactory.getLogger(FileUtil.class);

    static {
        FM_CONFIG = new Configuration(Configuration.VERSION_2_3_20);
        FM_CONFIG.setDefaultEncoding("utf-8");
        FM_CONFIG.setClassForTemplateLoading(FileUtil.class, "/template/");
    }

/**
     * 返回docx格式的文档,手机端也能打开
     *
     * @param templateName xx
     * @param dataMap      xx
     * @param fileName     xx
     * @param response     xx
     * @throws IOException        xx
     * @throws URISyntaxException xx
     */
 public static void generateDocNew(String templateName, Object dataMap, String fileName, HttpServletResponse response) throws IOException, URISyntaxException {
        // 模板document.xml名和docx名保持一致
        Template template = FM_CONFIG.getTemplate(templateName + ".ftl");
        URI path = FileUtil.class.getResource("/doc/" + templateName + ".docx").toURI();

        response.setContentType("application/octet-stream");
        // 编码文件名,防止文件名乱码
        response.setHeader("Content-disposition", "attachment; filename="
                + URLEncoder.encode(fileName, "UTF-8"));

        BufferedInputStream buffInputStream = null;
        OutputStreamWriter writer = null;

        // 不关闭ZipOutputStream会在web下载时数据格式出错,即未调用close方法会导致文件数据流末尾的格式数据未写入
        try (ZipFile zipFile = new ZipFile(path.getPath());
             ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(path.getPath())));
             ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()))
        ) {
            ZipEntry zipEntry;

            while ((zipEntry = zis.getNextEntry()) != null) {
                // 只需要zipEntry的名称,其他的根据具体的文件自动进行设置,不要直接传入zipEntry防止closeEntry时校验数据失败
                zos.putNextEntry(new ZipEntry(zipEntry.toString()));
                if ("word/document.xml".equals(zipEntry.getName())) {
                    ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
                     // 防止服务器默认编码造成问题
                    writer = new OutputStreamWriter(byteOut, StandardCharsets.UTF_8);

                    template.process(dataMap, writer);
                    zos.write(byteOut.toByteArray());
                    writer.close();
                } else {
                    buffInputStream = new BufferedInputStream(zipFile.getInputStream(zipEntry));
                    byte[] b = new byte[1024];
                    int len;
                    while ((len = buffInputStream.read(b)) != -1) {
                        //读取len长度,防止写入默认初始化值0
                        zos.write(b, 0, len);
                    }
                    buffInputStream.close();
                }

                zis.closeEntry();
                zos.closeEntry();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (buffInputStream != null) {
                buffInputStream.close();
            }
            if (writer != null) {
                writer.close();
            }
        }
    }
}

依赖Maven

       <!-- Freemarker-->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.28</version>
        </dependency>

因需求简单暂时只实现目前的效果。

参考:java使用freemarker模板导出word(docx格式;流形式输入输出)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值