Files
mp-java/src/main/java/com/gxwebsoft/credit/controller/CreditExternalController.java
赵忠林 7ba034ab1e feat(controller): 新增企业ID批量更新功能
- 在BatchImportSupport中添加CompanyIdRefreshStats统计类
- 实现基于企业名称匹配的companyId批量更新逻辑
- 添加normalizeCompanyName和addCompanyNameMapping辅助方法
- 在各个Credit控制器中注入CreditCompanyService依赖
- 为所有相关控制器添加/company-id/refresh接口端点
- 实现多租户环境下的安全匹配和更新机制
- 支持limit参数控制批量处理数量
- 提供详细的更新统计数据返回
2026-01-20 22:13:06 +08:00

410 lines
17 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.CreditExternal;
import com.gxwebsoft.credit.param.CreditExternalImportParam;
import com.gxwebsoft.credit.param.CreditExternalParam;
import com.gxwebsoft.credit.service.CreditCompanyService;
import com.gxwebsoft.credit.service.CreditExternalService;
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.List;
import java.util.Map;
/**
* 对外投资控制器
*
* @author 科技小王子
* @since 2025-12-19 19:50:12
*/
@Tag(name = "对外投资管理")
@RestController
@RequestMapping("/api/credit/credit-external")
public class CreditExternalController extends BaseController {
@Resource
private CreditExternalService creditExternalService;
@Resource
private BatchImportSupport batchImportSupport;
@Resource
private CreditCompanyService creditCompanyService;
@Operation(summary = "分页查询对外投资")
@GetMapping("/page")
public ApiResult<PageResult<CreditExternal>> page(CreditExternalParam param) {
// 使用关联查询
return success(creditExternalService.pageRel(param));
}
@Operation(summary = "查询全部对外投资")
@GetMapping()
public ApiResult<List<CreditExternal>> list(CreditExternalParam param) {
// 使用关联查询
return success(creditExternalService.listRel(param));
}
@Operation(summary = "根据id查询对外投资")
@GetMapping("/{id}")
public ApiResult<CreditExternal> get(@PathVariable("id") Integer id) {
// 使用关联查询
return success(creditExternalService.getByIdRel(id));
}
@PreAuthorize("hasAuthority('credit:creditExternal:save')")
@OperationLog
@Operation(summary = "添加对外投资")
@PostMapping()
public ApiResult<?> save(@RequestBody CreditExternal creditExternal) {
// 记录当前登录用户id
// User loginUser = getLoginUser();
// if (loginUser != null) {
// creditExternal.setUserId(loginUser.getUserId());
// }
if (creditExternalService.save(creditExternal)) {
return success("添加成功");
}
return fail("添加失败");
}
@PreAuthorize("hasAuthority('credit:creditExternal:update')")
@OperationLog
@Operation(summary = "修改对外投资")
@PutMapping()
public ApiResult<?> update(@RequestBody CreditExternal creditExternal) {
if (creditExternalService.updateById(creditExternal)) {
return success("修改成功");
}
return fail("修改失败");
}
@PreAuthorize("hasAuthority('credit:creditExternal:remove')")
@OperationLog
@Operation(summary = "删除对外投资")
@DeleteMapping("/{id}")
public ApiResult<?> remove(@PathVariable("id") Integer id) {
if (creditExternalService.removeById(id)) {
return success("删除成功");
}
return fail("删除失败");
}
@PreAuthorize("hasAuthority('credit:creditExternal:save')")
@OperationLog
@Operation(summary = "批量添加对外投资")
@PostMapping("/batch")
public ApiResult<?> saveBatch(@RequestBody List<CreditExternal> list) {
if (creditExternalService.saveBatch(list)) {
return success("添加成功");
}
return fail("添加失败");
}
@PreAuthorize("hasAuthority('credit:creditExternal:update')")
@OperationLog
@Operation(summary = "批量修改对外投资")
@PutMapping("/batch")
public ApiResult<?> removeBatch(@RequestBody BatchParam<CreditExternal> batchParam) {
if (batchParam.update(creditExternalService, "id")) {
return success("修改成功");
}
return fail("修改失败");
}
@PreAuthorize("hasAuthority('credit:creditExternal:remove')")
@OperationLog
@Operation(summary = "批量删除对外投资")
@DeleteMapping("/batch")
public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
if (creditExternalService.removeByIds(ids)) {
return success("删除成功");
}
return fail("删除失败");
}
/**
* 根据企业名称匹配企业并更新 companyId匹配 CreditCompany.name / CreditCompany.matchName
*
* <p>默认仅更新 companyId=0 的记录;如需覆盖更新,传 onlyNull=false。</p>
*/
@PreAuthorize("hasAuthority('credit:creditExternal: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(
creditExternalService,
creditCompanyService,
currentTenantId,
onlyNull,
limit,
CreditExternal::getId,
CreditExternal::setId,
CreditExternal::getName,
CreditExternal::getCompanyId,
CreditExternal::setCompanyId,
CreditExternal::getTenantId,
CreditExternal::new
);
if (!stats.anyDataRead) {
return success("无可更新数据", stats.toMap());
}
return success("更新完成,更新" + stats.updated + "", stats.toMap());
}
/**
* 批量导入对外投资
*/
@PreAuthorize("hasAuthority('credit:creditExternal: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;
try {
int sheetIndex = ExcelImportSupport.findSheetIndex(file, "对外投资", 0);
ExcelImportSupport.ImportResult<CreditExternalImportParam> importResult = ExcelImportSupport.read(
file, CreditExternalImportParam.class, this::isEmptyImportRow, sheetIndex);
List<CreditExternalImportParam> 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> urlByName = ExcelImportSupport.readUrlByKey(file, usedSheetIndex, usedTitleRows, usedHeadRows, "被投资企业名称");
final int chunkSize = 500;
final int mpBatchSize = 500;
List<CreditExternal> chunkItems = new ArrayList<>(chunkSize);
List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);
for (int i = 0; i < list.size(); i++) {
CreditExternalImportParam param = list.get(i);
try {
CreditExternal item = convertImportParamToEntity(param);
if (!ImportHelper.isBlank(item.getName())) {
String link = urlByName.get(item.getName().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.getRecommend() == null) {
item.setRecommend(0);
}
if (item.getDeleted() == null) {
item.setDeleted(0);
}
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
if (ImportHelper.isBlank(item.getName())) {
errorMessages.add("" + excelRowNumber + "行:被投资企业名称不能为空");
continue;
}
chunkItems.add(item);
chunkRowNumbers.add(excelRowNumber);
if (chunkItems.size() >= chunkSize) {
successCount += batchImportSupport.persistChunkWithFallback(
chunkItems,
chunkRowNumbers,
() -> batchImportSupport.upsertBySingleKey(
creditExternalService,
chunkItems,
CreditExternal::getId,
CreditExternal::setId,
CreditExternal::getName,
CreditExternal::getName,
null,
mpBatchSize
),
(rowItem, rowNumber) -> {
boolean saved = creditExternalService.save(rowItem);
if (!saved) {
CreditExternal existing = creditExternalService.lambdaQuery()
.eq(CreditExternal::getName, rowItem.getName())
.one();
if (existing != null) {
rowItem.setId(existing.getId());
if (creditExternalService.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(
creditExternalService,
chunkItems,
CreditExternal::getId,
CreditExternal::setId,
CreditExternal::getName,
CreditExternal::getName,
null,
mpBatchSize
),
(rowItem, rowNumber) -> {
boolean saved = creditExternalService.save(rowItem);
if (!saved) {
CreditExternal existing = creditExternalService.lambdaQuery()
.eq(CreditExternal::getName, rowItem.getName())
.one();
if (existing != null) {
rowItem.setId(existing.getId());
if (creditExternalService.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);
} else {
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<CreditExternalImportParam> templateList = new ArrayList<>();
CreditExternalImportParam example = new CreditExternalImportParam();
example.setName("示例科技有限公司");
example.setStatusTxt("存续");
example.setLegalRepresentative("李四");
example.setRegisteredCapital("10000");
example.setEstablishmentDate("2018-06-01");
example.setShareholdingRatio("20");
example.setSubscribedInvestmentAmount("2000");
example.setSubscribedInvestmentDate("2019-01-01");
example.setIndirectShareholdingRatio("5");
example.setInvestmentDate("2019-06-01");
example.setRegion("上海");
example.setIndustry("信息技术");
example.setInvestmentCount(1);
example.setRelatedProductsInstitutions("关联产品示例");
example.setComments("备注信息");
templateList.add(example);
Workbook workbook = ExcelImportSupport.buildTemplate("对外投资导入模板", "对外投资", CreditExternalImportParam.class, templateList);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=credit_external_import_template.xlsx");
workbook.write(response.getOutputStream());
workbook.close();
}
private boolean isEmptyImportRow(CreditExternalImportParam param) {
if (param == null) {
return true;
}
return ImportHelper.isBlank(param.getName())
&& ImportHelper.isBlank(param.getLegalRepresentative())
&& ImportHelper.isBlank(param.getRegisteredCapital())
&& ImportHelper.isBlank(param.getEstablishmentDate());
}
private CreditExternal convertImportParamToEntity(CreditExternalImportParam param) {
CreditExternal entity = new CreditExternal();
entity.setName(param.getName());
entity.setStatusTxt(param.getStatusTxt());
entity.setLegalRepresentative(param.getLegalRepresentative());
entity.setRegisteredCapital(param.getRegisteredCapital());
entity.setEstablishmentDate(param.getEstablishmentDate());
entity.setShareholdingRatio(param.getShareholdingRatio());
entity.setSubscribedInvestmentAmount(param.getSubscribedInvestmentAmount());
entity.setSubscribedInvestmentDate(param.getSubscribedInvestmentDate());
entity.setIndirectShareholdingRatio(param.getIndirectShareholdingRatio());
entity.setInvestmentDate(param.getInvestmentDate());
entity.setRegion(param.getRegion());
entity.setIndustry(param.getIndustry());
entity.setInvestmentCount(param.getInvestmentCount());
entity.setRelatedProductsInstitutions(param.getRelatedProductsInstitutions());
entity.setComments(param.getComments());
return entity;
}
}