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

server/2024/12/23 5:52:01/

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

java">word">public word">class LoopRowGroupTableRenderPolicy word">implements RenderPolicy {word">private String prefix;word">private String suffix;word">private word">boolean onSameLine;word">private TableGroupPolicy tableGroupPolicy;word">private word">final String MERGE_FLAG = "MERGE_FLAG";word">public LoopRowGroupTableRenderPolicy(TableGroupPolicy tableGroupPolicy) {word">this.prefix = "[";word">this.suffix = "]";word">this.onSameLine = false;word">this.tableGroupPolicy = tableGroupPolicy;}@Overrideword">public word">void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {RunTemplate runTemplate = (RunTemplate) eleTemplate;XWPFRun run = runTemplate.getRun();word">try {word">if (!TableTools.isInsideTable(run)) {word">throw word">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);word">int templateRowIndex = getTemplateRowIndex(tagCell);List<MergeDTO> mergeList = word">new ArrayList<>();word">if (data word">instanceof Iterable) {// 对数据分组List<Map<String, String>> group = groupData((List<Map<String, String>>) data);Iterator<?> iterator = ((Iterable<?>) group).iterator();XWPFTableRow templateRow = table.getRow(templateRowIndex);word">int step = templateRow.getTableICells().size();word">int insertPosition = templateRowIndex;TemplateResolver resolver = word">new TemplateResolver(template.getConfig().copy(prefix, suffix));word">boolean firstFlag = true;word">int index = 0;word">boolean hasNext = iterator.hasNext();word">while (hasNext) {HashMap root = (HashMap) iterator.next();word">if (root.containsKey(MERGE_FLAG) && "Y".equals(root.get(MERGE_FLAG))) {word">int start = tableGroupPolicy.getFromIndex() > 0 ? tableGroupPolicy.getFromIndex() : 0;word">int end = tableGroupPolicy.getToIndex() >= step ? step - 1 : tableGroupPolicy.getToIndex();mergeList.add(word">new MergeDTO(templateRowIndex, start, end));}hasNext = iterator.hasNext();insertPosition = templateRowIndex++;XWPFTableRow nextRow = table.insertNewTableRow(insertPosition);setTableRow(table, templateRow, insertPosition);// double set rowXmlCursor newCursor = templateRow.getCtRow().newCursor();newCursor.toPrevSibling();XmlObject object = newCursor.getObject();nextRow = word">new XWPFTableRow((CTRow) object, table);word">if (!firstFlag) {// update VMerge cells for non-first rowList<XWPFTableCell> tableCells = nextRow.getTableCells();word">for (XWPFTableCell cell : tableCells) {CTTcPr tcPr = TableTools.getTcPr(cell);CTVMerge vMerge = tcPr.getVMerge();word">if (word">null == vMerge) word">continue;word">if (STMerge.RESTART == vMerge.getVal()) {vMerge.setVal(STMerge.CONTINUE);}}} word">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());word">new DocumentProcessor(template, resolver, dataCompute).process(templates);});}}word">if (!CollectionUtils.isEmpty(mergeList)) {mergeList.forEach(c -> mergeCellsHorizontal(table, c.getIndex(), c.getFromIndex(), c.getToIndex()));}table.removeRow(templateRowIndex);} word">catch (Exception e) {word">throw word">new RenderException("HackLoopTable for " + eleTemplate + " error: " + e.getMessage(), e);}}word">private List<Map<String, String>> groupData(List<Map<String, String>> data) {List<Map<String, String>> result = word">new ArrayList<>();Map<String, List<Map<String, String>>> collect = data.stream().collect(Collectors.groupingBy(map -> {word">if (map.containsKey(tableGroupPolicy.getGroupFieldName())) {word">if (StringUtils.isNotEmpty(map.get(tableGroupPolicy.getGroupFieldName()))) {word">return map.get(tableGroupPolicy.getGroupFieldName());} word">else {word">return "";}} word">else {word">return "";}}));collect.keySet().forEach(c -> {Map<String, String> map = word">new HashMap<>();map.put(MERGE_FLAG, "Y");map.put(tableGroupPolicy.getFirstFieldName(), c);result.add(map);result.addAll(collect.get(c));});word">return result;}word">private word">int getTemplateRowIndex(XWPFTableCell tagCell) {XWPFTableRow tagRow = tagCell.getTableRow();word">return onSameLine ? getRowIndex(tagRow) : (getRowIndex(tagRow) + 1);}/*** word跨列合并单元格* table 表单对象* row  合并行* fromCell 起始列* toCell  结束列*/word">private word">static word">void mergeCellsHorizontal(XWPFTable table, Integer row, Integer fromCell, Integer toCell) {word">for (word">int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) {XWPFTableCell cell = table.getRow(row).getCell(cellIndex);word">if (cellIndex == fromCell) {// The first merged cell is set with RESTART merge valuecell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);} word">else {// Cells which join (merge) the first one, are set with CONTINUEcell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);}}}@SuppressWarnings("unchecked")word">private word">void setTableRow(XWPFTable table, XWPFTableRow templateRow, word">int pos) {List<XWPFTableRow> rows = (List<XWPFTableRow>) ReflectionUtils.getValue("tableRows", table);rows.set(pos, templateRow);table.getCTTbl().setTrArray(pos, templateRow.getCtRow());}word">private word">int getRowIndex(XWPFTableRow row) {List<XWPFTableRow> rows = row.getTable().getRows();word">return rows.indexOf(row);}@Dataword">public word">static word">class TableGroupPolicy {//  首字段名称word">private String firstFieldName;//  分组字段名称word">private String groupFieldName;//  合并开始下标word">private Integer fromIndex;//  合并结束下标word">private Integer toIndex;word">public TableGroupPolicy() {}word">public TableGroupPolicy(String firstFieldName, String groupFieldName, Integer fromIndex, Integer toIndex) {word">this.firstFieldName = firstFieldName;word">this.groupFieldName = groupFieldName;word">this.fromIndex = fromIndex;word">this.toIndex = toIndex;}}@Dataword">static word">class MergeDTO {//  当前下标word">private Integer index;//  合并开始下标word">private Integer fromIndex;//  合并结束下标word">private Integer toIndex;word">public MergeDTO() {}word">public MergeDTO(Integer index, Integer fromIndex, Integer toIndex) {word">this.index = index;word">this.fromIndex = fromIndex;word">this.toIndex = toIndex;}}}

绑定标签:

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

http://www.ppmy.cn/server/152419.html

相关文章

设计模式の命令访问者迭代器模式

文章目录 前言一、命令模式二、访问者模式三、迭代器模式 前言 本篇是关于设计模式中命令模式、访问者模式、以及迭代器模式的学习笔记。 一、命令模式 命令模式是一种行为型设计模式&#xff0c;其核心目的在于将命令的发送者和接受者解耦&#xff0c;提供一个中间层对命令进行…

android recycleview 中倒计时数据错乱

原因 recyceleview 当页面划出屏幕外后&#xff0c;默认会有两条进入缓存区&#xff0c;这些item的结构会被保存&#xff0c;数据被清除&#xff0c;方便其他新进入屏幕的数据复用item&#xff0c;超过两条外的item会进入缓存池被完全销毁重用。 如果我们的页面上有editText 或…

经典系统重塑(sql层)

内容 这个音乐门户网站是我一直在写的一个项目&#xff0c;因为周期较长&#xff0c;虽然功能都给予了大体实现&#xff0c;但是确实无论是sql层面还是业务层面都有很大缺陷。 先看最主要的music表&#xff0c;这music字段指的是音乐地址&#xff0c;名字需要改一下&#xff0…

【批量生成WORD和PDF文件】根据表格内容和模板文件批量创建word文件,一次性生成多个word文档和批量创建PDF文件

如何按照Word模板和表格的数据快速制作5000个word文档 &#xff1f; 在与客户的合作的中需要创建大量的合同&#xff0c;这些合同的模板大概都是一致的&#xff0c;是不是每次我们都需要填充不一样的数据来完成&#xff1f; 今天用表格数据完成合同模板的填充&#xff0c;批量…

分类模型的预测概率解读:3D概率分布可视化的直观呈现

背景 在分类模型中&#xff0c;预测概率不仅是结果&#xff0c;更是模型决策的关键依据。为了更直观地理解这些概率分布&#xff0c;3D可视化提供了一种生动的展示方式&#xff0c;本文通过3D概率分布图&#xff0c;直观展示分类模型的预测概率 代码实现 基于时间序列的3D分…

RBF分类-径向基函数神经网络(Radial Basis Function Neural Network)

RBF分类详细介绍 源码 什么是RBF分类&#xff1f; RBF分类&#xff08;径向基函数分类&#xff09;是一种基于**径向基函数神经网络&#xff08;Radial Basis Function Neural Network, RBFNN&#xff09;**的分类算法。RBF神经网络是一种前馈神经网络&#xff0c;广泛应用于…

城市灾害应急管理集成系统——系统介绍

1 项目概述 1.1选题背景 城市灾害已经成为影响我国发展的重要因素,近年来我国高度重视城市灾害应急研究。其中洪涝、团雾、火灾和地面塌陷等多种灾害是当前影响人民群众生产生活的主要灾害。中共中央提出,在第十四个五年计划期间要提升城市治理水平,加强城市治理中的风险防…

鸿蒙项目云捐助第十九讲云捐助百度智能名片识别

鸿蒙项目云捐助第十九讲云捐助百度智能名片识别 在鸿蒙云捐助项目中添加智能元素&#xff0c;这里实现鸿蒙云捐助的名片识别功能&#xff0c;用户只需要上传一张名片&#xff0c;就可以识别出地址和名字&#xff0c;根据地址和名字进行真实信息的确认。 首先找到OCR的名片识别…