POI-TL插件开发-表格分组插件

发布于:2024-12-23 ⋅ 阅读:(12) ⋅ 点赞:(0)

POI-TL版本:1.12.2
改造于:LoopRowTableRenderPolicy
模板设计:
在这里插入图片描述
分组之前:
在这里插入图片描述
分组之后:
在这里插入图片描述
代码实现:

public class LoopRowGroupTableRenderPolicy implements RenderPolicy {

    private String prefix;
    private String suffix;
    private boolean onSameLine;
    private TableGroupPolicy tableGroupPolicy;

    private final String MERGE_FLAG = "MERGE_FLAG";

    public LoopRowGroupTableRenderPolicy(TableGroupPolicy tableGroupPolicy) {
        this.prefix = "[";
        this.suffix = "]";
        this.onSameLine = false;
        this.tableGroupPolicy = tableGroupPolicy;
    }

    @Override
    public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
        RunTemplate runTemplate = (RunTemplate) eleTemplate;
        XWPFRun run = runTemplate.getRun();
        try {
            if (!TableTools.isInsideTable(run)) {
                throw new IllegalStateException(
                    "The template tag " + runTemplate.getSource() + " must be inside a table");
            }
            XWPFTableCell tagCell = (XWPFTableCell) ((XWPFParagraph) run.getParent()).getBody();
            XWPFTable table = tagCell.getTableRow().getTable();
            run.setText("", 0);

            int templateRowIndex = getTemplateRowIndex(tagCell);
            List<MergeDTO> mergeList = new ArrayList<>();
            if (data instanceof Iterable) {
                // 对数据分组
                List<Map<String, String>> group = groupData((List<Map<String, String>>) data);
                Iterator<?> iterator = ((Iterable<?>) group).iterator();
                XWPFTableRow templateRow = table.getRow(templateRowIndex);
                int step = templateRow.getTableICells().size();
                int insertPosition = templateRowIndex;

                TemplateResolver resolver = new TemplateResolver(template.getConfig().copy(prefix, suffix));
                boolean firstFlag = true;
                int index = 0;
                boolean hasNext = iterator.hasNext();
                while (hasNext) {
                    HashMap root = (HashMap) iterator.next();
                    if (root.containsKey(MERGE_FLAG) && "Y".equals(root.get(MERGE_FLAG))) {
                        int start = tableGroupPolicy.getFromIndex() > 0 ? tableGroupPolicy.getFromIndex() : 0;
                        int end = tableGroupPolicy.getToIndex() >= step ? step - 1 : tableGroupPolicy.getToIndex();
                        mergeList.add(new MergeDTO(templateRowIndex, start, end));
                    }
                    hasNext = iterator.hasNext();

                    insertPosition = templateRowIndex++;
                    XWPFTableRow nextRow = table.insertNewTableRow(insertPosition);
                    setTableRow(table, templateRow, insertPosition);

                    // double set row
                    XmlCursor newCursor = templateRow.getCtRow().newCursor();
                    newCursor.toPrevSibling();
                    XmlObject object = newCursor.getObject();
                    nextRow = new XWPFTableRow((CTRow) object, table);
                    if (!firstFlag) {
                        // update VMerge cells for non-first row
                        List<XWPFTableCell> tableCells = nextRow.getTableCells();
                        for (XWPFTableCell cell : tableCells) {
                            CTTcPr tcPr = TableTools.getTcPr(cell);
                            CTVMerge vMerge = tcPr.getVMerge();
                            if (null == vMerge) continue;
                            if (STMerge.RESTART == vMerge.getVal()) {
                                vMerge.setVal(STMerge.CONTINUE);
                            }
                        }
                    } else {
                        firstFlag = false;
                    }
                    setTableRow(table, nextRow, insertPosition);
                    RenderDataCompute dataCompute = template.getConfig()
                        .getRenderDataComputeFactory()
                        .newCompute(EnvModel.of(root, EnvIterator.makeEnv(index++, hasNext)));
                    List<XWPFTableCell> cells = nextRow.getTableCells();
                    cells.forEach(cell -> {
                        List<MetaTemplate> templates = resolver.resolveBodyElements(cell.getBodyElements());
                        new DocumentProcessor(template, resolver, dataCompute).process(templates);
                    });
                }
            }
            if (!CollectionUtils.isEmpty(mergeList)) {
                mergeList.forEach(c -> mergeCellsHorizontal(table, c.getIndex(), c.getFromIndex(), c.getToIndex()));
            }

            table.removeRow(templateRowIndex);
        } catch (Exception e) {
            throw new RenderException("HackLoopTable for " + eleTemplate + " error: " + e.getMessage(), e);
        }
    }

    private List<Map<String, String>> groupData(List<Map<String, String>> data) {
        List<Map<String, String>> result = new ArrayList<>();
        Map<String, List<Map<String, String>>> collect = data.stream().collect(Collectors.groupingBy(map -> {
            if (map.containsKey(tableGroupPolicy.getGroupFieldName())) {
                if (StringUtils.isNotEmpty(map.get(tableGroupPolicy.getGroupFieldName()))) {
                    return map.get(tableGroupPolicy.getGroupFieldName());
                } else {
                    return "";
                }
            } else {
                return "";
            }
        }));

        collect.keySet().forEach(c -> {
            Map<String, String> map = new HashMap<>();
            map.put(MERGE_FLAG, "Y");
            map.put(tableGroupPolicy.getFirstFieldName(), c);
            result.add(map);
            result.addAll(collect.get(c));
        });

        return result;
    }

    private int getTemplateRowIndex(XWPFTableCell tagCell) {
        XWPFTableRow tagRow = tagCell.getTableRow();
        return onSameLine ? getRowIndex(tagRow) : (getRowIndex(tagRow) + 1);
    }

    /**
     * word跨列合并单元格
     * table 表单对象
     * row  合并行
     * fromCell 起始列
     * toCell  结束列
     */
    private static void mergeCellsHorizontal(XWPFTable table, Integer row, Integer fromCell, Integer toCell) {
        for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) {
            XWPFTableCell cell = table.getRow(row).getCell(cellIndex);
            if (cellIndex == fromCell) {
                // The first merged cell is set with RESTART merge value
                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
            } else {
                // Cells which join (merge) the first one, are set with CONTINUE
                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
            }
        }
    }

    @SuppressWarnings("unchecked")
    private void setTableRow(XWPFTable table, XWPFTableRow templateRow, int pos) {
        List<XWPFTableRow> rows = (List<XWPFTableRow>) ReflectionUtils.getValue("tableRows", table);
        rows.set(pos, templateRow);
        table.getCTTbl().setTrArray(pos, templateRow.getCtRow());
    }

    private int getRowIndex(XWPFTableRow row) {
        List<XWPFTableRow> rows = row.getTable().getRows();
        return rows.indexOf(row);
    }


    @Data
    public static class TableGroupPolicy {
        //  首字段名称
        private String firstFieldName;
        //  分组字段名称
        private String groupFieldName;
        //  合并开始下标
        private Integer fromIndex;
        //  合并结束下标
        private Integer toIndex;

        public TableGroupPolicy() {
        }

        public TableGroupPolicy(String firstFieldName, String groupFieldName, Integer fromIndex, Integer toIndex) {
            this.firstFieldName = firstFieldName;
            this.groupFieldName = groupFieldName;
            this.fromIndex = fromIndex;
            this.toIndex = toIndex;
        }
    }

    @Data
    static class MergeDTO {
        //  当前下标
        private Integer index;
        //  合并开始下标
        private Integer fromIndex;
        //  合并结束下标
        private Integer toIndex;

        public MergeDTO() {
        }

        public MergeDTO(Integer index, Integer fromIndex, Integer toIndex) {
            this.index = index;
            this.fromIndex = fromIndex;
            this.toIndex = toIndex;
        }
    }

}

绑定标签:

        Configure.builder().bind("商品列表", new LoopRowGroupTableRenderPolicy(new LoopRowGroupTableRenderPolicy.TableGroupPolicy("名称","分类",0,2)));


网站公告

今日签到

点亮在社区的每一天
去签到