定义导入的excel模板
定义需要导入的EXCEL模板,EXCEL格式变更,只需要变更对应的枚举信息就可以,如果定义多个EXCEL模板,
只要定义多个枚举就行
package org.util.excel; import lombok.AllArgsConstructor; import lombok.Getter; import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * @author zhangfuzeng * @date 2021/9/12 */ public class ImportExcelTitle { @Getter @AllArgsConstructor public enum TaskImportExcel { /** * 表头信息 */ PUBLIC_DATA_ID("ID", "publicDataId", 0, true), PUBLIC_DATA_NAME("名称", "publicDataName", 40, true), TASK_USER_NAME("任务担当人", "taskUserName", 0, false), END_TIME("任务到期日", "endTime", 0, false), ; /** * 中文标题,对应EXCEL的标题,不一致会报错 */ private final String titleCn; /** * 查出的值对应Map的key */ private final String valueKey; /** * 对应的字段长度 * 为0时代表不限制 */ private final Integer titleLength; /** * 是否必填 */ private final Boolean isRequired; /** * 获取excel对应的数据 */ public static Map<String, String> getKeyValue() { return Arrays.stream(TaskImportExcel.values()).collect( Collectors.toMap(TaskImportExcel::getTitleCn, TaskImportExcel::getValueKey)); } /** * 根据值获取对应的信息 */ public static Map<String, TaskImportExcel> getExcelTitle() { return Arrays.stream(TaskImportExcel.values()).collect( Collectors.toMap(TaskImportExcel::getValueKey, title -> title)); } public static List<String> checkData(TaskImportExcel taskImportExcel, String value) { return checkDataCommon(value, taskImportExcel.getIsRequired(), taskImportExcel.getTitleCn(), taskImportExcel.getTitleLength()); } } /** * 校验导入信息长度和必填选项 */ private static List<String> checkDataCommon(String value, Boolean isRequired, String titleCn, Integer titleLength) { List<String> result = new ArrayList<>(); if (Boolean.TRUE.equals(isRequired) && StringUtils.isBlank(value)) { result.add(String.format("%s信息未填", titleCn)); } if (titleLength != 0 && value != null && value.length() > titleLength) { result.add(String.format("%s过长", titleCn)); } return result; } }
导入的excel处理
对导入的excel进行处理,按照上述ImportExcelTitle.java中的配置,将导入的excel转化成List<Map<String, String>>格式,
Map<String, String>中key是ImportExcelTitle.java中定义的valueKey,value对应的是excel导入的值。
package org.util.excel; import lombok.extern.slf4j.Slf4j; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.IOException; import java.io.InputStream; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author zhangfuzeng * @date 2021/9/16 */ @Slf4j public class ImportExcelUtil { private ImportExcelUtil() { } /** * 2003- 版本的excel */ private static final String EXCEL_2003L = ".xls"; /** * 2007+ 版本的excel */ private static final String EXCEL_2007U = ".xlsx"; private static final String GENERAL = "General"; private static final String M_D_YY = "m/d/yy"; /** * 将流中的Excel数据转成List<Map> * * @param in 输入流 * @param fileName 文件名(判断Excel版本) * @return EXCEL转化后的数据 */ public static List<Map<String, String>> parseExcel(InputStream in, String fileName, Map<String, String> titleKey) throws IOException { // 根据文件名来创建Excel工作薄 Workbook work = getWorkbook(in, fileName); Sheet sheet; Row row; Cell cell; // 返回数据 List<Map<String, String>> ls = new ArrayList<>(); // 遍历Excel中所有的sheet sheet = work.getSheetAt(0); if (sheet == null) { return ls; } // 取第一行标题 Row topRow = sheet.getRow(0); if (null == topRow) { return ls; } row = sheet.getRow(0); String[] title; if (row == null) { return ls; } title = new String[row.getLastCellNum()]; for (int y = row.getFirstCellNum(); y < row.getLastCellNum(); y++) { cell = row.getCell(y); title[y] = (String) getCellValue(cell); } // 遍历当前sheet中的所有行 // 坑:sheet.getLastRowNum() 最后一行行标,比行数小1 for (int j = 1; j <= sheet.getLastRowNum(); j++) { row = sheet.getRow(j); Map<String, String> m = new HashMap<>(row.getLastCellNum()); // 遍历所有的列 for (int y = row.getFirstCellNum(); y < row.getLastCellNum(); y++) { cell = row.getCell(y); String key = title[y].replace(" ", ""); if (titleKey.get(key) == null) { log.error("导入excel出现错误的标题:" + key); throw new RuntimeException("excel出现错误的标题:" + key); } m.put(titleKey.get(key), getCellValue(cell).toString().trim()); } ls.add(m); } work.close(); return ls; } /** * 描述:根据文件后缀,自适应上传文件的版本 * * @param inStr ,fileName * @return 返回的数据 */ public static Workbook getWorkbook(InputStream inStr, String fileName) throws IOException { Workbook wb; String fileType = fileName.substring(fileName.lastIndexOf(".")); if (EXCEL_2003L.equals(fileType)) { // 2003- wb = new HSSFWorkbook(inStr); } else if (EXCEL_2007U.equals(fileType)) { // 2007+ wb = new XSSFWorkbook(inStr); } else { throw new RuntimeException("解析的文件格式有误!"); } return wb; } public static Object getCellValue(Cell cell) { Object value = new Object(); // 日期格式化 SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd"); if (cell == null) { return ""; } switch (cell.getCellType()) { case STRING: case FORMULA: value = cell.getRichStringCellValue().getString(); break; case NUMERIC: if (GENERAL.equals(cell.getCellStyle().getDataFormatString())) { double cellValue = cell.getNumericCellValue(); value = replace(String.valueOf(cellValue)); } else if (M_D_YY.equals(cell.getCellStyle().getDataFormatString())) { value = sdf.format(cell.getDateCellValue()); } else { DataFormatter formatter = new DataFormatter(); // 直接获取到单元格的值 value = formatter.formatCellValue(cell); } break; case BOOLEAN: value = cell.getBooleanCellValue(); break; case BLANK: value = ""; break; default: break; } return value; } public static String replace(String s) { char a = '.'; if (s.indexOf(a) >= 0) { //去掉多余的0 s = s.replaceAll("0+$", ""); //如最后一位是.则去掉 s = s.replaceAll("[.]$", ""); } return s; } }
调用导入任务信息
测试调用, 拿到List<Map<String, String>> excelList就是解析excel的结果,后续根据自己的业务做相应的处理。
@ApiOperation(value = "导入任务信息") @PostMapping("/importTask") public void importTask(@RequestParam(value = "file") MultipartFile fileToUpload) { List<Map<String, String>> excelList; try { excelList = ImportExcelUtil.parseExcel( fileToUpload.getInputStream(), fileToUpload.getOriginalFilename(), ImportExcelTitle.TaskImportExcel.getKeyValue()); } catch (IOException e) { log.error("解析excel时失败" + e.getMessage()); } }
如果你觉着本文配置太过复杂,想直接可以使用,或者导入的数据量过大,想优化性能,可以看我的另一篇博客,使用阿里的easyExcel工具包,上手绝对快的一批
JAVA使用EasyExcel导入excel