Files
mp-java/src/main/java/com/gxwebsoft/credit/controller/CreditJudiciaryController.java
赵忠林 e6736d41ff refactor(import): 优化批量导入功能提升性能
- 在多个控制器中引入 BatchImportSupport 工具类
- 实现分块处理机制,每批次处理 500 条记录
- 使用 persistChunkWithFallback 方法替代逐条保存
- 保持原有的数据校验和去重逻辑不变
- 显著提升大量数据导入时的执行效率
- 减少数据库操作次数降低系统负载
2026-01-16 00:55:49 +08:00

386 lines
14 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 cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
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.CreditJudiciary;
import com.gxwebsoft.credit.param.CreditJudiciaryImportParam;
import com.gxwebsoft.credit.param.CreditJudiciaryParam;
import com.gxwebsoft.credit.service.CreditJudiciaryService;
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;
/**
* 司法案件控制器
*
* @author 科技小王子
* @since 2025-12-16 15:23:58
*/
@Tag(name = "司法案件管理")
@RestController
@RequestMapping("/api/credit/credit-judiciary")
public class CreditJudiciaryController extends BaseController {
@Resource
private CreditJudiciaryService creditJudiciaryService;
@Resource
private BatchImportSupport batchImportSupport;
@Operation(summary = "分页查询司法案件")
@GetMapping("/page")
public ApiResult<PageResult<CreditJudiciary>> page(CreditJudiciaryParam param) {
// 使用关联查询
return success(creditJudiciaryService.pageRel(param));
}
@Operation(summary = "查询全部司法案件")
@GetMapping()
public ApiResult<List<CreditJudiciary>> list(CreditJudiciaryParam param) {
// 使用关联查询
return success(creditJudiciaryService.listRel(param));
}
@Operation(summary = "根据id查询司法案件")
@GetMapping("/{id}")
public ApiResult<CreditJudiciary> get(@PathVariable("id") Integer id) {
// 使用关联查询
return success(creditJudiciaryService.getByIdRel(id));
}
@PreAuthorize("hasAuthority('credit:creditJudiciary:save')")
@OperationLog
@Operation(summary = "添加司法案件")
@PostMapping()
public ApiResult<?> save(@RequestBody CreditJudiciary creditJudiciary) {
if (creditJudiciaryService.save(creditJudiciary)) {
return success("添加成功");
}
return fail("添加失败");
}
@PreAuthorize("hasAuthority('credit:creditJudiciary:update')")
@OperationLog
@Operation(summary = "修改司法案件")
@PutMapping()
public ApiResult<?> update(@RequestBody CreditJudiciary creditJudiciary) {
if (creditJudiciaryService.updateById(creditJudiciary)) {
return success("修改成功");
}
return fail("修改失败");
}
@PreAuthorize("hasAuthority('credit:creditJudiciary:remove')")
@OperationLog
@Operation(summary = "删除司法案件")
@DeleteMapping("/{id}")
public ApiResult<?> remove(@PathVariable("id") Integer id) {
if (creditJudiciaryService.removeById(id)) {
return success("删除成功");
}
return fail("删除失败");
}
@PreAuthorize("hasAuthority('credit:creditJudiciary:save')")
@OperationLog
@Operation(summary = "批量添加司法案件")
@PostMapping("/batch")
public ApiResult<?> saveBatch(@RequestBody List<CreditJudiciary> list) {
if (creditJudiciaryService.saveBatch(list)) {
return success("添加成功");
}
return fail("添加失败");
}
@PreAuthorize("hasAuthority('credit:creditJudiciary:update')")
@OperationLog
@Operation(summary = "批量修改司法案件")
@PutMapping("/batch")
public ApiResult<?> removeBatch(@RequestBody BatchParam<CreditJudiciary> batchParam) {
if (batchParam.update(creditJudiciaryService, "id")) {
return success("修改成功");
}
return fail("修改失败");
}
@PreAuthorize("hasAuthority('credit:creditJudiciary:remove')")
@OperationLog
@Operation(summary = "批量删除司法案件")
@DeleteMapping("/batch")
public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
if (creditJudiciaryService.removeByIds(ids)) {
return success("删除成功");
}
return fail("删除失败");
}
/**
* 批量导入司法案件
*/
@PreAuthorize("hasAuthority('credit:creditJudiciary: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 {
List<CreditJudiciaryImportParam> list = null;
int usedTitleRows = 0;
int usedHeadRows = 0;
int[][] tryConfigs = new int[][]{{1, 1}, {0, 1}, {0, 2}, {0, 3}};
for (int[] config : tryConfigs) {
list = filterEmptyRows(tryImport(file, config[0], config[1]));
if (!CollectionUtils.isEmpty(list)) {
usedTitleRows = config[0];
usedHeadRows = config[1];
break;
}
}
if (CollectionUtils.isEmpty(list)) {
return fail("未读取到数据,请确认模板表头与示例格式一致", null);
}
User loginUser = getLoginUser();
Integer currentUserId = loginUser != null ? loginUser.getUserId() : null;
Integer currentTenantId = loginUser != null ? loginUser.getTenantId() : null;
final int chunkSize = 500;
final int mpBatchSize = 500;
List<CreditJudiciary> chunkItems = new ArrayList<>(chunkSize);
List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);
for (int i = 0; i < list.size(); i++) {
CreditJudiciaryImportParam param = list.get(i);
try {
CreditJudiciary item = convertImportParamToEntity(param);
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.getType() == null) {
item.setType(0);
}
if (item.getDeleted() == null) {
item.setDeleted(0);
}
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
// 验证必填字段
if (item.getName() == null || item.getName().trim().isEmpty()) {
errorMessages.add("" + excelRowNumber + "行:项目名称不能为空");
continue;
}
if (item.getCode() == null || item.getCode().trim().isEmpty()) {
errorMessages.add("" + excelRowNumber + "行:唯一标识不能为空");
continue;
}
chunkItems.add(item);
chunkRowNumbers.add(excelRowNumber);
if (chunkItems.size() >= chunkSize) {
successCount += batchImportSupport.persistChunkWithFallback(
chunkItems,
chunkRowNumbers,
() -> batchImportSupport.upsertBySingleKey(
creditJudiciaryService,
chunkItems,
CreditJudiciary::getId,
CreditJudiciary::setId,
CreditJudiciary::getName,
CreditJudiciary::getName,
null,
mpBatchSize
),
(rowItem, rowNumber) -> {
boolean saved = creditJudiciaryService.save(rowItem);
if (!saved) {
CreditJudiciary existing = creditJudiciaryService.getByName(rowItem.getName());
if (existing != null) {
rowItem.setId(existing.getId());
if (creditJudiciaryService.updateById(rowItem)) {
return true;
}
}
} else {
return true;
}
errorMessages.add("" + rowNumber + "行:保存失败");
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(
creditJudiciaryService,
chunkItems,
CreditJudiciary::getId,
CreditJudiciary::setId,
CreditJudiciary::getName,
CreditJudiciary::getName,
null,
mpBatchSize
),
(rowItem, rowNumber) -> {
boolean saved = creditJudiciaryService.save(rowItem);
if (!saved) {
CreditJudiciary existing = creditJudiciaryService.getByName(rowItem.getName());
if (existing != null) {
rowItem.setId(existing.getId());
if (creditJudiciaryService.updateById(rowItem)) {
return true;
}
}
} else {
return true;
}
errorMessages.add("" + rowNumber + "行:保存失败");
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<CreditJudiciaryImportParam> templateList = new ArrayList<>();
CreditJudiciaryImportParam example = new CreditJudiciaryImportParam();
example.setName("示例客户");
example.setCode("C0001");
example.setInfoType("执行案件");
example.setReason("买卖合同纠纷");
example.setProcessDate("2025-08-27");
example.setCaseProgress("首次执行");
example.setCaseIdentity("被执行人");
example.setCode("2025闽0103执5480号");
example.setCourt("福建省福州市台江区人民法院");
example.setCaseAmount("5134060.00");
templateList.add(example);
ExportParams exportParams = new ExportParams("司法案件导入模板", "司法案件");
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, CreditJudiciaryImportParam.class, templateList);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=credit_judiciary_import_template.xlsx");
workbook.write(response.getOutputStream());
workbook.close();
}
private List<CreditJudiciaryImportParam> tryImport(MultipartFile file, int titleRows, int headRows) throws Exception {
ImportParams importParams = new ImportParams();
importParams.setTitleRows(titleRows);
importParams.setHeadRows(headRows);
importParams.setStartSheetIndex(0);
importParams.setSheetNum(1);
return ExcelImportUtil.importExcel(file.getInputStream(), CreditJudiciaryImportParam.class, importParams);
}
/**
* 过滤掉完全空白的导入行,避免空行导致导入失败
*/
private List<CreditJudiciaryImportParam> filterEmptyRows(List<CreditJudiciaryImportParam> rawList) {
if (CollectionUtils.isEmpty(rawList)) {
return rawList;
}
rawList.removeIf(this::isEmptyImportRow);
return rawList;
}
private boolean isEmptyImportRow(CreditJudiciaryImportParam param) {
if (param == null) {
return true;
}
return isBlank(param.getName())
&& isBlank(param.getCode())
&& isBlank(param.getName())
&& isBlank(param.getInfoType());
}
private boolean isBlank(String value) {
return value == null || value.trim().isEmpty();
}
/**
* 将CreditJudiciaryImportParam转换为CreditJudiciary实体
*/
private CreditJudiciary convertImportParamToEntity(CreditJudiciaryImportParam param) {
CreditJudiciary entity = new CreditJudiciary();
entity.setCode(param.getCode());
entity.setName(param.getName());
entity.setInfoType(param.getInfoType());
entity.setReason(param.getReason());
entity.setProcessDate(param.getProcessDate());
entity.setCaseProgress(param.getCaseProgress());
entity.setCaseIdentity(param.getCaseIdentity());
entity.setCourt(param.getCourt());
entity.setCaseAmount(param.getCaseAmount());
return entity;
}
}