当前位置:   article > 正文

poi-tl(1.10.0)动态合并同列不同行单元格(动态数据)_dynamictablerenderpolicy动态表格用法

dynamictablerenderpolicy动态表格用法

一、在有些业务场景下,我们需要导出一些word文档的报告等,这里我推荐一下poi-tl,这是我开发当中用到的。由于业务数据的复杂性,easyWord没法满足需求,所以这里推荐使用poi-tl,因为它提供了针对处理复杂数据的很多接口策略,还可以根据自己具体的业务需求来扩展。

二、这次是关于如何动态合并单元格。参考了其他帖子,但是他们用到的数据都是固定的,但是对于动态数据是不适用的,下面直接上代码,分享一下我是如何处理的?

  1. package com.cantai.qmsat.utils.poi;
  2. import com.cantai.qmsat.at.operate.entity.InstrumentEntity;
  3. import com.deepoove.poi.data.CellRenderData;
  4. import com.deepoove.poi.data.RowRenderData;
  5. import com.deepoove.poi.policy.DynamicTableRenderPolicy;
  6. import com.deepoove.poi.policy.TableRenderPolicy;
  7. import com.deepoove.poi.util.TableTools;
  8. import org.apache.poi.xwpf.usermodel.XWPFTable;
  9. import org.apache.poi.xwpf.usermodel.XWPFTableCell;
  10. import org.apache.poi.xwpf.usermodel.XWPFTableRow;
  11. import java.util.ArrayList;
  12. import java.util.HashMap;
  13. import java.util.HashSet;
  14. import java.util.List;
  15. import java.util.stream.Collectors;
  16. /**
  17. * @author shijin
  18. * @create 2022-11-04 19:30
  19. */
  20. public class RowspanPolicy extends DynamicTableRenderPolicy {
  21. @Override
  22. public void render(XWPFTable table, Object data) throws Exception {
  23. int num = 0;
  24. if (null == data) return;
  25. List<RowRenderData> detailData = (List<RowRenderData>) data;
  26. if (null != detailData) {
  27. table.removeRow(2);
  28. // 循环插入行,必须采用这种遍历,不然数据会反过来
  29. for (int i = detailData.size() - 1; i >= 0; i--) {
  30. //根据数据长度创建对应行数
  31. XWPFTableRow insertNewTableRow = table.insertNewTableRow(2);
  32. for (int j = 0; j < 5; j++) {
  33. //根据列的数量创建对应单元格
  34. insertNewTableRow.createCell();
  35. }
  36. // 单行渲染
  37. TableRenderPolicy.Helper.renderRow(table.getRow(2), detailData.get(i));
  38. }
  39. //遍历完整个图表之后再合并
  40. List<String> list = new ArrayList<>();
  41. HashMap<String, Object> nameNumMap = new HashMap<>();
  42. for (int i = 0; i < detailData.size(); i++) {
  43. String typeName = detailData.get(i).getCells().get(1).getParagraphs().get(0).getContents().get(0).toString();
  44. list.add(typeName);
  45. }
  46. List<String> collect = list.stream().distinct().collect(Collectors.toList());
  47. for (String s : collect) {
  48. for (int i = 0; i < detailData.size(); i++) {
  49. String typeName1 = detailData.get(i).getCells().get(1).getParagraphs().get(0).getContents().get(0).toString();
  50. if (s == typeName1) {
  51. num++;
  52. }
  53. }
  54. nameNumMap.put(s, num);
  55. num = 0;
  56. }
  57. //开始合并
  58. for (String s : collect) {
  59. //从我们map中取出刚才放入的单位的个数
  60. Integer change = Integer.parseInt(String.valueOf(nameNumMap.get(s)));
  61. //开始循环数据
  62. //元素第一次出现的位置
  63. int firstLocation = list.lastIndexOf(s) + 1;
  64. int fromRow = firstLocation - change + 2;
  65. int toRow = list.lastIndexOf(s) + 2;
  66. if (change > 1) {
  67. TableTools.mergeCellsVertically(table, 1, fromRow, toRow);
  68. }
  69. }
  70. }
  71. }
  72. }
  1. 创建一个类RowspanPolicy继承DynamicTableRenderPolicy,重写render方

  1. 准备数据:参考了官网的合并方法,data中的数据类型要转为RowRenderData,所以在组装数据的时候,直接组装成RowRenderData类型的,如下:

  1. for (AfTtiInstrumentVo afTtiInstrumentVo : instrumentVos) {
  2. int i = instrumentVos.indexOf(afTtiInstrumentVo) + 1;
  3. DateFormat cst = new SimpleDateFormat("yyyy-MM-dd");
  4. DateFormat gmt = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ENGLISH);
  5. Date date1 = gmt.parse(afTtiInstrumentVo.getNextCalibrationDate().toString());
  6. String date2 = cst.format(date1);
  7. RowRenderData rowRenderData = Rows.of(Integer.toString(i), afTtiInstrumentVo.getTestName(), afTtiInstrumentVo.getDeviceName(), afTtiInstrumentVo.getFactoryNumber(), date2).center().create();
  8. instrumentList1.add(rowRenderData);
  9. }
  1. 数据准备好之后,开始重写DynamicTableRenderPolicy策略接口,首先是将数据逐个添加到每一个的单元格,如下:

  1. //如果顺序遍历的话,数据的顺序和原来的顺序会相反(这是在debug的时候发现的,具体原因也没深究),所以采取倒叙遍历
  2. for (int i = detailData.size() - 1; i >= 0; i--) {
  3. //根据数据长度创建对应行数
  4. XWPFTableRow insertNewTableRow = table.insertNewTableRow(2);
  5. for (int j = 0; j < 5; j++) {
  6. //根据列的数量创建对应单元格
  7. insertNewTableRow.createCell();
  8. }
  9. // 单行渲染数据
  10. TableRenderPolicy.Helper.renderRow(table.getRow(2), detailData.get(i));
  11. }
  1. 下面就开始合并同一列下的数据相同的单元格

  1. //收集操作列的全部数据,放在List中(我这里需要操作的是第2列数据getCells().get(1))
  2. List<String> list = new ArrayList<>();
  3. HashMap<String, Object> nameNumMap = new HashMap<>();
  4. for (int i = 0; i < detailData.size(); i++) {
  5. String typeName = detailData.get(i).getCells().get(1).getParagraphs().get(0).getContents().get(0).toString();
  6. list.add(typeName);
  7. }
  8. //筛选出不同的数据重新放在新list中
  9. List<String> collect = list.stream().distinct().collect(Collectors.toList());
  10. //统计不同数据在全部数据中出现的次数num,并整合放在map中,后面合并的行数需要用到num
  11. for (String s : collect) {
  12. for (int i = 0; i < detailData.size(); i++) {
  13. String typeName1 = detailData.get(i).getCells().get(1).getParagraphs().get(0).getContents().get(0).toString();
  14. if (s == typeName1) {
  15. num++;
  16. }
  17. }
  18. nameNumMap.put(s, num);
  19. //每统计完一个,需要重置num
  20. num = 0;
  21. }
  22. //开始合并
  23. for (String s : collect) {
  24. //从我们map中取出刚才放入的单位的个数
  25. Integer change = Integer.parseInt(String.valueOf(nameNumMap.get(s)));
  26. //开始循环数据
  27. //元素第一次出现的位置
  28. int firstLocation = list.lastIndexOf(s) + 1;
  29. int fromRow = firstLocation - change + 2;
  30. int toRow = list.lastIndexOf(s) + 2;
  31. //由于TableTools.mergeCellsVertically中参数toRow要大于fromRow,否则会报错,所以num>1的才参与合并
  32. if (change > 1) {
  33. TableTools.mergeCellsVertically(table, 1, fromRow, toRow);
  34. }
  35. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/606776
推荐阅读
相关标签
  

闽ICP备14008679号