Springboot操作Poi进行Excel导入
以上就是我所要导入的Excel模板。
需求重点
经过这次需求的实现,发现这个需求最难的点 就在 模板模板模板!
模板中数据的关系,理清楚思路
模板中的数据,到底是多sheet还是说有合并单元进行导入
实现感悟
不管是多个sheet、还是说合并单元格、最重要的思想都是说将Excel中的数据进行拼接为一条一条的List记录进行新增数据。
/**
* 用于检测是否是表头行,此方法就是说代码再执行的时候找到一级这个字段的名称,然后知道获取字段从此开始
*
* @param row
* @return
*/
private boolean isHeaderRow(Row row) {
Cell firstCell = row.getCell(1);
return firstCell != null && "一级".equals(firstCell.getStringCellValue().trim());
}
/**
*
* 上传文件,进行解析
* @param file 文件
* @return
*/
public Result<?> importExcels(MultipartFile file) {
Map<Integer, List<Object>> sheetDataMap = new HashMap<>();
try {
// 获取工作簿,解析整个Excel文件
Workbook workbook = new XSSFWorkbook(file.getInputStream());
// 循环遍历每个Sheet
for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
Sheet sheet = workbook.getSheetAt(i);
// 解析每个Sheet的数据
List<Object> sheetData = parseSheet(sheet);
// 将Sheet的数据存储到Map中,以Sheet名称为Key
sheetDataMap.put(i, sheetData);
}
} catch (Exception e) {
e.printStackTrace();
}
// 处理数据
processingData(sheetDataMap);
return Result.ok(sheetDataMap);
}
/**
* 解析给定的Sheet,并将数据存储到List中
*
* @param sheet 要解析的Sheet
* @return 包含每行数据的List
*/
private List<Object> parseSheet(Sheet sheet) {
List<Object> data = new ArrayList<>();
boolean isHeaderFound = false;
// 循环遍历每一行数据
for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
Row row = sheet.getRow(rowIndex);
if (row == null) continue; // 跳过空行
// 检查是否为标题行
if (!isHeaderFound) {
if (isHeaderRow(row)) {
isHeaderFound = true; // 找到标题行
}
continue; // 跳过标题行的处理
}
// 收集每列的数据
List<Object> rowData = new ArrayList<>();
for (int cellIndex = 1; cellIndex <= row.getLastCellNum(); cellIndex++) {
Cell cell = row.getCell(cellIndex);
if (cell != null && isMergedCell(sheet, row, cell)) {
rowData.add(getMergedCellValue(sheet, row, cell));
} else if (cell != null && !cell.toString().trim().isEmpty()) {
rowData.add(cell.toString()); // 仅当单元格不为空且不为空字符串时才添加
}
}
if (!rowData.isEmpty()) {
data.add(rowData); // 仅在行数据非空时才添加到数据列表中
}
}
return data;
}
/**
* 获取合并单元格的值
*/
private String getMergedCellValue(Sheet sheet, Row row, Cell cell) {
int rowIndex = row.getRowNum();
int colIndex = cell.getColumnIndex();
for (int i = 1; i < sheet.getNumMergedRegions(); i++) {
CellRangeAddress range = sheet.getMergedRegion(i);
if (range.isInRange(rowIndex, colIndex)) {
Row firstRow = sheet.getRow(range.getFirstRow());
Cell firstCell = firstRow.getCell(range.getFirstColumn());
return firstCell.toString().replace("\n", " ");
}
}
return null;
}
/**
* 判断指定单元格是否是合并单元格
*/
private boolean isMergedCell(Sheet sheet, Row row, Cell cell) {
int rowIndex = row.getRowNum();
int colIndex = cell.getColumnIndex();
for (int i = 0; i < sheet.getNumMergedRegions(); i++) {
CellRangeAddress range = sheet.getMergedRegion(i);
if (range.isInRange(rowIndex, colIndex)) {
return true;
}
}
return false;
}
/**
* 对于读取的Excel数据进行处理。
*
* @param data
*/
private boolean processingData(Map<Integer, List<Object>> data) {
boolean flag = false;
try {
// 遍历每个层级的数据,从0开始,每个level对应一个sheet的数据
for (int level = 0; level < data.size(); level++) {
List<Object> levelList = data.get(level);
if (levelList == null) {
continue; // 如果当前层级没有数据,跳过
}
// 遍历当前层级中的每一行数据
for (Object o : levelList) {
List<String> rowData = (List<String>) o;
// 获取父类名称(如果是第一级,则父类名称为null)
String parentName = level == 0 ? null : rowData.get(level - 1);
// 获取当前的名称
String currentName = rowData.get(level);
try {
String parentId = "0"; // 默认父类ID为"0",表示顶级目录
if (level > 0 && parentName != null) {
// 如果不是第一级,通过父类名称查询父类ID
Zbk parentZbk = zbkMapper.selectOne(new LambdaQueryWrapper<Zbk>()
.eq(Zbk::getName, parentName.replace("\n", "")) // 去除换行符后匹配名称
.eq(Zbk::getType, 1) // 类型为目录
.eq(Zbk::getDeleted, 0)); // 未被删除
if (parentZbk != null) {
parentId = parentZbk.getId(); // 如果找到父类,获取父类ID
} else {
log.warn("父类不存在: " + parentName);
continue;
}
}
// 查询是否已经存在当前名称的指标/目录
Zbk existingZbk = zbkMapper.selectOne(new LambdaQueryWrapper<Zbk>()
.eq(Zbk::getName, currentName.replace("\n", "")) // 去除换行符后匹配名称
.eq(Zbk::getType, level == data.size() - 1 ? 0 : 1) // 如果是最后一级,类型为指标,否则为目录
.eq(Zbk::getDeleted, 0) // 未被删除
.eq(Zbk::getPid, parentId)); // 父类ID匹配
// 如果当前名称的指标/目录不存在,插入新的记录
if (existingZbk == null) {
Zbk zbk = new Zbk();
zbk.setName(currentName);
zbk.setDeleted(0); // 逻辑删除标志设为未删除
zbk.setType(level == data.size() - 1 ? 0 : 1); // 设置类型,0为指标,1为目录
zbk.setEvaluationObject("1382586667761336322");
zbk.setZbSourceType("build");
zbk.setDisable(false); // 未禁用
zbk.setPid(parentId); // 设置父类ID
zbkMapper.insert(zbk); // 插入新记录
// 如果是最后一级(观测点),处理观测点的额外逻辑
if (level == data.size() - 1) {
flag = true;
// 获取指标类型
String indicatorType = rowData.get(rowData.size() - 2);
// 获取指标分值
String indicatorScore = rowData.get(rowData.size() - 1);
if (!StringUtils.isEmpty(indicatorType) && !StringUtils.isEmpty(indicatorScore)) {
// 处理指标数据
processingIndicators(indicatorType, indicatorScore, zbk.getId());
}
}
}
} catch (Exception e) {
log.error("处理数据时发生异常: ", e);
continue; // 如果发生异常,跳过当前循环
}
}
}
} catch (Exception e) {
log.error("处理数据时发生异常: ", e);
e.printStackTrace();
}
return flag; // 返回处理结果的标志
}