springboot整合poi-tl实现word文档模板动态渲染数据-附完整实例

目录

  • 一、先看效果
    • 1.1、实现前(word模板)
    • 1.2、实现后(最新版-已新增样式)
  • 二、测试地址
  • 三、贴出部分代码
    • 3.1、pom.xml
    • 3.2、测试类(PoiDemoApplicationTests)
    • 3.3、初始化数据
    • 3.4、初始化需要动态渲染表格
    • 3.5、定义一个类实现插件接口并重写
  • 四、项目整体路径

一、先看效果

1.1、实现前(word模板)

springboot整合poi-tl实现word文档模板动态渲染数据-附完整实例_第1张图片

1.2、实现后(最新版-已新增样式)

springboot整合poi-tl实现word文档模板动态渲染数据-附完整实例_第2张图片

二、测试地址

建议还是拉下代码下来看 【点击此处进行跳转】
结合图片来解析 例如
springboot整合poi-tl实现word文档模板动态渲染数据-附完整实例_第3张图片

三、贴出部分代码

3.1、pom.xml

官方文档: http://deepoove.com/poi-tl/#_%E5%9B%BE%E7%89%87


    com.deepoove
    poi-tl
    1.12.1

3.2、测试类(PoiDemoApplicationTests)

    @Test
    void contextLoads() throws IOException {
        // 一、初始化数据
        // 1)初始化模板数据-实际是去数据库查询-自行整合
        Templates templates = initTemplates();
        // 2)初始化家庭成员信息-实际是去数据库查询-自行整合
        List familyMemberList = initFamilyMember();
        // 3)初始化工作情况-实际是去数据库查询-自行整合
        List goingList = initGoing();

        // 二、初始化动态数据-并整合一个完整的对象
        // 1)处理动态数据->转为RowRenderData类型即List->List
        TemplateRowRenderData templateRowRenderData = new TemplateRowRenderData(familyMemberList,goingList);
        // 2)完整数据
        TemplateData templateData = new TemplateData(templates,templateRowRenderData);

        // 三、绑定插件
        // 1)插件绑定-【TemplateTableRenderPolicy】插件中data能获取到【TemplateRowRenderData】动态数据的关键
        // 注意:模板中也是根据该字段进行渲染:templateRowRenderData 如图resources/pictures/images1.jpg   特别注意不要用到了中文画框花,鼠鼠我郁闷了一早上也想不明道插件为什么不生效
        Configure config = Configure.builder().bind("templateRowRenderData", new TemplateTableRenderPolicy()).build();

        //  四、导出
        ClassPathResource classPathResource = new ClassPathResource("templates" + File.separator + "鼠鼠教你如何实现动态导出.docx");
        XWPFTemplate template = XWPFTemplate.compile(classPathResource.getInputStream(),config).render(
                templateData);

        // 通过浏览器下载自行整合下即可
        // controller获取HttpServerResponse
        template.writeAndClose(new FileOutputStream("C:\\Users\\muyangren\\Desktop\\output.docx"));
    }

3.3、初始化数据

    private Templates initTemplates() {
        // 填充一些基本信息
        Templates templates = new Templates();
        templates.setName("吃了没");
        templates.setAliases("吃我一拳");
        templates.setDeptName("勿入鼠穴");
        templates.setSexName("gay");
        templates.setPeoples("汉族");
        templates.setBirth("2000");
        templates.setCulture("胎教");
        return templates;
    }

    /**
     * 测试数据、实际是需要查询数据库的
     * @return
     */
    private List initFamilyMember() {
        List familyMemberList = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            FamilyMember familyMember = new FamilyMember();
            familyMember.setRelationship("好兄弟" + i);
            familyMember.setName("姓名" + i);
            familyMember.setPosition("摸鱼关系户" + i);
            familyMemberList.add(familyMember);
        }
        return familyMemberList;
    }

    /**
     * 测试数据
     *
     * @return
     */
    private List initGoing() {
        List goingList = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            Going going = new Going();
            going.setCompany("比命苦美式" + i);
            going.setAddress("来一杯比我命还苦的冰美式、不加糖" + i);
            going.setPhone("程序跑不起来,美式,我能跑就行" + i);
            goingList.add(going);
        }
        return goingList;
    }

3.4、初始化需要动态渲染表格

import com.deepoove.poi.data.*;
import com.deepoove.poi.data.style.*;
import com.deepoove.poi.policy.TableRenderPolicy;
import com.muyangren.poidemo.entity.FamilyMember;
import com.muyangren.poidemo.entity.Going;
import lombok.Data;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Data
public class TemplateRowRenderData {
    /**
     * 家庭人员
     */
    private List familyRowRenderDataList;

    /**
     * 工作情况
     */
    private List goingRowRenderDataList;

    private RowStyle rowStyle;

    public TemplateRowRenderData(List familyMemberList, List goingList) {
        // 初始化样式
        initStyle();
        // 初始化动态数据
        initData(familyMemberList, goingList);
    }

    private void initStyle() {
        // 此处定义样式的优先级高:想看样式获取顺序可以看【TemplateTableRenderPolicy】中的【TableRenderPolicy.Helper.renderRow(xwpfTable.getRow(familyMemberRow), familyRowRenderDataList.get(i))】 谢谢你作者 很规范 nmd

        // 字体样式
        Style style = new Style("宋体", 10);

        // 段落样式
        ParagraphStyle paragraphStyle = new ParagraphStyle();
        paragraphStyle.setDefaultTextStyle(style);
        // ps:这里才是字体居中对齐
        paragraphStyle.setAlign(ParagraphAlignment.CENTER);

        // 表格样式
        CellStyle cellStyle = new CellStyle();
        // ps:表格也需要居中,否则字体不在正中间,会偏上
        cellStyle.setVertAlign(XWPFTableCell.XWPFVertAlign.CENTER);
        cellStyle.setDefaultParagraphStyle(paragraphStyle);

        // 行样式
        this.rowStyle = new RowStyle();
        rowStyle.setDefaultCellStyle(cellStyle);
    }

    private void initData(List familyMemberList, List goingList) {
        List newFamilyRowRenderDataList = new ArrayList<>();
        List newGoingRowRenderDataList = new ArrayList<>();

        // 判空-家庭人员
        if (CollectionUtils.isNotEmpty(familyMemberList)) {
            for (FamilyMember familyMember : familyMemberList) {
                // 创建一行五表格(根据实际情况来哈)
                List cellDataList = new ArrayList<>();
                // 留两个空格(为什么要留两个空白格,大家可以试试自己去添加下行就知道了) 如图:resources/pictures/images3.jpg|images2.jpg
                cellDataList.add(new CellRenderData().addParagraph(new ParagraphRenderData().addText("")));
                cellDataList.add(new CellRenderData().addParagraph(new ParagraphRenderData().addText("")));
                cellDataList.add(new CellRenderData().addParagraph(new ParagraphRenderData().addText(familyMember.getRelationship())));
                cellDataList.add(new CellRenderData().addParagraph(new ParagraphRenderData().addText(familyMember.getName())));
                cellDataList.add(new CellRenderData().addParagraph(new ParagraphRenderData().addText(familyMember.getPosition())));
                RowRenderData rowRenderData = new RowRenderData();
                // 样式
                rowRenderData.setRowStyle(rowStyle);
                rowRenderData.setCells(cellDataList);
                newFamilyRowRenderDataList.add(rowRenderData);
            }
            this.familyRowRenderDataList = newFamilyRowRenderDataList;
        }else {
            // 要是不存在传null值的话,插件里就要多一层判断了
            this.familyRowRenderDataList= Collections.emptyList();
        }

        // 判空-工作情况
        if (CollectionUtils.isNotEmpty(goingList)) {
            for (Going going : goingList) {
                // 创建一行四表格(根据实际情况来哈)
                List cellDataList = new ArrayList<>();
                // 保留一个空格(如【家庭成员所示】)
                cellDataList.add(new CellRenderData().addParagraph(new ParagraphRenderData().addText("")));
                cellDataList.add(new CellRenderData().addParagraph(new ParagraphRenderData().addText(going.getCompany())));
                cellDataList.add(new CellRenderData().addParagraph(new ParagraphRenderData().addText(going.getAddress())));
                cellDataList.add(new CellRenderData().addParagraph(new ParagraphRenderData().addText(going.getPhone())));
                RowRenderData rowRenderData = new RowRenderData();
                // 样式
                rowRenderData.setRowStyle(rowStyle);
                rowRenderData.setCells(cellDataList);
                newGoingRowRenderDataList.add(rowRenderData);
            }
            this.goingRowRenderDataList = newGoingRowRenderDataList;
        }else {
            this.goingRowRenderDataList= Collections.emptyList();
        }
    }
}

3.5、定义一个类实现插件接口并重写

import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.policy.DynamicTableRenderPolicy;
import com.deepoove.poi.policy.TableRenderPolicy;
import com.deepoove.poi.util.TableTools;
import lombok.NoArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;

import java.util.List;

@NoArgsConstructor
public class TemplateTableRenderPolicy extends DynamicTableRenderPolicy {

    @Override
    public void render(XWPFTable xwpfTable, Object data) throws Exception {
        if (null == data) {
            return;
        }
     //-----------------------------------先别急,一行一行看下去-------------------------------------------------------
        // 因为我们前面用Config绑定了【List】渲染规则
        TemplateRowRenderData templateRowRenderData = (TemplateRowRenderData) data;

        // 一、处理家庭成员数据
        List familyRowRenderDataList = templateRowRenderData.getFamilyRowRenderDataList();
        if (CollectionUtils.isNotEmpty(familyRowRenderDataList)) {
            // 1)计算家庭成员表头所在行数 如图:resource/pictures/images4.jpg
             int familyMemberRow = 9;
            // 2)删掉空白内容:xwpfTable.removeRow是从下标0开始计算的,所以这里删除的是空白内容如图:resource/pictures/images5.jpg
            xwpfTable.removeRow(familyMemberRow);
            // 3)获取该表家庭成员表头高度 【familyMemberRow-1】即家庭成员表头的下标  作用:统一高度
            XWPFTableRow xwpfTableRow = xwpfTable.getRow(familyMemberRow-1);
            // 4)循环插入行 (倒序插入)ps:这里是一直在第9行插入表格。
            for (int i = familyRowRenderDataList.size() - 1; i > -1; i--) {
                // 4.1)插入表格
                XWPFTableRow insertNewTableRow = xwpfTable.insertNewTableRow(familyMemberRow);
                // 4.1.1)控制表格高度
                insertNewTableRow.setHeight(xwpfTableRow.getHeight());
                // 4.2)每行添加11个表格,这里需要根据实际情况填充。秉持多则退少补原则
                // 如图:假如我添加12个 resource/pictures/images6.jpg
                // 如图:假如我添加10个 resource/pictures/images7.jpg
                // 注:想看效果时记得注释下面的代码 【TableTools.mergeCellsHorizonal】,【TableTools.mergeCellsVertically】
                for (int j = 0; j < 11; j++) {
                    insertNewTableRow.createCell();
                }

                // 基本信息占1格,家庭成员占1个,关系、姓名、职位各占3 刚好11格
                // 5)合并上面创建的11个单元格  fromCol-toCol 且 fromCol(起始) < toCol(结束)
                // 5.1)【关系】下标为2,所以2(fromCol)合并至4(toCol)的单元格
                TableTools.mergeCellsHorizonal(xwpfTable, familyMemberRow, 2, 4);
                // 5.2)【姓名】下标为3,所以3(fromCol)合并至5(toCol)的单元格:注意:按上一个合并后的结果再数格子并合并
                TableTools.mergeCellsHorizonal(xwpfTable, familyMemberRow, 3, 5);
                // 5.3)【职位】下标为4,所以4(fromCol)合并至6(toCol)的单元格:注意:按上一个合并后的结果再数格子并合并
                TableTools.mergeCellsHorizonal(xwpfTable, familyMemberRow, 4, 6);

                // 6) 渲染数据(表格对齐后在进行渲染数据)
                TableRenderPolicy.Helper.renderRow(xwpfTable.getRow(familyMemberRow), familyRowRenderDataList.get(i));
            }
            // 7)跨行合并行 参数说明: 1-操作表格方法 2-需要合并行 3-开始合并列 4-结束合并列
            // 7.1) 合并前:resource/pictures/images8.jpg
            // 7.2) 合并后:resource/pictures/images9.jpg
            int fromRow = familyMemberRow - 1;
            // 7.3)合并下标为1的行 合并列为fromRow->familyRowRenderDataList.size() + fromRow
            // 7.4)合并下标为0的行 合并列为0->familyRowRenderDataList.size() + fromRow
            TableTools.mergeCellsVertically(xwpfTable, 1, fromRow, familyRowRenderDataList.size() + fromRow);
            TableTools.mergeCellsVertically(xwpfTable, 0, 0, familyRowRenderDataList.size() + fromRow);
        }
//---------------------------------------以上为家庭成员的数据渲染------------------------------------------------------------

        // 二、处理工作情况数据-关键处此篇不给出解析,大家根据【家庭成员】 自行填写
        List goingRowRenderDataList = templateRowRenderData.getGoingRowRenderDataList();
        // 1)判空
        if (CollectionUtils.isNotEmpty(goingRowRenderDataList)) {
            // 2)工作情况所在行数 ps:其实我们从0开始数的话、可以省很多事
            int goingMemberRow = 11;
            if (!CollectionUtils.isEmpty(familyRowRenderDataList)) {
                goingMemberRow = 11 + familyRowRenderDataList.size() - 1;
            }
            // 3)
            xwpfTable.removeRow(goingMemberRow);
            // 4)
            XWPFTableRow xwpfTableRow = xwpfTable.getRow(goingMemberRow-1);
            // 5)循环插入行(倒序插入)
            for (int i = goingRowRenderDataList.size() - 1; i > -1; i--) {
                XWPFTableRow insertNewTableRow = xwpfTable.insertNewTableRow(goingMemberRow);
                insertNewTableRow.setHeight(xwpfTableRow.getHeight());
                // 6)
                for (int j = 0; j < 11; j++) {
                    insertNewTableRow.createCell();
                }
                // 7)
                // 7.1)合并表格
                TableTools.mergeCellsHorizonal(xwpfTable, goingMemberRow, 1, 2);
                // 7.2)合并表格
                TableTools.mergeCellsHorizonal(xwpfTable, goingMemberRow, 2, 7);
                // 7.3)合并表格
                TableTools.mergeCellsHorizonal(xwpfTable, goingMemberRow, 3, 4);
                // 8)渲染数据
                TableRenderPolicy.Helper.renderRow(xwpfTable.getRow(goingMemberRow), goingRowRenderDataList.get(i));
            }
            // 9)合并行
            TableTools.mergeCellsVertically(xwpfTable,0,goingMemberRow-1,goingMemberRow +goingRowRenderDataList.size()-1);
        }
    }
}

四、项目整体路径

springboot整合poi-tl实现word文档模板动态渲染数据-附完整实例_第4张图片

  • 如果该篇文章对您有帮助 麻烦点个赞以及star支持下哈

你可能感兴趣的:(功能点汇总,spring,boot,word,java)