You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

227 lines
8.3 KiB

  1. package cn.afterturn.easypoi.util;
  2. import java.util.ArrayList;
  3. import java.util.HashMap;
  4. import java.util.List;
  5. import java.util.Map;
  6. import java.util.Set;
  7. import org.apache.commons.lang3.StringUtils;
  8. import org.apache.poi.ss.usermodel.Cell;
  9. import org.apache.poi.ss.usermodel.Row;
  10. import org.apache.poi.ss.usermodel.Sheet;
  11. import org.apache.poi.ss.util.CellRangeAddress;
  12. import cn.afterturn.easypoi.excel.entity.params.MergeEntity;
  13. import cn.afterturn.easypoi.exception.excel.ExcelExportException;
  14. import org.slf4j.Logger;
  15. import org.slf4j.LoggerFactory;
  16. /**
  17. * 纵向合并单元格工具类
  18. *
  19. * @author JueYue
  20. * 2015年6月21日 上午11:21:40
  21. */
  22. public final class PoiMergeCellUtil {
  23. private static final Logger LOGGER = LoggerFactory.getLogger(PoiMergeCellUtil.class);
  24. private PoiMergeCellUtil() {
  25. }
  26. /**
  27. * 纵向合并相同内容的单元格
  28. *
  29. * @param sheet
  30. * @param startRow 开始行
  31. * @param columns 需要处理的列
  32. */
  33. public static void mergeCells(Sheet sheet, int startRow, Integer... columns) {
  34. if (columns == null) {
  35. throw new ExcelExportException("至少需要处理1列");
  36. }
  37. Map<Integer, int[]> mergeMap = new HashMap<Integer, int[]>();
  38. for (int i = 0; i < columns.length; i++) {
  39. mergeMap.put(columns[i], null);
  40. }
  41. mergeCells(sheet, mergeMap, startRow, sheet.getLastRowNum());
  42. }
  43. /**
  44. * 纵向合并相同内容的单元格
  45. *
  46. * @param sheet
  47. * @param mergeMap key--列,value--依赖的列,没有传空
  48. * @param startRow 开始行
  49. */
  50. public static void mergeCells(Sheet sheet, Map<Integer, int[]> mergeMap, int startRow) {
  51. mergeCells(sheet, mergeMap, startRow, sheet.getLastRowNum());
  52. }
  53. /**
  54. * 纵向合并相同内容的单元格
  55. *
  56. * @param sheet
  57. * @param mergeMap key--列,value--依赖的列,没有传空
  58. * @param startRow 开始行
  59. * @param endRow 结束行
  60. */
  61. public static void mergeCells(Sheet sheet, Map<Integer, int[]> mergeMap, int startRow,
  62. int endRow) {
  63. Map<Integer, MergeEntity> mergeDataMap = new HashMap<Integer, MergeEntity>();
  64. if (mergeMap.size() == 0) {
  65. return;
  66. }
  67. Row row;
  68. Set<Integer> sets = mergeMap.keySet();
  69. String text;
  70. for (int i = startRow; i <= endRow; i++) {
  71. row = sheet.getRow(i);
  72. for (Integer index : sets) {
  73. if (row == null || row.getCell(index) == null) {
  74. if (mergeDataMap.get(index) == null) {
  75. continue;
  76. }
  77. if (mergeDataMap.get(index).getEndRow() == 0) {
  78. mergeDataMap.get(index).setEndRow(i - 1);
  79. }
  80. } else {
  81. text = PoiCellUtil.getCellValue(row.getCell(index));
  82. if (StringUtils.isNotEmpty(text)) {
  83. handlerMergeCells(index, i, text, mergeDataMap, sheet, row.getCell(index),
  84. mergeMap.get(index));
  85. } else {
  86. mergeCellOrContinue(index, mergeDataMap, sheet);
  87. }
  88. }
  89. }
  90. }
  91. if (mergeDataMap.size() > 0) {
  92. for (Integer index : mergeDataMap.keySet()) {
  93. if (mergeDataMap.get(index).getEndRow() > mergeDataMap.get(index).getStartRow()) {
  94. PoiMergeCellUtil.addMergedRegion(sheet, mergeDataMap.get(index).getStartRow(),
  95. mergeDataMap.get(index).getEndRow(), index, index);
  96. }
  97. }
  98. }
  99. }
  100. /**
  101. * 处理合并单元格
  102. *
  103. * @param index
  104. * @param rowNum
  105. * @param text
  106. * @param mergeDataMap
  107. * @param sheet
  108. * @param cell
  109. * @param delys
  110. */
  111. private static void handlerMergeCells(Integer index, int rowNum, String text,
  112. Map<Integer, MergeEntity> mergeDataMap, Sheet sheet,
  113. Cell cell, int[] delys) {
  114. if (mergeDataMap.containsKey(index)) {
  115. if (checkIsEqualByCellContents(mergeDataMap.get(index), text, cell, delys, rowNum)) {
  116. mergeDataMap.get(index).setEndRow(rowNum);
  117. } else {
  118. if (mergeDataMap.get(index).getEndRow() > mergeDataMap.get(index).getStartRow()) {
  119. PoiMergeCellUtil.addMergedRegion(sheet, mergeDataMap.get(index).getStartRow(),
  120. mergeDataMap.get(index).getEndRow(), index, index);
  121. }
  122. mergeDataMap.put(index, createMergeEntity(text, rowNum, cell, delys));
  123. }
  124. } else {
  125. mergeDataMap.put(index, createMergeEntity(text, rowNum, cell, delys));
  126. }
  127. }
  128. /**
  129. * 字符为空的情况下判断
  130. *
  131. * @param index
  132. * @param mergeDataMap
  133. * @param sheet
  134. */
  135. private static void mergeCellOrContinue(Integer index, Map<Integer, MergeEntity> mergeDataMap,
  136. Sheet sheet) {
  137. if (mergeDataMap.containsKey(index)
  138. && mergeDataMap.get(index).getEndRow() != mergeDataMap.get(index).getStartRow()) {
  139. try {
  140. PoiMergeCellUtil.addMergedRegion(sheet, mergeDataMap.get(index).getStartRow(),
  141. mergeDataMap.get(index).getEndRow(), index, index);
  142. } catch (Exception e) {
  143. }
  144. mergeDataMap.remove(index);
  145. }
  146. }
  147. private static MergeEntity createMergeEntity(String text, int rowNum, Cell cell, int[] delys) {
  148. MergeEntity mergeEntity = new MergeEntity(text, rowNum, rowNum);
  149. // 存在依赖关系
  150. if (delys != null && delys.length != 0) {
  151. List<String> list = new ArrayList<String>(delys.length);
  152. mergeEntity.setRelyList(list);
  153. for (int i = 0; i < delys.length; i++) {
  154. list.add(getCellNotNullText(cell, delys[i], rowNum));
  155. }
  156. }
  157. return mergeEntity;
  158. }
  159. private static boolean checkIsEqualByCellContents(MergeEntity mergeEntity, String text,
  160. Cell cell, int[] delys, int rowNum) {
  161. // 没有依赖关系
  162. if (delys == null || delys.length == 0) {
  163. return mergeEntity.getText().equals(text);
  164. }
  165. // 存在依赖关系 测试
  166. if (mergeEntity.getText().equals(text)) {
  167. for (int i = 0; i < delys.length; i++) {
  168. if (mergeEntity.getRelyList().get(i) == null || !mergeEntity.getRelyList().get(i)
  169. .equals(getCellNotNullText(cell, delys[i], rowNum))) {
  170. return false;
  171. }
  172. }
  173. return true;
  174. }
  175. return false;
  176. }
  177. /**
  178. * 获取一个单元格的值,确保这个单元格必须有值,不然向上查询
  179. *
  180. * @param cell
  181. * @param index
  182. * @param rowNum
  183. * @return
  184. */
  185. private static String getCellNotNullText(Cell cell, int index, int rowNum) {
  186. if (cell == null || cell.getRow() == null) {
  187. return null;
  188. }
  189. if (cell.getRow().getCell(index) != null
  190. && StringUtils.isNotEmpty(PoiCellUtil.getCellValue(cell.getRow().getCell(index)))) {
  191. return PoiCellUtil.getCellValue(cell.getRow().getCell(index));
  192. }
  193. return getCellNotNullText(cell.getRow().getSheet().getRow(--rowNum).getCell(index), index,
  194. rowNum);
  195. }
  196. public static void addMergedRegion(Sheet sheet, int firstRow, int lastRow, int firstCol, int lastCol) {
  197. try {
  198. sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol));
  199. } catch (Exception e) {
  200. LOGGER.error("发生了一次合并单元格错误,{},{},{},{}", new Integer[]{
  201. firstRow, lastRow, firstCol, lastCol
  202. });
  203. // 忽略掉合并的错误,不打印异常
  204. LOGGER.debug(e.getMessage(), e);
  205. }
  206. }
  207. }