ExcelUtils.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. package com.shkpr.service.alambizplugin.commtools;
  2. import com.global.base.log.LogLevelFlag;
  3. import com.global.base.log.LogPrintMgr;
  4. import com.shkpr.service.alambizplugin.annotation.ExcelMapping;
  5. import com.shkpr.service.alambizplugin.constants.ExcelEnum;
  6. import com.shkpr.service.alambizplugin.constants.LogFlagBusiType;
  7. import org.apache.commons.lang3.StringUtils;
  8. import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  9. import org.apache.poi.ss.usermodel.Cell;
  10. import org.apache.poi.ss.usermodel.CellType;
  11. import org.apache.poi.ss.usermodel.DateUtil;
  12. import org.apache.poi.ss.usermodel.Row;
  13. import org.apache.poi.ss.usermodel.Sheet;
  14. import org.apache.poi.ss.usermodel.Workbook;
  15. import org.apache.poi.xssf.usermodel.XSSFCell;
  16. import org.apache.poi.xssf.usermodel.XSSFCellStyle;
  17. import org.apache.poi.xssf.usermodel.XSSFFont;
  18. import org.apache.poi.xssf.usermodel.XSSFRichTextString;
  19. import org.apache.poi.xssf.usermodel.XSSFRow;
  20. import org.apache.poi.xssf.usermodel.XSSFSheet;
  21. import org.apache.poi.xssf.usermodel.XSSFWorkbook;
  22. import java.io.IOException;
  23. import java.io.InputStream;
  24. import java.io.OutputStream;
  25. import java.lang.reflect.Field;
  26. import java.lang.reflect.InvocationTargetException;
  27. import java.nio.file.Files;
  28. import java.nio.file.Paths;
  29. import java.text.DecimalFormat;
  30. import java.util.ArrayList;
  31. import java.util.Arrays;
  32. import java.util.Date;
  33. import java.util.HashMap;
  34. import java.util.List;
  35. import java.util.Map;
  36. import java.util.function.Function;
  37. import java.util.stream.Collectors;
  38. import java.util.stream.IntStream;
  39. /**
  40. * excel工具类
  41. *
  42. * @author 欧阳劲驰
  43. * @serial 1.0.0
  44. */
  45. public class ExcelUtils {
  46. /**
  47. * log
  48. */
  49. private static final String mStrClassName = "ExcelUtils";
  50. private static final String mBizType = LogFlagBusiType.BUSI_GIS_SURVEY.toStrValue();
  51. /**
  52. * 解析excel文件
  53. *
  54. * @param path 文件地址
  55. * @param headerRowNum 表头行
  56. * @param dataRowNum 数据行
  57. * @return 数据(key : 页名, v : 数据)
  58. */
  59. public static Map<String, List<Map<String, String>>> parseExcelFile(String path, Integer headerRowNum, Integer dataRowNum) {
  60. //excel枚举
  61. ExcelEnum excelEnum = null;
  62. //文件后缀
  63. String ext = path.substring(path.lastIndexOf("."));
  64. //根据后缀名指定枚举
  65. if (".xls".equalsIgnoreCase(ext)) excelEnum = ExcelEnum.XLS;
  66. else if (".xlsx".equalsIgnoreCase(ext)) excelEnum = ExcelEnum.XLS;
  67. if (excelEnum == null) return null;
  68. //解析文件
  69. try {
  70. return parseExcelFile(Files.newInputStream(Paths.get(path)), excelEnum, headerRowNum, dataRowNum);
  71. } catch (IOException e) {
  72. LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
  73. , String.format("excel文件解释失败 msg:%s", e.getMessage())
  74. );
  75. return null;
  76. }
  77. }
  78. /**
  79. * 解析excel文件
  80. *
  81. * @param inputStream 输入流
  82. * @param excelEnum excel类型
  83. * @param headerRowNum 表头行
  84. * @param dataRowNum 数据行
  85. * @return 数据(key : 页名, v : 数据)
  86. */
  87. public static Map<String, List<Map<String, String>>> parseExcelFile(InputStream inputStream, ExcelEnum excelEnum
  88. , Integer headerRowNum, Integer dataRowNum) {
  89. if (inputStream == null || excelEnum == null || excelEnum == ExcelEnum.CSV) return null;
  90. //读取输入流
  91. try (Workbook workbook = excelEnum == ExcelEnum.XLSX ? new XSSFWorkbook(inputStream) : new HSSFWorkbook(inputStream)) {
  92. if (workbook.getNumberOfSheets() <= 0) return null;
  93. //结果
  94. Map<String, List<Map<String, String>>> results = new HashMap<>(workbook.getNumberOfSheets());
  95. //遍历页,并解析
  96. for (Sheet sheet : workbook) results.put(sheet.getSheetName(), parseSheet(sheet, headerRowNum, dataRowNum));
  97. return results;
  98. } catch (IOException e) {
  99. LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
  100. , String.format("excel文件解释失败 msg:%s", e.getMessage())
  101. );
  102. return null;
  103. }
  104. }
  105. /**
  106. * 解析页
  107. *
  108. * @param sheet 页
  109. * @param headerRowNum 表头行
  110. * @param dataRowNum 数据行
  111. * @return 数据
  112. */
  113. private static List<Map<String, String>> parseSheet(Sheet sheet, Integer headerRowNum, Integer dataRowNum) {
  114. //数据集合
  115. List<Map<String, String>> dataList = new ArrayList<>();
  116. if (sheet == null) return dataList;
  117. //行数
  118. int rowsNum = sheet.getPhysicalNumberOfRows();
  119. if (rowsNum <= 1) return dataList;
  120. //页头行
  121. Row rowHead = sheet.getRow(headerRowNum);
  122. //字段映射
  123. Map<Integer, String> fieldMap = new HashMap<>();
  124. for (Cell cell : rowHead) {
  125. //获取值,如不为空,则存入索引关系
  126. String cellValue = getCellValue(cell);
  127. if (!StringUtils.isEmpty(cellValue)) {
  128. fieldMap.put(cell.getColumnIndex(), cellValue);
  129. }
  130. }
  131. //遍历行
  132. for (Row row : sheet) {
  133. //跳过非数据行
  134. if (row == null || row.getRowNum() < dataRowNum) continue;
  135. //跳过空行
  136. if (IntStream.range(row.getFirstCellNum(), row.getLastCellNum())
  137. .mapToObj(row::getCell)
  138. .allMatch(cell -> cell == null || cell.getCellTypeEnum() == CellType.BLANK)) continue;
  139. //数据
  140. Map<String, String> data = new HashMap<>();
  141. //遍历字段映射
  142. for (Map.Entry<Integer, String> entry : fieldMap.entrySet()) {
  143. //获取单元格
  144. Cell cell = row.getCell(entry.getKey());
  145. //设置值
  146. data.put(entry.getValue(), getCellValue(cell));
  147. }
  148. //添加数据
  149. dataList.add(data);
  150. }
  151. return dataList;
  152. }
  153. /**
  154. * excel文件转数据集合
  155. *
  156. * @param path 文件地址
  157. * @param clazz 数据类型
  158. * @param headerRowNum 表头行
  159. * @param dataRowNum 数据行
  160. * @param <E> 数据泛形
  161. * @return 数据集合
  162. */
  163. public static <E> Map<String, List<E>> parseExcelFile(String path, Class<E> clazz, Integer headerRowNum, Integer dataRowNum) {
  164. //excel枚举
  165. ExcelEnum excelEnum = null;
  166. //文件后缀
  167. String ext = path.substring(path.lastIndexOf("."));
  168. //根据后缀名指定枚举
  169. if (".xls".equalsIgnoreCase(ext)) excelEnum = ExcelEnum.XLS;
  170. else if (".xlsx".equalsIgnoreCase(ext)) excelEnum = ExcelEnum.XLS;
  171. if (excelEnum == null) return null;
  172. //解析文件
  173. try {
  174. return parseExcelFile(Files.newInputStream(Paths.get(path)), clazz, excelEnum, headerRowNum, dataRowNum);
  175. } catch (IOException e) {
  176. LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
  177. , String.format("excel文件解释失败 msg:%s", e.getMessage())
  178. );
  179. return null;
  180. }
  181. }
  182. /**
  183. * excel文件转数据集合
  184. *
  185. * @param inputStream input流
  186. * @param clazz 数据类型
  187. * @param excelEnum excel枚举
  188. * @param headerRowNum 表头行
  189. * @param dataRowNum 数据行
  190. * @param <E> 数据泛形
  191. * @return 数据集合
  192. */
  193. public static <E> Map<String, List<E>> parseExcelFile(InputStream inputStream, Class<E> clazz, ExcelEnum excelEnum
  194. , Integer headerRowNum, Integer dataRowNum) {
  195. if (inputStream == null || excelEnum == null || excelEnum == ExcelEnum.CSV) return null;
  196. //读取表
  197. try (Workbook workbook = excelEnum == ExcelEnum.XLSX ? new XSSFWorkbook(inputStream) : new HSSFWorkbook(inputStream)) {
  198. if (workbook.getNumberOfSheets() <= 0) return null;
  199. //结果
  200. Map<String, List<E>> results = new HashMap<>(workbook.getNumberOfSheets());
  201. //遍历页,并解析
  202. for (Sheet sheet : workbook)
  203. results.put(sheet.getSheetName(), parseSheet(sheet, clazz, headerRowNum, dataRowNum));
  204. return results;
  205. } catch (IOException e) {
  206. LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
  207. , String.format("excel文件解释失败 msg:%s", e.getMessage())
  208. );
  209. return null;
  210. }
  211. }
  212. /**
  213. * 解析页
  214. *
  215. * @param sheet 页
  216. * @param clazz 类型
  217. * @param headerRowNum 表头行
  218. * @param dataRowNum 数据行
  219. * @param <E> 数据泛形
  220. * @return 数据
  221. */
  222. private static <E> List<E> parseSheet(Sheet sheet, Class<E> clazz, Integer headerRowNum, Integer dataRowNum) {
  223. try {
  224. //数据集合
  225. List<E> dataList = new ArrayList<>();
  226. if (sheet == null) return dataList;
  227. //行数
  228. int rowsNum = sheet.getPhysicalNumberOfRows();
  229. if (rowsNum <= 1) return dataList;
  230. //页头行
  231. Row headerRow = sheet.getRow(headerRowNum);
  232. //字段映射
  233. Map<Integer, Field> fieldMap = Arrays.stream(clazz.getDeclaredFields())
  234. //过滤需要导出的字段
  235. .filter(f -> f.isAnnotationPresent(ExcelMapping.class))
  236. //设置字段公开
  237. .peek(f -> f.setAccessible(true))
  238. .collect(Collectors.toMap(
  239. f -> {
  240. //获取excel映射值
  241. String excelMappingValue = f.getAnnotation(ExcelMapping.class).value();
  242. //获取对应的索引
  243. return IntStream.range(0, headerRow.getLastCellNum())
  244. //过滤相同的值
  245. .filter(index -> headerRow.getCell(index).getStringCellValue().equals(excelMappingValue))
  246. .findFirst().orElse(-1);
  247. }, Function.identity()
  248. ));
  249. //遍历行
  250. for (Row row : sheet) {
  251. //跳过第非数据
  252. if (row == null || row.getRowNum() < dataRowNum) continue;
  253. //跳过空行
  254. if (IntStream.range(row.getFirstCellNum(), row.getLastCellNum())
  255. .mapToObj(row::getCell)
  256. .allMatch(cell -> cell == null || cell.getCellTypeEnum() == CellType.BLANK)) continue;
  257. //实列化数据
  258. E data = clazz.getDeclaredConstructor().newInstance();
  259. //遍历字段映射
  260. for (Map.Entry<Integer, Field> fieldEntry : fieldMap.entrySet()) {
  261. //跳过未找到的字段
  262. if (fieldEntry.getKey() == -1) continue;
  263. //获取单元格
  264. Cell cell = row.getCell(fieldEntry.getKey());
  265. //设置值
  266. setObjValue(data, fieldEntry.getValue(), getCellValue(cell));
  267. }
  268. //添加数据
  269. dataList.add(data);
  270. }
  271. return dataList;
  272. } catch (NoSuchMethodException | InvocationTargetException | InstantiationException |
  273. IllegalAccessException e) {
  274. LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName
  275. , String.format("excel页解释失败 msg:%s", e.getMessage())
  276. );
  277. return null;
  278. }
  279. }
  280. /**
  281. * @param rowsWithColsData
  282. * @param outputStream
  283. */
  284. public static void writeExcel(List<List<Object>> rowsWithColsData, OutputStream outputStream, boolean hasHeader) {
  285. if (rowsWithColsData == null || rowsWithColsData.size() <= 0 || outputStream == null)
  286. return;
  287. XSSFWorkbook xssfWorkbook = new XSSFWorkbook();
  288. XSSFSheet xssfSheet = xssfWorkbook.createSheet("sheet1");
  289. XSSFCellStyle colHeaderStyle = null;
  290. if (hasHeader) {
  291. colHeaderStyle = xssfWorkbook.createCellStyle();
  292. XSSFFont colHeaderFont = xssfWorkbook.createFont();
  293. colHeaderFont.setBold(true);
  294. colHeaderStyle.setFont(colHeaderFont);
  295. }
  296. for (int i = 0, j = rowsWithColsData.size(); i < j; i++) {
  297. XSSFRow xssfRow = xssfSheet.createRow(i);
  298. List<Object> columnData = rowsWithColsData.get(i);
  299. if (columnData == null)
  300. continue;
  301. for (int m = 0, n = columnData.size(); m < n; m++) {
  302. XSSFCell xssfCell = xssfRow.createCell(m);
  303. Object col = columnData.get(m);
  304. if (i == 0 && colHeaderStyle != null)
  305. xssfCell.setCellStyle(colHeaderStyle);
  306. if (col == null) {
  307. xssfCell.setCellValue("");
  308. } else {
  309. if (col instanceof String) {
  310. xssfCell.setCellValue(new XSSFRichTextString((String) col));
  311. } else if (col instanceof Date) {
  312. xssfCell.setCellValue((Date) col);
  313. } else if (col instanceof Boolean) {
  314. xssfCell.setCellValue((Boolean) col);
  315. } else if (col instanceof Double) {
  316. xssfCell.setCellValue((Double) col);
  317. } else
  318. xssfCell.setCellValue(new XSSFRichTextString(String.valueOf(col)));
  319. }
  320. if (i != 0 && i == j - 1)
  321. xssfSheet.autoSizeColumn(m);
  322. }
  323. }
  324. try {
  325. xssfWorkbook.write(outputStream);
  326. outputStream.flush();
  327. outputStream.close();
  328. } catch (IOException e) {
  329. e.printStackTrace();
  330. }
  331. }
  332. /**
  333. * 获取单元格值
  334. *
  335. * @param cell 单元格
  336. * @return 值
  337. */
  338. private static String getCellValue(Cell cell) {
  339. if (cell == null) return null;
  340. //值
  341. String value = null;
  342. try {
  343. switch (cell.getCellTypeEnum()) {
  344. case NUMERIC: {
  345. if (DateUtil.isCellDateFormatted(cell)) {
  346. value = TimeTool.convertDateObj2DateStr(cell.getDateCellValue(), cell.getCellStyle().getDataFormatString());
  347. } else if (String.valueOf(cell.getNumericCellValue()).contains(".")) {
  348. DecimalFormat df = new DecimalFormat("#.####");
  349. value = df.format(cell.getNumericCellValue());
  350. } else
  351. value = String.valueOf(cell.getNumericCellValue());
  352. }
  353. break;
  354. case STRING:
  355. value = cell.getRichStringCellValue().toString();
  356. break;
  357. case BOOLEAN:
  358. value = String.valueOf(cell.getBooleanCellValue());
  359. break;
  360. case FORMULA:
  361. value = String.valueOf(cell.getNumericCellValue());
  362. break;
  363. default:
  364. break;
  365. }
  366. } catch (Exception ignored) {
  367. }
  368. return value == null ? "" : value.trim();
  369. }
  370. /**
  371. * 设置数据值
  372. *
  373. * @param data 数据
  374. * @param field 字段
  375. * @param value 值
  376. * @param <E> 数据泛形
  377. * @throws IllegalAccessException 非法访问异常
  378. */
  379. private static <E> void setObjValue(E data, Field field, Object value) throws IllegalAccessException {
  380. //值判断空
  381. if (value != null) {
  382. //判断数据类型是否相同,如相同直接设置值,如不同,则转换值
  383. if (field.getType().isAssignableFrom(value.getClass())) {
  384. //设置值
  385. field.set(data, value);
  386. } else {
  387. //如值为double类型
  388. if (value instanceof Double) {
  389. //对double类型兼容的类型处理
  390. if (field.getType() == short.class || field.getType() == Short.class)
  391. field.set(data, ((Double) value).shortValue());
  392. else if (field.getType() == int.class || field.getType() == Integer.class)
  393. field.set(data, ((Double) value).intValue());
  394. else if (field.getType() == long.class || field.getType() == Long.class)
  395. field.set(data, ((Double) value).longValue());
  396. else if (field.getType() == float.class || field.getType() == Float.class)
  397. field.set(data, ((Double) value).floatValue());
  398. }
  399. }
  400. }
  401. }
  402. }