🐛 修复货物类型导入未整批回滚,并把导入回滚异常迁到公共模块
问题:CargoTypeServiceImpl.importCargoType 循环内吞掉异常后正常 return, 方法正常返回导致 Spring 照常提交事务,@Transactional 起不到回滚作用。 含 1 行错误的文件会写入前面若干行正确数据,与「任一行失败即整批零写入」口径不符。 改动: - ImportFailureException 由 org.springblade.system.excel 迁至 org.springblade.common.excel(与 ImportFailureExcelUtil 同包)。 blade-transport 只依赖 blade-system-api,原先拿不到该异常, 迁到 blade-common 后 blade-system 与 blade-transport 均可引用。 - CargoTypeServiceImpl.importCargoType 补 @Transactional(rollbackFor = Exception.class), 错误收集完毕后抛 ImportFailureException 触发回滚,不再 return failureList。 - CargoTypeController.importCargoType 由「拿返回值导出」改为 「catch 异常 → 取 failureList 导出 → return null」,并补上传文件校验, 对齐 PortTerminalController 的写法。 - PortTerminalController / PortTerminalServiceImpl 仅调整 import 指向新包,行为不变。 验证: - mvn install -DskipTests 全量编译通过。 - 港口码头回归 45/45 通过,确认「异常搬家」未破坏既有基线。 - 货物类型回归 24/24 通过,含 02_一行错误多行正确_应零写入(库中零写入)。
This commit is contained in:
+9
-3
@@ -23,7 +23,7 @@
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.system.excel;
|
||||
package org.springblade.common.excel;
|
||||
|
||||
import org.springblade.core.log.exception.ServiceException;
|
||||
|
||||
@@ -33,8 +33,14 @@ import java.util.List;
|
||||
/**
|
||||
* 导入失败异常,携带失败明细用于导出原表并标注错误。
|
||||
* <p>
|
||||
* 批量导入采用「全失败即整批回滚」语义:任一行校验失败都会抛出本异常触发事务回滚,
|
||||
* 失败明细在抛异常前已收集完毕,因此回滚不影响明细的内容。
|
||||
* 批量导入采用「任一行失败即整批回滚」语义:循环内先收集完全部错误明细,
|
||||
* 再抛出本异常触发事务回滚。明细在抛异常前已收集完毕,因此回滚不影响明细内容。
|
||||
* <p>
|
||||
* 注意:仅标注 {@code @Transactional} 并不足够。若循环内把异常吞掉(catch 后
|
||||
* 只往 errorList 塞数据并正常 return),方法会正常返回,Spring 会照常提交事务。
|
||||
* 必须抛出异常才能让事务真正回滚。
|
||||
* <p>
|
||||
* 本类位于 blade-common,供 blade-system 与 blade-transport 等模块共用。
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
+22
-5
@@ -46,9 +46,9 @@ import org.springblade.core.tool.api.R;
|
||||
import org.springblade.core.tool.utils.DateUtil;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.common.excel.ImportFailureExcelUtil;
|
||||
import org.springblade.common.excel.ImportFailureException;
|
||||
import org.springblade.system.excel.CargoTypeExcel;
|
||||
import org.springblade.system.excel.CargoTypeExportExcel;
|
||||
import org.springblade.system.excel.CargoTypeImportFailureExcel;
|
||||
import org.springblade.system.pojo.entity.CargoType;
|
||||
import org.springblade.system.pojo.vo.CargoTypeVO;
|
||||
import org.springblade.system.service.ICargoTypeService;
|
||||
@@ -156,15 +156,32 @@ public class CargoTypeController extends BladeController {
|
||||
@ApiOperationSupport(order = 7)
|
||||
@Operation(summary = "导入货物类型", description = "传入excel")
|
||||
public R importCargoType(MultipartFile file, HttpServletResponse response) {
|
||||
List<CargoTypeExcel> data = ExcelUtil.read(file, CargoTypeExcel.class);
|
||||
List<CargoTypeImportFailureExcel> failureList = cargoTypeService.importCargoType(data);
|
||||
if (Func.isNotEmpty(failureList)) {
|
||||
ImportFailureExcelUtil.export(response, "货物类型导入失败明细" + DateUtil.time(), "导入失败明细", failureList, CargoTypeExcel.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 {
|
||||
cargoTypeService.importCargoType(ExcelUtil.read(file, CargoTypeExcel.class));
|
||||
} catch (ImportFailureException exception) {
|
||||
// 任一行失败即整批回滚,导出原表全部数据并标注错误,用户修正后重新导入。
|
||||
exportFailure(response, exception.getFailureList());
|
||||
return null;
|
||||
}
|
||||
return R.success("导入数据成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出导入失败明细,内容为原表全部数据并在末尾追加失败原因列。
|
||||
* <p>
|
||||
* 失败数据仅标红出错单元格与失败原因列,表头保持默认样式。
|
||||
*/
|
||||
private void exportFailure(HttpServletResponse response, List<?> failureList) {
|
||||
ImportFailureExcelUtil.exportFailureReasonOnly(response, "货物类型导入失败明细" + DateUtil.time(), "导入失败明细", failureList, CargoTypeExcel.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出货物类型
|
||||
*/
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ import org.springblade.core.tool.api.R;
|
||||
import org.springblade.core.tool.utils.DateUtil;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.common.excel.ImportFailureExcelUtil;
|
||||
import org.springblade.system.excel.ImportFailureException;
|
||||
import org.springblade.common.excel.ImportFailureException;
|
||||
import org.springblade.system.excel.PortTerminalExcel;
|
||||
import org.springblade.system.excel.PortTerminalExportExcel;
|
||||
import org.springblade.system.excel.PortTerminalImporter;
|
||||
|
||||
+10
@@ -29,6 +29,7 @@ import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import org.springblade.common.excel.ImportFailureException;
|
||||
import org.springblade.core.log.exception.ServiceException;
|
||||
import org.springblade.core.mp.base.BaseServiceImpl;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
@@ -134,10 +135,14 @@ public class CargoTypeServiceImpl extends BaseServiceImpl<CargoTypeMapper, Cargo
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<CargoTypeImportFailureExcel> importCargoType(List<CargoTypeExcel> data) {
|
||||
if (Func.isEmpty(data)) {
|
||||
throw new ServiceException("导入数据不能为空");
|
||||
}
|
||||
// 全量校验:任何一行失败都整批回滚,因此先收集所有错误再统一抛出。
|
||||
// 注意不能只往 errorList 里塞数据就 return——异常被吞掉后方法会正常返回,
|
||||
// Spring 会照常提交事务,@Transactional 起不到回滚作用。
|
||||
List<CargoTypeImportFailureExcel> failureList = new ArrayList<>();
|
||||
for (int index = 0; index < data.size(); index++) {
|
||||
CargoTypeExcel excel = data.get(index);
|
||||
@@ -152,6 +157,11 @@ public class CargoTypeServiceImpl extends BaseServiceImpl<CargoTypeMapper, Cargo
|
||||
failureList.add(toImportFailureExcel(excel, message));
|
||||
}
|
||||
}
|
||||
if (Func.isNotEmpty(failureList)) {
|
||||
// 抛出携带失败明细的异常,触发事务回滚。
|
||||
// 明细为原表全部行(未出错行仅无错误原因),用户可对照原表修正后重新导入。
|
||||
throw new ImportFailureException(data);
|
||||
}
|
||||
return failureList;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -34,8 +34,8 @@ import org.springblade.core.log.exception.ServiceException;
|
||||
import org.springblade.core.mp.base.BaseServiceImpl;
|
||||
import org.springblade.core.tool.utils.BeanUtil;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.common.excel.ImportFailureException;
|
||||
import org.springblade.system.cache.UserCache;
|
||||
import org.springblade.system.excel.ImportFailureException;
|
||||
import org.springblade.system.excel.PortTerminalExcel;
|
||||
import org.springblade.system.excel.PortTerminalExportExcel;
|
||||
import org.springblade.system.mapper.PortTerminalMapper;
|
||||
|
||||
Reference in New Issue
Block a user