refactor(credit): 优化Excel导入功能并改进表头匹配

- 移除过时的Excel导入相关依赖和方法
- 使用ExcelImportSupport替代原有的多配置尝试导入方式
- 添加表头文本标准化处理以解决空白字符导致的匹配问题
- 引入ExcelHeaderAlias注解支持表头别名匹配
- 简化导入逻辑并提高表头识别准确性
This commit is contained in:
2026-02-27 16:14:08 +08:00
parent 5f6a8ab089
commit 5cc9219801
2 changed files with 20 additions and 31 deletions

View File

@@ -1,9 +1,7 @@
package com.gxwebsoft.credit.controller;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import com.gxwebsoft.common.core.annotation.OperationLog;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
@@ -205,19 +203,11 @@ public class CreditUserController extends BaseController {
try {
int sheetIndex = ExcelImportSupport.findSheetIndex(file, "招投标", 0);
List<CreditUserImportParam> list = null;
int usedTitleRows = 0;
int usedHeadRows = 0;
int[][] tryConfigs = new int[][]{{1, 1}, {0, 1}, {0, 2}, {0, 3}};
for (int[] config : tryConfigs) {
list = filterEmptyRows(tryImport(file, config[0], config[1], sheetIndex));
if (!CollectionUtils.isEmpty(list)) {
usedTitleRows = config[0];
usedHeadRows = config[1];
break;
}
}
ExcelImportSupport.ImportResult<CreditUserImportParam> importResult =
ExcelImportSupport.read(file, CreditUserImportParam.class, this::isEmptyImportRow, sheetIndex);
List<CreditUserImportParam> list = importResult.getData();
int usedTitleRows = importResult.getTitleRows();
int usedHeadRows = importResult.getHeadRows();
if (CollectionUtils.isEmpty(list)) {
return fail("未读取到数据,请确认模板表头与示例格式一致", null);
}
@@ -354,15 +344,6 @@ public class CreditUserController extends BaseController {
workbook.close();
}
private List<CreditUserImportParam> tryImport(MultipartFile file, int titleRows, int headRows, int sheetIndex) throws Exception {
ImportParams importParams = new ImportParams();
importParams.setTitleRows(titleRows);
importParams.setHeadRows(headRows);
importParams.setStartSheetIndex(sheetIndex);
importParams.setSheetNum(1);
return ExcelImportUtil.importExcel(file.getInputStream(), CreditUserImportParam.class, importParams);
}
/**
* 读取“项目名称”列的超链接,按数据行顺序返回。
*/
@@ -379,7 +360,7 @@ public class CreditUserController extends BaseController {
if (headerRow != null) {
for (int c = headerRow.getFirstCellNum(); c < headerRow.getLastCellNum(); c++) {
Cell cell = headerRow.getCell(c);
if (cell != null && "项目名称".equals(cell.getStringCellValue())) {
if (cell != null && "项目名称".equals(normalizeHeaderText(cell.getStringCellValue()))) {
nameColIndex = c;
break;
}
@@ -404,14 +385,20 @@ public class CreditUserController extends BaseController {
}
/**
* 过滤掉完全空白的导入行,避免空行导致导入失败
* 用于表头匹配:仅做最常见的空白字符规整(避免表头中存在换行/空格导致无法定位列)。
*/
private List<CreditUserImportParam> filterEmptyRows(List<CreditUserImportParam> rawList) {
if (CollectionUtils.isEmpty(rawList)) {
return rawList;
private static String normalizeHeaderText(String text) {
if (text == null) {
return "";
}
rawList.removeIf(this::isEmptyImportRow);
return rawList;
return text
.replace(" ", "")
.replace("\t", "")
.replace("\r", "")
.replace("\n", "")
.replace("\u00A0", "")
.replace(" ", "")
.trim();
}
private boolean isEmptyImportRow(CreditUserImportParam param) {

View File

@@ -1,6 +1,7 @@
package com.gxwebsoft.credit.param;
import cn.afterturn.easypoi.excel.annotation.Excel;
import com.gxwebsoft.credit.excel.ExcelHeaderAlias;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -56,6 +57,7 @@ public class CreditUserImportParam implements Serializable {
private String procurementName;
@Excel(name = "中标单位")
@ExcelHeaderAlias({"中标单位(最多展示50家)"})
private String winningName;
@Excel(name = "中标金额")