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

POI-TL版本:1.12.2

改造于:LoopRowTableRenderPolicy
模板设计:

分组之前:

分组之后:

代码实现:

java 复制代码
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;
        }
    }

}

绑定标签:

java 复制代码
        Configure.builder().bind("商品列表", new LoopRowGroupTableRenderPolicy(new LoopRowGroupTableRenderPolicy.TableGroupPolicy("名称","分类",0,2)));
相关推荐
追逐梦想永不停10 分钟前
Java连接chatGPT步骤(免费key获取方法)
java·开发语言·chatgpt
知识分享小能手11 分钟前
Java学习教程,从入门到精通,Java LinkedList(链表)语法知识点及案例代码(62)
java·大数据·开发语言·学习·链表·intellij-idea·大数据开发
ybq1951334543111 分钟前
javaEE--计算机是如何工作的-1
java·前端·java-ee
暗夜绿16 分钟前
【GoF23种设计模式】02_单例模式(Singleton Pattern)
java·spring·单例模式·设计模式
White graces18 分钟前
掌握HTML, 从零开始的网页设计
开发语言·前端·windows·edge·html·visual studio code
Nijika...24 分钟前
Spring整合Redis基本操作步骤
java·redis·后端·spring
Q_192849990629 分钟前
基于Spring Boot的水果蔬菜商城系统
java·spring boot
Ava_J39 分钟前
【Java入门指南 Day12:Java集合框架】
java·开发语言·python
Zyyyyu_1 小时前
捣鼓小玩意-分批处理工具类
java
付宇轩1 小时前
leetcode 3195.包含所有1的最小矩形面积I
java·算法·leetcode