feat: 添加信贷客户家庭关系Service实现类和Controller
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user