精华内容
下载资源
问答
  • poi导出word 合并自定义表格,自定义标题,更新目录

    poi-tl 入门示例

    可参照poi-tl 官方api文档:poi-tl
    引入maven 后

    							<dependency>
    							  <groupId>com.deepoove</groupId>
    							  <artifactId>poi-tl</artifactId>
    							  <version>1.11.0</version>
    							</dependency>
    

    1.准备word模板

    word模板的内容

    2.代码

      public class PoiTest {
       public static void main(String[] args) throws IOException {
            //要写入模板的数据
            Map<String,Object> exampleData = new HashMap<>();
            exampleData.put("username","admin");
            exampleData.put("password","123456");
            FileInputStream inputStream = new FileInputStream("D:/test_word/example1.docx");
            XWPFTemplate template = XWPFTemplate.compile(inputStream)
                    .render(exampleData);
            //文件输出流
            FileOutputStream out = new FileOutputStream("D:/test_word/example1.docx");
            template.write(out);
            out.flush();
            out.close();
            template.close();
        }
    }
    

    自定义列表序号

    1. poi-tl 支持的序号列表,直接使用文档种说明即可

    poi-tl支持的序号列表

    2. 要是没有,可以利用NumberingFormat类去生成指定的样式;例如生成 a) b)的序号

    要生成的列表序号样式

    3. 同样按照官方api指定{{*var}}后

    4. 具体代码如下

    public class test {
    
    
        public static void main(String[] args) throws IOException {
            //要写入模板的数据
            Map<String, Object> datas1 = new HashMap<String, Object>();
            //列表集合
            List<String> varList = Arrays.asList("序号1",
                    "序号2");
    
            //自定义序号的样式为  a)  b)  c)
            NumberingFormat.Builder builder = NumberingFormat.
                    builder("%{0})") //%{0}) 可以指定自己需要的样式
                    .withNumFmt(NumFormat.LOWER_LETTER);  //小写字母
            NumberingFormat numberingFormat = builder.build(0);
            Numberings.NumberingBuilder of = Numberings.of(numberingFormat);//a)  b)  c)
            //列表 数据赋值
            varList.forEach(s -> of.addItem(s));
            NumberingRenderData numberingRenderData = of.create();
            datas1.put("var", numberingRenderData);
            XWPFTemplate.compile("D:/test_word/test.docx")
                    .render(datas1).writeToFile("D:/test_word/test1.docx");
        }
    }
    

    自定义表格宽度和表格合并

    poi-tl导出的word表格默认宽度是自适应的,若是想要指定列的宽度增加,可以采用如下方式:
    最终实现的word表格
    

    word表格

    1. 在word模板文件中,生成表格位置添加标签:{{#check_table}}

    2. 具体整体代码如下

     public class test {
    
    
        public static void main(String[] args) throws IOException {
    
            Map<String, Object> datas = new HashMap<String, Object>();
            // create table
            //word的 表格
            List tableList = new ArrayList<>();
            tableList.add("数据1");
            tableList.add("数据2");
            tableList.add("数据3");
            tableList.add("数据4");
            tableList.add("数据5");
            tableList.add("数据6");
            //验证类型集合
            List<String> typeList = Arrays.asList("MC0",
                    "MC1",
                    "MC2",
                    "MC3",
                    "MC4",
                    "MC5",
                    "MC6",
                    "MC7",
                    "MC8",
                    "MC9");
            //表头是两行
            //第一行数据是固定内容 "序号", "章节号", "项目", "内容", "验证方法", "备注"
            List<String> headerCellListTemp1 = Arrays.asList("序号", "章节号", "项目", "内容", "验证方法");
            List<String> headerCellList1 = new ArrayList<>(headerCellListTemp1);
            //验证方法,可能是多列数据  第一列是验证方法,后面是赋空字符串,用于合并单元格;
            //数据类型:验证方法 "" "" ""
            //验证类型长度
            int typeListSize = typeList.size();
            for (int k = 0; k < typeListSize - 1; k++) {
                headerCellList1.add(" "); //赋空字符串
            }
            headerCellList1.add("备注");
    
            String[] headerCell1 = headerCellList1.toArray(new String[headerCellList1.size()]);
    
            RowRenderData header1 = Rows.of(headerCell1).center().create();
    
    
            //headerCell2 :验证方法对应列,是动态内容
            List<String> headerCellListTemp2 = Arrays.asList("序号", "章节号", "项目", "内容");
            List<String> headerCellList2 = new ArrayList<>(headerCellListTemp2);
            // 验证方法对应列
            headerCellList2.addAll(typeList);
            //备注对应的列 赋空值
            headerCellList2.add(" ");
    
            String[] headerCell2 = headerCellList2.toArray(new String[headerCellList2.size()]);
            RowRenderData header2 = Rows.of(headerCell2).center().create();
            //表格 列的数量
            int cellLength = headerCell1.length;
    
            //无数据只有表头数据 tableList 无值
            if (CollectionUtil.isEmpty(tableList)) {
                RowRenderData[] RowRenderDataHeader = new RowRenderData[2];
                RowRenderDataHeader[0] = header1;
                RowRenderDataHeader[1] = header2;
    
                TableRenderData check_table = setTableRenderDataAndColWidth(RowRenderDataHeader, cellLength);
    
    
                // table 只有表头数据
                datas.put("check_table", check_table);
            } else {
                int length = 2 + tableList.size();
                //行数据 数组
                RowRenderData[] RowRenderData = new RowRenderData[length];
    
                RowRenderData[0] = header1;
                RowRenderData[1] = header2;
    
                for (int i = 0; i < tableList.size(); i++) {
    
                    String index = Integer.toString(i + 1);
                    List<String> tempList = Arrays.asList("A", "B", "C",
                            "D", "E", "F", "G", "H", "I", "G");
    
                    String[] cellString = new String[cellLength];
                    cellString[0] = index; //序号
                    cellString[1] = "5.1.1";//标题序号
                    cellString[2] = "项目"; // 项目
                    cellString[3] = "说明"; //内容 : 描述
                    //验证方法对应数据赋值
                    if (headerCell2.length > 4) {
                        for (int j = 0; j < tempList.size(); j++) {
                            cellString[j + 4] = tempList.get(j);
                        }
                    }
    
                    //备注
                    cellString[cellLength - 1] = "备注";
                    RowRenderData rowRenderData = Rows.of(cellString).
                            center().create();
                    //行数据赋值
                    RowRenderData[2 + i] = rowRenderData;
    
                }
                TableRenderData check_table = setTableRenderDataAndColWidth(RowRenderData, cellLength);
                // table
                datas.put("check_table", check_table);
    
    
            }
            XWPFTemplate.compile("D:/test_word/test.docx")
                    .render(datas).writeToFile("D:/test_word/test1.docx");
        }
    
        /**
         * 表格赋值,
         * 设置列宽和合并单元格
         *
         * @param rowRenderDataArray
         * @param cellLength
         * @return
         */
        private static TableRenderData setTableRenderDataAndColWidth(RowRenderData[] rowRenderDataArray, Integer cellLength) {
            //table赋值set方法需要list
            List<RowRenderData> RowRenderDataList = Arrays.asList(rowRenderDataArray);
            //设置列宽:
            double[] colWidthsCm = new double[cellLength];
            for (int i = 0; i < cellLength; i++) {
                // "章节号", "项目", "内容" 设置为 2
                if (i == 1 || i == 2 || i == 3) {
                    colWidthsCm[i] = 2D;
                } else {
                    colWidthsCm[i] = 1D;
                }
            }
            //18.450000762939453D A4纸张
            TableRenderData check_table = Tables.ofWidth(18.450000762939453D, colWidthsCm).center().create();
            check_table.setRows(RowRenderDataList);
            //合并单元格
            MergeCellRule.MergeCellRuleBuilder mergeCellRuleBuilder = mergeCell(cellLength);
            check_table.setMergeRule(mergeCellRuleBuilder.build());
    
            return check_table;
        }
        /**
         * 表格 合并单元格
         *
         * @param cellLength
         * @return
         */
        private static MergeCellRule.MergeCellRuleBuilder mergeCell(Integer cellLength) {
            /**
             * 设置表格合并规则 从0开始
             * 1.起始行 MergeCellRule.Grid.of(i, j) i: 行 j: 列
             * 2.结束行 MergeCellRule.Grid.of(i, j) i: 行 j: 列
             */
            //合并单元格
            //合并到【备注】前一列
            MergeCellRule.MergeCellRuleBuilder mergeCellRuleBuilder = MergeCellRule.builder();
            mergeCellRuleBuilder.map(MergeCellRule.Grid.of(0, 0), MergeCellRule.Grid.of(1, 0));//序号合并
            mergeCellRuleBuilder.map(MergeCellRule.Grid.of(0, 1), MergeCellRule.Grid.of(1, 1));//章节号合并
            mergeCellRuleBuilder.map(MergeCellRule.Grid.of(0, 2), MergeCellRule.Grid.of(1, 2));//项目合并
            mergeCellRuleBuilder.map(MergeCellRule.Grid.of(0, 3), MergeCellRule.Grid.of(1, 3));//内容合并
            mergeCellRuleBuilder.map(MergeCellRule.Grid.of(0, 4), MergeCellRule.Grid.of(0, cellLength - 2));//验证类型合并 第一行
            mergeCellRuleBuilder.map(MergeCellRule.Grid.of(0, cellLength - 1), MergeCellRule.Grid.of(1, cellLength - 1));//备注合并
            return mergeCellRuleBuilder;
        }
    
    }
    

    3. 设置表格宽度 setTableRenderDataAndColWidth

      /**
         * 表格赋值,
         * 设置列宽和合并单元格
         *
         * @param rowRenderDataArray
         * @param cellLength
         * @return
         */
        private static TableRenderData setTableRenderDataAndColWidth(RowRenderData[] rowRenderDataArray, Integer cellLength) {
            //table赋值set方法需要list
            List<RowRenderData> RowRenderDataList = Arrays.asList(rowRenderDataArray);
            //设置列宽:
            double[] colWidthsCm = new double[cellLength];
            for (int i = 0; i < cellLength; i++) {
                // "章节号", "项目", "内容" 设置为 2 ;这几列宽度大
                if (i == 1 || i == 2 || i == 3) {
                    colWidthsCm[i] = 2D;
                } else {
                    colWidthsCm[i] = 1D;
                }
            }
            //18.450000762939453D A4纸张
            TableRenderData check_table = Tables.ofWidth(18.450000762939453D, colWidthsCm).center().create();
            check_table.setRows(RowRenderDataList);
            //合并单元格
            MergeCellRule.MergeCellRuleBuilder mergeCellRuleBuilder = mergeCell(cellLength);
            check_table.setMergeRule(mergeCellRuleBuilder.build());
    
            return check_table;
        }
    

    4. 表格合并方法 mergeCell

     /**
         * 表格 合并单元格
         *
         * @param cellLength
         * @return
         */
        private static MergeCellRule.MergeCellRuleBuilder mergeCell(Integer cellLength) {
            /**
             * 设置表格合并规则 从0开始
             * 1.起始行 MergeCellRule.Grid.of(i, j) i: 行 j: 列
             * 2.结束行 MergeCellRule.Grid.of(i, j) i: 行 j: 列
             */
            //合并单元格
            //合并到【备注】前一列
            MergeCellRule.MergeCellRuleBuilder mergeCellRuleBuilder = MergeCellRule.builder();
            mergeCellRuleBuilder.map(MergeCellRule.Grid.of(0, 0), MergeCellRule.Grid.of(1, 0));//序号合并 上下行合并
            mergeCellRuleBuilder.map(MergeCellRule.Grid.of(0, 1), MergeCellRule.Grid.of(1, 1));//章节号合并
            mergeCellRuleBuilder.map(MergeCellRule.Grid.of(0, 2), MergeCellRule.Grid.of(1, 2));//项目合并
            mergeCellRuleBuilder.map(MergeCellRule.Grid.of(0, 3), MergeCellRule.Grid.of(1, 3));//内容合并
            mergeCellRuleBuilder.map(MergeCellRule.Grid.of(0, 4), MergeCellRule.Grid.of(0, cellLength - 2));//验证类型合并 第一行
            mergeCellRuleBuilder.map(MergeCellRule.Grid.of(0, cellLength - 1), MergeCellRule.Grid.of(1, cellLength - 1));//备注合并
            return mergeCellRuleBuilder;
        }
    
    

    自定义标题

    标题可以采用原生poi生成,这里实现利用的是poi-tl的Markdown插件中的标题;
    最终生成的样式如下
    在这里插入图片描述

    1. word模板内容如下

    {{?comment}}
    Heading1简介
    Heading2简介
    Heading3简介
    Heading4简介
    Heading5简介
    {{/comment}}
    {{md}}

    黑色内容是word模板上的内容
    在这里插入图片描述 ## 2. md文件内容如下
    在这里插入图片描述

    3. 需要生成的标题按照md文件格式拼接为字符串即可

    代码如下:

    public class test {
    
    
        public static void main(String[] args) throws IOException {
            //要写入模板的数据
            Map<String, Object> datas = new HashMap<String, Object>();
            //标题的数据  需要按照md文件,标题的格式拼接数据
            MarkdownRenderData code = new MarkdownRenderData();
    //        byte[] bytes = Files.readAllBytes(Paths.get("src/test/resources/markdown/basic1.md"));
    //        String mkdn = new String(bytes);
            String mkdn = "### Heading 31\n" +
                    "#### Heading 41\n" +
                    "### Heading 32\n" +
                    "#### Heading 42";
            code.setMarkdown(mkdn);
    
            MarkdownStyle style = MarkdownStyle.newStyle();
            style.setShowHeaderNumber(true); //设置标题序号
            code.setStyle(style);
    
            //标题的数据
            datas.put("md", code);
            Configure config = Configure.builder().bind("md", new MarkdownRenderPolicy()).build();
            XWPFTemplate.compile("src/test/resources/template_finnish/test_title.docx", config)
                    .render(datas)
                    .writeToFile("src/test/resources/out/out_markdown2.docx");
        }
    

    生成标题其他注意点

    1. 自己指定生成标题序号开始位置:重写DocumentVisitor.class 类

    下面的内容是修改后的内容:
    直接标题赋值时指定值:在这里插入图片描述
    或者是修改原生的getHeaderNumber() 方法

       private String getHeaderNumber(int level) {
            if (level == 1) return "";
            String str = StringUtils.join(Arrays.
                    copyOfRange(headerNumberArray, 2, headerNumberArray.length), '.');
            String substring = str.substring(0, (level - 1) * 2 >= str.length() ? str.length() : (level - 1) * 2);
            //目前是 5.2.1.
            //去除标题序号的.    保持和文档上一致 类似这种5.2.1
            if (StringUtils.isNotEmpty(substring)) {
                substring = substring.substring(0, substring.length() - 1);
            }
    
            return substring + " ";
        }
    

    2. 自动生成标题的样式,也可以按照自己想要的方式设置

    方式是修改DocumentVisitor 类中的visit()方法
    代码如下:展示的代码都是自己修改后的

       @Override
        public void visit(Heading heading) {
            int level = heading.getLevel();
            resetHeaderNumberArray(level);
    
            ParagraphBuilder paraOf = Paragraphs.of().styleId(String.valueOf(level)).left().allowWordBreak();
            if (style.isShowHeaderNumber()) {
                paraOf.addText(Texts.of(getHeaderNumber(level)).style(getStyle(level)).create());
            }
            DocumentRenderData renderData = parseNode(heading);
            if (!renderData.getContents().isEmpty()) {
                ParagraphRenderData headerParagraph = (ParagraphRenderData) renderData.getContents().get(0);
               // paraOf.addParagraph(headerParagraph);
               // paraOf.addText(Texts.of("").bookmark(evalText(headerParagraph)).create());
                paraOf.addText(Texts.of(evalText(headerParagraph)).style(getStyle(level)).create());
            }
            of.addParagraph(paraOf.create());
        }
    
    /**
         * 自定义标题的样式;
         * 不使用该方法,标题样式都是标签{{md}}的样式
         *
         * @param level
         * @return
         */
    
        private Style getStyle(int level) {
            Style style = null;
            switch (level) {
                case 2: //标题1
                    style = new Style("宋体", 22D); //二号字体
                    break;
                case 3: //标题2
                    style = new Style("宋体", 16D);//三号字体
                    break;
                case 4: //标题3
                    style = new Style("宋体", 14D);//四号字体
                    break;
                //其他都是4号字体
                default:
                    style = new Style("宋体", 14D);//二号字体
                    break;
            }
            return style;
        }
    

    上述代码中,getStyle方法用于指定自己想要修改的样式

    更新目录 (wps 不支持,只支持office)

    网上搜到的方式,直接采用该方法,可以生成并且更新目录

    转载链接如下:
    转载生成poi目录

    poi-tl的方式

    word模板添加标签 {{TOC}}

    在这里插入图片描述

    代码如下

    public class AutoMenuWordPoi {
    
    
        public static void main(String[] args) throws IOException, InvalidFormatException {
    
    
            //要写入模板的数据
            Map<String, Object> datas = new HashMap<String, Object>();
            datas.put("TOC", "TOC");
            Configure config = Configure.builder().bind("TOC", new TOCRenderPolicy()).build();
    
    
            XWPFTemplate.compile("src/test/resources/out/out_markdownToc_poi.docx", config)
                    .render(datas)
                    .writeToFile("src/test/resources/out/out_menu1.docx");
    
    
    
        }
    
    
    }
    

    也可以word已经生成目录,后面只是修改了添加标题,去更新目录

    采用如下代码也可以:

    public class AutoMenuWord2 {
        private static final String HEADING1 = "1";
    
        public static void main(String[] args) throws IOException, InvalidFormatException {
    
    
            XWPFDocument doc = new XWPFDocument(new FileInputStream("src/test/resources/out/out_markdown2.docx"));
            doc.enforceUpdateFields(); // 更新目录
    
    
    
    
            doc.write(new FileOutputStream("src/test/resources/out/out_markdown3.docx"));
            doc.close();
    
    
        }
    

    }

    展开全文
  • 学习分享:POI-TL 导出Word复杂表格合并分享

    千次阅读 多人点赞 2021-01-11 15:39:35
    学习分享:POI-TL 导出Word合并表格 文章目录学习分享:POI-TL 导出Word合并表格关于POI-TL 导出Word的一些使用一、前期准备?二、代码演示1.数据结构2.代码示例2.1 写入表头表体的数据2.2 设置合并规则2.3 输出结果...


    关于POI-TL 导出Word的一些使用

    最近在做项目时候遇到的一个关于导出Word的文件的需求,简单的数据展示可以根据POI-TL的官方的文档还是可以做出来的,但是有一些表格的合并处理poi-tl只是给了简单例子,前期的学习可以参考POI-TL(http://deepoove.com/poi-tl/)官方文档,及给出的一些简单的源码(https://github.com/Sayi/poi-tl),话不多说上代码


    提示:以下是本篇文章正文内容,下面案例可供参考

    一、前期准备?

    <font color=#999AAA

    Apache POI 4.1.2+
    JDK 1.8+

    这个地方需要注意的是:要根据自己项目的JDK来引入的对应版本的,POI-TL 官方给出来的JDK对应的版本要求
    在这里插入图片描述

    二、代码演示

    1.数据结构

    public class DocData {
        private String title;
        private String date;
        private TableRenderData renderData;
    }
    

    在这里插入图片描述

    GET SET方法就省略了,这个数据结构换成你自己需要的数据结构就可以了,图片是对应的WORD 模板,{{}}里面放入对象中对应的属性,{{#}}是获取TableRenderData 表格数据的方式,这些都可以在POI-TL官方学习到

    2.代码示例

    2.1 写入表头表体的数据

    		DocData docData = new DocData();
            TableRenderData renderData = new TableRenderData();
            //设置的合并规则
            MergeCellRule.MergeCellRuleBuilder mergeCellRuleBuilder = MergeCellRule.builder();
            //设置表头
            RowRenderData header = Rows.of("姓名", "特长", "是否获奖").bgColor("F2F2F2").center()
                    .textColor("7F7f7F").textFontFamily("Hei").textFontSize(9).create();
            //表体内容
            RowRenderData row = Rows.of("小红", "游泳", "否").center().create();
            RowRenderData row1 = Rows.of("小红", "钢琴", "八级").center().create();
            RowRenderData row2 = Rows.of("小红", "围棋", "否").center().create();
            RowRenderData row3 = Rows.of("小明", "游泳", "全国一等奖").center().create();
            RowRenderData row4 = Rows.of("小明", "击剑", "无").center().create();
            RowRenderData row5 = Rows.of("小梅", "围棋", "无").center().create();
            RowRenderData row6 = Rows.of("小梅", "跆拳道", "黑带").center().create();
            RowRenderData row7 = Rows.of("小梅", "长跑", "国家一级运动员").center().create();
            RowRenderData row8 = Rows.of("小梅", "举重", "无").center().create();
            RowRenderData row9 = Rows.of("小刚", "脸特长", "").center().create();
    

    可以看出我们设置了表头内容分别是姓名、特长、获奖情况。姓名是重复的数据,我们希望将相同的姓名合并在一起,我们需要用到 **MergeCellRule.MergeCellRuleBuilder mergeCellRuleBuilder = MergeCellRule.builder();**设置合并的规则

    2.2 设置合并规则

    代码中标明注释,表格的合并根据自己的需求去设置规则。

    		//设置样式颜色尺寸等等
            TableStyle.BorderStyle borderStyle = new TableStyle.BorderStyle();
            borderStyle.setColor("A6A6A6");
            borderStyle.setSize(4);
            borderStyle.setType(XWPFTable.XWPFBorderType.SINGLE);
            TableRenderData tableRenderData = Tables.ofA4MediumWidth().addRow(header)
                    .addRow(row).addRow(row1).addRow(row2).addRow(row3).addRow(row4)
                    .addRow(row5).addRow(row6).addRow(row7).addRow(row8).addRow(row9)
                    .border(borderStyle).center()
                    .create();
            /**
             * 设置表格合并规则
             * 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(3, 0));//小红合并
            mergeCellRuleBuilder.map(MergeCellRule.Grid.of(4, 0), MergeCellRule.Grid.of(5, 0));//小明合并
            mergeCellRuleBuilder.map(MergeCellRule.Grid.of(6, 0), MergeCellRule.Grid.of(9, 0));//小梅合并
    
            /**
             * MergeCellRule支持多合并规则,会以Map的形式存入可以看一下源码
             * !!! 一定要设置完规则后再调用 MergeCellRule的build方法进行构建
             */
            tableRenderData.setMergeRule(mergeCellRuleBuilder.build());
    

    2.3 输出结果

    		docData.setTitle("测试测试测试");
            docData.setDate(DateUtil.formatAsDatetime(new Date()));
            docData.setRenderData(tableRenderData);
            File file = ResourceUtils.getFile("D:\\Java\\ideawork\\word\\target\\test-classes\\demo.docx");
            XWPFTemplate template = XWPFTemplate.compile(file).render(docData);
            template.writeToFile("D:\\测试例子.docx");
    

    这里获取的是绝对路径,根据自己WORD模板放在的位置进行获取,输出位置自己设定就好了,最后是我们输出的结果展示,可以看到名字相同的人已经进行了合并。

    在这里插入图片描述


    总结

    第一次分享,不足的地方请指出,需要源码请私信,看到后会及时处理。

    展开全文
  • SpringBoot+Poi-tl根据Word模板动态生成含动态表格的word文档。 Poi-tl官方文档:http://deepoove.com/poi-tl/ 实现过程 1.添加必要依赖 <!-- word导出 --> <!-- poi-tl是基于Apache POI的Word模板引擎。...

    SpringBoot+Poi-tl根据Word模板动态生成含动态行表格的word文档。

    Poi-tl官方文档http://deepoove.com/poi-tl/

    一、实现过程

    1.添加必要依赖

        <!-- word导出 -->
    	<dependency>
    	   <groupId>com.deepoove</groupId>
    		<artifactId>poi-tl</artifactId>
    		<version>1.7.3</version>
    	</dependency>
    	<!--  上面需要的依赖-->
         <dependency>
             <groupId>org.apache.poi</groupId>
             <artifactId>poi-ooxml</artifactId>
             <version>4.1.2</version>
         </dependency>
        <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml-schemas</artifactId>
                <version>4.1.2</version>
            </dependency>
        <dependency>
             <groupId>org.apache.poi</groupId>
             <artifactId>poi</artifactId>
             <version>4.1.2</version>
         </dependency>
    
    	<!-- 对JSP的支持 -->
    	<dependency>
    		<groupId>javax.servlet</groupId>
    		<artifactId>javax.servlet-api</artifactId>
    	</dependency>
    	<dependency>
    		<groupId>org.apache.tomcat.embed</groupId>
    		<artifactId>tomcat-embed-jasper</artifactId>
    	</dependency>
    	<dependency>
    		<groupId>javax.servlet</groupId>
    		<artifactId>jstl</artifactId>
    	</dependency>
    

    2.新建一个word,编写word模板:

    在这里插入图片描述
    把该模板放到项目中的static/template/文件夹下:
    在这里插入图片描述

    3.编写一个controller 类,导出销售订单信息的接口类,供页面请求

    package com.example.word.controller;
    
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.text.DecimalFormat;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Calendar;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.util.ClassUtils;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.servlet.ModelAndView;
    
    import com.deepoove.poi.XWPFTemplate;
    import com.deepoove.poi.config.Configure;
    import com.deepoove.poi.data.PictureRenderData;
    import com.deepoove.poi.policy.HackLoopTableRenderPolicy;
    import com.example.word.common.MoneyUtils;
    
    /**
     * 导出Word
     * @author Administrator
     *
     */
    @RequestMapping("/auth/exportWord/")
    @RestController
    public class ExportWordController {
    
    		/**
    	 * 销售订单信息导出word --- poi-tl(包含动态表格)
    	 * @throws IOException 
    	 */
    	@RequestMapping("/exportDataWord3")
    	public void exportDataWord3(HttpServletRequest request,HttpServletResponse response) throws IOException{
    		try {
    			Map<String, Object> params = new HashMap<>();
    	
    	        // TODO 渲染其他类型的数据请参考官方文档
    	        DecimalFormat df = new DecimalFormat("######0.00");   
    	        Calendar now = Calendar.getInstance(); 
    	        double money = 0;//总金额
    	        //组装表格列表数据
    	        List<Map<String,Object>> detailList=new ArrayList<Map<String,Object>>();
    	        for (int i = 0; i < 6; i++) {
    	        	 Map<String,Object> detailMap = new HashMap<String, Object>();
    	        	 detailMap.put("index", i+1);//序号
    	        	 detailMap.put("title", "商品"+i);//商品名称
    	        	 detailMap.put("product_description", "套");//商品规格
    	        	 detailMap.put("buy_num", 3+i);//销售数量
    	        	 detailMap.put("saleprice", 100+i);//销售价格
    	        	
    	        	 double saleprice=Double.valueOf(String.valueOf(100+i));
    	             Integer buy_num=Integer.valueOf(String.valueOf(3+i));
    	             String buy_price=df.format(saleprice*buy_num);
    	             detailMap.put("buy_price", buy_price);//单个商品总价格
    	             money=money+Double.valueOf(buy_price);
    	             
    	             detailList.add(detailMap);
    	        }
    	        //总金额
    	        String order_money=String.valueOf(money);
    	        //金额中文大写
    	        String money_total = MoneyUtils.change(money);
    	      	
    	      	//word模板地址获取方式一:缺点---打jar包获取不到该路径
    //	      	String basePath=ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/template/";
    //	      	String resource =basePath+"order1.docx";//word模板地址
    	        //word模板地址获取方式二:优点---相比上一种方式,这种方法不会在linux或者jar上失效
    	      	ClassPathResource classPathResource = new ClassPathResource("static/template/order1.docx");
    			String resource = classPathResource.getURL().getPath();
    	        //渲染表格
    	        HackLoopTableRenderPolicy  policy = new HackLoopTableRenderPolicy();
    	        Configure config = Configure.newBuilder().bind("detailList", policy).build();
    	        XWPFTemplate template = XWPFTemplate.compile(resource, config).render(
    	        		new HashMap<String, Object>() {{
    			        put("detailList", detailList);
    			        put("order_number", "2356346346645");
    			        put("y", now.get(Calendar.YEAR));//当前年
    			        put("m", (now.get(Calendar.MONTH) + 1));//当前月
    			        put("d", now.get(Calendar.DAY_OF_MONTH));//当前日
    			        put("order_money",order_money);//总金额
    			        put("money_total",money_total);//金额中文大写
    			    }}
    			);
    	        //=================生成文件保存在本地D盘某目录下=================
    	        String temDir="D:/mimi/"+File.separator+"file/word/"; ;//生成临时文件存放地址
    			//生成文件名
    			Long time = new Date().getTime();
    	        // 生成的word格式
    	        String formatSuffix = ".docx";
    	        // 拼接后的文件名
    	        String fileName = time + formatSuffix;//文件名  带后缀
    	        
    	        FileOutputStream fos = new FileOutputStream(temDir+fileName);
    	        template.write(fos);
    	        //=================生成word到设置浏览默认下载地址=================
                // 设置强制下载不打开
                response.setContentType("application/force-download");
                // 设置文件名
                response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
                OutputStream out = response.getOutputStream();
                template.write(out);
                out.flush();
                out.close();
                template.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    	}
    }
    
    

    需要注意的是:
    方法中的代码:

     FileOutputStream fos = new FileOutputStream(temDir+fileName);//输出路径(下载到指定路径)
    

    exportDataWord3方法中的两行代码:

    //浏览器下载
    response.setContentType("application/force-download");
    response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
    

    如果想要显示浏览器下载exportDataWord3方法中的这两行代码必须显示

    5.MoneyUtils 工具类

    package com.example.word.common;
    
    
    /**
     * 金额转换工具类
     */
    public class MoneyUtils {
        private static final String UNIT = "万千佰拾亿千佰拾万千佰拾元角分";
        private static final String DIGIT = "零壹贰叁肆伍陆柒捌玖";
        private static final double MAX_VALUE = 9999999999999.99D;
        public static String change(double v) {
            if (v < 0 || v > MAX_VALUE){
                return "参数非法!";
            }
            long l = Math.round(v * 100);
            if (l == 0){
                return "零元整";
            }
            String strValue = l + "";
            // i用来控制数
            int i = 0;
            // j用来控制单位
            int j = UNIT.length() - strValue.length();
            String rs = "";
            boolean isZero = false;
            for (; i < strValue.length(); i++, j++) {
                char ch = strValue.charAt(i);
                if (ch == '0') {
                    isZero = true;
                    if (UNIT.charAt(j) == '亿' || UNIT.charAt(j) == '万' || UNIT.charAt(j) == '元') {
                        rs = rs + UNIT.charAt(j);
                        isZero = false;
                    }
                } else {
                    if (isZero) {
                        rs = rs + "零";
                        isZero = false;
                    }
                    rs = rs + DIGIT.charAt(ch - '0') + UNIT.charAt(j);
                }
            }
            if (!rs.endsWith("分")) {
                rs = rs + "整";
            }
            rs = rs.replaceAll("亿万", "亿");
            return rs;
        }
     
        public static void main(String[] args){
            System.out.println(MoneyUtils.change(12356789.9845));
        }
    }
    
    

    5.jsp部分代码:

    <a href="#" class="easyui-linkbutton" onclick="doExportWord3();" data-options="iconCls:'icon-save'">导出word(包含动态表格)</a>
    function doExportWord3(){
      window.location.href="<%=basePath%>/auth/exportWord/exportDataWord3";
    }
    

    6.导出结果:
    在这里插入图片描述
    在这里插入图片描述

    二、完整代码

    点击此处获取

    三、功能延伸

    SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格、合并单元格)

    展开全文
  • POI-TL使用及工具类

    千次阅读 2020-04-15 16:16:15
    -- poi-tl --> <!-- http://deepoove.com/poi-tl/ --> <dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> <ver...

    maven依赖

    <!-- poi-tl -->
    		<!-- http://deepoove.com/poi-tl/ -->
    		<dependency>
    			<groupId>com.deepoove</groupId>
    			<artifactId>poi-tl</artifactId>
    			<version>1.7.1</version>
    		</dependency>
    		  <!-- excel工具 -->
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
            </dependency>
    

    工具类所需目录结构:
    在这里插入图片描述
    核心工具类:

    package com.ruoyi.common.utils.poi;
    
    import com.deepoove.poi.XWPFTemplate;
    import com.deepoove.poi.config.Configure;
    import com.deepoove.poi.data.*;
    import com.deepoove.poi.data.style.Style;
    import com.deepoove.poi.data.style.TableStyle;
    import com.ruoyi.common.utils.poi.custom.CustomListRenderPolicyWP;
    import com.ruoyi.common.utils.poi.custom.CustomTableRenderPolicyWP;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
    
    import java.io.FileOutputStream;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * description: PoiTlUtils <br>
     * date: 2020/2/10 14:26 <br>
     * author: <br>
     * version: 1.0 <br>
     */
    public class PoiTlUtils {
    
        public static void main(String[] args){
            Map<String,Object> map = new HashMap<>();
            ArrayList<String[]> strings = new ArrayList<>();
            String[] heard = new String[]{"t1","t2"};
            String[] row1 = new String[]{"r1","r2"};
            String[] row2 = new String[]{"s1","s2"};
            strings.add(row1);
            strings.add(row2);
            MiniTableRenderData miniTableRenderData = list2Table(heard, strings);
            map.put("test",miniTableRenderData);
            try {
                CustomTableRenderPolicy customTableRenderPolicy = new CustomTableRenderPolicy();
                ITableToolsMCImpl tableToolsMC = new ITableToolsMCImpl();
                customTableRenderPolicy.setMergeCells(true);
                customTableRenderPolicy.setiTableToolsMC(tableToolsMC);
                createDocByTemplateName("test.docx","D:\\ruoyi\\resultPath\\test.docx",map,customTableRenderPolicy);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    
        }
    
        /** 功能描述: 根据指定的模板和数据生成docx文件到指定的路径
         * @param templateName
         * @param docPath
         * @param data
        * @return: void
        * @Author: 
        * @Date: 2020/2/20 14:31
        */
        public static void createDocByTemplateName(String templateName,
                                               String docPath,
                                               Object data) throws Exception{
            String docTemplatePath = PoiTlUtils.class.getClassLoader()
                    .getResource("docTemplates/" + templateName).getPath(); // 模板文件的路径
            createDocByTemplate(docTemplatePath,docPath,data,null);
        }
    
        public static void createDocByTemplateName(String templateName,String docPath,
                                               Object data,CustomTableRenderPolicy customTableRenderPolicy) throws Exception{
            String docTemplatePath = PoiTlUtils.class.getClassLoader()
                    .getResource("docTemplates/" + templateName).getPath(); // 模板文件的路径
            createDocByTemplate(docTemplatePath,docPath,data,customTableRenderPolicy);
        }
    
        public static void createDocByTemplate(String docTemplatePath,
                                               String docPath,
                                               Object data,CustomTableRenderPolicy customTableRenderPolicy) throws Exception{
            if(customTableRenderPolicy == null){
                customTableRenderPolicy = new CustomTableRenderPolicy();
                customTableRenderPolicy.setMergeCells(false);
            }
    
            // 自定义表格控件覆盖原有控件
            Configure config = Configure.newBuilder()
                    .addPlugin('#', customTableRenderPolicy)
                    .addPlugin('+', new CustomTableRenderPolicyWP()) // zidingyibaioghhe
                    .addPlugin('>', new CustomListRenderPolicyWP())  // 自定义列表
                    .build();
    
            // 生成报告doc文件
            XWPFTemplate template = XWPFTemplate
                    .compile(docTemplatePath,config)
                    .render(data);
            FileOutputStream out = new FileOutputStream(docPath);
            template.write(out);
            out.flush();
            out.close();
            template.close();
        }
    
    
        public static MiniTableRenderData list2Table(
                String[] headerArr,
                List<String[]> datas){
            // 通用样式
            TableStyle tableStyle = new TableStyle();
            tableStyle.setAlign(STJc.Enum.forInt(2));
    
            RowRenderData header = null;
            if(headerArr != null){
                List<TextRenderData> headerDatas = new ArrayList();
                for (String headerText: headerArr){
                    headerDatas.add(new TextRenderData(headerText));
                }
                 header = new RowRenderData(headerDatas,"eeeeee"); // 表头
            }
    
    
            List<RowRenderData> rows = new ArrayList<>();
            for (String[] dataRow: datas){
                List<TextRenderData> rowData = new ArrayList();
                for (String cellData: dataRow){
                    rowData.add(new TextRenderData( cellData)); // 每行
                }
                RowRenderData row = new RowRenderData(rowData,null); // 行数据
                rows.add(row);
            }
    
    
            MiniTableRenderData tableRenderData = new MiniTableRenderData(header,rows,MiniTableRenderData.WIDTH_A4_MEDIUM_FULL);
    
            return tableRenderData;
        }
    
    
        public static MiniTableRenderData list2Table4Pcr2(
                String[] headerArr,
                List<String[]> datas){
            // 通用样式
            TableStyle tableStyle = new TableStyle();
            tableStyle.setAlign(STJc.Enum.forInt(2));
    
                    RowRenderData header = null;
            if(headerArr != null){
                List<TextRenderData> headerDatas = new ArrayList();
                for (String headerText: headerArr){
                    headerDatas.add(new TextRenderData(headerText));
                }
                 header = new RowRenderData(headerDatas,"d3dce9"); // 表头
            }
    
            String backgroundColor = "ffffff";
            List<RowRenderData> rows = new ArrayList<>();
            for (int i = 0; i < datas.size(); i++) {
                String[] dataRow = datas.get(i);
                List<TextRenderData> rowData = new ArrayList();
                for (String cellData: dataRow){
                    rowData.add(new TextRenderData( cellData)); // 每行
                }
                if (i == datas.size() - 1) backgroundColor = "d3dce9";
                RowRenderData row = new RowRenderData(rowData,backgroundColor); // 行数据
                rows.add(row);
            }
            MiniTableRenderData tableRenderData = new MiniTableRenderData(header,rows,MiniTableRenderData.WIDTH_A4_FULL);
            return tableRenderData;
        }
    
    
        /** 功能描述: map 列表转表格
         * @param headerArr
         * @param cellKeyArr
         * @param mapLists
        * @return: com.deepoove.poi.data.MiniTableRenderData
        * @Author: 
        * @Date: 2020/2/16 16:21
        */
        public static MiniTableRenderData listMap2Table(
                String[] headerArr, String[] cellKeyArr,
                List<Map<String,String>>... mapLists){
    
            List<Map<String,String>> mapList = new ArrayList<>();
            for (List<Map<String,String>> list: mapLists){
                mapList.addAll(list);
            }
    
            // 表头单元格样式
            Style style = new Style();
            style.setBold(true); // 加粗
    
            // 表头样式
            TableStyle headerStyle = new TableStyle();
            headerStyle.setAlign(STJc.Enum.forInt(2)); // 文字居中
            headerStyle.setBackgroundColor("eeeeee");
    
    
            // 内容样式
            TableStyle contentStyle = new TableStyle();
            contentStyle.setAlign(STJc.Enum.forInt(2)); // 文字居中
    
    
            CellRenderData cellRenderData = new CellRenderData();
            List<TextRenderData> headerDatas = new ArrayList();
            for (String headerText: headerArr){
                TextRenderData textRenderData = new TextRenderData(headerText,style);
                headerDatas.add(new TextRenderData(headerText,style));
            }
            RowRenderData header = new RowRenderData(headerDatas,"eeeeee"); // 表头
            header.setRowStyle(headerStyle);
    
    
            List<RowRenderData> rows = new ArrayList<>();
            for (Map<String,String> map: mapList){
                List<TextRenderData> rowData = new ArrayList();
                for (String cellKey: cellKeyArr){
                    rowData.add(new TextRenderData(map.get(cellKey))); // 每行
                }
                RowRenderData row = new RowRenderData(rowData,null); // 行数据
                row.setRowStyle(contentStyle);
                rows.add(row);
            }
    
    
            MiniTableRenderData tableRenderData = new MiniTableRenderData(header,rows,MiniTableRenderData.WIDTH_A4_MEDIUM_FULL);
            tableRenderData.setNoDatadesc("无");
    
            return tableRenderData;
        }
    
    
    
        /* 功能描述: String 列表转带序号的表格
         * @param headerArr 必须是偶数个 [序号 , 名字 ,  序号 , 名字]
         * @param strList
        * @return: com.deepoove.poi.data.MiniTableRenderData
        * @Author: 
        * @Date: 2020/2/15 17:51
        *
        * 例子:  序号  名字   序号  名字
        *         1   张三   3    李四
        *         2   王五   4    赵柳
        */
        public static MiniTableRenderData listStr2TableWithNum(
                String[] headerArr,
                List<String> strList){
    
            Style style = new Style();
            style.setBold(true); // 加粗
    
            // 表头
            List<TextRenderData> headerDatas = new ArrayList();
            for (String headerText: headerArr){
                headerDatas.add(new TextRenderData(headerText,style));
            }
            RowRenderData header = new RowRenderData(headerDatas,"eeeeee"); // 表头
    
    
            // 内容
            // 算出来除去序号多少列
            int leiCount = headerArr.length / 2;
            if (strList.size() < leiCount){
                leiCount = strList.size();
            }
    
            // 算出来应该占多少行
            int hangCount = strList.size()%leiCount==0?strList.size() / leiCount:strList.size() / leiCount +1;
    
            List<RowRenderData> rows = new ArrayList<>();
    
            for (int hangNum = 1; hangNum <= hangCount; hangNum++) {
                int num = hangNum;
                List<TextRenderData> rowData = new ArrayList();
                for (int lieNum = 1; lieNum <= leiCount; lieNum++) {
                    if (strList.size() >= num){
                        rowData.add(new TextRenderData(String.valueOf(num))); // 每行
                        rowData.add(new TextRenderData(strList.get(num - 1))); // 每行
                    }else {
                        rowData.add(new TextRenderData("")); // 每行
                        rowData.add(new TextRenderData("")); // 每行
                    }
    
                    num += hangCount;
                }
                RowRenderData row = new RowRenderData(rowData, null); // 行数据
                rows.add(row);
            }
    
    
            MiniTableRenderData tableRenderData =
                    new MiniTableRenderData(header,rows,MiniTableRenderData.WIDTH_A4_MEDIUM_FULL); // 列宽
    
            return tableRenderData;
        }
    
    
    
    
        /* 功能描述: 文本列表  转 doc列表  带字体颜色
         * @param textList
         * @param color  "FFFFFF"
         * @param fontSize  9 - 小五
        * @return: com.deepoove.poi.data.NumbericRenderData
        * @Author: 
        * @Date: 2020/2/13 20:40
        */
        public static NumbericRenderData list2DocList(List<String> textList,Style style){
            List<TextRenderData> list = new ArrayList<TextRenderData>();
            for (String text: textList){
                TextRenderData data = new TextRenderData(text);
                if (style != null){
                    data.setStyle(style);
                }
                list.add(data);
            }
            return new NumbericRenderData(NumbericRenderData.FMT_DECIMAL,list);  // NumbericRenderData.FMT_DECIMAL 数字列表
        }
    
        public static NumbericRenderData list2DocList(List<String> textList,
                                                      String color,
                                                      int fontSize){
            Style style = new Style();
            style.setColor(color);
            style.setFontSize(fontSize);
            return list2DocList(textList,style);
        }
    
        public static NumbericRenderData list2DocList(List<String> textList){
            return list2DocList(textList,null);
        }
    
    
    
        public static Style createStyle(String fontFamily, int fontSize, String color){
            Style style = new Style();
            if (fontSize != 0) style.setFontSize(fontSize);
            if (fontFamily != null) style.setFontFamily(fontFamily);
            style.setColor(color);
            return style;
        }
    
    }
    
    

    自定义poi-tl模板插件
    CustomTableRenderPolicy:

    package com.ruoyi.common.utils.poi;
    
    import com.deepoove.poi.data.CellRenderData;
    import com.deepoove.poi.data.MiniTableRenderData;
    import com.deepoove.poi.data.RowRenderData;
    import com.deepoove.poi.policy.AbstractRenderPolicy;
    import com.deepoove.poi.render.RenderContext;
    import com.deepoove.poi.util.TableTools;
    import com.deepoove.poi.xwpf.BodyContainer;
    import com.deepoove.poi.xwpf.BodyContainerFactory;
    import com.deepoove.poi.xwpf.NiceXWPFDocument;
    import com.ruoyi.common.utils.StringUtils;
    import org.apache.poi.xwpf.usermodel.*;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
    
    import java.math.BigInteger;
    import java.util.ArrayList;
    import java.util.List;
    
    /** 自定义word表格   -- 自定义poi-tl模板插件
     * description: CustomTableRenderPolicy <br>
     * date: 2020/2/28 13:47 <br>
     * author: <br>
     * version: 1.0 <br>
     */
    public class CustomTableRenderPolicy extends AbstractRenderPolicy<MiniTableRenderData> {
    
        private boolean isMergeCells;
    
        private ITableToolsMC iTableToolsMC;
    
        public ITableToolsMC getiTableToolsMC() {
            return iTableToolsMC;
        }
    
        public void setiTableToolsMC(ITableToolsMC iTableToolsMC) {
            this.iTableToolsMC = iTableToolsMC;
        }
    
        public boolean isMergeCells() {
            return isMergeCells;
        }
    
        public void setMergeCells(boolean mergeCells) {
            isMergeCells = mergeCells;
        }
    
        @Override
        protected void afterRender(RenderContext<MiniTableRenderData> context) {
            // 清空模板标签
            clearPlaceholder(context, true);
        }
    
        @Override
        public void doRender(RenderContext<MiniTableRenderData> context)
                throws Exception {
    
            NiceXWPFDocument doc = context.getXWPFDocument();
            XWPFRun run = context.getRun();
            Object data = context.getData();
            MiniTableRenderData miniTableRenderData = (MiniTableRenderData) data;
    
    
            // 当前位置的容器
            BodyContainer bodyContainer = BodyContainerFactory.getBodyContainer(run);
    
    
            List<CellRenderData> headerCellList = miniTableRenderData.getHeader().getCells();
            List<RowRenderData> rowsDataList = miniTableRenderData.getRows();
    
            // 定义行列
            int colCount = headerCellList.size(),
                    rowCount = rowsDataList.size() == 0?rowsDataList.size() + 2:rowsDataList.size() + 1;
            // 定义列宽
    //        String[] colWidthArr = new String[]{"1960","7670","5820","1640","1700"};
    
    
            // 创建表格
            // 当前位置插入表格
            XWPFTable table = bodyContainer.insertNewTable(run, rowCount, colCount);
    
    //        setTableWidth(table,"18790");
    
    
            // 设置表头
            XWPFTableRow headerRow = table.getRow(0);
            setRowHeight(headerRow,"400");
            for (int colNum = 0;colNum < colCount; colNum++){
                XWPFTableCell cell = headerRow.getCell(colNum);
    //            cell = cellCenterY(cell);
                setCellWidthAndXYAlign(cell,STVerticalJc.CENTER,STJc.CENTER,null);
                if (miniTableRenderData.getHeader().getRowStyle() != null){
                    cell.setColor(miniTableRenderData.getHeader().getRowStyle().getBackgroundColor());
                }
                cell.setText(headerCellList.get(colNum).getCellText().getText());
            }
    
            // 向表格添加数据
            for (int rowNum = 1;rowNum < rowCount;rowNum++){
                XWPFTableRow row = table.getRow(rowNum);
                if (rowsDataList.size() > 0){
                    List<CellRenderData> cellDataList = rowsDataList.get(rowNum -1).getCells();
                    for (int colNum = 0;colNum < colCount; colNum++){
                        XWPFTableCell cell = row.getCell(colNum);
                        setCellWidthAndXYAlign(cell,STVerticalJc.CENTER,STJc.CENTER,null);
                        cell.setText(cellDataList.get(colNum).getCellText().getText());
                        if (rowsDataList.get(rowNum -1).getRowStyle() != null){
                            cell.setColor(rowsDataList.get(rowNum -1).getRowStyle().getBackgroundColor());
                        }
                    }
                }else {
                    XWPFTableCell cell = row.getCell(0);
                    setCellWidthAndXYAlign(cell,STVerticalJc.CENTER,STJc.CENTER,null);
                    cell.setText("无数据");
                    TableTools.mergeCellsHorizonal(table, rowNum, 0, colCount - 1); // 水平合并
                }
            }
    
            // 定义表格宽度、边框和样式
            TableTools.widthTable(table, MiniTableRenderData.WIDTH_A4_MEDIUM_FULL, colCount);
            TableTools.borderTable(table, 4);
    
            // TODO 调用XWPFTable API操作表格:data对象可以包含任意你想要的数据,包括图片文本等
            // TODO 调用MiniTableRenderPolicy.Helper.renderRow方法快速方便的渲染一行数据
            // TODO 调用TableTools类方法操作表格,比如合并单元格
            // ......
    //        TableTools.mergeCellsHorizonal(table, 0, 0, 7); // 水平合并
            // 合并第0列的第2行到第4行的单元格
    //        TableTools.mergeCellsVertically(table, 0, 2, 4);
            if(isMergeCells){
                iTableToolsMC.mergeCells(table);
            }
    
        }
    
        private void setTableWidth(XWPFTable table, String width) {
            // 定义表格宽度
            CTTblPr tblPr = table.getCTTbl().getTblPr();
            tblPr.getTblW().setType(STTblWidth.DXA);
            tblPr.getTblW().setW(new BigInteger(width));
        }
    
    
        // 设置列宽和水平垂直居中
        public void setCellWidthAndXYAlign(XWPFTableCell cell, STVerticalJc.Enum typeEnum, STJc.Enum vAlign, String width) {
            CTTc cttc = cell.getCTTc();
            CTTcPr cellPr = cttc.addNewTcPr();
            cellPr.addNewVAlign().setVal(typeEnum);
            cttc.getPList().get(0).addNewPPr().addNewJc().setVal(vAlign);
            if(!StringUtils.isEmpty(width)){
                CTTblWidth tblWidth = cellPr.isSetTcW() ? cellPr.getTcW() : cellPr.addNewTcW();
                tblWidth.setType(STTblWidth.DXA);
                tblWidth.setW(new BigInteger(width));
            }
        }
    
        // 设置表格样式
        public void setCellStyle(XWPFTableCell cell,boolean bold) {
            XWPFParagraph p = cell.addParagraph();
            XWPFRun headRun = p.createRun();
            headRun.setBold(bold);// 是否粗体
        }
    
    
    
        private void setRowHeight(XWPFTableRow row, String height){
                CTTrPr trPr = row.getCtRow().addNewTrPr();
                CTHeight ht = trPr.addNewTrHeight();
                ht.setVal(new BigInteger(height));
        }
    
    
        private List<String[]> getList (){
            List<String[]> list = new ArrayList<>();
            String[] arr1 = new String[]{"1.1","1.2","1.3","1.4","1.5"};
            String[] arr2 = new String[]{"2.1","2.2","2.3","2.4","2.5"};
            String[] arr3 = new String[]{"3.1","3.2","3.3","3.4","3.5"};
            String[] arr4 = new String[]{"4.1","4.2","4.3","4.4","4.5"};
            String[] arr5 = new String[]{"5.1","5.2","5.3","5.4","5.5"};
            list.add(arr1);
            list.add(arr2);
            list.add(arr3);
            list.add(arr4);
            list.add(arr5);
    
            return list;
        }
    }
    
    

    CustomListRenderPolicyWP:

    package com.ruoyi.common.utils.poi.custom;
    
    import com.deepoove.poi.XWPFTemplate;
    import com.deepoove.poi.data.RowRenderData;
    import com.deepoove.poi.data.TextRenderData;
    import com.deepoove.poi.data.style.Style;
    import com.deepoove.poi.policy.AbstractRenderPolicy;
    import com.deepoove.poi.policy.DynamicTableRenderPolicy;
    import com.deepoove.poi.policy.MiniTableRenderPolicy;
    import com.deepoove.poi.policy.RenderPolicy;
    import com.deepoove.poi.render.RenderContext;
    import com.deepoove.poi.template.ElementTemplate;
    import com.deepoove.poi.template.run.RunTemplate;
    import com.deepoove.poi.util.TableTools;
    import com.deepoove.poi.xwpf.BodyContainer;
    import com.deepoove.poi.xwpf.BodyContainerFactory;
    import org.apache.poi.xwpf.usermodel.*;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
    
    import java.math.BigInteger;
    import java.util.List;
    
    /** 自定义word表格   -- 自定义poi-tl模板插件
     * description: CustomTableRenderPolicy <br>
     * date: 2020/2/28 13:47 <br>
     * author: <br>
     * version: 1.0 <br>
     */
    public class CustomListRenderPolicyWP extends AbstractRenderPolicy<MyListDataWP> {
    
        @Override
        protected void afterRender(RenderContext<MyListDataWP> context) {
            // 清空模板标签
            clearPlaceholder(context, true);
        }
    
        @Override
        public void doRender(RenderContext<MyListDataWP> context) throws Exception {
            XWPFRun run = context.getRun();
            BodyContainer bodyContainer = BodyContainerFactory.getBodyContainer(run);
            XWPFParagraph paragraph = bodyContainer.insertNewParagraph(run);
            MyListDataWP data = context.getData();
    
            paragraphList(paragraph,bodyContainer,data);//
        }
    
    
    
        /** 功能描述: 在当前位置插入多个段落组成的列表
         * @param paragraph
         * @param bodyContainer
         * @param dataWP
        * @return: void
        * @Author: 
        * @Date: 2020/3/25 14:02
        */
        private void paragraphList(XWPFParagraph paragraph,
                                   BodyContainer bodyContainer,
                                   MyListDataWP dataWP){
            List<TextRenderData> textList = dataWP.getTextList();
    
            int firstLineIndent = dataWP.getFirstLineIndent() * 200;
    
            paragraph.setFirstLineIndent(firstLineIndent); // 首行缩进  具体怎么换算的不清楚
            XWPFRun pRun = paragraph.createRun();
    //		p.setAlignment(ParagraphAlignment.CENTER); // 居中
    //		p.setSpacingBefore(1000); // 段前
    
            for (int i = 0; i < textList.size() - 1; i++) {
                TextRenderData text = textList.get(i);
                XWPFParagraph p = bodyContainer.insertNewParagraph(pRun);
                paragraph.setFirstLineIndent(firstLineIndent); // 首行缩进  具体怎么换算的不清楚
    
                XWPFRun r = p.createRun();
                r.setText(text.getText());
                setRunStyle(r,text.getStyle());
            }
    
            TextRenderData text = textList.get(textList.size() - 1);
            pRun.setText(text.getText());
            setRunStyle(pRun,text.getStyle());
        }
    
    
        /* 功能描述: 为 run设置style
         * @param run
         * @param style
        * @return: void
        * @Author: 
        * @Date: 2020/3/25 14:03
        */
        private void setRunStyle(XWPFRun run,Style style){
            if (style != null){
                run.setColor(style.getColor());
                run.setFontFamily(style.getFontFamily());
                if (style.getFontSize() != 0){
                    run.setFontSize(style.getFontSize());
                }
            }
        }
    }
    
    

    CustomTableRenderPolicyWP:

    package com.ruoyi.common.utils.poi.custom;
    
    import com.deepoove.poi.data.RowRenderData;
    import com.deepoove.poi.policy.AbstractRenderPolicy;
    import com.deepoove.poi.policy.DynamicTableRenderPolicy;
    import com.deepoove.poi.policy.MiniTableRenderPolicy;
    import com.deepoove.poi.render.RenderContext;
    import com.deepoove.poi.util.TableTools;
    import com.deepoove.poi.xwpf.NiceXWPFDocument;
    import com.ruoyi.common.utils.StringUtils;
    import org.apache.poi.xwpf.usermodel.*;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
    
    import java.math.BigInteger;
    import java.util.List;
    
    /** 自定义word表格   -- 自定义poi-tl模板插件
     * description: CustomTableRenderPolicy <br>
     * date: 2020/2/28 13:47 <br>
     * author: <br>
     * version: 1.0 <br>
     */
    public class CustomTableRenderPolicyWP extends DynamicTableRenderPolicy {
    
        @Override
        public void render(XWPFTable table, Object data) {
    
            if (null == data) return;
            MiniTableDataWP tableDataWP = (MiniTableDataWP) data;
    
            int dataStartRowNum = tableDataWP.getDataStartRowNum(); // 数据从第几行开始填充
            int colCount = tableDataWP.getColCount(); // 总列数
    
            List<RowRenderData> rowDataList = tableDataWP.getRowDataList();
            if (null != rowDataList && rowDataList.size() > 0) {
                table.removeRow(dataStartRowNum);
                // 循环插入行
                for (int i = 0; i < rowDataList.size(); i++) {
                    XWPFTableRow insertNewTableRow = table.insertNewTableRow(dataStartRowNum);
                    for (int j = 0; j < colCount; j++) { // 循环初始化每列的单元格
                        setCellXYAlign(insertNewTableRow.createCell(),STVerticalJc.CENTER,STJc.CENTER); // 内容水平垂直剧中
                    }
                    // 合并单元格
    //                TableTools.mergeCellsHorizonal(table, dataStartRowNum, 0, 3);
                    MiniTableRenderPolicy.Helper.renderRow(table, dataStartRowNum, rowDataList.get(i));
                    dataStartRowNum ++;
                }
    
    
                // 垂直合并
                // TableTools.mergeCellsVertically(table,0,4,5); // 合并  第0列 的 4~5行
                if (tableDataWP.getMergeCellsVerticallyDataList() != null
                        && tableDataWP.getMergeCellsVerticallyDataList().size() > 0){
                    for (MergeCellsVerticallydata mergeCellsVerticallydata: tableDataWP.getMergeCellsVerticallyDataList()){
                        TableTools.mergeCellsVertically(table,
                                mergeCellsVerticallydata.getCellNum(),
                                mergeCellsVerticallydata.getStartRowNum(),
                                mergeCellsVerticallydata.getEndRowNum()); // 垂直合并
                    }
                }
            }else {
                table.removeRow(dataStartRowNum);
                XWPFTableRow insertNewTableRow = table.insertNewTableRow(dataStartRowNum);
                for (int j = 0; j < colCount; j++) { // 循环初始化每列的单元格
                    XWPFTableCell cell = insertNewTableRow.createCell();
                    cell.setText("/");
                    setCellXYAlign(cell,STVerticalJc.CENTER,STJc.CENTER); // 内容水平垂直剧中
                }
            }
        }
    
    
    
        // 设置单元格 水平垂直居中
        public void setCellXYAlign(XWPFTableCell cell, STVerticalJc.Enum typeEnum, STJc.Enum vAlign) {
            CTTc cttc = cell.getCTTc();
            CTTcPr cellPr = cttc.addNewTcPr();
            cellPr.addNewVAlign().setVal(typeEnum);
            cttc.getPList().get(0).addNewPPr().addNewJc().setVal(vAlign);
        }
    }
    
    

    自定义样式相关:
    MergeCellsVerticallydata:

    package com.ruoyi.common.utils.poi.custom;
    
    import lombok.Data;
    
    /** 垂直合并
     * description: mergeCellsVerticallydata <br>
     * date: 2020/3/11 10:50 <br>
     * author: <br>
     * version: 1.0 <br>
     */
    @Data
    public class MergeCellsVerticallydata {
    
        private int cellNum; // 第几列
    
        private int startRowNum; // 开始行
    
        private int endRowNum; // 结束行
    
        public MergeCellsVerticallydata(int cellNum,int startRowNum,int endRowNum){
            this.cellNum = cellNum;
            this.startRowNum = startRowNum;
            this.endRowNum = endRowNum;
        }
    
    }
    
    

    MiniTableDataWP:

    package com.ruoyi.common.utils.poi.custom;
    
    import com.deepoove.poi.data.RowRenderData;
    import lombok.Data;
    
    import java.util.List;
    
    /** 针对自定义poi-tl插件封装的word表格实体
     * description: CustomTableWP <br>
     * date: 2020/3/10 15:15 <br>
     * author:  <br>
     * version: 1.0 <br>
     */
    @Data
    public class MiniTableDataWP {
        private int colCount; // 总列数
        private int dataStartRowNum; // 从第几行开始填充数据
    
        List<RowRenderData> rowDataList; // 数据
    
        List<MergeCellsVerticallydata> mergeCellsVerticallyDataList; // 需要合并行的数据
    
        public MiniTableDataWP(int dataStartRowNum, int colCount, List<RowRenderData> rowDataList){
            this.colCount = colCount;
            this.dataStartRowNum = dataStartRowNum;
            this.rowDataList = rowDataList;
        }
    }
    
    

    MyListDataWP:

    package com.ruoyi.common.utils.poi.custom;
    
    import com.deepoove.poi.data.RowRenderData;
    import com.deepoove.poi.data.TextRenderData;
    import lombok.Data;
    
    import java.util.List;
    
    /* 功能描述: 针对自定义poi-tl插件封装的word列表实体
     * @param null
    * @return:
    * @Author: 
    * @Date: 2020/3/25 13:05
    */
    @Data
    public class MyListDataWP {
        List<TextRenderData> textList;
    
        int firstLineIndent; // 首行缩进
    
    
        public MyListDataWP(List<TextRenderData> textList,int firstLineIndent){
            this.textList = textList;
            this.firstLineIndent = firstLineIndent;
        }
    }
    
    

    使用例子1:

    //这是要输出到word中的数据集map
     Map<String,Object> templateMap = Maps.newHashMap();
                    templateMap.put("age","1");
    //这是生成word的模版路径
    String templateFileName = "pcr/PCR_REPORT_TEMPLATE_8.docx";
     ArrayList<String[]> strings = new ArrayList<>();//这是word中表格行数据集
                        List<GeneraResultsItem> generaResultsItemList = genera.getGeneraResults().getGeneraResultsItemList();//业务代码,查询出要绑定的数据源
                        if(generaResultsItemList != null && !generaResultsItemList.isEmpty()){
                            int len = generaResultsItemList.size() -1;
                            for (int i = 0; i < len; i++) {
                                GeneraResultsItem generaResultsItem = generaResultsItemList.get(i);
                                GeneraResultsItem generaResultsItem1 = generaResultsItemList.get(i+1);
                                GeneraResultsItem generaResultsItem2 = generaResultsItemList.get(i+2);
                                String[] row = new String[]{generaResultsItem.getItemName()+"("+generaResultsItem.getGeneraItemResults()+")"
                                        ,generaResultsItem1.getItemName()+"("+generaResultsItem1.getGeneraItemResults()+")"
                                        ,generaResultsItem2.getItemName()+"("+generaResultsItem2.getGeneraItemResults()+")"};//这是一行数据
                                strings.add(row);//放到数组中
    
                                i += 2;
                            }
                        }
                        List<RowRenderData> rows = PoiTlUtils.list2Table(new String[]{"", "", ""}, strings).getRows();//获取所有的表格数据,第一个参数为表格表头数组
    					//创建自定义插件表格数据源对象
                        MiniTableDataWP miniTableDataWP = new MiniTableDataWP(0,3,rows);
    					//存放到map中
                        templateMap.put("tables",miniTableDataWP);
    

    例子1模版中使用方法:
    普通字段绑定:
    在这里插入图片描述
    表格部分绑定:
    在这里插入图片描述
    例子2:

    templateFileName = "pcr/PCR_REPORT_TEMPLATE_6.docx";//模版路径
                        templateMap.put("age","1");
                        //表格的表头
                        String[] heard = new String[]{"项目","数据(CT)","结果","项目","数据(CT)","结果"};
                        //表的行数据源
                        ArrayList<String[]> strings = new ArrayList<>();
                        List<GeneraResultsItem> generaResultsItemList = genera.getGeneraResults().getGeneraResultsItemList();
                        if(generaResultsItemList != null && !generaResultsItemList.isEmpty()){
                            int size = generaResultsItemList.size();
                            int len = size /2 ;
                            for (int i = 0; i < len; i++) {
                                GeneraResultsItem generaResultsItem = generaResultsItemList.get(i);
                                GeneraResultsItem generaResultsItem1 = generaResultsItemList.get(i+len);
                                String[] row = new String[]{generaResultsItem.getItemName(),"No Ct",generaResultsItem.getGeneraItemResults()
                                        ,generaResultsItem1.getItemName(),"No Ct",generaResultsItem1.getGeneraItemResults()};
                                strings.add(row);
                            }
    
                        }
                        templateMap.put("tables",PoiTlUtils.list2Table(heard,strings));
    

    例子2模版中使用方法:
    普通字段绑定:
    在这里插入图片描述
    表格绑定:
    在这里插入图片描述

    20200702补充基础类:

    
    import com.deepoove.poi.data.CellRenderData;
    import com.deepoove.poi.data.MiniTableRenderData;
    import com.deepoove.poi.data.RowRenderData;
    import com.deepoove.poi.policy.AbstractRenderPolicy;
    import com.deepoove.poi.render.RenderContext;
    import com.deepoove.poi.util.TableTools;
    import com.deepoove.poi.xwpf.BodyContainer;
    import com.deepoove.poi.xwpf.BodyContainerFactory;
    import com.deepoove.poi.xwpf.NiceXWPFDocument;
    import com.ruoyi.common.utils.StringUtils;
    import org.apache.poi.xwpf.usermodel.*;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
    
    import java.math.BigInteger;
    import java.util.ArrayList;
    import java.util.List;
    
    /** 自定义word表格   -- 自定义poi-tl模板插件
     * description: CustomTableRenderPolicy <br>
     * version: 1.0 <br>
     */
    public class CustomTableRenderPolicy extends AbstractRenderPolicy<MiniTableRenderData> {
    
        private boolean isMergeCells;
    
        private ITableToolsMC iTableToolsMC;
    
        public ITableToolsMC getiTableToolsMC() {
            return iTableToolsMC;
        }
    
        public void setiTableToolsMC(ITableToolsMC iTableToolsMC) {
            this.iTableToolsMC = iTableToolsMC;
        }
    
        public boolean isMergeCells() {
            return isMergeCells;
        }
    
        public void setMergeCells(boolean mergeCells) {
            isMergeCells = mergeCells;
        }
    
        @Override
        protected void afterRender(RenderContext<MiniTableRenderData> context) {
            // 清空模板标签
            clearPlaceholder(context, true);
        }
    
        @Override
        public void doRender(RenderContext<MiniTableRenderData> context)
                throws Exception {
    
            NiceXWPFDocument doc = context.getXWPFDocument();
            XWPFRun run = context.getRun();
            Object data = context.getData();
            MiniTableRenderData miniTableRenderData = (MiniTableRenderData) data;
    
    
            // 当前位置的容器
            BodyContainer bodyContainer = BodyContainerFactory.getBodyContainer(run);
    
    
            List<CellRenderData> headerCellList = miniTableRenderData.getHeader().getCells();
            List<RowRenderData> rowsDataList = miniTableRenderData.getRows();
    
            // 定义行列
            int colCount = headerCellList.size(),
                    rowCount = rowsDataList.size() == 0?rowsDataList.size() + 2:rowsDataList.size() + 1;
            // 定义列宽
    //        String[] colWidthArr = new String[]{"1960","7670","5820","1640","1700"};
    
    
            // 创建表格
            // 当前位置插入表格
            XWPFTable table = bodyContainer.insertNewTable(run, rowCount, colCount);
    
    //        setTableWidth(table,"18790");
    
    
            // 设置表头
            XWPFTableRow headerRow = table.getRow(0);
            setRowHeight(headerRow,"400");
            for (int colNum = 0;colNum < colCount; colNum++){
                XWPFTableCell cell = headerRow.getCell(colNum);
    //            cell = cellCenterY(cell);
                setCellWidthAndXYAlign(cell,STVerticalJc.CENTER,STJc.CENTER,null);
                if (miniTableRenderData.getHeader().getRowStyle() != null){
                    cell.setColor(miniTableRenderData.getHeader().getRowStyle().getBackgroundColor());
                }
                cell.setText(headerCellList.get(colNum).getCellText().getText());
            }
    
            // 向表格添加数据
            for (int rowNum = 1;rowNum < rowCount;rowNum++){
                XWPFTableRow row = table.getRow(rowNum);
                if (rowsDataList.size() > 0){
                    List<CellRenderData> cellDataList = rowsDataList.get(rowNum -1).getCells();
                    for (int colNum = 0;colNum < colCount; colNum++){
                        XWPFTableCell cell = row.getCell(colNum);
                        setCellWidthAndXYAlign(cell,STVerticalJc.CENTER,STJc.CENTER,null);
                        cell.setText(cellDataList.get(colNum).getCellText().getText());
                        if (rowsDataList.get(rowNum -1).getRowStyle() != null){
                            cell.setColor(rowsDataList.get(rowNum -1).getRowStyle().getBackgroundColor());
                        }
                    }
                }else {
                    XWPFTableCell cell = row.getCell(0);
                    setCellWidthAndXYAlign(cell,STVerticalJc.CENTER,STJc.CENTER,null);
                    cell.setText("无数据");
                    TableTools.mergeCellsHorizonal(table, rowNum, 0, colCount - 1); // 水平合并
                }
            }
    
            // 定义表格宽度、边框和样式
            TableTools.widthTable(table, MiniTableRenderData.WIDTH_A4_MEDIUM_FULL, colCount);
            TableTools.borderTable(table, 4);
    
            // TODO 调用XWPFTable API操作表格:data对象可以包含任意你想要的数据,包括图片文本等
            // TODO 调用MiniTableRenderPolicy.Helper.renderRow方法快速方便的渲染一行数据
            // TODO 调用TableTools类方法操作表格,比如合并单元格
            // ......
    //        TableTools.mergeCellsHorizonal(table, 0, 0, 7); // 水平合并
            // 合并第0列的第2行到第4行的单元格
    //        TableTools.mergeCellsVertically(table, 0, 2, 4);
            if(isMergeCells){
                iTableToolsMC.mergeCells(table);
            }
    
        }
    
        private void setTableWidth(XWPFTable table, String width) {
            // 定义表格宽度
            CTTblPr tblPr = table.getCTTbl().getTblPr();
            tblPr.getTblW().setType(STTblWidth.DXA);
            tblPr.getTblW().setW(new BigInteger(width));
        }
    
    
        // 设置列宽和水平垂直居中
        public void setCellWidthAndXYAlign(XWPFTableCell cell, STVerticalJc.Enum typeEnum, STJc.Enum vAlign, String width) {
            CTTc cttc = cell.getCTTc();
            CTTcPr cellPr = cttc.addNewTcPr();
            cellPr.addNewVAlign().setVal(typeEnum);
            cttc.getPList().get(0).addNewPPr().addNewJc().setVal(vAlign);
            if(!StringUtils.isEmpty(width)){
                CTTblWidth tblWidth = cellPr.isSetTcW() ? cellPr.getTcW() : cellPr.addNewTcW();
                tblWidth.setType(STTblWidth.DXA);
                tblWidth.setW(new BigInteger(width));
            }
        }
    
        // 设置表格样式
        public void setCellStyle(XWPFTableCell cell,boolean bold) {
            XWPFParagraph p = cell.addParagraph();
            XWPFRun headRun = p.createRun();
            headRun.setBold(bold);// 是否粗体
        }
    
    
    
        private void setRowHeight(XWPFTableRow row, String height){
                CTTrPr trPr = row.getCtRow().addNewTrPr();
                CTHeight ht = trPr.addNewTrHeight();
                ht.setVal(new BigInteger(height));
        }
    
    
        private List<String[]> getList (){
            List<String[]> list = new ArrayList<>();
            String[] arr1 = new String[]{"1.1","1.2","1.3","1.4","1.5"};
            String[] arr2 = new String[]{"2.1","2.2","2.3","2.4","2.5"};
            String[] arr3 = new String[]{"3.1","3.2","3.3","3.4","3.5"};
            String[] arr4 = new String[]{"4.1","4.2","4.3","4.4","4.5"};
            String[] arr5 = new String[]{"5.1","5.2","5.3","5.4","5.5"};
            list.add(arr1);
            list.add(arr2);
            list.add(arr3);
            list.add(arr4);
            list.add(arr5);
    
            return list;
        }
    }
    
    public interface ITableToolsMC {
        void mergeCells(XWPFTable table);
    }
    
    import com.deepoove.poi.util.TableTools;
    import org.apache.poi.xwpf.usermodel.XWPFTable;
    
    
    
    public class ITableToolsMCImpl implements ITableToolsMC {
        @Override
        public void mergeCells( XWPFTable table) {
            // 合并第0列的第0行到第1行的单元格
            TableTools.mergeCellsVertically(table, 0, 0, 1);
        }
    }
    

    如有不足请留言补充

    展开全文
  • 本编文章继SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格)文章之后 介绍Poi-tl导出word的延伸功能: 所需依赖以及word模板所属位置 见 SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格),这里...
  • java使用poi-tl操作word文件

    千次阅读 2019-12-12 23:28:29
    场景 某一天,笔者在写计算机组成原理实验报告的...使用poi-tl 通过百度“java操作word”关键词,搜索到的文章基本上都是使用poi来操作word。但是今天要介绍的是一个比poi简单的,代码更加简洁的工具:poi-pl 官...
  • poi-tl 根据 模板 生成 word 文档1.依赖2.模板样式3. java代码4. 效果 1.依赖 <dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> <version>...
  • poi导出word内嵌表格设计分析部分后端代码部分xml文件配置实体类controller层使用到的工具类service层前端代码部分测试页面 设计分析部分 首先要对导出word的需求进行分析,以下展示,本项目中,导出的word格式 出于...
  • 通过poi-tl实现报告的循环导出
  • 首先奉上poi-tl官方文档地址:http://deepoove.com/poi-tl/#_%E7%89%88%E6%9C%AC 1.导包 maven: <dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> ...
  • 1.引入依赖 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.0</version> ...
  • java poi获取word文档自动生成的序号

    千次阅读 2020-01-16 16:58:55
    POI不能获取word自动生成的序号,但是可以自己根据级别自己写出来。 maven <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-scratchpad</artifactId> ...
  • [简单]poi word2007设置表格边框样式

    千次阅读 2014-11-03 18:52:38
    直接上代码:   import java.io.FileOutputStream; import java.math.BigInteger; import java.util.ArrayList; import java.util.List;...import org.apache.poi.xwpf.usermodel.BreakType; impo...
  • POI 生成word 文档 一般有两种方法:① word模板 生成word 文档 ;② 写代码直接生成 word 文档;我这里演示的是第二种方法,即写代码生成 word文档,不多说废话,直接代码;/*** 镇街日报导出word*/@RequestMapping...
  • import org.apache.poi.xwpf.usermodel.ParagraphAlignment; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel....

空空如也

空空如也

1 2 3
收藏数 59
精华内容 23
关键字:

poi-tl表格序号