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)));
相关推荐
步行cgn4 小时前
Spring c 命名空间注入详解
java·后端·spring
明月_清风4 小时前
Maven 到底是什么?一篇文章搞懂 Java 项目构建与依赖管理
java·后端·maven
aramae5 小时前
MySQL复合查询(8)
java·c语言·开发语言·后端·算法
Rain的Java大神之路5 小时前
如何快速上传10G文件
java·spring boot·redis·后端·mysql·spring cloud·面试
Wang's Blog6 小时前
Java 接入Redis: 通用命令与键管理
java·服务器·redis
Wang's Blog6 小时前
Java 接入Redis: 列表集合与有序集合操作命令
java·服务器·redis
Ivanqhz6 小时前
SVD++算法
java·服务器·网络·深度学习·神经网络
qq_2518364577 小时前
springboot vue3 开发实现 拼豆管理系统
java·开发语言·ai编程
caoerzhong7 小时前
JeeWMS 开源仓库管理系统全景解读:一套 Java WMS 如何把 WMS/OMS/BMS/TMS 装进同一个系统
java·开源
曹牧8 小时前
Java集合框架:List、ArrayList、Map 和 HashMap
java