最近弄一个业务需要搞很多的word文档导出,供前端下载。之前的实现方式一般是先把word转成XML格式,然后赋值变量,这种方式虽然可行,但是遇到那种长篇且变量又多的文档,就很让人头大,密密麻麻的一堆代码,看着十分繁乱,不好修改模板。于是在技术选型上找到了XDocReport,该技术可以直接使用word文档作为模板,使用Velocity或Freemarker语法来设置要替换的变量,从而实现复杂的文档导出。
一.XDocReport技术Java实现
使用该模板的操作主要是 IXDocReport 和 IContext 对象,封装两个工具类来对他们进行获取和操作,用 IContext 的 put(key,value)赋值模板变量即可
 //获取Word模板,模板存放路径在项目的resources目录下template文件夹
 InputStream ins = this.getClass().getClassLoader().getResourceAsStream("template" +
             File.separator + "test.docx");
 IXDocReport report = XDocReportRegistry.getRegistry().loadReport(ins,
             TemplateEngineKind.Freemarker);
//创建xdocreport上下文对象
IContext context = report.createContext();
//创建字段元数据
FieldsMetadata fm = report.createFieldsMetadata();
//1.业务逻辑
//2.模板传递参数
//2.1集合变量
context.put("certList", certificateList);
fm.load("certList", CbgkShipCertificate.class, true);
//2.2实体变量
context.put("cancelCertify", cancelCertifyVO);
fm.load("cancelCertify", CbgkCancelCertifyVO.class, false);
//2.3单一变量
context.put("moreCatalog", 0);
//2.4图片变量
fm.addFieldAsImage("imgUrl");
File file = UrltoFile(personImage.getUrl());     //该方法在下头
IImageProvider iImageProvider = new FileImageProvider(file, false);
context.put("imgUrl", iImageProvider);
report.setFieldsMetadata(fm);
response.setContentType("application/msword");
response.setCharacterEncoding("UTF-8");
String fileName = URLEncoder.encode(peopleInfoVO.getName() + "综合材料.docx", "UTF-8");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
try (ServletOutputStream outputStream = response.getOutputStream()) {
      report.process(context, outputStream);
      outputStream.flush();
}
    /**
     * 将Url转换为File
     * @param url
     * @return
     * @throws Exception
     */
    public static File UrltoFile(String url) throws Exception {
        log.error("图片的url: " + url);
        InputStream ins = null;
        File file = null;
        OutputStream os = null;
        HttpURLConnection httpUrl = null;
        try {
            httpUrl = (HttpURLConnection) new URL(url).openConnection();
            httpUrl.setConnectTimeout(300000);
            httpUrl.setReadTimeout(300000);
            httpUrl.setRequestProperty("Content-Length", "1000");
            httpUrl.connect();
            ins = httpUrl.getInputStream();
            file = new File(System.getProperty("java.io.tmpdir") + File.separator + "seat" + System.currentTimeMillis());
            if (file.exists()) {
                file.delete();
            }
            os = new FileOutputStream(file);
            int bytesRead;
            int len = 8192;
            byte[] buffer = new byte[len];
            while ((bytesRead = ins.read(buffer, 0, len)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
        } catch (IOException e) {
            log.error("地址请求不可用或响应超时");
            e.printStackTrace();
        } finally {
            os.close();
            ins.close();
            if (httpUrl != null) {
                httpUrl.disconnect();
            }
        }
        return file;
    }二.Word模板的制作
2.1 新建word文档,在需要替换变量位置的地方键盘Ctrl + F9,鼠标右击编辑域,选择邮件合并类型,输入"MERGEFIELD ${name}"

2.2 插入模板图片

插入图片书签,调整尺寸大小,方便变量替换


模板制作的基操基本如此,就不详细介绍了,这边的变量赋值的控制语言作者是使用的Freemarker,如需要复杂实现的可以百度了解下这个模板引擎的语句。这里作者提供一些常见的语句参考。
//1.判断catalogFirstList集合非空则遍历该集合,单实体使用别名catalog
MERGEFIELD @before-row[#if (catalogFirstList)??][#list catalogFirstList as catalog]
MERGEFIELD ${catalog.name!}
MERGEFIELD @after-row[/#list][/#if]
//2.if语句
MERGEFIELD [#if (notarize.purpose)??][#if notarize.purpose=='其它船舶']☑[#else]□[/#if][#else]□[/#if]
MERGEFIELD [#if shipownerType == '0']
MERGEFIELD [/#if]
//3.大于等于
MERGEFIELD [#if shipPicSize gte 1]
//4.大于
MERGEFIELD [#if shipPicSize > 0]
5.或运算
MERGEFIELD [#if shipowner.type == '1' || shipowner.type == '0']
6.时间格式化(防止非空报错)
MERGEFIELD [#if (record.takeOverTime)??]
MERGEFIELD ${record.takeOverTime?string('yyyy-MM-dd HH:mm:ss')}
MERGEFIELD [/#if]
7.单个变量防止空指针
MERGEFIELD ${notarize.name!} 

















![[bug] 记录version `GLIBCXX_3.4.29‘ not found 解决方法](https://img-blog.csdnimg.cn/340321d324154ed5a7991073959c0df8.png)

