🐛 记录类导入(第二批 4 个模块)失败明细返回全量原表

覆盖:里程记录 / 油电记录 / 其他费用记录 / 运输变更记录。

问题同第一批:收集 errorList 后 setRollbackOnly 并 return,控制器据此导出
「仅错误行」——失败明细不是原表全量,用户无法对照原表修正。

改动(同构):
- 服务层:抛 ImportFailureException(data),明细携带原表全部行;
  回滚由异常触发(替代 setRollbackOnly)。
- 控制器:catch 异常取 getFailureList() 导出(用 export 保留按列标红),
  补上传文件校验。

验证:mvn install -DskipTests 通过;记录类回归 80/80
(10 模块 × 2 用例,含第一批 6 个模块的回归确认)。
This commit is contained in:
2026-09-26 10:52:02 +08:00
parent f24209fa8e
commit 96010cf542
8 changed files with 60 additions and 20 deletions
@@ -116,9 +116,18 @@ public class MileageRecordController extends BladeController {
@ApiOperationSupport(order = 5)
@Operation(summary = "导入里程记录", description = "传入excel")
public R importMileageRecord(MultipartFile file, HttpServletResponse response) {
List<MileageRecordExcel> failureList = mileageRecordService.importMileageRecord(ExcelUtil.read(file, MileageRecordExcel.class));
if (Func.isNotEmpty(failureList)) {
org.springblade.common.excel.ImportFailureExcelUtil.export(response, "里程记录导入失败明细" + DateUtil.time(), "导入失败明细", failureList, MileageRecordExcel.class);
if (file == null || file.isEmpty()) {
return R.fail("上传文件不能为空");
}
String fileName = Func.toStrWithEmpty(file.getOriginalFilename(), "").toLowerCase();
if (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx")) {
return R.fail("请上传 .xls,.xlsx 标准格式文件");
}
try {
mileageRecordService.importMileageRecord(ExcelUtil.read(file, MileageRecordExcel.class));
} catch (org.springblade.common.excel.ImportFailureException exception) {
// 任一行失败即整批回滚,导出原表全部数据并标注错误(含按列标红)。
org.springblade.common.excel.ImportFailureExcelUtil.export(response, "里程记录导入失败明细" + DateUtil.time(), "导入失败明细", exception.getFailureList(), MileageRecordExcel.class);
return null;
}
return R.success("操作成功");
@@ -94,9 +94,18 @@ public class OilElectricRecordController extends BladeController {
@ApiOperationSupport(order = 5)
@Operation(summary = "导入油电记录", description = "传入excel")
public R importOilElectricRecord(MultipartFile file, HttpServletResponse response) {
List<OilElectricRecordExcel> failureList = oilElectricRecordService.importOilElectricRecord(ExcelUtil.read(file, OilElectricRecordExcel.class));
if (Func.isNotEmpty(failureList)) {
org.springblade.common.excel.ImportFailureExcelUtil.export(response, "油电记录导入失败明细" + DateUtil.time(), "导入失败明细", failureList, OilElectricRecordExcel.class);
if (file == null || file.isEmpty()) {
return R.fail("上传文件不能为空");
}
String fileName = Func.toStrWithEmpty(file.getOriginalFilename(), "").toLowerCase();
if (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx")) {
return R.fail("请上传 .xls,.xlsx 标准格式文件");
}
try {
oilElectricRecordService.importOilElectricRecord(ExcelUtil.read(file, OilElectricRecordExcel.class));
} catch (org.springblade.common.excel.ImportFailureException exception) {
// 任一行失败即整批回滚,导出原表全部数据并标注错误(含按列标红)。
org.springblade.common.excel.ImportFailureExcelUtil.export(response, "油电记录导入失败明细" + DateUtil.time(), "导入失败明细", exception.getFailureList(), OilElectricRecordExcel.class);
return null;
}
return R.success("操作成功");
@@ -94,9 +94,18 @@ public class OtherExpenseRecordController extends BladeController {
@ApiOperationSupport(order = 5)
@Operation(summary = "导入其他费用记录", description = "传入excel")
public R importOtherExpenseRecord(MultipartFile file, HttpServletResponse response) {
List<OtherExpenseRecordExcel> failureList = otherExpenseRecordService.importOtherExpenseRecord(ExcelUtil.read(file, OtherExpenseRecordExcel.class));
if (Func.isNotEmpty(failureList)) {
org.springblade.common.excel.ImportFailureExcelUtil.export(response, "其他费用记录导入失败明细" + DateUtil.time(), "导入失败明细", failureList, OtherExpenseRecordExcel.class);
if (file == null || file.isEmpty()) {
return R.fail("上传文件不能为空");
}
String fileName = Func.toStrWithEmpty(file.getOriginalFilename(), "").toLowerCase();
if (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx")) {
return R.fail("请上传 .xls,.xlsx 标准格式文件");
}
try {
otherExpenseRecordService.importOtherExpenseRecord(ExcelUtil.read(file, OtherExpenseRecordExcel.class));
} catch (org.springblade.common.excel.ImportFailureException exception) {
// 任一行失败即整批回滚,导出原表全部数据并标注错误(含按列标红)。
org.springblade.common.excel.ImportFailureExcelUtil.export(response, "其他费用记录导入失败明细" + DateUtil.time(), "导入失败明细", exception.getFailureList(), OtherExpenseRecordExcel.class);
return null;
}
return R.success("操作成功");
@@ -113,9 +113,18 @@ public class TransportChangeRecordController extends BladeController {
@ApiOperationSupport(order = 5)
@Operation(summary = "导入变更记录", description = "传入excel")
public R importTransportChangeRecord(MultipartFile file, HttpServletResponse response) {
List<TransportChangeRecordExcel> failureList = transportChangeRecordService.importTransportChangeRecord(ExcelUtil.read(file, TransportChangeRecordExcel.class));
if (Func.isNotEmpty(failureList)) {
org.springblade.common.excel.ImportFailureExcelUtil.export(response, "变更记录导入失败明细" + DateUtil.time(), "导入失败明细", failureList, TransportChangeRecordExcel.class);
if (file == null || file.isEmpty()) {
return R.fail("上传文件不能为空");
}
String fileName = Func.toStrWithEmpty(file.getOriginalFilename(), "").toLowerCase();
if (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx")) {
return R.fail("请上传 .xls,.xlsx 标准格式文件");
}
try {
transportChangeRecordService.importTransportChangeRecord(ExcelUtil.read(file, TransportChangeRecordExcel.class));
} catch (org.springblade.common.excel.ImportFailureException exception) {
// 任一行失败即整批回滚,导出原表全部数据并标注错误(含按列标红)。
org.springblade.common.excel.ImportFailureExcelUtil.export(response, "运输变更记录导入失败明细" + DateUtil.time(), "导入失败明细", exception.getFailureList(), TransportChangeRecordExcel.class);
return null;
}
return R.success("操作成功");
@@ -105,8 +105,9 @@ public class MileageRecordServiceImpl extends BaseServiceImpl<MileageRecordMappe
}
}
if (Func.isNotEmpty(errorList)) {
org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return errorList;
// 抛出携带失败明细的异常,触发事务回滚(替代旧的 setRollbackOnly)。
// 明细为原表全部行(未出错行仅无错误原因),用户可对照原表修正后重新导入。
throw new org.springblade.common.excel.ImportFailureException(data);
}
for (MileageRecord mileageRecord : mileageRecordList) {
if (!save(mileageRecord)) {
@@ -94,8 +94,9 @@ public class OilElectricRecordServiceImpl extends BaseServiceImpl<OilElectricRec
}
}
if (Func.isNotEmpty(errorList)) {
org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return errorList;
// 抛出携带失败明细的异常,触发事务回滚(替代旧的 setRollbackOnly)。
// 明细为原表全部行(未出错行仅无错误原因),用户可对照原表修正后重新导入。
throw new org.springblade.common.excel.ImportFailureException(data);
}
for (OilElectricRecord oilElectricRecord : oilElectricRecordList) {
if (!save(oilElectricRecord)) {
@@ -92,8 +92,9 @@ public class OtherExpenseRecordServiceImpl extends BaseServiceImpl<OtherExpenseR
}
}
if (Func.isNotEmpty(errorList)) {
org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return errorList;
// 抛出携带失败明细的异常,触发事务回滚(替代旧的 setRollbackOnly)。
// 明细为原表全部行(未出错行仅无错误原因),用户可对照原表修正后重新导入。
throw new org.springblade.common.excel.ImportFailureException(data);
}
for (OtherExpenseRecord otherExpenseRecord : otherExpenseRecordList) {
if (!save(otherExpenseRecord)) {
@@ -104,8 +104,9 @@ public class TransportChangeRecordServiceImpl extends BaseServiceImpl<TransportC
}
}
if (Func.isNotEmpty(errorList)) {
org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return errorList;
// 抛出携带失败明细的异常,触发事务回滚(替代旧的 setRollbackOnly)。
// 明细为原表全部行(未出错行仅无错误原因),用户可对照原表修正后重新导入。
throw new org.springblade.common.excel.ImportFailureException(data);
}
for (TransportChangeRecord transportChangeRecord : transportChangeRecordList) {
if (!save(transportChangeRecord)) {