- 在多个控制器中引入 BatchImportSupport 工具类 - 实现分块处理机制,每批次处理 500 条记录 - 使用 persistChunkWithFallback 方法替代逐条保存 - 保持原有的数据校验和去重逻辑不变 - 显著提升大量数据导入时的执行效率 - 减少数据库操作次数降低系统负载
386 lines
14 KiB
Java
386 lines
14 KiB
Java
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;
|
||
}
|
||
|
||
}
|