feat: 添加信贷客户家庭关系Service实现类和Controller

This commit is contained in:
wkc
2026-02-11 15:51:59 +08:00
parent 74f3c04146
commit 38ef48f656
2 changed files with 325 additions and 0 deletions

View File

@@ -0,0 +1,165 @@
package com.ruoyi.ccdi.service.impl;
import com.alibaba.excel.EasyExcel;
import com.ruoyi.ccdi.domain.CcdiCustFmyRelation;
import com.ruoyi.ccdi.domain.excel.CcdiCustFmyRelationExcel;
import com.ruoyi.ccdi.domain.vo.CustFmyRelationImportFailureVO;
import com.ruoyi.ccdi.mapper.CcdiCustFmyRelationMapper;
import com.ruoyi.ccdi.service.ICcdiCustFmyRelationImportService;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 信贷客户家庭关系导入Service实现
*
* @author ruoyi
* @date 2026-02-11
*/
@Service
public class CcdiCustFmyRelationImportServiceImpl implements ICcdiCustFmyRelationImportService {
private static final Logger log = LoggerFactory.getLogger(CcdiCustFmyRelationImportServiceImpl.class);
@Resource
private CcdiCustFmyRelationMapper mapper;
@Resource
private RedisTemplate<String, Object> redisTemplate;
private static final String IMPORT_TASK_KEY_PREFIX = "import:custFmyRelation:";
private static final String IMPORT_FAILURE_KEY_PREFIX = "import:custFmyRelation:failures:";
@Async
@Override
@Transactional(rollbackFor = Exception.class)
public void importRelationsAsync(List<CcdiCustFmyRelationExcel> excels, String taskId) {
List<CcdiCustFmyRelation> validRelations = new ArrayList<>();
List<CustFmyRelationImportFailureVO> failures = new ArrayList<>();
try {
for (int i = 0; i < excels.size(); i++) {
CcdiCustFmyRelationExcel excel = excels.get(i);
Integer rowNum = i + 2; // Excel行号从2开始(第1行是表头)
String errorMessage = validateExcelRow(excel, rowNum);
if (errorMessage != null) {
CustFmyRelationImportFailureVO failure = new CustFmyRelationImportFailureVO();
failure.setRowNum(rowNum);
failure.setPersonId(excel.getPersonId());
failure.setRelationType(excel.getRelationType());
failure.setRelationName(excel.getRelationName());
failure.setErrorMessage(errorMessage);
failures.add(failure);
continue;
}
CcdiCustFmyRelation relation = convertToRelation(excel);
validRelations.add(relation);
}
// 批量插入有效数据
if (!validRelations.isEmpty()) {
mapper.insertBatch(validRelations);
}
// 保存失败记录到Redis(24小时过期)
if (!failures.isEmpty()) {
redisTemplate.opsForValue().set(
IMPORT_FAILURE_KEY_PREFIX + taskId,
failures,
24,
TimeUnit.HOURS
);
}
// 更新任务状态
redisTemplate.opsForValue().set(
IMPORT_TASK_KEY_PREFIX + taskId,
"COMPLETED:" + validRelations.size() + ":" + failures.size(),
1,
TimeUnit.HOURS
);
} catch (Exception e) {
log.error("导入失败", e);
redisTemplate.opsForValue().set(
IMPORT_TASK_KEY_PREFIX + taskId,
"FAILED:" + e.getMessage(),
1,
TimeUnit.HOURS
);
}
}
@Override
public String validateExcelRow(CcdiCustFmyRelationExcel excel, Integer rowNum) {
if (excel.getPersonId() == null || excel.getPersonId().trim().isEmpty()) {
return "信贷客户身份证号不能为空";
}
if (excel.getRelationType() == null || excel.getRelationType().trim().isEmpty()) {
return "关系类型不能为空";
}
if (excel.getRelationName() == null || excel.getRelationName().trim().isEmpty()) {
return "关系人姓名不能为空";
}
if (excel.getRelationCertType() == null || excel.getRelationCertType().trim().isEmpty()) {
return "关系人证件类型不能为空";
}
if (excel.getRelationCertNo() == null || excel.getRelationCertNo().trim().isEmpty()) {
return "关系人证件号码不能为空";
}
// 检查是否已存在相同的关系
CcdiCustFmyRelation existing = mapper.selectExistingRelations(
excel.getPersonId(),
excel.getRelationType(),
excel.getRelationCertNo()
);
if (existing != null) {
return "该关系已存在,请勿重复导入";
}
return null; // 校验通过
}
@Override
@SuppressWarnings("unchecked")
public List<CustFmyRelationImportFailureVO> getImportFailures(String taskId) {
Object obj = redisTemplate.opsForValue().get(IMPORT_FAILURE_KEY_PREFIX + taskId);
if (obj != null) {
return (List<CustFmyRelationImportFailureVO>) obj;
}
return new ArrayList<>();
}
private CcdiCustFmyRelation convertToRelation(CcdiCustFmyRelationExcel excel) {
CcdiCustFmyRelation relation = new CcdiCustFmyRelation();
org.springframework.beans.BeanUtils.copyProperties(excel, relation);
relation.setIsEmpFamily(false);
relation.setIsCustFamily(true);
relation.setStatus(excel.getStatus() != null ? excel.getStatus() : 1);
relation.setDataSource("IMPORT");
relation.setCreatedBy(SecurityUtils.getUsername());
relation.setCreateTime(new Date());
return relation;
}
}

View File

@@ -0,0 +1,160 @@
package com.ruoyi.ccdi.service.impl;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.ccdi.domain.CcdiCustFmyRelation;
import com.ruoyi.ccdi.domain.dto.CcdiCustFmyRelationAddDTO;
import com.ruoyi.ccdi.domain.dto.CcdiCustFmyRelationEditDTO;
import com.ruoyi.ccdi.domain.dto.CcdiCustFmyRelationQueryDTO;
import com.ruoyi.ccdi.domain.excel.CcdiCustFmyRelationExcel;
import com.ruoyi.ccdi.domain.vo.CcdiCustFmyRelationVO;
import com.ruoyi.ccdi.mapper.CcdiCustFmyRelationMapper;
import com.ruoyi.ccdi.service.ICcdiCustFmyRelationImportService;
import com.ruoyi.ccdi.service.ICcdiCustFmyRelationService;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* 信贷客户家庭关系Service实现
*
* @author ruoyi
* @date 2026-02-11
*/
@Service
public class CcdiCustFmyRelationServiceImpl implements ICcdiCustFmyRelationService {
@Resource
private CcdiCustFmyRelationMapper mapper;
@Resource
private ICcdiCustFmyRelationImportService importService;
@Resource
private RedisTemplate<String, Object> redisTemplate;
private static final String IMPORT_TASK_KEY_PREFIX = "import:custFmyRelation:";
private static final String IMPORT_FAILURE_KEY_PREFIX = "import:custFmyRelation:failures:";
@Override
public Page<CcdiCustFmyRelationVO> selectRelationPage(CcdiCustFmyRelationQueryDTO query,
Integer pageNum, Integer pageSize) {
Page<CcdiCustFmyRelationVO> page = new Page<>(pageNum, pageSize);
return mapper.selectRelationPage(page, query);
}
@Override
public CcdiCustFmyRelationVO selectRelationById(Long id) {
return mapper.selectRelationById(id);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean insertRelation(CcdiCustFmyRelationAddDTO addDTO) {
CcdiCustFmyRelation relation = new CcdiCustFmyRelation();
BeanUtils.copyProperties(addDTO, relation);
// 关键设置:客户家庭关系
relation.setIsEmpFamily(false);
relation.setIsCustFamily(true);
relation.setStatus(1);
relation.setDataSource("MANUAL");
return mapper.insert(relation) > 0;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateRelation(CcdiCustFmyRelationEditDTO editDTO) {
CcdiCustFmyRelation relation = new CcdiCustFmyRelation();
BeanUtils.copyProperties(editDTO, relation);
return mapper.updateById(relation) > 0;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean deleteRelationByIds(Long[] ids) {
return mapper.deleteBatchIds(List.of(ids)) > 0;
}
@Override
public void exportRelations(CcdiCustFmyRelationQueryDTO query, HttpServletResponse response) {
// 查询所有符合条件的数据(不分页)
Page<CcdiCustFmyRelationVO> page = new Page<>(1, 10000);
Page<CcdiCustFmyRelationVO> result = mapper.selectRelationPage(page, query);
List<CcdiCustFmyRelationExcel> excels = result.getRecords().stream()
.map(this::convertToExcel)
.toList();
// 使用EasyExcel导出
try {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("信贷客户家庭关系", StandardCharsets.UTF_8)
.replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), CcdiCustFmyRelationExcel.class)
.sheet("信贷客户家庭关系")
.doWrite(excels);
} catch (Exception e) {
throw new RuntimeException("导出失败", e);
}
}
@Override
public void importTemplate(HttpServletResponse response) {
try {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("信贷客户家庭关系导入模板", StandardCharsets.UTF_8)
.replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), CcdiCustFmyRelationExcel.class)
.sheet("模板")
.doWrite(Collections.emptyList());
} catch (Exception e) {
throw new RuntimeException("模板下载失败", e);
}
}
@Override
public String importRelations(List<CcdiCustFmyRelationExcel> excels) {
String taskId = UUID.randomUUID().toString();
// 保存任务状态到Redis
redisTemplate.opsForValue().set(IMPORT_TASK_KEY_PREFIX + taskId, "PROCESSING", 1, TimeUnit.HOURS);
// 异步导入
importService.importRelationsAsync(excels, taskId);
return taskId;
}
@Override
public List<com.ruoyi.ccdi.domain.vo.CustFmyRelationImportFailureVO> getImportFailures(String taskId) {
return importService.getImportFailures(taskId);
}
private CcdiCustFmyRelationExcel convertToExcel(CcdiCustFmyRelationVO vo) {
CcdiCustFmyRelationExcel excel = new CcdiCustFmyRelationExcel();
BeanUtils.copyProperties(vo, excel);
return excel;
}
}