OnceReadListener.java 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. package cn.exlive.exbooter.excel;
  2. import com.alibaba.excel.context.AnalysisContext;
  3. import com.alibaba.excel.event.AnalysisEventListener;
  4. import com.google.common.collect.Lists;
  5. import com.google.common.collect.Sets;
  6. import org.apache.commons.lang3.StringUtils;
  7. import java.util.ArrayList;
  8. import java.util.HashMap;
  9. import java.util.HashSet;
  10. import java.util.Iterator;
  11. import java.util.List;
  12. import java.util.Map;
  13. import java.util.Set;
  14. import java.util.stream.Collectors;
  15. /**
  16. * Excel 读取数据,滑动读取表头,读取到表头后,开始读取数据。如果没有读取到表头,就没有数据。
  17. *
  18. * <pre>
  19. *
  20. * Created by zhenqin.
  21. * User: zhenqin
  22. * Date: 2022/10/6
  23. * Time: 下午5:44
  24. * Vendor: yiidata.com
  25. *
  26. * </pre>
  27. *
  28. * @author zhenqin
  29. */
  30. public class OnceReadListener extends AnalysisEventListener<Object> {
  31. /**
  32. * 预期的标题 Header
  33. */
  34. final Map<String, String> headerFieldMapping;
  35. /**
  36. * 实际数据
  37. */
  38. private List<Object> list = new ArrayList<Object>();
  39. /**
  40. * 实际的 Header
  41. */
  42. Map<Integer, String> headMap;
  43. /**
  44. * 是否有 header
  45. */
  46. volatile boolean hasHeader;
  47. public OnceReadListener(Map<String, String> headerFieldMapping) {
  48. this.headerFieldMapping = headerFieldMapping;
  49. }
  50. /**
  51. * 滑动读取表头
  52. * @param headMap Excel 实际表头
  53. * @param context
  54. */
  55. @Override
  56. public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
  57. Map<Integer, String> newHeadMap = new HashMap<>(headMap.size());
  58. // 使用 Stream API 对换 Key 和 Value
  59. Map<String, Integer> headMapInverse = new HashMap<>(headMap.size());
  60. for (Map.Entry<Integer, String> entry : headMap.entrySet()) {
  61. final String oriHead = entry.getValue();
  62. headMapInverse.put(oriHead, entry.getKey());
  63. String head = oriHead;
  64. // head 可能包含特殊字符
  65. if(head.contains("*")) {
  66. head = head.replaceAll("\\*", "");
  67. } else if(head.contains("(")) {
  68. head = head.startsWith("(") ? head.substring(head.indexOf(")") + 1) : head.substring(0, head.indexOf("("));
  69. } else if(head.contains("(")) {
  70. head = head.startsWith("(") ? head.substring(head.indexOf(")") + 1) : head.substring(0, head.indexOf("("));
  71. } else if(head.contains("【")) {
  72. head = head.startsWith("【") ? head.substring(head.indexOf("】") + 1) : head.substring(0, head.indexOf("【"));
  73. } else if(head.contains("[")) {
  74. head = head.startsWith("[") ? head.substring(head.indexOf("]") + 1) : head.substring(0, head.indexOf("["));
  75. }
  76. // oriHead 中 包含特殊字符
  77. if(!StringUtils.equals(oriHead, head)) {
  78. headMapInverse.put(head, entry.getKey());
  79. }
  80. }
  81. int matchCount = 0;
  82. final HashSet<Map.Entry<String, String>> entries = new HashSet<>(headerFieldMapping.entrySet());
  83. for (Map.Entry<String, String> entry : entries) {
  84. String key = entry.getKey();
  85. if(key.contains("*")) {
  86. key = key.replaceAll("\\*", "");
  87. } else if(key.contains("(")) {
  88. key = key.startsWith("(") ? key.substring(key.indexOf(")") + 1) : key.substring(0, key.indexOf("("));
  89. } else if(key.contains("(")) {
  90. key = key.startsWith("(") ? key.substring(key.indexOf(")") + 1) : key.substring(0, key.indexOf("("));
  91. } else if(key.contains("【")) {
  92. key = key.startsWith("【") ? key.substring(key.indexOf("】") + 1) : key.substring(0, key.indexOf("【"));
  93. } else if(key.contains("[")) {
  94. key = key.startsWith("[") ? key.substring(key.indexOf("]") + 1) : key.substring(0, key.indexOf("["));
  95. }
  96. final Integer index = headMapInverse.get(key);
  97. if(index != null) {
  98. matchCount++;
  99. newHeadMap.put(index, key);
  100. }
  101. // 检测是否发生了变化,如果变化,则重新放入
  102. if(!StringUtils.equals(entry.getKey(), key)) {
  103. // 重新放入新的字段
  104. headerFieldMapping.put(key, entry.getValue());
  105. }
  106. }
  107. // 如果 10个 header,满足了 6 个,则成功
  108. if((matchCount * 1.0f / headerFieldMapping.size()) >= 0.5f) {
  109. this.headMap = newHeadMap;
  110. this.hasHeader = true;
  111. }
  112. }
  113. /**
  114. * 处理数据,需要判断 header 是否读取到,读取不到则往下继续读,直到结束
  115. * @param object one row value. It is same as {@link AnalysisContext#readRowHolder()}
  116. * @param context analysis context
  117. */
  118. @Override
  119. public void invoke(Object object, AnalysisContext context) {
  120. // 先找到表头,有时候表头不在第一行
  121. if(!hasHeader) {
  122. this.invokeHeadMap((Map<Integer, String>)object, context);
  123. return;
  124. }
  125. //System.out.println(object);
  126. list.add(object);
  127. }
  128. @Override
  129. public void doAfterAllAnalysed(AnalysisContext context) {
  130. }
  131. /**
  132. * 返回表头,如果没有读取到表头,则返回 null
  133. * @return
  134. */
  135. public Map<Integer, String> getHeadMap() {
  136. return headMap;
  137. }
  138. @Override
  139. public boolean hasNext(AnalysisContext context) {
  140. return super.hasNext(context);
  141. }
  142. /**
  143. * 返回数据列表
  144. * @return
  145. */
  146. public List<Object> getList() {
  147. return list;
  148. }
  149. public void setList(List<Object> list) {
  150. this.list = list;
  151. }
  152. }