feat(import): 添加批量导入功能支持历史数据处理
- 新增 upsertBySingleKeyAndIncrementCounterOnUpdate 方法用于单字段键匹配的批量更新插入操作 - 新增 upsertByCodeOrNameAndIncrementCounterOnUpdate 方法用于代码或名称匹配的批量更新插入操作 - 在 CreditAdministrativeLicenseController 中添加历史行政许可批量导入接口 - 在 CreditBankruptcyController 中添加历史破产重整批量导入接口 - 在 CreditBreachOfTrustController 中添加历史失信被执行人批量导入接口 - 在 CreditCourtSessionController 中添加历史开庭公告批量导入接口 - 实现基于案号或名称的重复数据检测和计数器递增逻辑 - 添加 Excel 文件解析和超链接读取功能支持 - 实现分块处理机制提高大批量数据导入性能 - 添加异常处理和错误消息收集机制确保导入过程稳定性
This commit is contained in:
@@ -209,6 +209,216 @@ public class BatchImportSupport {
|
||||
return updates.size() + inserts.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量 upsert:按单字段 key 匹配(key 非空)。当匹配到已存在记录时:
|
||||
* - 覆盖更新
|
||||
* - 将 counter(通常是 recommend)在数据库原值基础上 +1,用于记录“被更新次数”
|
||||
*
|
||||
* <p>注意:counter 会被覆盖写入(不是 SQL 自增),因此该方法适合导入场景。</p>
|
||||
*/
|
||||
public <T> int upsertBySingleKeyAndIncrementCounterOnUpdate(IService<T> service,
|
||||
List<T> items,
|
||||
SFunction<T, Integer> idColumn,
|
||||
BiConsumer<T, Integer> idSetter,
|
||||
SFunction<T, String> keyColumn,
|
||||
Function<T, String> keyGetter,
|
||||
SFunction<T, Integer> counterColumn,
|
||||
BiConsumer<T, Integer> counterSetter,
|
||||
Consumer<LambdaQueryWrapper<T>> extraConditions,
|
||||
int batchSize) {
|
||||
if (CollectionUtils.isEmpty(items)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
List<String> keys = new ArrayList<>(items.size());
|
||||
for (T item : items) {
|
||||
if (item == null) {
|
||||
continue;
|
||||
}
|
||||
String key = normalize(keyGetter.apply(item));
|
||||
if (key != null) {
|
||||
keys.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Integer> idByKey = new HashMap<>();
|
||||
Map<String, Integer> counterByKey = new HashMap<>();
|
||||
if (!keys.isEmpty()) {
|
||||
LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>();
|
||||
if (extraConditions != null) {
|
||||
extraConditions.accept(wrapper);
|
||||
}
|
||||
wrapper.in(keyColumn, keys);
|
||||
wrapper.select(idColumn, keyColumn, counterColumn);
|
||||
for (T dbRow : service.list(wrapper)) {
|
||||
String key = normalize(keyGetter.apply(dbRow));
|
||||
Integer id = extractId(dbRow, idColumn);
|
||||
if (key == null || id == null) {
|
||||
continue;
|
||||
}
|
||||
idByKey.putIfAbsent(key, id);
|
||||
if (counterColumn != null) {
|
||||
counterByKey.putIfAbsent(key, counterColumn.apply(dbRow));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<T> updates = new ArrayList<>();
|
||||
List<T> inserts = new ArrayList<>();
|
||||
for (T item : items) {
|
||||
if (item == null) {
|
||||
continue;
|
||||
}
|
||||
String key = normalize(keyGetter.apply(item));
|
||||
Integer id = key != null ? idByKey.get(key) : null;
|
||||
if (id != null) {
|
||||
idSetter.accept(item, id);
|
||||
Integer old = key != null ? counterByKey.get(key) : null;
|
||||
if (counterSetter != null) {
|
||||
counterSetter.accept(item, old == null ? 1 : old + 1);
|
||||
}
|
||||
updates.add(item);
|
||||
} else {
|
||||
// insert:如果未提供 counterSetter,则不做处理;如果提供则默认 0。
|
||||
if (counterSetter != null) {
|
||||
counterSetter.accept(item, 0);
|
||||
}
|
||||
inserts.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (!updates.isEmpty()) {
|
||||
service.updateBatchById(updates, batchSize);
|
||||
}
|
||||
if (!inserts.isEmpty()) {
|
||||
service.saveBatch(inserts, batchSize);
|
||||
}
|
||||
return updates.size() + inserts.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量 upsert:优先按 code 匹配;code 为空时按 name 匹配。匹配到已存在记录时 counter +1。
|
||||
*/
|
||||
public <T> int upsertByCodeOrNameAndIncrementCounterOnUpdate(IService<T> service,
|
||||
List<T> items,
|
||||
SFunction<T, Integer> idColumn,
|
||||
BiConsumer<T, Integer> idSetter,
|
||||
SFunction<T, String> codeColumn,
|
||||
Function<T, String> codeGetter,
|
||||
SFunction<T, String> nameColumn,
|
||||
Function<T, String> nameGetter,
|
||||
SFunction<T, Integer> counterColumn,
|
||||
BiConsumer<T, Integer> counterSetter,
|
||||
Consumer<LambdaQueryWrapper<T>> extraConditions,
|
||||
int batchSize) {
|
||||
if (CollectionUtils.isEmpty(items)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
List<String> codes = new ArrayList<>();
|
||||
List<String> names = new ArrayList<>();
|
||||
for (T item : items) {
|
||||
if (item == null) {
|
||||
continue;
|
||||
}
|
||||
String code = normalize(codeGetter.apply(item));
|
||||
if (code != null) {
|
||||
codes.add(code);
|
||||
} else {
|
||||
String name = normalize(nameGetter.apply(item));
|
||||
if (name != null) {
|
||||
names.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Integer> idByCode = new HashMap<>();
|
||||
Map<String, Integer> counterByCode = new HashMap<>();
|
||||
if (!codes.isEmpty()) {
|
||||
LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>();
|
||||
if (extraConditions != null) {
|
||||
extraConditions.accept(wrapper);
|
||||
}
|
||||
wrapper.in(codeColumn, codes);
|
||||
wrapper.select(idColumn, codeColumn, counterColumn);
|
||||
for (T dbRow : service.list(wrapper)) {
|
||||
String code = normalize(codeGetter.apply(dbRow));
|
||||
Integer id = extractId(dbRow, idColumn);
|
||||
if (code == null || id == null) {
|
||||
continue;
|
||||
}
|
||||
idByCode.putIfAbsent(code, id);
|
||||
if (counterColumn != null) {
|
||||
counterByCode.putIfAbsent(code, counterColumn.apply(dbRow));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Integer> idByName = new HashMap<>();
|
||||
Map<String, Integer> counterByName = new HashMap<>();
|
||||
if (!names.isEmpty()) {
|
||||
LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>();
|
||||
if (extraConditions != null) {
|
||||
extraConditions.accept(wrapper);
|
||||
}
|
||||
wrapper.in(nameColumn, names);
|
||||
wrapper.select(idColumn, nameColumn, counterColumn);
|
||||
for (T dbRow : service.list(wrapper)) {
|
||||
String name = normalize(nameGetter.apply(dbRow));
|
||||
Integer id = extractId(dbRow, idColumn);
|
||||
if (name == null || id == null) {
|
||||
continue;
|
||||
}
|
||||
idByName.putIfAbsent(name, id);
|
||||
if (counterColumn != null) {
|
||||
counterByName.putIfAbsent(name, counterColumn.apply(dbRow));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<T> updates = new ArrayList<>();
|
||||
List<T> inserts = new ArrayList<>();
|
||||
for (T item : items) {
|
||||
if (item == null) {
|
||||
continue;
|
||||
}
|
||||
String code = normalize(codeGetter.apply(item));
|
||||
Integer id = null;
|
||||
Integer old = null;
|
||||
if (code != null) {
|
||||
id = idByCode.get(code);
|
||||
old = counterByCode.get(code);
|
||||
} else {
|
||||
String name = normalize(nameGetter.apply(item));
|
||||
if (name != null) {
|
||||
id = idByName.get(name);
|
||||
old = counterByName.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
if (id != null) {
|
||||
idSetter.accept(item, id);
|
||||
if (counterSetter != null) {
|
||||
counterSetter.accept(item, old == null ? 1 : old + 1);
|
||||
}
|
||||
updates.add(item);
|
||||
} else {
|
||||
if (counterSetter != null) {
|
||||
counterSetter.accept(item, 0);
|
||||
}
|
||||
inserts.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (!updates.isEmpty()) {
|
||||
service.updateBatchById(updates, batchSize);
|
||||
}
|
||||
if (!inserts.isEmpty()) {
|
||||
service.saveBatch(inserts, batchSize);
|
||||
}
|
||||
return updates.size() + inserts.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量失败时降级逐行,尽量保留“第 N 行”错误定位。
|
||||
*/
|
||||
@@ -257,4 +467,3 @@ public class BatchImportSupport {
|
||||
return idColumn.apply(entity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -322,6 +323,240 @@ public class CreditAdministrativeLicenseController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导入历史行政许可(仅解析“历史行政许可”选项卡)
|
||||
* 规则:优先按编号(code)匹配;code 为空时按名称(name)匹配;匹配到则覆盖更新(recommend++ 记录更新次数)。
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('credit:creditAdministrativeLicense: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;
|
||||
|
||||
try {
|
||||
int sheetIndex = ExcelImportSupport.findSheetIndex(file, "历史行政许可");
|
||||
if (sheetIndex < 0) {
|
||||
return fail("未读取到数据,请确认文件中存在“历史行政许可”选项卡且表头与示例格式一致", null);
|
||||
}
|
||||
|
||||
ExcelImportSupport.ImportResult<CreditAdministrativeLicenseImportParam> importResult = ExcelImportSupport.read(
|
||||
file, CreditAdministrativeLicenseImportParam.class, this::isEmptyImportRow, sheetIndex);
|
||||
List<CreditAdministrativeLicenseImportParam> 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> urlByCode = ExcelImportSupport.readHyperlinksByHeaderKey(file, usedSheetIndex, usedTitleRows, usedHeadRows, "决定文书/许可编号");
|
||||
Map<String, String> urlByName = ExcelImportSupport.readHyperlinksByHeaderKey(file, usedSheetIndex, usedTitleRows, usedHeadRows, "决定文书/许可证名称");
|
||||
|
||||
LinkedHashMap<String, CreditAdministrativeLicense> latestByKey = new LinkedHashMap<>();
|
||||
LinkedHashMap<String, Integer> latestRowByKey = new LinkedHashMap<>();
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
CreditAdministrativeLicenseImportParam param = list.get(i);
|
||||
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
|
||||
try {
|
||||
CreditAdministrativeLicense item = convertImportParamToEntity(param);
|
||||
if (item.getCode() != null) {
|
||||
item.setCode(item.getCode().trim());
|
||||
}
|
||||
if (item.getName() != null) {
|
||||
item.setName(item.getName().trim());
|
||||
}
|
||||
|
||||
if (ImportHelper.isBlank(item.getName())) {
|
||||
errorMessages.add("第" + excelRowNumber + "行:决定文书/许可证名称不能为空");
|
||||
continue;
|
||||
}
|
||||
|
||||
String link = null;
|
||||
if (!ImportHelper.isBlank(item.getCode())) {
|
||||
link = urlByCode.get(item.getCode());
|
||||
}
|
||||
if ((link == null || link.isEmpty()) && !ImportHelper.isBlank(item.getName())) {
|
||||
link = urlByName.get(item.getName());
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
String dedupKey = !ImportHelper.isBlank(item.getCode()) ? ("CODE:" + item.getCode()) : ("NAME:" + item.getName());
|
||||
latestByKey.put(dedupKey, item);
|
||||
latestRowByKey.put(dedupKey, excelRowNumber);
|
||||
} catch (Exception e) {
|
||||
errorMessages.add("第" + excelRowNumber + "行:" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (latestByKey.isEmpty()) {
|
||||
if (errorMessages.isEmpty()) {
|
||||
return fail("未读取到数据,请确认模板表头与示例格式一致", null);
|
||||
}
|
||||
return success("导入完成,成功0条,失败" + errorMessages.size() + "条", errorMessages);
|
||||
}
|
||||
|
||||
final int chunkSize = 500;
|
||||
final int mpBatchSize = 500;
|
||||
List<CreditAdministrativeLicense> chunkItems = new ArrayList<>(chunkSize);
|
||||
List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);
|
||||
|
||||
for (Map.Entry<String, CreditAdministrativeLicense> entry : latestByKey.entrySet()) {
|
||||
String dedupKey = entry.getKey();
|
||||
CreditAdministrativeLicense item = entry.getValue();
|
||||
Integer rowNo = latestRowByKey.get(dedupKey);
|
||||
chunkItems.add(item);
|
||||
chunkRowNumbers.add(rowNo != null ? rowNo : -1);
|
||||
if (chunkItems.size() >= chunkSize) {
|
||||
successCount += batchImportSupport.persistChunkWithFallback(
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
() -> batchImportSupport.upsertByCodeOrNameAndIncrementCounterOnUpdate(
|
||||
creditAdministrativeLicenseService,
|
||||
chunkItems,
|
||||
CreditAdministrativeLicense::getId,
|
||||
CreditAdministrativeLicense::setId,
|
||||
CreditAdministrativeLicense::getCode,
|
||||
CreditAdministrativeLicense::getCode,
|
||||
CreditAdministrativeLicense::getName,
|
||||
CreditAdministrativeLicense::getName,
|
||||
CreditAdministrativeLicense::getRecommend,
|
||||
CreditAdministrativeLicense::setRecommend,
|
||||
null,
|
||||
mpBatchSize
|
||||
),
|
||||
(rowItem, rowNumber) -> {
|
||||
if (rowItem.getRecommend() == null) {
|
||||
rowItem.setRecommend(0);
|
||||
}
|
||||
boolean saved = creditAdministrativeLicenseService.save(rowItem);
|
||||
if (!saved) {
|
||||
CreditAdministrativeLicense existing = null;
|
||||
if (!ImportHelper.isBlank(rowItem.getCode())) {
|
||||
existing = creditAdministrativeLicenseService.lambdaQuery()
|
||||
.eq(CreditAdministrativeLicense::getCode, rowItem.getCode())
|
||||
.select(CreditAdministrativeLicense::getId, CreditAdministrativeLicense::getRecommend)
|
||||
.one();
|
||||
}
|
||||
if (existing == null && !ImportHelper.isBlank(rowItem.getName())) {
|
||||
existing = creditAdministrativeLicenseService.lambdaQuery()
|
||||
.eq(CreditAdministrativeLicense::getName, rowItem.getName())
|
||||
.select(CreditAdministrativeLicense::getId, CreditAdministrativeLicense::getRecommend)
|
||||
.one();
|
||||
}
|
||||
if (existing != null) {
|
||||
rowItem.setId(existing.getId());
|
||||
Integer old = existing.getRecommend();
|
||||
rowItem.setRecommend(old == null ? 1 : old + 1);
|
||||
if (creditAdministrativeLicenseService.updateById(rowItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
String prefix = rowNumber > 0 ? ("第" + rowNumber + "行:") : "";
|
||||
errorMessages.add(prefix + "保存失败");
|
||||
return false;
|
||||
},
|
||||
errorMessages
|
||||
);
|
||||
chunkItems.clear();
|
||||
chunkRowNumbers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!chunkItems.isEmpty()) {
|
||||
successCount += batchImportSupport.persistChunkWithFallback(
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
() -> batchImportSupport.upsertByCodeOrNameAndIncrementCounterOnUpdate(
|
||||
creditAdministrativeLicenseService,
|
||||
chunkItems,
|
||||
CreditAdministrativeLicense::getId,
|
||||
CreditAdministrativeLicense::setId,
|
||||
CreditAdministrativeLicense::getCode,
|
||||
CreditAdministrativeLicense::getCode,
|
||||
CreditAdministrativeLicense::getName,
|
||||
CreditAdministrativeLicense::getName,
|
||||
CreditAdministrativeLicense::getRecommend,
|
||||
CreditAdministrativeLicense::setRecommend,
|
||||
null,
|
||||
mpBatchSize
|
||||
),
|
||||
(rowItem, rowNumber) -> {
|
||||
if (rowItem.getRecommend() == null) {
|
||||
rowItem.setRecommend(0);
|
||||
}
|
||||
boolean saved = creditAdministrativeLicenseService.save(rowItem);
|
||||
if (!saved) {
|
||||
CreditAdministrativeLicense existing = null;
|
||||
if (!ImportHelper.isBlank(rowItem.getCode())) {
|
||||
existing = creditAdministrativeLicenseService.lambdaQuery()
|
||||
.eq(CreditAdministrativeLicense::getCode, rowItem.getCode())
|
||||
.select(CreditAdministrativeLicense::getId, CreditAdministrativeLicense::getRecommend)
|
||||
.one();
|
||||
}
|
||||
if (existing == null && !ImportHelper.isBlank(rowItem.getName())) {
|
||||
existing = creditAdministrativeLicenseService.lambdaQuery()
|
||||
.eq(CreditAdministrativeLicense::getName, rowItem.getName())
|
||||
.select(CreditAdministrativeLicense::getId, CreditAdministrativeLicense::getRecommend)
|
||||
.one();
|
||||
}
|
||||
if (existing != null) {
|
||||
rowItem.setId(existing.getId());
|
||||
Integer old = existing.getRecommend();
|
||||
rowItem.setRecommend(old == null ? 1 : old + 1);
|
||||
if (creditAdministrativeLicenseService.updateById(rowItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
String prefix = rowNumber > 0 ? ("第" + rowNumber + "行:") : "";
|
||||
errorMessages.add(prefix + "保存失败");
|
||||
return false;
|
||||
},
|
||||
errorMessages
|
||||
);
|
||||
}
|
||||
|
||||
if (errorMessages.isEmpty()) {
|
||||
return success("成功导入" + successCount + "条数据", null);
|
||||
}
|
||||
return success("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "条", errorMessages);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return fail("导入失败:" + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载行政许可导入模板
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,7 @@ import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -297,6 +298,206 @@ public class CreditBankruptcyController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导入历史破产重整(仅解析“历史破产重整”选项卡)
|
||||
* 规则:案号/唯一标识相同则覆盖更新(recommend++ 记录更新次数);不存在则插入。
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('credit:creditBankruptcy: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;
|
||||
|
||||
try {
|
||||
int sheetIndex = ExcelImportSupport.findSheetIndex(file, "历史破产重整");
|
||||
if (sheetIndex < 0) {
|
||||
return fail("未读取到数据,请确认文件中存在“历史破产重整”选项卡且表头与示例格式一致", null);
|
||||
}
|
||||
|
||||
ExcelImportSupport.ImportResult<CreditBankruptcyImportParam> importResult = ExcelImportSupport.read(
|
||||
file, CreditBankruptcyImportParam.class, this::isEmptyImportRow, sheetIndex);
|
||||
List<CreditBankruptcyImportParam> 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> urlByCode = ExcelImportSupport.readHyperlinksByHeaderKey(file, usedSheetIndex, usedTitleRows, usedHeadRows, "案号");
|
||||
|
||||
LinkedHashMap<String, CreditBankruptcy> latestByCode = new LinkedHashMap<>();
|
||||
LinkedHashMap<String, Integer> latestRowByCode = new LinkedHashMap<>();
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
CreditBankruptcyImportParam param = list.get(i);
|
||||
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
|
||||
try {
|
||||
CreditBankruptcy item = convertImportParamToEntity(param);
|
||||
if (item.getCode() != null) {
|
||||
item.setCode(item.getCode().trim());
|
||||
}
|
||||
if (ImportHelper.isBlank(item.getCode())) {
|
||||
errorMessages.add("第" + excelRowNumber + "行:案号不能为空");
|
||||
continue;
|
||||
}
|
||||
|
||||
String link = urlByCode.get(item.getCode());
|
||||
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);
|
||||
}
|
||||
|
||||
latestByCode.put(item.getCode(), item);
|
||||
latestRowByCode.put(item.getCode(), excelRowNumber);
|
||||
} catch (Exception e) {
|
||||
errorMessages.add("第" + excelRowNumber + "行:" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (latestByCode.isEmpty()) {
|
||||
if (errorMessages.isEmpty()) {
|
||||
return fail("未读取到数据,请确认模板表头与示例格式一致", null);
|
||||
}
|
||||
return success("导入完成,成功0条,失败" + errorMessages.size() + "条", errorMessages);
|
||||
}
|
||||
|
||||
final int chunkSize = 500;
|
||||
final int mpBatchSize = 500;
|
||||
List<CreditBankruptcy> chunkItems = new ArrayList<>(chunkSize);
|
||||
List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);
|
||||
|
||||
for (Map.Entry<String, CreditBankruptcy> entry : latestByCode.entrySet()) {
|
||||
String code = entry.getKey();
|
||||
CreditBankruptcy item = entry.getValue();
|
||||
Integer rowNo = latestRowByCode.get(code);
|
||||
chunkItems.add(item);
|
||||
chunkRowNumbers.add(rowNo != null ? rowNo : -1);
|
||||
if (chunkItems.size() >= chunkSize) {
|
||||
successCount += batchImportSupport.persistChunkWithFallback(
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
() -> batchImportSupport.upsertBySingleKeyAndIncrementCounterOnUpdate(
|
||||
creditBankruptcyService,
|
||||
chunkItems,
|
||||
CreditBankruptcy::getId,
|
||||
CreditBankruptcy::setId,
|
||||
CreditBankruptcy::getCode,
|
||||
CreditBankruptcy::getCode,
|
||||
CreditBankruptcy::getRecommend,
|
||||
CreditBankruptcy::setRecommend,
|
||||
null,
|
||||
mpBatchSize
|
||||
),
|
||||
(rowItem, rowNumber) -> {
|
||||
if (rowItem.getRecommend() == null) {
|
||||
rowItem.setRecommend(0);
|
||||
}
|
||||
boolean saved = creditBankruptcyService.save(rowItem);
|
||||
if (!saved) {
|
||||
CreditBankruptcy existing = creditBankruptcyService.lambdaQuery()
|
||||
.eq(CreditBankruptcy::getCode, rowItem.getCode())
|
||||
.select(CreditBankruptcy::getId, CreditBankruptcy::getRecommend)
|
||||
.one();
|
||||
if (existing != null) {
|
||||
rowItem.setId(existing.getId());
|
||||
Integer old = existing.getRecommend();
|
||||
rowItem.setRecommend(old == null ? 1 : old + 1);
|
||||
if (creditBankruptcyService.updateById(rowItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
String prefix = rowNumber > 0 ? ("第" + rowNumber + "行:") : "";
|
||||
errorMessages.add(prefix + "保存失败");
|
||||
return false;
|
||||
},
|
||||
errorMessages
|
||||
);
|
||||
chunkItems.clear();
|
||||
chunkRowNumbers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!chunkItems.isEmpty()) {
|
||||
successCount += batchImportSupport.persistChunkWithFallback(
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
() -> batchImportSupport.upsertBySingleKeyAndIncrementCounterOnUpdate(
|
||||
creditBankruptcyService,
|
||||
chunkItems,
|
||||
CreditBankruptcy::getId,
|
||||
CreditBankruptcy::setId,
|
||||
CreditBankruptcy::getCode,
|
||||
CreditBankruptcy::getCode,
|
||||
CreditBankruptcy::getRecommend,
|
||||
CreditBankruptcy::setRecommend,
|
||||
null,
|
||||
mpBatchSize
|
||||
),
|
||||
(rowItem, rowNumber) -> {
|
||||
if (rowItem.getRecommend() == null) {
|
||||
rowItem.setRecommend(0);
|
||||
}
|
||||
boolean saved = creditBankruptcyService.save(rowItem);
|
||||
if (!saved) {
|
||||
CreditBankruptcy existing = creditBankruptcyService.lambdaQuery()
|
||||
.eq(CreditBankruptcy::getCode, rowItem.getCode())
|
||||
.select(CreditBankruptcy::getId, CreditBankruptcy::getRecommend)
|
||||
.one();
|
||||
if (existing != null) {
|
||||
rowItem.setId(existing.getId());
|
||||
Integer old = existing.getRecommend();
|
||||
rowItem.setRecommend(old == null ? 1 : old + 1);
|
||||
if (creditBankruptcyService.updateById(rowItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
String prefix = rowNumber > 0 ? ("第" + rowNumber + "行:") : "";
|
||||
errorMessages.add(prefix + "保存失败");
|
||||
return false;
|
||||
},
|
||||
errorMessages
|
||||
);
|
||||
}
|
||||
|
||||
if (errorMessages.isEmpty()) {
|
||||
return success("成功导入" + successCount + "条数据", null);
|
||||
}
|
||||
return success("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "条", errorMessages);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return fail("导入失败:" + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载破产重整导入模板
|
||||
*/
|
||||
|
||||
@@ -23,6 +23,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -294,6 +295,207 @@ public class CreditBreachOfTrustController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导入历史失信被执行人(仅解析“历史失信被执行人”选项卡)
|
||||
* 规则:案号相同则覆盖更新(recommend++ 记录更新次数);案号不存在则插入。
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('credit:creditBreachOfTrust: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;
|
||||
|
||||
try {
|
||||
int sheetIndex = ExcelImportSupport.findSheetIndex(file, "历史失信被执行人");
|
||||
if (sheetIndex < 0) {
|
||||
return fail("未读取到数据,请确认文件中存在“历史失信被执行人”选项卡且表头与示例格式一致", null);
|
||||
}
|
||||
|
||||
ExcelImportSupport.ImportResult<CreditBreachOfTrustImportParam> importResult = ExcelImportSupport.read(
|
||||
file, CreditBreachOfTrustImportParam.class, this::isEmptyImportRow, sheetIndex);
|
||||
List<CreditBreachOfTrustImportParam> 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, "案号");
|
||||
|
||||
// 同案号多条:以导入文件中“最后一条”为准(视为最新)
|
||||
LinkedHashMap<String, CreditBreachOfTrust> latestByCaseNumber = new LinkedHashMap<>();
|
||||
LinkedHashMap<String, Integer> latestRowByCaseNumber = new LinkedHashMap<>();
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
CreditBreachOfTrustImportParam param = list.get(i);
|
||||
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
|
||||
try {
|
||||
CreditBreachOfTrust 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);
|
||||
}
|
||||
|
||||
latestByCaseNumber.put(item.getCaseNumber(), item);
|
||||
latestRowByCaseNumber.put(item.getCaseNumber(), excelRowNumber);
|
||||
} catch (Exception e) {
|
||||
errorMessages.add("第" + excelRowNumber + "行:" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (latestByCaseNumber.isEmpty()) {
|
||||
if (errorMessages.isEmpty()) {
|
||||
return fail("未读取到数据,请确认模板表头与示例格式一致", null);
|
||||
}
|
||||
return success("导入完成,成功0条,失败" + errorMessages.size() + "条", errorMessages);
|
||||
}
|
||||
|
||||
final int chunkSize = 500;
|
||||
final int mpBatchSize = 500;
|
||||
List<CreditBreachOfTrust> chunkItems = new ArrayList<>(chunkSize);
|
||||
List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);
|
||||
|
||||
for (Map.Entry<String, CreditBreachOfTrust> entry : latestByCaseNumber.entrySet()) {
|
||||
String caseNumber = entry.getKey();
|
||||
CreditBreachOfTrust item = entry.getValue();
|
||||
Integer rowNo = latestRowByCaseNumber.get(caseNumber);
|
||||
chunkItems.add(item);
|
||||
chunkRowNumbers.add(rowNo != null ? rowNo : -1);
|
||||
if (chunkItems.size() >= chunkSize) {
|
||||
successCount += batchImportSupport.persistChunkWithFallback(
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
() -> batchImportSupport.upsertBySingleKeyAndIncrementCounterOnUpdate(
|
||||
creditBreachOfTrustService,
|
||||
chunkItems,
|
||||
CreditBreachOfTrust::getId,
|
||||
CreditBreachOfTrust::setId,
|
||||
CreditBreachOfTrust::getCaseNumber,
|
||||
CreditBreachOfTrust::getCaseNumber,
|
||||
CreditBreachOfTrust::getRecommend,
|
||||
CreditBreachOfTrust::setRecommend,
|
||||
null,
|
||||
mpBatchSize
|
||||
),
|
||||
(rowItem, rowNumber) -> {
|
||||
if (rowItem.getRecommend() == null) {
|
||||
rowItem.setRecommend(0);
|
||||
}
|
||||
boolean saved = creditBreachOfTrustService.save(rowItem);
|
||||
if (!saved) {
|
||||
CreditBreachOfTrust existing = creditBreachOfTrustService.lambdaQuery()
|
||||
.eq(CreditBreachOfTrust::getCaseNumber, rowItem.getCaseNumber())
|
||||
.select(CreditBreachOfTrust::getId, CreditBreachOfTrust::getRecommend)
|
||||
.one();
|
||||
if (existing != null) {
|
||||
rowItem.setId(existing.getId());
|
||||
Integer old = existing.getRecommend();
|
||||
rowItem.setRecommend(old == null ? 1 : old + 1);
|
||||
if (creditBreachOfTrustService.updateById(rowItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
String prefix = rowNumber > 0 ? ("第" + rowNumber + "行:") : "";
|
||||
errorMessages.add(prefix + "保存失败");
|
||||
return false;
|
||||
},
|
||||
errorMessages
|
||||
);
|
||||
chunkItems.clear();
|
||||
chunkRowNumbers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!chunkItems.isEmpty()) {
|
||||
successCount += batchImportSupport.persistChunkWithFallback(
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
() -> batchImportSupport.upsertBySingleKeyAndIncrementCounterOnUpdate(
|
||||
creditBreachOfTrustService,
|
||||
chunkItems,
|
||||
CreditBreachOfTrust::getId,
|
||||
CreditBreachOfTrust::setId,
|
||||
CreditBreachOfTrust::getCaseNumber,
|
||||
CreditBreachOfTrust::getCaseNumber,
|
||||
CreditBreachOfTrust::getRecommend,
|
||||
CreditBreachOfTrust::setRecommend,
|
||||
null,
|
||||
mpBatchSize
|
||||
),
|
||||
(rowItem, rowNumber) -> {
|
||||
if (rowItem.getRecommend() == null) {
|
||||
rowItem.setRecommend(0);
|
||||
}
|
||||
boolean saved = creditBreachOfTrustService.save(rowItem);
|
||||
if (!saved) {
|
||||
CreditBreachOfTrust existing = creditBreachOfTrustService.lambdaQuery()
|
||||
.eq(CreditBreachOfTrust::getCaseNumber, rowItem.getCaseNumber())
|
||||
.select(CreditBreachOfTrust::getId, CreditBreachOfTrust::getRecommend)
|
||||
.one();
|
||||
if (existing != null) {
|
||||
rowItem.setId(existing.getId());
|
||||
Integer old = existing.getRecommend();
|
||||
rowItem.setRecommend(old == null ? 1 : old + 1);
|
||||
if (creditBreachOfTrustService.updateById(rowItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
String prefix = rowNumber > 0 ? ("第" + rowNumber + "行:") : "";
|
||||
errorMessages.add(prefix + "保存失败");
|
||||
return false;
|
||||
},
|
||||
errorMessages
|
||||
);
|
||||
}
|
||||
|
||||
if (errorMessages.isEmpty()) {
|
||||
return success("成功导入" + successCount + "条数据", null);
|
||||
}
|
||||
return success("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "条", errorMessages);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return fail("导入失败:" + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载失信被执行人导入模板
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,7 @@ import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -299,6 +300,206 @@ public class CreditCourtSessionController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导入历史开庭公告(仅解析“历史开庭公告”选项卡)
|
||||
* 规则:案号相同则覆盖更新(recommend++ 记录更新次数);案号不存在则插入。
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('credit:creditCourtSession: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;
|
||||
|
||||
try {
|
||||
int sheetIndex = ExcelImportSupport.findSheetIndex(file, "历史开庭公告");
|
||||
if (sheetIndex < 0) {
|
||||
return fail("未读取到数据,请确认文件中存在“历史开庭公告”选项卡且表头与示例格式一致", null);
|
||||
}
|
||||
|
||||
ExcelImportSupport.ImportResult<CreditCourtSessionImportParam> importResult = ExcelImportSupport.read(
|
||||
file, CreditCourtSessionImportParam.class, this::isEmptyImportRow, sheetIndex);
|
||||
List<CreditCourtSessionImportParam> 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, "案号");
|
||||
|
||||
LinkedHashMap<String, CreditCourtSession> latestByCaseNumber = new LinkedHashMap<>();
|
||||
LinkedHashMap<String, Integer> latestRowByCaseNumber = new LinkedHashMap<>();
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
CreditCourtSessionImportParam param = list.get(i);
|
||||
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
|
||||
try {
|
||||
CreditCourtSession 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);
|
||||
}
|
||||
|
||||
latestByCaseNumber.put(item.getCaseNumber(), item);
|
||||
latestRowByCaseNumber.put(item.getCaseNumber(), excelRowNumber);
|
||||
} catch (Exception e) {
|
||||
errorMessages.add("第" + excelRowNumber + "行:" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (latestByCaseNumber.isEmpty()) {
|
||||
if (errorMessages.isEmpty()) {
|
||||
return fail("未读取到数据,请确认模板表头与示例格式一致", null);
|
||||
}
|
||||
return success("导入完成,成功0条,失败" + errorMessages.size() + "条", errorMessages);
|
||||
}
|
||||
|
||||
final int chunkSize = 500;
|
||||
final int mpBatchSize = 500;
|
||||
List<CreditCourtSession> chunkItems = new ArrayList<>(chunkSize);
|
||||
List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);
|
||||
|
||||
for (Map.Entry<String, CreditCourtSession> entry : latestByCaseNumber.entrySet()) {
|
||||
String caseNumber = entry.getKey();
|
||||
CreditCourtSession item = entry.getValue();
|
||||
Integer rowNo = latestRowByCaseNumber.get(caseNumber);
|
||||
chunkItems.add(item);
|
||||
chunkRowNumbers.add(rowNo != null ? rowNo : -1);
|
||||
if (chunkItems.size() >= chunkSize) {
|
||||
successCount += batchImportSupport.persistChunkWithFallback(
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
() -> batchImportSupport.upsertBySingleKeyAndIncrementCounterOnUpdate(
|
||||
creditCourtSessionService,
|
||||
chunkItems,
|
||||
CreditCourtSession::getId,
|
||||
CreditCourtSession::setId,
|
||||
CreditCourtSession::getCaseNumber,
|
||||
CreditCourtSession::getCaseNumber,
|
||||
CreditCourtSession::getRecommend,
|
||||
CreditCourtSession::setRecommend,
|
||||
null,
|
||||
mpBatchSize
|
||||
),
|
||||
(rowItem, rowNumber) -> {
|
||||
if (rowItem.getRecommend() == null) {
|
||||
rowItem.setRecommend(0);
|
||||
}
|
||||
boolean saved = creditCourtSessionService.save(rowItem);
|
||||
if (!saved) {
|
||||
CreditCourtSession existing = creditCourtSessionService.lambdaQuery()
|
||||
.eq(CreditCourtSession::getCaseNumber, rowItem.getCaseNumber())
|
||||
.select(CreditCourtSession::getId, CreditCourtSession::getRecommend)
|
||||
.one();
|
||||
if (existing != null) {
|
||||
rowItem.setId(existing.getId());
|
||||
Integer old = existing.getRecommend();
|
||||
rowItem.setRecommend(old == null ? 1 : old + 1);
|
||||
if (creditCourtSessionService.updateById(rowItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
String prefix = rowNumber > 0 ? ("第" + rowNumber + "行:") : "";
|
||||
errorMessages.add(prefix + "保存失败");
|
||||
return false;
|
||||
},
|
||||
errorMessages
|
||||
);
|
||||
chunkItems.clear();
|
||||
chunkRowNumbers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!chunkItems.isEmpty()) {
|
||||
successCount += batchImportSupport.persistChunkWithFallback(
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
() -> batchImportSupport.upsertBySingleKeyAndIncrementCounterOnUpdate(
|
||||
creditCourtSessionService,
|
||||
chunkItems,
|
||||
CreditCourtSession::getId,
|
||||
CreditCourtSession::setId,
|
||||
CreditCourtSession::getCaseNumber,
|
||||
CreditCourtSession::getCaseNumber,
|
||||
CreditCourtSession::getRecommend,
|
||||
CreditCourtSession::setRecommend,
|
||||
null,
|
||||
mpBatchSize
|
||||
),
|
||||
(rowItem, rowNumber) -> {
|
||||
if (rowItem.getRecommend() == null) {
|
||||
rowItem.setRecommend(0);
|
||||
}
|
||||
boolean saved = creditCourtSessionService.save(rowItem);
|
||||
if (!saved) {
|
||||
CreditCourtSession existing = creditCourtSessionService.lambdaQuery()
|
||||
.eq(CreditCourtSession::getCaseNumber, rowItem.getCaseNumber())
|
||||
.select(CreditCourtSession::getId, CreditCourtSession::getRecommend)
|
||||
.one();
|
||||
if (existing != null) {
|
||||
rowItem.setId(existing.getId());
|
||||
Integer old = existing.getRecommend();
|
||||
rowItem.setRecommend(old == null ? 1 : old + 1);
|
||||
if (creditCourtSessionService.updateById(rowItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
String prefix = rowNumber > 0 ? ("第" + rowNumber + "行:") : "";
|
||||
errorMessages.add(prefix + "保存失败");
|
||||
return false;
|
||||
},
|
||||
errorMessages
|
||||
);
|
||||
}
|
||||
|
||||
if (errorMessages.isEmpty()) {
|
||||
return success("成功导入" + successCount + "条数据", null);
|
||||
}
|
||||
return success("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "条", errorMessages);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return fail("导入失败:" + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载开庭公告司法大数据导入模板
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,7 @@ import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -299,6 +300,206 @@ public class CreditFinalVersionController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导入历史终本案件(仅解析“历史终本案件”选项卡)
|
||||
* 规则:案号相同则覆盖更新(recommend++ 记录更新次数);案号不存在则插入。
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('credit:creditFinalVersion: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;
|
||||
|
||||
try {
|
||||
int sheetIndex = ExcelImportSupport.findSheetIndex(file, "历史终本案件");
|
||||
if (sheetIndex < 0) {
|
||||
return fail("未读取到数据,请确认文件中存在“历史终本案件”选项卡且表头与示例格式一致", null);
|
||||
}
|
||||
|
||||
ExcelImportSupport.ImportResult<CreditFinalVersionImportParam> importResult = ExcelImportSupport.read(
|
||||
file, CreditFinalVersionImportParam.class, this::isEmptyImportRow, sheetIndex);
|
||||
List<CreditFinalVersionImportParam> 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, "案号");
|
||||
|
||||
LinkedHashMap<String, CreditFinalVersion> latestByCaseNumber = new LinkedHashMap<>();
|
||||
LinkedHashMap<String, Integer> latestRowByCaseNumber = new LinkedHashMap<>();
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
CreditFinalVersionImportParam param = list.get(i);
|
||||
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
|
||||
try {
|
||||
CreditFinalVersion 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);
|
||||
}
|
||||
|
||||
latestByCaseNumber.put(item.getCaseNumber(), item);
|
||||
latestRowByCaseNumber.put(item.getCaseNumber(), excelRowNumber);
|
||||
} catch (Exception e) {
|
||||
errorMessages.add("第" + excelRowNumber + "行:" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (latestByCaseNumber.isEmpty()) {
|
||||
if (errorMessages.isEmpty()) {
|
||||
return fail("未读取到数据,请确认模板表头与示例格式一致", null);
|
||||
}
|
||||
return success("导入完成,成功0条,失败" + errorMessages.size() + "条", errorMessages);
|
||||
}
|
||||
|
||||
final int chunkSize = 500;
|
||||
final int mpBatchSize = 500;
|
||||
List<CreditFinalVersion> chunkItems = new ArrayList<>(chunkSize);
|
||||
List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);
|
||||
|
||||
for (Map.Entry<String, CreditFinalVersion> entry : latestByCaseNumber.entrySet()) {
|
||||
String caseNumber = entry.getKey();
|
||||
CreditFinalVersion item = entry.getValue();
|
||||
Integer rowNo = latestRowByCaseNumber.get(caseNumber);
|
||||
chunkItems.add(item);
|
||||
chunkRowNumbers.add(rowNo != null ? rowNo : -1);
|
||||
if (chunkItems.size() >= chunkSize) {
|
||||
successCount += batchImportSupport.persistChunkWithFallback(
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
() -> batchImportSupport.upsertBySingleKeyAndIncrementCounterOnUpdate(
|
||||
creditFinalVersionService,
|
||||
chunkItems,
|
||||
CreditFinalVersion::getId,
|
||||
CreditFinalVersion::setId,
|
||||
CreditFinalVersion::getCaseNumber,
|
||||
CreditFinalVersion::getCaseNumber,
|
||||
CreditFinalVersion::getRecommend,
|
||||
CreditFinalVersion::setRecommend,
|
||||
null,
|
||||
mpBatchSize
|
||||
),
|
||||
(rowItem, rowNumber) -> {
|
||||
if (rowItem.getRecommend() == null) {
|
||||
rowItem.setRecommend(0);
|
||||
}
|
||||
boolean saved = creditFinalVersionService.save(rowItem);
|
||||
if (!saved) {
|
||||
CreditFinalVersion existing = creditFinalVersionService.lambdaQuery()
|
||||
.eq(CreditFinalVersion::getCaseNumber, rowItem.getCaseNumber())
|
||||
.select(CreditFinalVersion::getId, CreditFinalVersion::getRecommend)
|
||||
.one();
|
||||
if (existing != null) {
|
||||
rowItem.setId(existing.getId());
|
||||
Integer old = existing.getRecommend();
|
||||
rowItem.setRecommend(old == null ? 1 : old + 1);
|
||||
if (creditFinalVersionService.updateById(rowItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
String prefix = rowNumber > 0 ? ("第" + rowNumber + "行:") : "";
|
||||
errorMessages.add(prefix + "保存失败");
|
||||
return false;
|
||||
},
|
||||
errorMessages
|
||||
);
|
||||
chunkItems.clear();
|
||||
chunkRowNumbers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!chunkItems.isEmpty()) {
|
||||
successCount += batchImportSupport.persistChunkWithFallback(
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
() -> batchImportSupport.upsertBySingleKeyAndIncrementCounterOnUpdate(
|
||||
creditFinalVersionService,
|
||||
chunkItems,
|
||||
CreditFinalVersion::getId,
|
||||
CreditFinalVersion::setId,
|
||||
CreditFinalVersion::getCaseNumber,
|
||||
CreditFinalVersion::getCaseNumber,
|
||||
CreditFinalVersion::getRecommend,
|
||||
CreditFinalVersion::setRecommend,
|
||||
null,
|
||||
mpBatchSize
|
||||
),
|
||||
(rowItem, rowNumber) -> {
|
||||
if (rowItem.getRecommend() == null) {
|
||||
rowItem.setRecommend(0);
|
||||
}
|
||||
boolean saved = creditFinalVersionService.save(rowItem);
|
||||
if (!saved) {
|
||||
CreditFinalVersion existing = creditFinalVersionService.lambdaQuery()
|
||||
.eq(CreditFinalVersion::getCaseNumber, rowItem.getCaseNumber())
|
||||
.select(CreditFinalVersion::getId, CreditFinalVersion::getRecommend)
|
||||
.one();
|
||||
if (existing != null) {
|
||||
rowItem.setId(existing.getId());
|
||||
Integer old = existing.getRecommend();
|
||||
rowItem.setRecommend(old == null ? 1 : old + 1);
|
||||
if (creditFinalVersionService.updateById(rowItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
String prefix = rowNumber > 0 ? ("第" + rowNumber + "行:") : "";
|
||||
errorMessages.add(prefix + "保存失败");
|
||||
return false;
|
||||
},
|
||||
errorMessages
|
||||
);
|
||||
}
|
||||
|
||||
if (errorMessages.isEmpty()) {
|
||||
return success("成功导入" + successCount + "条数据", null);
|
||||
}
|
||||
return success("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "条", errorMessages);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return fail("导入失败:" + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载终本案件导入模板
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,7 @@ import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -320,6 +321,227 @@ public class CreditGqdjController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导入历史股权冻结(仅解析“历史股权冻结”选项卡)
|
||||
* 规则:执行通知文书号/案号相同则覆盖更新(recommend++ 记录更新次数);不存在则插入。
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('credit:creditGqdj: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;
|
||||
|
||||
try {
|
||||
int sheetIndex = ExcelImportSupport.findSheetIndex(file, "历史股权冻结");
|
||||
if (sheetIndex < 0) {
|
||||
return fail("未读取到数据,请确认文件中存在“历史股权冻结”选项卡且表头与示例格式一致", null);
|
||||
}
|
||||
|
||||
ExcelImportSupport.ImportResult<CreditGqdjImportParam> importResult = ExcelImportSupport.read(
|
||||
file, CreditGqdjImportParam.class, this::isEmptyImportRow, sheetIndex);
|
||||
List<CreditGqdjImportParam> 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;
|
||||
|
||||
String caseNumberHeader = "执行通知文书号";
|
||||
Map<String, String> urlByCaseNumber = ExcelImportSupport.readHyperlinksByHeaderKey(
|
||||
file, usedSheetIndex, usedTitleRows, usedHeadRows, caseNumberHeader);
|
||||
Map<String, String> urlByCaseNumberFromUrlCol = ExcelImportSupport.readKeyValueByHeaders(
|
||||
file, usedSheetIndex, usedTitleRows, usedHeadRows, caseNumberHeader, "url");
|
||||
if (urlByCaseNumberFromUrlCol.isEmpty()) {
|
||||
urlByCaseNumberFromUrlCol = ExcelImportSupport.readKeyValueByHeaders(
|
||||
file, usedSheetIndex, usedTitleRows, usedHeadRows, caseNumberHeader, "URL");
|
||||
}
|
||||
if (urlByCaseNumberFromUrlCol.isEmpty()) {
|
||||
urlByCaseNumberFromUrlCol = ExcelImportSupport.readKeyValueByHeaders(
|
||||
file, usedSheetIndex, usedTitleRows, usedHeadRows, caseNumberHeader, "网址");
|
||||
}
|
||||
if (urlByCaseNumberFromUrlCol.isEmpty()) {
|
||||
urlByCaseNumberFromUrlCol = ExcelImportSupport.readKeyValueByHeaders(
|
||||
file, usedSheetIndex, usedTitleRows, usedHeadRows, caseNumberHeader, "链接");
|
||||
}
|
||||
|
||||
LinkedHashMap<String, CreditGqdj> latestByCaseNumber = new LinkedHashMap<>();
|
||||
LinkedHashMap<String, Integer> latestRowByCaseNumber = new LinkedHashMap<>();
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
CreditGqdjImportParam param = list.get(i);
|
||||
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
|
||||
try {
|
||||
CreditGqdj item = convertImportParamToEntity(param);
|
||||
if (item.getCaseNumber() != null) {
|
||||
item.setCaseNumber(item.getCaseNumber().trim());
|
||||
}
|
||||
if (ImportHelper.isBlank(item.getCaseNumber())) {
|
||||
errorMessages.add("第" + excelRowNumber + "行:案号不能为空");
|
||||
continue;
|
||||
}
|
||||
|
||||
String key = item.getCaseNumber();
|
||||
String link = urlByCaseNumber.get(key);
|
||||
if (ImportHelper.isBlank(link)) {
|
||||
link = urlByCaseNumberFromUrlCol.get(key);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
latestByCaseNumber.put(item.getCaseNumber(), item);
|
||||
latestRowByCaseNumber.put(item.getCaseNumber(), excelRowNumber);
|
||||
} catch (Exception e) {
|
||||
errorMessages.add("第" + excelRowNumber + "行:" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (latestByCaseNumber.isEmpty()) {
|
||||
if (errorMessages.isEmpty()) {
|
||||
return fail("未读取到数据,请确认模板表头与示例格式一致", null);
|
||||
}
|
||||
return success("导入完成,成功0条,失败" + errorMessages.size() + "条", errorMessages);
|
||||
}
|
||||
|
||||
final int chunkSize = 500;
|
||||
final int mpBatchSize = 500;
|
||||
List<CreditGqdj> chunkItems = new ArrayList<>(chunkSize);
|
||||
List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);
|
||||
|
||||
for (Map.Entry<String, CreditGqdj> entry : latestByCaseNumber.entrySet()) {
|
||||
String caseNumber = entry.getKey();
|
||||
CreditGqdj item = entry.getValue();
|
||||
Integer rowNo = latestRowByCaseNumber.get(caseNumber);
|
||||
chunkItems.add(item);
|
||||
chunkRowNumbers.add(rowNo != null ? rowNo : -1);
|
||||
if (chunkItems.size() >= chunkSize) {
|
||||
successCount += batchImportSupport.persistChunkWithFallback(
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
() -> batchImportSupport.upsertBySingleKeyAndIncrementCounterOnUpdate(
|
||||
creditGqdjService,
|
||||
chunkItems,
|
||||
CreditGqdj::getId,
|
||||
CreditGqdj::setId,
|
||||
CreditGqdj::getCaseNumber,
|
||||
CreditGqdj::getCaseNumber,
|
||||
CreditGqdj::getRecommend,
|
||||
CreditGqdj::setRecommend,
|
||||
null,
|
||||
mpBatchSize
|
||||
),
|
||||
(rowItem, rowNumber) -> {
|
||||
if (rowItem.getRecommend() == null) {
|
||||
rowItem.setRecommend(0);
|
||||
}
|
||||
boolean saved = creditGqdjService.save(rowItem);
|
||||
if (!saved) {
|
||||
CreditGqdj existing = creditGqdjService.lambdaQuery()
|
||||
.eq(CreditGqdj::getCaseNumber, rowItem.getCaseNumber())
|
||||
.select(CreditGqdj::getId, CreditGqdj::getRecommend)
|
||||
.one();
|
||||
if (existing != null) {
|
||||
rowItem.setId(existing.getId());
|
||||
Integer old = existing.getRecommend();
|
||||
rowItem.setRecommend(old == null ? 1 : old + 1);
|
||||
if (creditGqdjService.updateById(rowItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
String prefix = rowNumber > 0 ? ("第" + rowNumber + "行:") : "";
|
||||
errorMessages.add(prefix + "保存失败");
|
||||
return false;
|
||||
},
|
||||
errorMessages
|
||||
);
|
||||
chunkItems.clear();
|
||||
chunkRowNumbers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!chunkItems.isEmpty()) {
|
||||
successCount += batchImportSupport.persistChunkWithFallback(
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
() -> batchImportSupport.upsertBySingleKeyAndIncrementCounterOnUpdate(
|
||||
creditGqdjService,
|
||||
chunkItems,
|
||||
CreditGqdj::getId,
|
||||
CreditGqdj::setId,
|
||||
CreditGqdj::getCaseNumber,
|
||||
CreditGqdj::getCaseNumber,
|
||||
CreditGqdj::getRecommend,
|
||||
CreditGqdj::setRecommend,
|
||||
null,
|
||||
mpBatchSize
|
||||
),
|
||||
(rowItem, rowNumber) -> {
|
||||
if (rowItem.getRecommend() == null) {
|
||||
rowItem.setRecommend(0);
|
||||
}
|
||||
boolean saved = creditGqdjService.save(rowItem);
|
||||
if (!saved) {
|
||||
CreditGqdj existing = creditGqdjService.lambdaQuery()
|
||||
.eq(CreditGqdj::getCaseNumber, rowItem.getCaseNumber())
|
||||
.select(CreditGqdj::getId, CreditGqdj::getRecommend)
|
||||
.one();
|
||||
if (existing != null) {
|
||||
rowItem.setId(existing.getId());
|
||||
Integer old = existing.getRecommend();
|
||||
rowItem.setRecommend(old == null ? 1 : old + 1);
|
||||
if (creditGqdjService.updateById(rowItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
String prefix = rowNumber > 0 ? ("第" + rowNumber + "行:") : "";
|
||||
errorMessages.add(prefix + "保存失败");
|
||||
return false;
|
||||
},
|
||||
errorMessages
|
||||
);
|
||||
}
|
||||
|
||||
if (errorMessages.isEmpty()) {
|
||||
return success("成功导入" + successCount + "条数据", null);
|
||||
}
|
||||
return success("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "条", errorMessages);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return fail("导入失败:" + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载股权冻结导入模板
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,7 @@ import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -302,6 +303,213 @@ public class CreditJudicialDocumentController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导入历史裁判文书(仅解析“历史裁判文书”选项卡)
|
||||
* 规则:案号相同则覆盖更新(recommend++ 记录更新次数);案号不存在则插入。
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('credit:creditJudicialDocument: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;
|
||||
|
||||
try {
|
||||
int sheetIndex = ExcelImportSupport.findSheetIndex(file, "历史裁判文书");
|
||||
if (sheetIndex < 0) {
|
||||
return fail("未读取到数据,请确认文件中存在“历史裁判文书”选项卡且表头与示例格式一致", null);
|
||||
}
|
||||
|
||||
ExcelImportSupport.ImportResult<CreditJudicialDocumentImportParam> importResult = ExcelImportSupport.read(
|
||||
file, CreditJudicialDocumentImportParam.class, this::isEmptyImportRow, sheetIndex);
|
||||
List<CreditJudicialDocumentImportParam> 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, "案号");
|
||||
Map<String, String> urlByTitle = ExcelImportSupport.readUrlByKey(file, usedSheetIndex, usedTitleRows, usedHeadRows, "文书标题");
|
||||
|
||||
LinkedHashMap<String, CreditJudicialDocument> latestByCaseNumber = new LinkedHashMap<>();
|
||||
LinkedHashMap<String, Integer> latestRowByCaseNumber = new LinkedHashMap<>();
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
CreditJudicialDocumentImportParam param = list.get(i);
|
||||
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
|
||||
try {
|
||||
CreditJudicialDocument item = convertImportParamToEntity(param);
|
||||
if (item.getCaseNumber() != null) {
|
||||
item.setCaseNumber(item.getCaseNumber().trim());
|
||||
}
|
||||
if (ImportHelper.isBlank(item.getCaseNumber())) {
|
||||
errorMessages.add("第" + excelRowNumber + "行:案号不能为空");
|
||||
continue;
|
||||
}
|
||||
|
||||
String link = null;
|
||||
if (!ImportHelper.isBlank(item.getCaseNumber())) {
|
||||
link = urlByCaseNumber.get(item.getCaseNumber());
|
||||
}
|
||||
if (ImportHelper.isBlank(link) && !ImportHelper.isBlank(item.getTitle())) {
|
||||
link = urlByTitle.get(item.getTitle().trim());
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
latestByCaseNumber.put(item.getCaseNumber(), item);
|
||||
latestRowByCaseNumber.put(item.getCaseNumber(), excelRowNumber);
|
||||
} catch (Exception e) {
|
||||
errorMessages.add("第" + excelRowNumber + "行:" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (latestByCaseNumber.isEmpty()) {
|
||||
if (errorMessages.isEmpty()) {
|
||||
return fail("未读取到数据,请确认模板表头与示例格式一致", null);
|
||||
}
|
||||
return success("导入完成,成功0条,失败" + errorMessages.size() + "条", errorMessages);
|
||||
}
|
||||
|
||||
final int chunkSize = 500;
|
||||
final int mpBatchSize = 500;
|
||||
List<CreditJudicialDocument> chunkItems = new ArrayList<>(chunkSize);
|
||||
List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);
|
||||
|
||||
for (Map.Entry<String, CreditJudicialDocument> entry : latestByCaseNumber.entrySet()) {
|
||||
String caseNumber = entry.getKey();
|
||||
CreditJudicialDocument item = entry.getValue();
|
||||
Integer rowNo = latestRowByCaseNumber.get(caseNumber);
|
||||
chunkItems.add(item);
|
||||
chunkRowNumbers.add(rowNo != null ? rowNo : -1);
|
||||
if (chunkItems.size() >= chunkSize) {
|
||||
successCount += batchImportSupport.persistChunkWithFallback(
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
() -> batchImportSupport.upsertBySingleKeyAndIncrementCounterOnUpdate(
|
||||
creditJudicialDocumentService,
|
||||
chunkItems,
|
||||
CreditJudicialDocument::getId,
|
||||
CreditJudicialDocument::setId,
|
||||
CreditJudicialDocument::getCaseNumber,
|
||||
CreditJudicialDocument::getCaseNumber,
|
||||
CreditJudicialDocument::getRecommend,
|
||||
CreditJudicialDocument::setRecommend,
|
||||
null,
|
||||
mpBatchSize
|
||||
),
|
||||
(rowItem, rowNumber) -> {
|
||||
if (rowItem.getRecommend() == null) {
|
||||
rowItem.setRecommend(0);
|
||||
}
|
||||
boolean saved = creditJudicialDocumentService.save(rowItem);
|
||||
if (!saved) {
|
||||
CreditJudicialDocument existing = creditJudicialDocumentService.lambdaQuery()
|
||||
.eq(CreditJudicialDocument::getCaseNumber, rowItem.getCaseNumber())
|
||||
.select(CreditJudicialDocument::getId, CreditJudicialDocument::getRecommend)
|
||||
.one();
|
||||
if (existing != null) {
|
||||
rowItem.setId(existing.getId());
|
||||
Integer old = existing.getRecommend();
|
||||
rowItem.setRecommend(old == null ? 1 : old + 1);
|
||||
if (creditJudicialDocumentService.updateById(rowItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
String prefix = rowNumber > 0 ? ("第" + rowNumber + "行:") : "";
|
||||
errorMessages.add(prefix + "保存失败");
|
||||
return false;
|
||||
},
|
||||
errorMessages
|
||||
);
|
||||
chunkItems.clear();
|
||||
chunkRowNumbers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!chunkItems.isEmpty()) {
|
||||
successCount += batchImportSupport.persistChunkWithFallback(
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
() -> batchImportSupport.upsertBySingleKeyAndIncrementCounterOnUpdate(
|
||||
creditJudicialDocumentService,
|
||||
chunkItems,
|
||||
CreditJudicialDocument::getId,
|
||||
CreditJudicialDocument::setId,
|
||||
CreditJudicialDocument::getCaseNumber,
|
||||
CreditJudicialDocument::getCaseNumber,
|
||||
CreditJudicialDocument::getRecommend,
|
||||
CreditJudicialDocument::setRecommend,
|
||||
null,
|
||||
mpBatchSize
|
||||
),
|
||||
(rowItem, rowNumber) -> {
|
||||
if (rowItem.getRecommend() == null) {
|
||||
rowItem.setRecommend(0);
|
||||
}
|
||||
boolean saved = creditJudicialDocumentService.save(rowItem);
|
||||
if (!saved) {
|
||||
CreditJudicialDocument existing = creditJudicialDocumentService.lambdaQuery()
|
||||
.eq(CreditJudicialDocument::getCaseNumber, rowItem.getCaseNumber())
|
||||
.select(CreditJudicialDocument::getId, CreditJudicialDocument::getRecommend)
|
||||
.one();
|
||||
if (existing != null) {
|
||||
rowItem.setId(existing.getId());
|
||||
Integer old = existing.getRecommend();
|
||||
rowItem.setRecommend(old == null ? 1 : old + 1);
|
||||
if (creditJudicialDocumentService.updateById(rowItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
String prefix = rowNumber > 0 ? ("第" + rowNumber + "行:") : "";
|
||||
errorMessages.add(prefix + "保存失败");
|
||||
return false;
|
||||
},
|
||||
errorMessages
|
||||
);
|
||||
}
|
||||
|
||||
if (errorMessages.isEmpty()) {
|
||||
return success("成功导入" + successCount + "条数据", null);
|
||||
}
|
||||
return success("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "条", errorMessages);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return fail("导入失败:" + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载裁判文书导入模板
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,7 @@ import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -299,6 +300,206 @@ public class CreditXgxfController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导入历史限制高消费(仅解析“历史限制高消费”选项卡)
|
||||
* 规则:案号相同则覆盖更新(recommend++ 记录更新次数);案号不存在则插入。
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('credit:creditXgxf: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;
|
||||
|
||||
try {
|
||||
int sheetIndex = ExcelImportSupport.findSheetIndex(file, "历史限制高消费");
|
||||
if (sheetIndex < 0) {
|
||||
return fail("未读取到数据,请确认文件中存在“历史限制高消费”选项卡且表头与示例格式一致", null);
|
||||
}
|
||||
|
||||
ExcelImportSupport.ImportResult<CreditXgxfImportParam> importResult = ExcelImportSupport.read(
|
||||
file, CreditXgxfImportParam.class, this::isEmptyImportRow, sheetIndex);
|
||||
List<CreditXgxfImportParam> 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, "案号");
|
||||
|
||||
LinkedHashMap<String, CreditXgxf> latestByCaseNumber = new LinkedHashMap<>();
|
||||
LinkedHashMap<String, Integer> latestRowByCaseNumber = new LinkedHashMap<>();
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
CreditXgxfImportParam param = list.get(i);
|
||||
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
|
||||
try {
|
||||
CreditXgxf 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);
|
||||
}
|
||||
|
||||
latestByCaseNumber.put(item.getCaseNumber(), item);
|
||||
latestRowByCaseNumber.put(item.getCaseNumber(), excelRowNumber);
|
||||
} catch (Exception e) {
|
||||
errorMessages.add("第" + excelRowNumber + "行:" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (latestByCaseNumber.isEmpty()) {
|
||||
if (errorMessages.isEmpty()) {
|
||||
return fail("未读取到数据,请确认模板表头与示例格式一致", null);
|
||||
}
|
||||
return success("导入完成,成功0条,失败" + errorMessages.size() + "条", errorMessages);
|
||||
}
|
||||
|
||||
final int chunkSize = 500;
|
||||
final int mpBatchSize = 500;
|
||||
List<CreditXgxf> chunkItems = new ArrayList<>(chunkSize);
|
||||
List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);
|
||||
|
||||
for (Map.Entry<String, CreditXgxf> entry : latestByCaseNumber.entrySet()) {
|
||||
String caseNumber = entry.getKey();
|
||||
CreditXgxf item = entry.getValue();
|
||||
Integer rowNo = latestRowByCaseNumber.get(caseNumber);
|
||||
chunkItems.add(item);
|
||||
chunkRowNumbers.add(rowNo != null ? rowNo : -1);
|
||||
if (chunkItems.size() >= chunkSize) {
|
||||
successCount += batchImportSupport.persistChunkWithFallback(
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
() -> batchImportSupport.upsertBySingleKeyAndIncrementCounterOnUpdate(
|
||||
creditXgxfService,
|
||||
chunkItems,
|
||||
CreditXgxf::getId,
|
||||
CreditXgxf::setId,
|
||||
CreditXgxf::getCaseNumber,
|
||||
CreditXgxf::getCaseNumber,
|
||||
CreditXgxf::getRecommend,
|
||||
CreditXgxf::setRecommend,
|
||||
null,
|
||||
mpBatchSize
|
||||
),
|
||||
(rowItem, rowNumber) -> {
|
||||
if (rowItem.getRecommend() == null) {
|
||||
rowItem.setRecommend(0);
|
||||
}
|
||||
boolean saved = creditXgxfService.save(rowItem);
|
||||
if (!saved) {
|
||||
CreditXgxf existing = creditXgxfService.lambdaQuery()
|
||||
.eq(CreditXgxf::getCaseNumber, rowItem.getCaseNumber())
|
||||
.select(CreditXgxf::getId, CreditXgxf::getRecommend)
|
||||
.one();
|
||||
if (existing != null) {
|
||||
rowItem.setId(existing.getId());
|
||||
Integer old = existing.getRecommend();
|
||||
rowItem.setRecommend(old == null ? 1 : old + 1);
|
||||
if (creditXgxfService.updateById(rowItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
String prefix = rowNumber > 0 ? ("第" + rowNumber + "行:") : "";
|
||||
errorMessages.add(prefix + "保存失败");
|
||||
return false;
|
||||
},
|
||||
errorMessages
|
||||
);
|
||||
chunkItems.clear();
|
||||
chunkRowNumbers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!chunkItems.isEmpty()) {
|
||||
successCount += batchImportSupport.persistChunkWithFallback(
|
||||
chunkItems,
|
||||
chunkRowNumbers,
|
||||
() -> batchImportSupport.upsertBySingleKeyAndIncrementCounterOnUpdate(
|
||||
creditXgxfService,
|
||||
chunkItems,
|
||||
CreditXgxf::getId,
|
||||
CreditXgxf::setId,
|
||||
CreditXgxf::getCaseNumber,
|
||||
CreditXgxf::getCaseNumber,
|
||||
CreditXgxf::getRecommend,
|
||||
CreditXgxf::setRecommend,
|
||||
null,
|
||||
mpBatchSize
|
||||
),
|
||||
(rowItem, rowNumber) -> {
|
||||
if (rowItem.getRecommend() == null) {
|
||||
rowItem.setRecommend(0);
|
||||
}
|
||||
boolean saved = creditXgxfService.save(rowItem);
|
||||
if (!saved) {
|
||||
CreditXgxf existing = creditXgxfService.lambdaQuery()
|
||||
.eq(CreditXgxf::getCaseNumber, rowItem.getCaseNumber())
|
||||
.select(CreditXgxf::getId, CreditXgxf::getRecommend)
|
||||
.one();
|
||||
if (existing != null) {
|
||||
rowItem.setId(existing.getId());
|
||||
Integer old = existing.getRecommend();
|
||||
rowItem.setRecommend(old == null ? 1 : old + 1);
|
||||
if (creditXgxfService.updateById(rowItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
String prefix = rowNumber > 0 ? ("第" + rowNumber + "行:") : "";
|
||||
errorMessages.add(prefix + "保存失败");
|
||||
return false;
|
||||
},
|
||||
errorMessages
|
||||
);
|
||||
}
|
||||
|
||||
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