• 【java】poi-tl 1.9.1 word模板插入文本及动态复杂表格



    前言

    • word生成是较为常见的功能,通常解决方案有freemarker、poi-tl等。
    • 一般常规的word模板替换可采用第三方封装好的工具实现。
    • 本文涉及动态复杂表格的插入,最好还是采用poi-tl。
    • poi-tl版本差异性较大,如果被版本束缚,较难找到对应版本的copy代码,这时候可以参考其他版本再对照自己版本的jar包文件来对应实现。
      poi 与 poi-tl 版本对应关系 http://deepoove.com/poi-tl

    一、需求

    根据模板生成对应的word文件。

    1. 包含文本替换
    2. 动态表格,涉及动态合并单元格
    3. word中包含分割线的图片
      前期难点在于动态表格的绘制和锚点替换,后期难点在于poi-tl版本约束(由于某些原因,必须用1.9.1版本)。

    二、方案

    1. poi 从头到尾画(即时这个word并不大,code硬编码起来也较为复杂,主要是比较难受,还要考虑各种样式,图片插入等)
    2. 拼html写入word(同上的硬编码较为麻烦,但样式结构可以word另存html后直接用,代码和word打开后的模式不友好,默认为web模式)
    3. 死磕poi-tl

    三、实现

    1.生成word 关键代码

    //构建模板替换的map对象
    Map<String, Object> dataMap = wordMaps(findDTO);
    //获取模板信息等
    String fileName = UUIDUtil.uuid() + ".docx";
    String midPath = "uploadFile" + File.separator + "duty" + File.separator;
    String filePath = fileUploadRoot + midPath;
    String templatePath = this.getFullPathName("evaluate.docx");
    //主要执行代码 指定替换内容形式为${xxxx},指定${table}标签的渲染规则为DetailTablePolicy
    Configure builder = Configure.newBuilder().buildGramer("${", "}").bind("table", new DetailTablePolicy()).build();
    XWPFTemplate template = XWPFTemplate.compile(templatePath, builder).render(dataMap);
    try {
        template.writeToFile(filePath + fileName);
        template.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.自定义规则类

    package com.gsafety.gemp.evaluate.manage.rule.impl;
    
    import com.deepoove.poi.XWPFTemplate;
    import com.deepoove.poi.data.MergeCellRule;
    import com.deepoove.poi.data.RowRenderData;
    import com.deepoove.poi.data.TableRenderData;
    import com.deepoove.poi.data.Tables;
    import com.deepoove.poi.data.style.TableStyle;
    import com.deepoove.poi.policy.RenderPolicy;
    import com.deepoove.poi.policy.TableRenderPolicy;
    import com.deepoove.poi.policy.TextRenderPolicy;
    import com.deepoove.poi.template.ElementTemplate;
    import com.deepoove.poi.template.run.RunTemplate;
    import com.deepoove.poi.xwpf.NiceXWPFDocument;
    import lombok.SneakyThrows;
    import org.apache.poi.xwpf.usermodel.XWPFRun;
    import org.apache.poi.xwpf.usermodel.XWPFTable;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Set;
    import java.util.stream.Collectors;
    
    /**
     * @author Mr.wanter
     * @time 2022-9-7 0007
     * @description
     */
    public class DetailTablePolicy implements RenderPolicy {
    
        @SneakyThrows
        @Override
        public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
            NiceXWPFDocument doc = template.getXWPFDocument();
            RunTemplate runTemplate = (RunTemplate) eleTemplate;
            XWPFRun run = runTemplate.getRun();
            if (null == data) {
                return;
            }
            List<RowRenderData> rows = (List<RowRenderData>) data;
            TableStyle.BorderStyle borderStyle = new TableStyle.BorderStyle();
            borderStyle.setColor("A6A6A6");
            borderStyle.setSize(4);
            borderStyle.setType(XWPFTable.XWPFBorderType.SINGLE);
            TableRenderData tableRenderData = Tables.ofA4MediumWidth()
                    .border(borderStyle).center()
                    .create();
            rows.forEach(r -> {
                tableRenderData.addRow(r);
            });
    
            MergeCellRule.MergeCellRuleBuilder mergeCellRuleBuilder = MergeCellRule.builder();
            /**
             * 设置表格合并规则
             * 1.起始行 MergeCellRule.Grid.of(i, j) i: 行 j: 列
             * 2.结束行 MergeCellRule.Grid.of(i, j) i: 行 j: 列
             */
            //评估对象合并
            mergeCellRuleBuilder.map(MergeCellRule.Grid.of(1, 0), MergeCellRule.Grid.of(rows.size() - 1, 0));
            List<String> subTargetContent = new ArrayList<>();
            rows.forEach(r -> {
                subTargetContent.add(r.getCells().get(1).getParagraphs().get(0).getContents().get(0).toString());
            });
            Set<String> set = subTargetContent.stream().collect(Collectors.toSet());
            set.forEach(s -> {
                //只有重复的合并,获取到需要合并项的列的行起始索引后进行合并
                if (subTargetContent.stream().filter(st -> s.equals(st)).count() > 1) {
                    mergeCellRuleBuilder.map(MergeCellRule.Grid.of(subTargetContent.indexOf(s), 1), MergeCellRule.Grid.of(subTargetContent.lastIndexOf(s), 1));//评估项合并
                    mergeCellRuleBuilder.map(MergeCellRule.Grid.of(subTargetContent.indexOf(s), 4), MergeCellRule.Grid.of(subTargetContent.lastIndexOf(s), 4));//权重合并
                }
            });
    
            /**
             * MergeCellRule支持多合并规则,会以Map的形式存入可以看一下源码
             * !!! 一定要设置完规则后再调用 MergeCellRule的build方法进行构建
             */
            tableRenderData.setMergeRule(mergeCellRuleBuilder.build());
            TableRenderPolicy.Helper.renderTable(run, tableRenderData);
            //todo 如果不加入下面代码生成的word会保留模板中的${table}
            TextRenderPolicy.Helper.renderTextRun(run, "");
        }
    }
    
    • 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

    3.效果展示
    在这里插入图片描述
    在这里插入图片描述

    总结

    poi版本差异较大,很难拿来即用。
    参考:https://blog.csdn.net/weixin_45051216/article/details/112471339解决了:

    1. table样式
    2. RowRenderData的构建方式。
    3. 合并单元格

    表格渲染失败(不知道是不是版本问题),最终还是要仔细看jar包中都有哪些类和方法,根据文件名一点一点研究出来。渲染table的关键:TableRenderPolicy.Helper.renderTable(run, tableRenderData)

    在这里插入图片描述

  • 相关阅读:
    基于北方苍鹰优化算法的函数寻优算法
    MyBatis中#{}和${}的不同之处是什么呢?
    python基于django或flask开发的健身俱乐部网站rix1z
    CS资质证书获证后企业需要注意哪些问题?
    Kotlin 中注解 @JvmOverloads 的作用
    请讲一讲JS中的 for...in 与 for...of (下)
    【操作系统】进程管理
    c++知识点
    在Linux中tomcat占用内存过高可以通过导出hprof日志来解决
    第5讲 使用pytorch实现线性回归
  • 原文地址:https://blog.csdn.net/zhanghuaiyu_35/article/details/126763195