poi-tl渲染word复杂表格(合并行,列)

Scroll Down

poi-tl渲染word复杂表格(合并行,列)

poi-tl(poi template language)是Word模板引擎,基于Microsoft Word模板和数据生成新的文档。

官方文档: http://deepoove.com/poi-tl
github: https://github.com/Sayi/poi-tl

该项目基于Apache-poi操作word, 通过标签渲染模板十分方便, 本文主要研究如何实现相对复杂的word表格
模板:
image.png
实现效果图
image.png
代码:

package cn.exrick.xboot.modules.report.controller.policyimpl;

import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.data.TextRenderData;
import com.deepoove.poi.data.style.TableStyle;
import com.deepoove.poi.policy.DynamicTableRenderPolicy;
import com.deepoove.poi.policy.MiniTableRenderPolicy;
import com.deepoove.poi.util.TableTools;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBorder;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblBorders;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STBorder;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc;

import java.math.BigInteger;
import java.util.*;

/**
 * 生成word复杂表
 */
public class DyyxTablePolicy extends DynamicTableRenderPolicy {

    private String lastName = "";
    private int k = 1;
    private int i = 0;
    private int j = 0;
    private int j2 = 0;

    @Override
    public void render(XWPFTable table, Object data) {
        this.k = 1;
        this.i = 0;
        this.j = 0;
        this.j2 = 0;
        this.lastName = "";
        setTable(table);
        if (null == data) return;
        List<Map<String, Object>> tableData = (List<Map<String, Object>>) data;

        List<RowRenderData> dest = new LinkedList<>();

        TableStyle rowStyle = new TableStyle();
        rowStyle.setAlign(STJc.CENTER);

        TreeMap<Integer, Integer> mergeMap = new TreeMap<>();

        //list-map转list-RowRenderData-list
        tableData.forEach(o -> {
            //Map转普通List
            List<String> list = new ArrayList<String>() {{
                if (!lastName.equals(o.get("company").toString())) {
                    add(o.get("index").toString());
                    add(o.get("company").toString());
                    //预处理合并列
                    if (o.get("company").toString().matches(".*中心")) {
                        mergeMap.put(j, 1);
                        j2 = j;
                    }
                } else {
                    //预处理合并列
                    mergeMap.put(j2, mergeMap.get(j2) + 1);
                    add("");
                    add("");
                }

                add(o.get("dyyj").toString());
                add(o.get("dykh").toString());
                add(o.get("gyyj").toString());
                add(o.get("gykh").toString());
            }};

            this.j++;
            lastName = o.get("company").toString();
            if (!" - ".equals(o.get("group").toString())) {
                list.add(2, o.get("group").toString());
            }

            //普通List转RowRenderData-list
            String[] values = new String[list.size()];
            list.toArray(values);
            System.out.println(list);
            RowRenderData build = RowRenderData.build(values);
            build.setRowStyle(rowStyle);
            dest.add(build);
        });

        dest.forEach(o -> {
            TextRenderData text = o.getCells().get(0).getCellText();
            TextRenderData text1 = o.getCells().get(1).getCellText();
            //对索引重定义
            if (text1.getText().matches("(.*公司)|(.*中心)")) {
                text.setText(Integer.valueOf(k).toString());
                this.k++;
            }
            //行合并起点
            if (!o.getCells().get(1).getCellText().getText().matches(".*公司")) {
                this.i++;
            }

        });

        /*
            处理列合并索引
                1. 匹配 中心 单位 记录出现位置 到map<位置,次数>
                2. 相同单位时map的value自增
                3. 遍历map 位置 = 位置加自增数
                4. 合并时,从位置-自增数 到位置合并
         */
        TreeMap<Integer, Integer> temp = new TreeMap<>();
        mergeMap.forEach((k, v) -> {
            temp.put(k + v, v);
        });
        mergeMap.clear();
        mergeMap.putAll(temp);

        if (tableData == null) {
            return;
        }

        // 循环插入行
        table.removeRow(2);
        for (int i = 0; i < dest.size(); i++) {
            XWPFTableRow insertNewTableRow = table.insertNewTableRow(2 + i);
            for (int j = 0; j < 7; j++) {
                insertNewTableRow.createCell()
                        .setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
            }
            // 合并垂直单元格
            if (mergeMap.get(i) != null) {
                Integer colNum = mergeMap.get(i);
                int flag = i == this.i ? 1 : 0;
                TableTools.mergeCellsVertically(table, 0, 2 + i - colNum, 2 + i - flag);
                TableTools.mergeCellsVertically(table, 1, 2 + i - colNum, 2 + i - flag);
            }
            // 合并水平单元格
            if (i >= this.i) {
                TableTools.mergeCellsHorizonal(table, 2 + i, 1, 2);
            }
            MiniTableRenderPolicy.Helper.renderRow(table, 2 + i, dest.get(i));
        }
    }

    /**
     * 单元格加边框
     *
     * @param table
     */
    private void setTable(XWPFTable table) {
        CTTblBorders borders = table.getCTTbl().getTblPr().addNewTblBorders();
        CTBorder hBorder = borders.addNewInsideH();
        hBorder.setVal(STBorder.Enum.forString("single"));  // 线条类型
        hBorder.setSz(new BigInteger("1")); // 线条大小
        hBorder.setColor("000000"); // 设置颜色

        CTBorder vBorder = borders.addNewInsideV();
        vBorder.setVal(STBorder.Enum.forString("single"));
        vBorder.setSz(new BigInteger("1"));
        vBorder.setColor("000000");

        CTBorder lBorder = borders.addNewLeft();
        lBorder.setVal(STBorder.Enum.forString("single"));
        lBorder.setSz(new BigInteger("1"));
        lBorder.setColor("000000");

        CTBorder rBorder = borders.addNewRight();
        rBorder.setVal(STBorder.Enum.forString("single"));
        rBorder.setSz(new BigInteger("1"));
        rBorder.setColor("000000");

        CTBorder tBorder = borders.addNewTop();
        tBorder.setVal(STBorder.Enum.forString("single"));
        tBorder.setSz(new BigInteger("1"));
        tBorder.setColor("000000");

        CTBorder bBorder = borders.addNewBottom();
        bBorder.setVal(STBorder.Enum.forString("single"));
        bBorder.setSz(new BigInteger("1"));
        bBorder.setColor("000000");
    }


}