Files
mp-java/src/main/java/com/gxwebsoft/credit/controller/CreditBankruptcyController.java
赵忠林 5e804bbf9a feat(data): 更新公司记录计数服务并优化导入功能
- 在多个控制器中引入 CreditCompanyRecordCountService 依赖注入
- 添加 HashSet 和 Set 类型导入以支持公司ID集合操作
- 在Excel导入过程中跟踪受影响的公司ID集合
- 实现导入完成后批量刷新公司记录计数的功能
- 扩展 CreditCompany 实体类添加各类信用记录计数字段
- 优化导入逻辑确保公司记录计数实时更新
2026-01-28 21:46:30 +08:00

628 lines
28 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.gxwebsoft.credit.controller;
import com.gxwebsoft.common.core.annotation.OperationLog;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.credit.entity.CreditBankruptcy;
import com.gxwebsoft.credit.param.CreditBankruptcyImportParam;
import com.gxwebsoft.credit.param.CreditBankruptcyParam;
import com.gxwebsoft.credit.service.CreditCompanyService;
import com.gxwebsoft.credit.service.CreditCompanyRecordCountService;
import com.gxwebsoft.credit.service.CreditBankruptcyService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 破产重整控制器
*
* @author 科技小王子
* @since 2026-01-07 13:52:14
*/
@Tag(name = "破产重整管理")
@RestController
@RequestMapping("/api/credit/credit-bankruptcy")
public class CreditBankruptcyController extends BaseController {
@Resource
private CreditBankruptcyService creditBankruptcyService;
@Resource
private BatchImportSupport batchImportSupport;
@Resource
private CreditCompanyService creditCompanyService;
@Resource
private CreditCompanyRecordCountService creditCompanyRecordCountService;
@Operation(summary = "分页查询破产重整")
@GetMapping("/page")
public ApiResult<PageResult<CreditBankruptcy>> page(CreditBankruptcyParam param) {
// 使用关联查询
return success(creditBankruptcyService.pageRel(param));
}
@Operation(summary = "查询全部破产重整")
@GetMapping()
public ApiResult<List<CreditBankruptcy>> list(CreditBankruptcyParam param) {
// 使用关联查询
return success(creditBankruptcyService.listRel(param));
}
@Operation(summary = "根据id查询破产重整")
@GetMapping("/{id}")
public ApiResult<CreditBankruptcy> get(@PathVariable("id") Integer id) {
// 使用关联查询
return success(creditBankruptcyService.getByIdRel(id));
}
@PreAuthorize("hasAuthority('credit:creditBankruptcy:save')")
@OperationLog
@Operation(summary = "添加破产重整")
@PostMapping()
public ApiResult<?> save(@RequestBody CreditBankruptcy creditBankruptcy) {
// 记录当前登录用户id
// User loginUser = getLoginUser();
// if (loginUser != null) {
// creditBankruptcy.setUserId(loginUser.getUserId());
// }
if (creditBankruptcyService.save(creditBankruptcy)) {
return success("添加成功");
}
return fail("添加失败");
}
@PreAuthorize("hasAuthority('credit:creditBankruptcy:update')")
@OperationLog
@Operation(summary = "修改破产重整")
@PutMapping()
public ApiResult<?> update(@RequestBody CreditBankruptcy creditBankruptcy) {
if (creditBankruptcyService.updateById(creditBankruptcy)) {
return success("修改成功");
}
return fail("修改失败");
}
@PreAuthorize("hasAuthority('credit:creditBankruptcy:remove')")
@OperationLog
@Operation(summary = "删除破产重整")
@DeleteMapping("/{id}")
public ApiResult<?> remove(@PathVariable("id") Integer id) {
if (creditBankruptcyService.removeById(id)) {
return success("删除成功");
}
return fail("删除失败");
}
@PreAuthorize("hasAuthority('credit:creditBankruptcy:save')")
@OperationLog
@Operation(summary = "批量添加破产重整")
@PostMapping("/batch")
public ApiResult<?> saveBatch(@RequestBody List<CreditBankruptcy> list) {
if (creditBankruptcyService.saveBatch(list)) {
return success("添加成功");
}
return fail("添加失败");
}
@PreAuthorize("hasAuthority('credit:creditBankruptcy:update')")
@OperationLog
@Operation(summary = "批量修改破产重整")
@PutMapping("/batch")
public ApiResult<?> removeBatch(@RequestBody BatchParam<CreditBankruptcy> batchParam) {
if (batchParam.update(creditBankruptcyService, "id")) {
return success("修改成功");
}
return fail("修改失败");
}
@PreAuthorize("hasAuthority('credit:creditBankruptcy:remove')")
@OperationLog
@Operation(summary = "批量删除破产重整")
@DeleteMapping("/batch")
public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
if (creditBankruptcyService.removeByIds(ids)) {
return success("删除成功");
}
return fail("删除失败");
}
/**
* 根据企业名称匹配企业并更新 companyId匹配 CreditCompany.name / CreditCompany.matchName
*
* <p>默认仅更新 companyId=0 的记录;如需覆盖更新,传 onlyNull=false。</p>
*/
@PreAuthorize("hasAuthority('credit:creditBankruptcy:update')")
@OperationLog
@Operation(summary = "根据企业名称匹配并更新companyId")
@PostMapping("/company-id/refresh")
public ApiResult<Map<String, Object>> refreshCompanyIdByCompanyName(
@RequestParam(value = "onlyNull", required = false, defaultValue = "true") Boolean onlyNull,
@RequestParam(value = "limit", required = false) Integer limit
) {
User loginUser = getLoginUser();
Integer currentTenantId = loginUser != null ? loginUser.getTenantId() : null;
BatchImportSupport.CompanyIdRefreshStats stats = batchImportSupport.refreshCompanyIdByCompanyName(
creditBankruptcyService,
creditCompanyService,
currentTenantId,
onlyNull,
limit,
CreditBankruptcy::getId,
CreditBankruptcy::setId,
CreditBankruptcy::getParty,
CreditBankruptcy::getCompanyId,
CreditBankruptcy::setCompanyId,
CreditBankruptcy::getHasData,
CreditBankruptcy::setHasData,
CreditBankruptcy::getTenantId,
CreditBankruptcy::new
);
if (!stats.anyDataRead) {
return success("无可更新数据", stats.toMap());
}
return success("更新完成,更新" + stats.updated + "", stats.toMap());
}
/**
* 批量导入破产重整
*/
@PreAuthorize("hasAuthority('credit:creditBankruptcy:save')")
@Operation(summary = "批量导入破产重整")
@PostMapping("/import")
public ApiResult<List<String>> importBatch(@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 {
ExcelImportSupport.ImportResult<CreditBankruptcyImportParam> importResult = ExcelImportSupport.readAnySheet(
file, CreditBankruptcyImportParam.class, this::isEmptyImportRow);
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, "案号");
final int chunkSize = 500;
final int mpBatchSize = 500;
List<CreditBankruptcy> chunkItems = new ArrayList<>(chunkSize);
List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);
for (int i = 0; i < list.size(); i++) {
CreditBankruptcyImportParam param = list.get(i);
try {
CreditBankruptcy item = convertImportParamToEntity(param);
if (!ImportHelper.isBlank(item.getCode())) {
String link = urlByCode.get(item.getCode().trim());
if (link != null && !link.isEmpty()) {
item.setUrl(link);
}
}
if (item.getCompanyId() == null && companyId != null) {
item.setCompanyId(companyId);
}
if (item.getCompanyId() != null && item.getCompanyId() > 0) {
touchedCompanyIds.add(item.getCompanyId());
}
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.getRecommend() == null) {
item.setRecommend(0);
}
if (item.getDeleted() == null) {
item.setDeleted(0);
}
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
if (ImportHelper.isBlank(item.getCode())) {
errorMessages.add("" + excelRowNumber + "行:案号不能为空");
continue;
}
if (item.getCompanyId() != null && item.getCompanyId() > 0) {
touchedCompanyIds.add(item.getCompanyId());
}
chunkItems.add(item);
chunkRowNumbers.add(excelRowNumber);
if (chunkItems.size() >= chunkSize) {
successCount += batchImportSupport.persistChunkWithFallback(
chunkItems,
chunkRowNumbers,
() -> batchImportSupport.upsertBySingleKey(
creditBankruptcyService,
chunkItems,
CreditBankruptcy::getId,
CreditBankruptcy::setId,
CreditBankruptcy::getCode,
CreditBankruptcy::getCode,
null,
mpBatchSize
),
(rowItem, rowNumber) -> {
boolean saved = creditBankruptcyService.save(rowItem);
if (!saved) {
CreditBankruptcy existing = creditBankruptcyService.lambdaQuery()
.eq(CreditBankruptcy::getCode, rowItem.getCode())
.one();
if (existing != null) {
rowItem.setId(existing.getId());
if (creditBankruptcyService.updateById(rowItem)) {
return true;
}
}
} else {
return true;
}
String prefix = rowNumber > 0 ? ("" + rowNumber + "行:") : "";
errorMessages.add(prefix + "保存失败");
return false;
},
errorMessages
);
chunkItems.clear();
chunkRowNumbers.clear();
}
} catch (Exception e) {
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
errorMessages.add("" + excelRowNumber + "行:" + e.getMessage());
e.printStackTrace();
}
}
if (!chunkItems.isEmpty()) {
successCount += batchImportSupport.persistChunkWithFallback(
chunkItems,
chunkRowNumbers,
() -> batchImportSupport.upsertBySingleKey(
creditBankruptcyService,
chunkItems,
CreditBankruptcy::getId,
CreditBankruptcy::setId,
CreditBankruptcy::getCode,
CreditBankruptcy::getCode,
null,
mpBatchSize
),
(rowItem, rowNumber) -> {
boolean saved = creditBankruptcyService.save(rowItem);
if (!saved) {
CreditBankruptcy existing = creditBankruptcyService.lambdaQuery()
.eq(CreditBankruptcy::getCode, rowItem.getCode())
.one();
if (existing != null) {
rowItem.setId(existing.getId());
if (creditBankruptcyService.updateById(rowItem)) {
return true;
}
}
} else {
return true;
}
String prefix = rowNumber > 0 ? ("" + rowNumber + "行:") : "";
errorMessages.add(prefix + "保存失败");
return false;
},
errorMessages
);
}
creditCompanyRecordCountService.refresh(CreditCompanyRecordCountService.CountType.BANKRUPTCY, touchedCompanyIds);
if (errorMessages.isEmpty()) {
return success("成功导入" + successCount + "条数据", null);
} else {
return success("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "", errorMessages);
}
} catch (Exception e) {
e.printStackTrace();
return fail("导入失败:" + e.getMessage(), null);
}
}
/**
* 批量导入历史破产重整(仅解析“历史破产重整”选项卡)
* 规则:案号/唯一标识相同则覆盖更新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;
Set<Integer> touchedCompanyIds = new HashSet<>();
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
);
}
creditCompanyRecordCountService.refresh(CreditCompanyRecordCountService.CountType.BANKRUPTCY, touchedCompanyIds);
if (errorMessages.isEmpty()) {
return success("成功导入" + successCount + "条数据", null);
}
return success("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "", errorMessages);
} catch (Exception e) {
e.printStackTrace();
return fail("导入失败:" + e.getMessage(), null);
}
}
/**
* 下载破产重整导入模板
*/
@Operation(summary = "下载破产重整导入模板")
@GetMapping("/import/template")
public void downloadTemplate(HttpServletResponse response) throws IOException {
List<CreditBankruptcyImportParam> templateList = new ArrayList<>();
CreditBankruptcyImportParam example = new CreditBankruptcyImportParam();
example.setCode("2024示例案号");
example.setType("破产清算");
example.setParty("某某公司");
example.setCourt("某某人民法院");
example.setPublicDate("2024-01-10");
example.setComments("备注信息");
templateList.add(example);
Workbook workbook = ExcelImportSupport.buildTemplate("破产重整导入模板", "破产重整", CreditBankruptcyImportParam.class, templateList);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=credit_bankruptcy_import_template.xlsx");
workbook.write(response.getOutputStream());
workbook.close();
}
private boolean isEmptyImportRow(CreditBankruptcyImportParam param) {
if (param == null) {
return true;
}
if (isImportHeaderRow(param)) {
return true;
}
return ImportHelper.isBlank(param.getCode())
&& ImportHelper.isBlank(param.getParty())
&& ImportHelper.isBlank(param.getCourt());
}
private boolean isImportHeaderRow(CreditBankruptcyImportParam param) {
return isHeaderValue(param.getCode(), "案号")
|| isHeaderValue(param.getType(), "案件类型")
|| isHeaderValue(param.getParty(), "当事人");
}
private static boolean isHeaderValue(String value, String headerText) {
if (value == null) {
return false;
}
return headerText.equals(value.trim());
}
private CreditBankruptcy convertImportParamToEntity(CreditBankruptcyImportParam param) {
CreditBankruptcy entity = new CreditBankruptcy();
entity.setCode(param.getCode());
entity.setType(param.getType());
entity.setParty(param.getParty());
entity.setCourt(param.getCourt());
entity.setPublicDate(param.getPublicDate());
entity.setComments(param.getComments());
return entity;
}
}