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

devtools/2024/12/22 17:18:43/

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/devtools/144429.html

相关文章

免费送源码:Java+ssm++MVC+HTML+CSS+MySQL springboot 社区医院信息管理系统的设计与实现 计算机毕业设计原创定制

摘 要 随着互联网趋势的到来&#xff0c;各行各业都在考虑利用互联网将自己推广出去&#xff0c;最好方式就是建立自己的互联网系统&#xff0c;并对其进行维护和管理。在现实运用中&#xff0c;应用软件的工作规则和开发步骤&#xff0c;采用Java技术建设社区医院信息管理系统…

React与Vue的区别(相同点和不同点)

前言 JavaScript是世界上最流行的语言之一&#xff0c;React和Vue是JS最流行的两个框架。但各有优缺点&#xff0c;本文将详细对比两大框架 一、框架背景 React React是由Facebook开发的用于构建用户界面的JavaScript库&#xff0c;Facebook对市场上JavaScript MVC框架都不太…

Linux设置篇

查看主机名 hostname 修改主机名 hostnamectl set-hostname 主机名 配置ip映射 vi /etc/hosts 192.168.1.10 pure 限制SSH登录的IP a) 设置禁止所有ip连接服务器的SSH vi /etc/hosts.deny sshd:all:deny b) 设置允许指定ip连接服务器的SSH&#xff08;这边建议设置一个备…

【计算机网络】期末考试预习复习|上

作业讲解 物理层作业 共有4个用户进行CDMA通信。这4个用户的码片序列为&#xff1a; A: (–1 –1 –1 1 1 –1 1 1)&#xff1b;B: (–1 –1 1 –1 1 1 1 –1) C: (–1 1 –1 1 1 1 –1 –1)&#xff1b;D: (–1 1 –1 –1 –1 –1 1 –1) 现收到码片序列&#xff1a;(–1 1 –…

linux------vim命令

一、基本模式切换 普通模式&#xff08;Normal Mode&#xff09; 当你打开Vim时&#xff0c;默认进入普通模式。在这个模式下&#xff0c;可以使用各种命令来移动光标、删除文本、复制粘贴等操作。例如&#xff0c;使用h、j、k、l来移动光标。h是向左移动一个字符&#xff0c;j…

React 事件机制和原生 DOM 事件流有什么区别

发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【宝藏入口】。 React 的事件机制与原生 DOM 事件流在设计和实现上有一些显著的区别。了解这些区别有助于我们更好地理解 React 是如何管理事件的…

未来趋势系列 篇五:自主可控科技题材解析和股票梳理

文章目录 系列文章自主可控科技题材分析国产算力信创(信息技术应用创新)华为鸿蒙军工信息化半导体芯片卫星互联网工业软件股票梳理系列文章 未来趋势系列 篇一:AI题材解析和股票梳理 未来趋势系列 篇一(加更):AI医疗题材解析和股票梳理 未来趋势系列 篇二:HBM题材解析和…

本地maven项目打包部署到maven远程私库

目的&#xff1a;在自己的maven项目中&#xff0c;要把当前maven项目部署到maven私库&#xff0c;供其他人引入依赖使用。 首先要确保你当前能访问到你的私库&#xff0c;能拉私库的maven依赖即可。 maven部署命令&#xff1a; mvn deploy:deploy-file -Dmaven.test.skiptrue -…