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