feat(credit): 添加历史数据批量导入功能
- 在CreditCaseFilingController中新增批量导入历史立案信息接口 - 在CreditDeliveryNoticeController中新增批量导入历史送达公告接口 - 在CreditMediationController中新增批量导入历史诉前调解接口 - 实现Excel文件解析和数据验证逻辑 - 添加数据库唯一索引约束防止重复数据导入 - 统一将历史导入数据标记为"失效"状态 - 集成权限控制和用户信息自动填充 - 实现分块处理提高大批量数据导入性能 - 添加错误消息收集和返回机制
This commit is contained in:
@@ -309,6 +309,134 @@ public class CreditCaseFilingController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导入历史立案信息(仅解析“历史立案信息”选项卡)
|
||||
* 规则:使用数据库唯一索引约束,重复数据不导入。
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('credit:creditCaseFiling:save')")
|
||||
@Operation(summary = "批量导入历史立案信息")
|
||||
@PostMapping("/import/history")
|
||||
public ApiResult<List<String>> importHistoryBatch(@RequestParam("file") MultipartFile file,
|
||||
@RequestParam(value = "companyId", required = false) Integer companyId) {
|
||||
List<String> errorMessages = new ArrayList<>();
|
||||
int successCount = 0;
|
||||
Set<Integer> touchedCompanyIds = new HashSet<>();
|
||||
|
||||
try {
|
||||
int sheetIndex = ExcelImportSupport.findSheetIndex(file, "历史立案信息");
|
||||
if (sheetIndex < 0) {
|
||||
return fail("未读取到数据,请确认文件中存在“历史立案信息”选项卡且表头与示例格式一致", null);
|
||||
}
|
||||
|
||||
ExcelImportSupport.ImportResult<CreditCaseFilingImportParam> importResult = ExcelImportSupport.read(
|
||||
file, CreditCaseFilingImportParam.class, this::isEmptyImportRow, sheetIndex);
|
||||
List<CreditCaseFilingImportParam> list = importResult.getData();
|
||||
int usedTitleRows = importResult.getTitleRows();
|
||||
int usedHeadRows = importResult.getHeadRows();
|
||||
int usedSheetIndex = importResult.getSheetIndex();
|
||||
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return fail("未读取到数据,请确认模板表头与示例格式一致", null);
|
||||
}
|
||||
|
||||
User loginUser = getLoginUser();
|
||||
Integer currentUserId = loginUser != null ? loginUser.getUserId() : null;
|
||||
Integer currentTenantId = loginUser != null ? loginUser.getTenantId() : null;
|
||||
Map<String, String> urlByCaseNumber = ExcelImportSupport.readUrlByKey(file, usedSheetIndex, usedTitleRows, usedHeadRows, "案号");
|
||||
|
||||
final int chunkSize = 500;
|
||||
final int mpBatchSize = 500;
|
||||
List<CreditCaseFiling> chunkItems = new ArrayList<>(chunkSize);
|
||||
List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
CreditCaseFilingImportParam param = list.get(i);
|
||||
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
|
||||
try {
|
||||
CreditCaseFiling item = convertImportParamToEntity(param);
|
||||
if (item.getCaseNumber() != null) {
|
||||
item.setCaseNumber(item.getCaseNumber().trim());
|
||||
}
|
||||
if (ImportHelper.isBlank(item.getCaseNumber())) {
|
||||
errorMessages.add("第" + excelRowNumber + "行:案号不能为空");
|
||||
continue;
|
||||
}
|
||||
|
||||
String link = urlByCaseNumber.get(item.getCaseNumber());
|
||||
if (!ImportHelper.isBlank(link)) {
|
||||
item.setUrl(link.trim());
|
||||
}
|
||||
|
||||
if (item.getCompanyId() == null && companyId != null) {
|
||||
item.setCompanyId(companyId);
|
||||
}
|
||||
if (item.getUserId() == null && currentUserId != null) {
|
||||
item.setUserId(currentUserId);
|
||||
}
|
||||
if (item.getTenantId() == null && currentTenantId != null) {
|
||||
item.setTenantId(currentTenantId);
|
||||
}
|
||||
if (item.getStatus() == null) {
|
||||
item.setStatus(0);
|
||||
}
|
||||
if (item.getDeleted() == null) {
|
||||
item.setDeleted(0);
|
||||
}
|
||||
if (item.getRecommend() == null) {
|
||||
item.setRecommend(0);
|
||||
}
|
||||
// 历史导入的数据统一标记为“失效”
|
||||
item.setDataStatus("失效");
|
||||
|
||||
if (item.getCompanyId() != null && item.getCompanyId() > 0) {
|
||||
touchedCompanyIds.add(item.getCompanyId());
|
||||
}
|
||||
|
||||
chunkItems.add(item);
|
||||
chunkRowNumbers.add(excelRowNumber);
|
||||
if (chunkItems.size() >= chunkSize) {
|
||||
successCount += batchImportSupport.persistInsertOnlyChunk(
|
||||
creditCaseFilingService,
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
mpBatchSize,
|
||||
CreditCaseFiling::getCaseNumber,
|
||||
"",
|
||||
errorMessages
|
||||
);
|
||||
chunkItems.clear();
|
||||
chunkRowNumbers.clear();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errorMessages.add("第" + excelRowNumber + "行:" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (!chunkItems.isEmpty()) {
|
||||
successCount += batchImportSupport.persistInsertOnlyChunk(
|
||||
creditCaseFilingService,
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
mpBatchSize,
|
||||
CreditCaseFiling::getCaseNumber,
|
||||
"",
|
||||
errorMessages
|
||||
);
|
||||
}
|
||||
|
||||
creditCompanyRecordCountService.refresh(CreditCompanyRecordCountService.CountType.CASE_FILING, touchedCompanyIds);
|
||||
|
||||
if (errorMessages.isEmpty()) {
|
||||
return success("成功导入" + successCount + "条数据", null);
|
||||
}
|
||||
return success("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "条", errorMessages);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return fail("导入失败:" + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载立案信息导入模板
|
||||
*/
|
||||
|
||||
@@ -310,6 +310,134 @@ public class CreditDeliveryNoticeController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导入历史送达公告(仅解析“历史送达公告”选项卡)
|
||||
* 规则:使用数据库唯一索引约束,重复数据不导入。
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('credit:creditDeliveryNotice:save')")
|
||||
@Operation(summary = "批量导入历史送达公告司法大数据")
|
||||
@PostMapping("/import/history")
|
||||
public ApiResult<List<String>> importHistoryBatch(@RequestParam("file") MultipartFile file,
|
||||
@RequestParam(value = "companyId", required = false) Integer companyId) {
|
||||
List<String> errorMessages = new ArrayList<>();
|
||||
int successCount = 0;
|
||||
Set<Integer> touchedCompanyIds = new HashSet<>();
|
||||
|
||||
try {
|
||||
int sheetIndex = ExcelImportSupport.findSheetIndex(file, "历史送达公告");
|
||||
if (sheetIndex < 0) {
|
||||
return fail("未读取到数据,请确认文件中存在“历史送达公告”选项卡且表头与示例格式一致", null);
|
||||
}
|
||||
|
||||
ExcelImportSupport.ImportResult<CreditDeliveryNoticeImportParam> importResult = ExcelImportSupport.read(
|
||||
file, CreditDeliveryNoticeImportParam.class, this::isEmptyImportRow, sheetIndex);
|
||||
List<CreditDeliveryNoticeImportParam> list = importResult.getData();
|
||||
int usedTitleRows = importResult.getTitleRows();
|
||||
int usedHeadRows = importResult.getHeadRows();
|
||||
int usedSheetIndex = importResult.getSheetIndex();
|
||||
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return fail("未读取到数据,请确认模板表头与示例格式一致", null);
|
||||
}
|
||||
|
||||
User loginUser = getLoginUser();
|
||||
Integer currentUserId = loginUser != null ? loginUser.getUserId() : null;
|
||||
Integer currentTenantId = loginUser != null ? loginUser.getTenantId() : null;
|
||||
Map<String, String> urlByCaseNumber = ExcelImportSupport.readUrlByKey(file, usedSheetIndex, usedTitleRows, usedHeadRows, "案号");
|
||||
|
||||
final int chunkSize = 500;
|
||||
final int mpBatchSize = 500;
|
||||
List<CreditDeliveryNotice> chunkItems = new ArrayList<>(chunkSize);
|
||||
List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
CreditDeliveryNoticeImportParam param = list.get(i);
|
||||
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
|
||||
try {
|
||||
CreditDeliveryNotice item = convertImportParamToEntity(param);
|
||||
if (item.getCaseNumber() != null) {
|
||||
item.setCaseNumber(item.getCaseNumber().trim());
|
||||
}
|
||||
if (ImportHelper.isBlank(item.getCaseNumber())) {
|
||||
errorMessages.add("第" + excelRowNumber + "行:案号不能为空");
|
||||
continue;
|
||||
}
|
||||
|
||||
String link = urlByCaseNumber.get(item.getCaseNumber());
|
||||
if (!ImportHelper.isBlank(link)) {
|
||||
item.setUrl(link.trim());
|
||||
}
|
||||
|
||||
if (item.getCompanyId() == null && companyId != null) {
|
||||
item.setCompanyId(companyId);
|
||||
}
|
||||
if (item.getUserId() == null && currentUserId != null) {
|
||||
item.setUserId(currentUserId);
|
||||
}
|
||||
if (item.getTenantId() == null && currentTenantId != null) {
|
||||
item.setTenantId(currentTenantId);
|
||||
}
|
||||
if (item.getStatus() == null) {
|
||||
item.setStatus(0);
|
||||
}
|
||||
if (item.getDeleted() == null) {
|
||||
item.setDeleted(0);
|
||||
}
|
||||
if (item.getRecommend() == null) {
|
||||
item.setRecommend(0);
|
||||
}
|
||||
// 历史导入的数据统一标记为“失效”
|
||||
item.setDataStatus("失效");
|
||||
|
||||
if (item.getCompanyId() != null && item.getCompanyId() > 0) {
|
||||
touchedCompanyIds.add(item.getCompanyId());
|
||||
}
|
||||
|
||||
chunkItems.add(item);
|
||||
chunkRowNumbers.add(excelRowNumber);
|
||||
if (chunkItems.size() >= chunkSize) {
|
||||
successCount += batchImportSupport.persistInsertOnlyChunk(
|
||||
creditDeliveryNoticeService,
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
mpBatchSize,
|
||||
CreditDeliveryNotice::getCaseNumber,
|
||||
"",
|
||||
errorMessages
|
||||
);
|
||||
chunkItems.clear();
|
||||
chunkRowNumbers.clear();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errorMessages.add("第" + excelRowNumber + "行:" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (!chunkItems.isEmpty()) {
|
||||
successCount += batchImportSupport.persistInsertOnlyChunk(
|
||||
creditDeliveryNoticeService,
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
mpBatchSize,
|
||||
CreditDeliveryNotice::getCaseNumber,
|
||||
"",
|
||||
errorMessages
|
||||
);
|
||||
}
|
||||
|
||||
creditCompanyRecordCountService.refresh(CreditCompanyRecordCountService.CountType.DELIVERY_NOTICE, touchedCompanyIds);
|
||||
|
||||
if (errorMessages.isEmpty()) {
|
||||
return success("成功导入" + successCount + "条数据", null);
|
||||
}
|
||||
return success("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "条", errorMessages);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return fail("导入失败:" + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载送达公告导入模板
|
||||
*/
|
||||
|
||||
@@ -308,6 +308,134 @@ public class CreditMediationController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导入历史诉前调解(仅解析“历史诉前调解”选项卡)
|
||||
* 规则:使用数据库唯一索引约束,重复数据不导入。
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('credit:creditMediation:save')")
|
||||
@Operation(summary = "批量导入历史诉前调解")
|
||||
@PostMapping("/import/history")
|
||||
public ApiResult<List<String>> importHistoryBatch(@RequestParam("file") MultipartFile file,
|
||||
@RequestParam(value = "companyId", required = false) Integer companyId) {
|
||||
List<String> errorMessages = new ArrayList<>();
|
||||
int successCount = 0;
|
||||
Set<Integer> touchedCompanyIds = new HashSet<>();
|
||||
|
||||
try {
|
||||
int sheetIndex = ExcelImportSupport.findSheetIndex(file, "历史诉前调解");
|
||||
if (sheetIndex < 0) {
|
||||
return fail("未读取到数据,请确认文件中存在“历史诉前调解”选项卡且表头与示例格式一致", null);
|
||||
}
|
||||
|
||||
ExcelImportSupport.ImportResult<CreditMediationImportParam> importResult = ExcelImportSupport.read(
|
||||
file, CreditMediationImportParam.class, this::isEmptyImportRow, sheetIndex);
|
||||
List<CreditMediationImportParam> list = importResult.getData();
|
||||
int usedTitleRows = importResult.getTitleRows();
|
||||
int usedHeadRows = importResult.getHeadRows();
|
||||
int usedSheetIndex = importResult.getSheetIndex();
|
||||
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return fail("未读取到数据,请确认模板表头与示例格式一致", null);
|
||||
}
|
||||
|
||||
User loginUser = getLoginUser();
|
||||
Integer currentUserId = loginUser != null ? loginUser.getUserId() : null;
|
||||
Integer currentTenantId = loginUser != null ? loginUser.getTenantId() : null;
|
||||
Map<String, String> urlByCaseNumber = ExcelImportSupport.readUrlByKey(file, usedSheetIndex, usedTitleRows, usedHeadRows, "案号");
|
||||
|
||||
final int chunkSize = 500;
|
||||
final int mpBatchSize = 500;
|
||||
List<CreditMediation> chunkItems = new ArrayList<>(chunkSize);
|
||||
List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
CreditMediationImportParam param = list.get(i);
|
||||
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
|
||||
try {
|
||||
CreditMediation item = convertImportParamToEntity(param);
|
||||
if (item.getCaseNumber() != null) {
|
||||
item.setCaseNumber(item.getCaseNumber().trim());
|
||||
}
|
||||
if (ImportHelper.isBlank(item.getCaseNumber())) {
|
||||
errorMessages.add("第" + excelRowNumber + "行:案号不能为空");
|
||||
continue;
|
||||
}
|
||||
|
||||
String link = urlByCaseNumber.get(item.getCaseNumber());
|
||||
if (!ImportHelper.isBlank(link)) {
|
||||
item.setUrl(link.trim());
|
||||
}
|
||||
|
||||
if (item.getCompanyId() == null && companyId != null) {
|
||||
item.setCompanyId(companyId);
|
||||
}
|
||||
if (item.getUserId() == null && currentUserId != null) {
|
||||
item.setUserId(currentUserId);
|
||||
}
|
||||
if (item.getTenantId() == null && currentTenantId != null) {
|
||||
item.setTenantId(currentTenantId);
|
||||
}
|
||||
if (item.getStatus() == null) {
|
||||
item.setStatus(0);
|
||||
}
|
||||
if (item.getDeleted() == null) {
|
||||
item.setDeleted(0);
|
||||
}
|
||||
if (item.getRecommend() == null) {
|
||||
item.setRecommend(0);
|
||||
}
|
||||
// 历史导入的数据统一标记为“失效”
|
||||
item.setDataStatus("失效");
|
||||
|
||||
if (item.getCompanyId() != null && item.getCompanyId() > 0) {
|
||||
touchedCompanyIds.add(item.getCompanyId());
|
||||
}
|
||||
|
||||
chunkItems.add(item);
|
||||
chunkRowNumbers.add(excelRowNumber);
|
||||
if (chunkItems.size() >= chunkSize) {
|
||||
successCount += batchImportSupport.persistInsertOnlyChunk(
|
||||
creditMediationService,
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
mpBatchSize,
|
||||
CreditMediation::getCaseNumber,
|
||||
"",
|
||||
errorMessages
|
||||
);
|
||||
chunkItems.clear();
|
||||
chunkRowNumbers.clear();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errorMessages.add("第" + excelRowNumber + "行:" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (!chunkItems.isEmpty()) {
|
||||
successCount += batchImportSupport.persistInsertOnlyChunk(
|
||||
creditMediationService,
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
mpBatchSize,
|
||||
CreditMediation::getCaseNumber,
|
||||
"",
|
||||
errorMessages
|
||||
);
|
||||
}
|
||||
|
||||
creditCompanyRecordCountService.refresh(CreditCompanyRecordCountService.CountType.MEDIATION, touchedCompanyIds);
|
||||
|
||||
if (errorMessages.isEmpty()) {
|
||||
return success("成功导入" + successCount + "条数据", null);
|
||||
}
|
||||
return success("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "条", errorMessages);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return fail("导入失败:" + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载诉前调解导入模板
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user