员工异步导入
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -18,6 +18,7 @@ target/
|
|||||||
.project
|
.project
|
||||||
.settings
|
.settings
|
||||||
.springBeans
|
.springBeans
|
||||||
|
.claude
|
||||||
|
|
||||||
### IntelliJ IDEA ###
|
### IntelliJ IDEA ###
|
||||||
.idea
|
.idea
|
||||||
|
|||||||
Binary file not shown.
@@ -9,6 +9,7 @@ import com.ruoyi.ccdi.domain.vo.CcdiEmployeeVO;
|
|||||||
import com.ruoyi.ccdi.domain.vo.ImportFailureVO;
|
import com.ruoyi.ccdi.domain.vo.ImportFailureVO;
|
||||||
import com.ruoyi.ccdi.domain.vo.ImportResultVO;
|
import com.ruoyi.ccdi.domain.vo.ImportResultVO;
|
||||||
import com.ruoyi.ccdi.domain.vo.ImportStatusVO;
|
import com.ruoyi.ccdi.domain.vo.ImportStatusVO;
|
||||||
|
import com.ruoyi.ccdi.service.ICcdiEmployeeImportService;
|
||||||
import com.ruoyi.ccdi.service.ICcdiEmployeeService;
|
import com.ruoyi.ccdi.service.ICcdiEmployeeService;
|
||||||
import com.ruoyi.ccdi.utils.EasyExcelUtil;
|
import com.ruoyi.ccdi.utils.EasyExcelUtil;
|
||||||
import com.ruoyi.common.annotation.Log;
|
import com.ruoyi.common.annotation.Log;
|
||||||
@@ -43,6 +44,9 @@ public class CcdiEmployeeController extends BaseController {
|
|||||||
@Resource
|
@Resource
|
||||||
private ICcdiEmployeeService employeeService;
|
private ICcdiEmployeeService employeeService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ICcdiEmployeeImportService importAsyncService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询员工列表
|
* 查询员工列表
|
||||||
*/
|
*/
|
||||||
@@ -137,10 +141,11 @@ public class CcdiEmployeeController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 提交异步任务
|
// 提交异步任务
|
||||||
employeeService.importEmployeeAsync(list, updateSupport);
|
String taskId = employeeService.importEmployee(list, updateSupport);
|
||||||
|
|
||||||
// 立即返回,不等待后台任务完成
|
// 立即返回,不等待后台任务完成
|
||||||
ImportResultVO result = new ImportResultVO();
|
ImportResultVO result = new ImportResultVO();
|
||||||
|
result.setTaskId(taskId);
|
||||||
result.setStatus("PROCESSING");
|
result.setStatus("PROCESSING");
|
||||||
result.setMessage("导入任务已提交,正在后台处理");
|
result.setMessage("导入任务已提交,正在后台处理");
|
||||||
|
|
||||||
@@ -155,7 +160,7 @@ public class CcdiEmployeeController extends BaseController {
|
|||||||
@GetMapping("/importStatus/{taskId}")
|
@GetMapping("/importStatus/{taskId}")
|
||||||
public AjaxResult getImportStatus(@PathVariable String taskId) {
|
public AjaxResult getImportStatus(@PathVariable String taskId) {
|
||||||
try {
|
try {
|
||||||
ImportStatusVO status = employeeService.getImportStatus(taskId);
|
ImportStatusVO status = importAsyncService.getImportStatus(taskId);
|
||||||
return success(status);
|
return success(status);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return error(e.getMessage());
|
return error(e.getMessage());
|
||||||
@@ -173,7 +178,7 @@ public class CcdiEmployeeController extends BaseController {
|
|||||||
@RequestParam(defaultValue = "1") Integer pageNum,
|
@RequestParam(defaultValue = "1") Integer pageNum,
|
||||||
@RequestParam(defaultValue = "10") Integer pageSize) {
|
@RequestParam(defaultValue = "10") Integer pageSize) {
|
||||||
|
|
||||||
List<ImportFailureVO> failures = employeeService.getImportFailures(taskId);
|
List<ImportFailureVO> failures = importAsyncService.getImportFailures( taskId);
|
||||||
|
|
||||||
// 手动分页
|
// 手动分页
|
||||||
int fromIndex = (pageNum - 1) * pageSize;
|
int fromIndex = (pageNum - 1) * pageSize;
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.ruoyi.ccdi.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: wkc
|
||||||
|
* @CreateTime: 2026-02-06
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ImportResult {
|
||||||
|
|
||||||
|
private Integer totalCount;
|
||||||
|
private Integer successCount;
|
||||||
|
private Integer failureCount;
|
||||||
|
}
|
||||||
@@ -27,21 +27,8 @@ public interface CcdiEmployeeMapper extends BaseMapper<CcdiEmployee> {
|
|||||||
Page<CcdiEmployeeVO> selectEmployeePageWithDept(@Param("page") Page<CcdiEmployeeVO> page,
|
Page<CcdiEmployeeVO> selectEmployeePageWithDept(@Param("page") Page<CcdiEmployeeVO> page,
|
||||||
@Param("query") CcdiEmployeeQueryDTO queryDTO);
|
@Param("query") CcdiEmployeeQueryDTO queryDTO);
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询员工详情(包含亲属列表)
|
|
||||||
*
|
|
||||||
* @param employeeId 员工ID
|
|
||||||
* @return 员工VO
|
|
||||||
*/
|
|
||||||
CcdiEmployeeVO selectEmployeeWithRelatives(@Param("employeeId") Long employeeId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量插入或更新员工信息
|
|
||||||
* 使用ON DUPLICATE KEY UPDATE语法
|
|
||||||
*
|
|
||||||
* @param list 员工信息列表
|
|
||||||
* @return 影响行数
|
|
||||||
*/
|
|
||||||
int insertOrUpdateBatch(@Param("list") List<CcdiEmployee> list);
|
int insertOrUpdateBatch(@Param("list") List<CcdiEmployee> list);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.ruoyi.ccdi.service;
|
||||||
|
|
||||||
|
import com.ruoyi.ccdi.domain.excel.CcdiEmployeeExcel;
|
||||||
|
import com.ruoyi.ccdi.domain.vo.ImportFailureVO;
|
||||||
|
import com.ruoyi.ccdi.domain.vo.ImportStatusVO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: wkc
|
||||||
|
* @CreateTime: 2026-02-06
|
||||||
|
*/
|
||||||
|
public interface ICcdiEmployeeImportService {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步导入员工数据
|
||||||
|
*
|
||||||
|
* @param excelList Excel数据列表
|
||||||
|
* @param isUpdateSupport 是否更新已存在的数据
|
||||||
|
*/
|
||||||
|
void importEmployeeAsync(List<CcdiEmployeeExcel> excelList, Boolean isUpdateSupport, String taskId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询导入状态
|
||||||
|
*
|
||||||
|
* @param taskId 任务ID
|
||||||
|
* @return 导入状态信息
|
||||||
|
*/
|
||||||
|
ImportStatusVO getImportStatus(String taskId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取导入失败记录
|
||||||
|
*
|
||||||
|
* @param taskId 任务ID
|
||||||
|
* @return 失败记录列表
|
||||||
|
*/
|
||||||
|
List<ImportFailureVO> getImportFailures(String taskId);
|
||||||
|
}
|
||||||
@@ -6,12 +6,8 @@ import com.ruoyi.ccdi.domain.dto.CcdiEmployeeEditDTO;
|
|||||||
import com.ruoyi.ccdi.domain.dto.CcdiEmployeeQueryDTO;
|
import com.ruoyi.ccdi.domain.dto.CcdiEmployeeQueryDTO;
|
||||||
import com.ruoyi.ccdi.domain.excel.CcdiEmployeeExcel;
|
import com.ruoyi.ccdi.domain.excel.CcdiEmployeeExcel;
|
||||||
import com.ruoyi.ccdi.domain.vo.CcdiEmployeeVO;
|
import com.ruoyi.ccdi.domain.vo.CcdiEmployeeVO;
|
||||||
import com.ruoyi.ccdi.domain.vo.ImportFailureVO;
|
|
||||||
import com.ruoyi.ccdi.domain.vo.ImportResultVO;
|
|
||||||
import com.ruoyi.ccdi.domain.vo.ImportStatusVO;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 员工信息 服务层
|
* 员工信息 服务层
|
||||||
@@ -87,27 +83,4 @@ public interface ICcdiEmployeeService {
|
|||||||
*/
|
*/
|
||||||
String importEmployee(List<CcdiEmployeeExcel> excelList, Boolean isUpdateSupport);
|
String importEmployee(List<CcdiEmployeeExcel> excelList, Boolean isUpdateSupport);
|
||||||
|
|
||||||
/**
|
|
||||||
* 异步导入员工数据
|
|
||||||
*
|
|
||||||
* @param excelList Excel数据列表
|
|
||||||
* @param isUpdateSupport 是否更新已存在的数据
|
|
||||||
*/
|
|
||||||
void importEmployeeAsync(List<CcdiEmployeeExcel> excelList, Boolean isUpdateSupport);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询导入状态
|
|
||||||
*
|
|
||||||
* @param taskId 任务ID
|
|
||||||
* @return 导入状态信息
|
|
||||||
*/
|
|
||||||
ImportStatusVO getImportStatus(String taskId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取导入失败记录
|
|
||||||
*
|
|
||||||
* @param taskId 任务ID
|
|
||||||
* @return 失败记录列表
|
|
||||||
*/
|
|
||||||
List<ImportFailureVO> getImportFailures(String taskId);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,277 @@
|
|||||||
|
package com.ruoyi.ccdi.service.impl;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.ruoyi.ccdi.domain.CcdiEmployee;
|
||||||
|
import com.ruoyi.ccdi.domain.dto.CcdiEmployeeAddDTO;
|
||||||
|
import com.ruoyi.ccdi.domain.excel.CcdiEmployeeExcel;
|
||||||
|
import com.ruoyi.ccdi.domain.vo.ImportFailureVO;
|
||||||
|
import com.ruoyi.ccdi.domain.vo.ImportResult;
|
||||||
|
import com.ruoyi.ccdi.domain.vo.ImportStatusVO;
|
||||||
|
import com.ruoyi.ccdi.mapper.CcdiEmployeeMapper;
|
||||||
|
import com.ruoyi.ccdi.service.ICcdiEmployeeImportService;
|
||||||
|
import com.ruoyi.common.utils.IdCardUtil;
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: wkc
|
||||||
|
* @CreateTime: 2026-02-06
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@EnableAsync
|
||||||
|
public class CcdiEmployeeImportServiceImpl implements ICcdiEmployeeImportService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CcdiEmployeeMapper employeeMapper;
|
||||||
|
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Async
|
||||||
|
public void importEmployeeAsync(List<CcdiEmployeeExcel> excelList, Boolean isUpdateSupport, String taskId) {
|
||||||
|
List<CcdiEmployee> newRecords = new ArrayList<>();
|
||||||
|
List<CcdiEmployee> updateRecords = new ArrayList<>();
|
||||||
|
List<ImportFailureVO> failures = new ArrayList<>();
|
||||||
|
|
||||||
|
// 批量查询已存在的柜员号
|
||||||
|
Set<Long> existingIds = getExistingEmployeeIds(excelList);
|
||||||
|
|
||||||
|
// 分类数据
|
||||||
|
for (int i = 0; i < excelList.size(); i++) {
|
||||||
|
CcdiEmployeeExcel excel = excelList.get(i);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 转换为AddDTO进行验证
|
||||||
|
CcdiEmployeeAddDTO addDTO = new CcdiEmployeeAddDTO();
|
||||||
|
BeanUtils.copyProperties(excel, addDTO);
|
||||||
|
|
||||||
|
// 验证数据(支持更新模式)
|
||||||
|
validateEmployeeData(addDTO, isUpdateSupport, existingIds);
|
||||||
|
|
||||||
|
CcdiEmployee employee = new CcdiEmployee();
|
||||||
|
BeanUtils.copyProperties(excel, employee);
|
||||||
|
|
||||||
|
if (existingIds.contains(excel.getEmployeeId())) {
|
||||||
|
if (isUpdateSupport) {
|
||||||
|
updateRecords.add(employee);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("柜员号已存在且未启用更新支持");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newRecords.add(employee);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
ImportFailureVO failure = new ImportFailureVO();
|
||||||
|
BeanUtils.copyProperties(excel, failure);
|
||||||
|
failure.setErrorMessage(e.getMessage());
|
||||||
|
failures.add(failure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量插入新数据
|
||||||
|
if (!newRecords.isEmpty()) {
|
||||||
|
saveBatch(newRecords, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量更新已有数据(先删除再插入)
|
||||||
|
if (!updateRecords.isEmpty() && isUpdateSupport) {
|
||||||
|
employeeMapper.insertOrUpdateBatch(updateRecords);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存失败记录到Redis
|
||||||
|
if (!failures.isEmpty()) {
|
||||||
|
String failuresKey = "import:employee:" + taskId + ":failures";
|
||||||
|
redisTemplate.opsForValue().set(failuresKey, failures, 7, TimeUnit.DAYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportResult result = new ImportResult();
|
||||||
|
result.setTotalCount(excelList.size());
|
||||||
|
result.setSuccessCount(newRecords.size() + updateRecords.size());
|
||||||
|
result.setFailureCount(failures.size());
|
||||||
|
|
||||||
|
// 更新最终状态
|
||||||
|
String finalStatus = result.getFailureCount() == 0 ? "SUCCESS" : "PARTIAL_SUCCESS";
|
||||||
|
updateImportStatus("employee", taskId, finalStatus, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取导入失败记录
|
||||||
|
*
|
||||||
|
* @param taskId 任务ID
|
||||||
|
* @return 失败记录列表
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<ImportFailureVO> getImportFailures( String taskId) {
|
||||||
|
String key = "import:employee:" + taskId + ":failures";
|
||||||
|
Object failuresObj = redisTemplate.opsForValue().get(key);
|
||||||
|
|
||||||
|
if (failuresObj == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.parseArray(JSON.toJSONString(failuresObj), ImportFailureVO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询导入状态
|
||||||
|
*
|
||||||
|
* @param taskId 任务ID
|
||||||
|
* @return 导入状态信息
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ImportStatusVO getImportStatus(String taskId) {
|
||||||
|
String key = "import:employee:" + taskId;
|
||||||
|
Boolean hasKey = redisTemplate.hasKey(key);
|
||||||
|
|
||||||
|
if (Boolean.FALSE.equals(hasKey)) {
|
||||||
|
throw new RuntimeException("任务不存在或已过期");
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Object, Object> statusMap = redisTemplate.opsForHash().entries(key);
|
||||||
|
|
||||||
|
ImportStatusVO statusVO = new ImportStatusVO();
|
||||||
|
statusVO.setTaskId((String) statusMap.get("taskId"));
|
||||||
|
statusVO.setStatus((String) statusMap.get("status"));
|
||||||
|
statusVO.setTotalCount((Integer) statusMap.get("totalCount"));
|
||||||
|
statusVO.setSuccessCount((Integer) statusMap.get("successCount"));
|
||||||
|
statusVO.setFailureCount((Integer) statusMap.get("failureCount"));
|
||||||
|
statusVO.setProgress((Integer) statusMap.get("progress"));
|
||||||
|
statusVO.setStartTime((Long) statusMap.get("startTime"));
|
||||||
|
statusVO.setEndTime((Long) statusMap.get("endTime"));
|
||||||
|
statusVO.setMessage((String) statusMap.get("message"));
|
||||||
|
|
||||||
|
return statusVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新导入状态
|
||||||
|
*/
|
||||||
|
private void updateImportStatus(String taskType, String taskId, String status, ImportResult result) {
|
||||||
|
String key = "import:employee:" + taskId;
|
||||||
|
Map<String, Object> statusData = new HashMap<>();
|
||||||
|
statusData.put("status", status);
|
||||||
|
statusData.put("successCount", result.getSuccessCount());
|
||||||
|
statusData.put("failureCount", result.getFailureCount());
|
||||||
|
statusData.put("progress", 100);
|
||||||
|
statusData.put("endTime", System.currentTimeMillis());
|
||||||
|
|
||||||
|
if ("SUCCESS".equals(status)) {
|
||||||
|
statusData.put("message", "全部成功!共导入" + result.getTotalCount() + "条数据");
|
||||||
|
} else {
|
||||||
|
statusData.put("message", "成功" + result.getSuccessCount() + "条,失败" + result.getFailureCount() + "条");
|
||||||
|
}
|
||||||
|
|
||||||
|
redisTemplate.opsForHash().putAll(key, statusData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量查询已存在的员工ID
|
||||||
|
*/
|
||||||
|
private Set<Long> getExistingEmployeeIds(List<CcdiEmployeeExcel> excelList) {
|
||||||
|
List<Long> employeeIds = excelList.stream()
|
||||||
|
.map(CcdiEmployeeExcel::getEmployeeId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (employeeIds.isEmpty()) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<CcdiEmployee> existingEmployees = employeeMapper.selectBatchIds(employeeIds);
|
||||||
|
return existingEmployees.stream()
|
||||||
|
.map(CcdiEmployee::getEmployeeId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量保存
|
||||||
|
*/
|
||||||
|
private void saveBatch(List<CcdiEmployee> list, int batchSize) {
|
||||||
|
// 使用真正的批量插入,分批次执行以提高性能
|
||||||
|
for (int i = 0; i < list.size(); i += batchSize) {
|
||||||
|
int end = Math.min(i + batchSize, list.size());
|
||||||
|
List<CcdiEmployee> subList = list.subList(i, end);
|
||||||
|
employeeMapper.insertBatch(subList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证员工数据
|
||||||
|
*
|
||||||
|
* @param addDTO 新增DTO
|
||||||
|
* @param isUpdateSupport 是否支持更新
|
||||||
|
* @param existingIds 已存在的员工ID集合(导入场景使用,传null表示单条新增)
|
||||||
|
*/
|
||||||
|
public void validateEmployeeData(CcdiEmployeeAddDTO addDTO, Boolean isUpdateSupport, Set<Long> existingIds) {
|
||||||
|
// 验证必填字段
|
||||||
|
if (StringUtils.isEmpty(addDTO.getName())) {
|
||||||
|
throw new RuntimeException("姓名不能为空");
|
||||||
|
}
|
||||||
|
if (addDTO.getEmployeeId() == null) {
|
||||||
|
throw new RuntimeException("柜员号不能为空");
|
||||||
|
}
|
||||||
|
if (addDTO.getDeptId() == null) {
|
||||||
|
throw new RuntimeException("所属部门不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(addDTO.getIdCard())) {
|
||||||
|
throw new RuntimeException("身份证号不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(addDTO.getPhone())) {
|
||||||
|
throw new RuntimeException("电话不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(addDTO.getStatus())) {
|
||||||
|
throw new RuntimeException("状态不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证身份证号格式
|
||||||
|
String idCardError = IdCardUtil.getErrorMessage(addDTO.getIdCard());
|
||||||
|
if (idCardError != null) {
|
||||||
|
throw new RuntimeException(idCardError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单条新增场景:检查柜员号和身份证号唯一性
|
||||||
|
if (existingIds == null) {
|
||||||
|
// 检查柜员号(employeeId)唯一性
|
||||||
|
if (employeeMapper.selectById(addDTO.getEmployeeId()) != null) {
|
||||||
|
throw new RuntimeException("该柜员号已存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查身份证号唯一性
|
||||||
|
LambdaQueryWrapper<CcdiEmployee> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(CcdiEmployee::getIdCard, addDTO.getIdCard());
|
||||||
|
if (employeeMapper.selectCount(wrapper) > 0) {
|
||||||
|
throw new RuntimeException("该身份证号已存在");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 导入场景:如果柜员号不存在,才检查身份证号唯一性
|
||||||
|
if (!existingIds.contains(addDTO.getEmployeeId())) {
|
||||||
|
// 检查身份证号唯一性
|
||||||
|
LambdaQueryWrapper<CcdiEmployee> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(CcdiEmployee::getIdCard, addDTO.getIdCard());
|
||||||
|
if (employeeMapper.selectCount(wrapper) > 0) {
|
||||||
|
throw new RuntimeException("该身份证号已存在");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证状态
|
||||||
|
if (!"0".equals(addDTO.getStatus()) && !"1".equals(addDTO.getStatus())) {
|
||||||
|
throw new RuntimeException("状态只能填写'在职'或'离职'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.ruoyi.ccdi.service.impl;
|
package com.ruoyi.ccdi.service.impl;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.ruoyi.ccdi.domain.CcdiEmployee;
|
import com.ruoyi.ccdi.domain.CcdiEmployee;
|
||||||
@@ -9,13 +8,10 @@ import com.ruoyi.ccdi.domain.dto.CcdiEmployeeEditDTO;
|
|||||||
import com.ruoyi.ccdi.domain.dto.CcdiEmployeeQueryDTO;
|
import com.ruoyi.ccdi.domain.dto.CcdiEmployeeQueryDTO;
|
||||||
import com.ruoyi.ccdi.domain.excel.CcdiEmployeeExcel;
|
import com.ruoyi.ccdi.domain.excel.CcdiEmployeeExcel;
|
||||||
import com.ruoyi.ccdi.domain.vo.CcdiEmployeeVO;
|
import com.ruoyi.ccdi.domain.vo.CcdiEmployeeVO;
|
||||||
import com.ruoyi.ccdi.domain.vo.ImportFailureVO;
|
|
||||||
import com.ruoyi.ccdi.domain.vo.ImportResultVO;
|
|
||||||
import com.ruoyi.ccdi.domain.vo.ImportStatusVO;
|
|
||||||
import com.ruoyi.ccdi.enums.EmployeeStatus;
|
import com.ruoyi.ccdi.enums.EmployeeStatus;
|
||||||
import com.ruoyi.ccdi.mapper.CcdiEmployeeMapper;
|
import com.ruoyi.ccdi.mapper.CcdiEmployeeMapper;
|
||||||
|
import com.ruoyi.ccdi.service.ICcdiEmployeeImportService;
|
||||||
import com.ruoyi.ccdi.service.ICcdiEmployeeService;
|
import com.ruoyi.ccdi.service.ICcdiEmployeeService;
|
||||||
import com.ruoyi.common.utils.IdCardUtil;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
@@ -24,10 +20,7 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 员工信息 服务层处理
|
* 员工信息 服务层处理
|
||||||
@@ -41,11 +34,12 @@ public class CcdiEmployeeServiceImpl implements ICcdiEmployeeService {
|
|||||||
@Resource
|
@Resource
|
||||||
private CcdiEmployeeMapper employeeMapper;
|
private CcdiEmployeeMapper employeeMapper;
|
||||||
|
|
||||||
@Resource
|
|
||||||
private RedisTemplate<String, Object> redisTemplate;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private Executor importExecutor;
|
private ICcdiEmployeeImportService importAsyncService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询员工列表
|
* 查询员工列表
|
||||||
@@ -190,54 +184,6 @@ public class CcdiEmployeeServiceImpl implements ICcdiEmployeeService {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public String importEmployee(List<CcdiEmployeeExcel> excelList, Boolean isUpdateSupport) {
|
public String importEmployee(List<CcdiEmployeeExcel> excelList, Boolean isUpdateSupport) {
|
||||||
if (StringUtils.isNull(excelList) || excelList.isEmpty()) {
|
|
||||||
return "至少需要一条数据";
|
|
||||||
}
|
|
||||||
|
|
||||||
int successNum = 0;
|
|
||||||
int failureNum = 0;
|
|
||||||
StringBuilder successMsg = new StringBuilder();
|
|
||||||
StringBuilder failureMsg = new StringBuilder();
|
|
||||||
|
|
||||||
for (CcdiEmployeeExcel excel : excelList) {
|
|
||||||
try {
|
|
||||||
// 转换为AddDTO
|
|
||||||
CcdiEmployeeAddDTO addDTO = new CcdiEmployeeAddDTO();
|
|
||||||
BeanUtils.copyProperties(excel, addDTO);
|
|
||||||
|
|
||||||
// 验证数据
|
|
||||||
validateEmployeeData(addDTO, isUpdateSupport, null);
|
|
||||||
|
|
||||||
CcdiEmployee employee = new CcdiEmployee();
|
|
||||||
BeanUtils.copyProperties(addDTO, employee);
|
|
||||||
|
|
||||||
employeeMapper.insert(employee);
|
|
||||||
successNum++;
|
|
||||||
successMsg.append("<br/>").append(successNum).append("、").append(addDTO.getName()).append(" 导入成功");
|
|
||||||
} catch (Exception e) {
|
|
||||||
failureNum++;
|
|
||||||
failureMsg.append("<br/>").append(failureNum).append("、").append(excel.getName()).append(" 导入失败:");
|
|
||||||
failureMsg.append(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (failureNum > 0) {
|
|
||||||
failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
|
|
||||||
throw new RuntimeException(failureMsg.toString());
|
|
||||||
} else {
|
|
||||||
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条");
|
|
||||||
return successMsg.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 异步导入员工数据
|
|
||||||
*
|
|
||||||
* @param excelList Excel数据列表
|
|
||||||
* @param isUpdateSupport 是否更新已存在的数据
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void importEmployeeAsync(List<CcdiEmployeeExcel> excelList, Boolean isUpdateSupport) {
|
|
||||||
String taskId = UUID.randomUUID().toString();
|
String taskId = UUID.randomUUID().toString();
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
@@ -256,75 +202,12 @@ public class CcdiEmployeeServiceImpl implements ICcdiEmployeeService {
|
|||||||
redisTemplate.opsForHash().putAll(statusKey, statusData);
|
redisTemplate.opsForHash().putAll(statusKey, statusData);
|
||||||
redisTemplate.expire(statusKey, 7, TimeUnit.DAYS);
|
redisTemplate.expire(statusKey, 7, TimeUnit.DAYS);
|
||||||
|
|
||||||
// 在独立线程中异步执行导入,立即返回
|
importAsyncService.importEmployeeAsync(excelList, isUpdateSupport, taskId);
|
||||||
CompletableFuture.runAsync(() -> {
|
|
||||||
try {
|
|
||||||
// 在后台线程中执行导入
|
|
||||||
ImportResult result = doImport(excelList, isUpdateSupport, taskId);
|
|
||||||
|
|
||||||
// 更新最终状态
|
return taskId;
|
||||||
String finalStatus = result.getFailureCount() == 0 ? "SUCCESS" : "PARTIAL_SUCCESS";
|
|
||||||
updateImportStatus(taskId, finalStatus, result, startTime);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
// 处理异常
|
|
||||||
Map<String, Object> errorData = new HashMap<>();
|
|
||||||
errorData.put("status", "FAILED");
|
|
||||||
errorData.put("message", "导入失败: " + e.getMessage());
|
|
||||||
errorData.put("endTime", System.currentTimeMillis());
|
|
||||||
redisTemplate.opsForHash().putAll(statusKey, errorData);
|
|
||||||
}
|
|
||||||
}, importExecutor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询导入状态
|
|
||||||
*
|
|
||||||
* @param taskId 任务ID
|
|
||||||
* @return 导入状态信息
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public ImportStatusVO getImportStatus(String taskId) {
|
|
||||||
String key = "import:employee:" + taskId;
|
|
||||||
Boolean hasKey = redisTemplate.hasKey(key);
|
|
||||||
|
|
||||||
if (Boolean.FALSE.equals(hasKey)) {
|
|
||||||
throw new RuntimeException("任务不存在或已过期");
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<Object, Object> statusMap = redisTemplate.opsForHash().entries(key);
|
|
||||||
|
|
||||||
ImportStatusVO statusVO = new ImportStatusVO();
|
|
||||||
statusVO.setTaskId((String) statusMap.get("taskId"));
|
|
||||||
statusVO.setStatus((String) statusMap.get("status"));
|
|
||||||
statusVO.setTotalCount((Integer) statusMap.get("totalCount"));
|
|
||||||
statusVO.setSuccessCount((Integer) statusMap.get("successCount"));
|
|
||||||
statusVO.setFailureCount((Integer) statusMap.get("failureCount"));
|
|
||||||
statusVO.setProgress((Integer) statusMap.get("progress"));
|
|
||||||
statusVO.setStartTime((Long) statusMap.get("startTime"));
|
|
||||||
statusVO.setEndTime((Long) statusMap.get("endTime"));
|
|
||||||
statusVO.setMessage((String) statusMap.get("message"));
|
|
||||||
|
|
||||||
return statusVO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取导入失败记录
|
|
||||||
*
|
|
||||||
* @param taskId 任务ID
|
|
||||||
* @return 失败记录列表
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<ImportFailureVO> getImportFailures(String taskId) {
|
|
||||||
String key = "import:employee:" + taskId + ":failures";
|
|
||||||
Object failuresObj = redisTemplate.opsForValue().get(key);
|
|
||||||
|
|
||||||
if (failuresObj == null) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
return JSON.parseArray(JSON.toJSONString(failuresObj), ImportFailureVO.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建查询条件
|
* 构建查询条件
|
||||||
@@ -340,75 +223,12 @@ public class CcdiEmployeeServiceImpl implements ICcdiEmployeeService {
|
|||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证员工数据
|
|
||||||
*
|
|
||||||
* @param addDTO 新增DTO
|
|
||||||
* @param isUpdateSupport 是否支持更新
|
|
||||||
* @param existingIds 已存在的员工ID集合(导入场景使用,传null表示单条新增)
|
|
||||||
*/
|
|
||||||
private void validateEmployeeData(CcdiEmployeeAddDTO addDTO, Boolean isUpdateSupport, Set<Long> existingIds) {
|
|
||||||
// 验证必填字段
|
|
||||||
if (StringUtils.isEmpty(addDTO.getName())) {
|
|
||||||
throw new RuntimeException("姓名不能为空");
|
|
||||||
}
|
|
||||||
if (addDTO.getEmployeeId() == null) {
|
|
||||||
throw new RuntimeException("柜员号不能为空");
|
|
||||||
}
|
|
||||||
if (addDTO.getDeptId() == null) {
|
|
||||||
throw new RuntimeException("所属部门不能为空");
|
|
||||||
}
|
|
||||||
if (StringUtils.isEmpty(addDTO.getIdCard())) {
|
|
||||||
throw new RuntimeException("身份证号不能为空");
|
|
||||||
}
|
|
||||||
if (StringUtils.isEmpty(addDTO.getPhone())) {
|
|
||||||
throw new RuntimeException("电话不能为空");
|
|
||||||
}
|
|
||||||
if (StringUtils.isEmpty(addDTO.getStatus())) {
|
|
||||||
throw new RuntimeException("状态不能为空");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证身份证号格式
|
|
||||||
String idCardError = IdCardUtil.getErrorMessage(addDTO.getIdCard());
|
|
||||||
if (idCardError != null) {
|
|
||||||
throw new RuntimeException(idCardError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 单条新增场景:检查柜员号和身份证号唯一性
|
|
||||||
if (existingIds == null) {
|
|
||||||
// 检查柜员号(employeeId)唯一性
|
|
||||||
if (employeeMapper.selectById(addDTO.getEmployeeId()) != null) {
|
|
||||||
throw new RuntimeException("该柜员号已存在");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查身份证号唯一性
|
|
||||||
LambdaQueryWrapper<CcdiEmployee> wrapper = new LambdaQueryWrapper<>();
|
|
||||||
wrapper.eq(CcdiEmployee::getIdCard, addDTO.getIdCard());
|
|
||||||
if (employeeMapper.selectCount(wrapper) > 0) {
|
|
||||||
throw new RuntimeException("该身份证号已存在");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 导入场景:如果柜员号不存在,才检查身份证号唯一性
|
|
||||||
if (!existingIds.contains(addDTO.getEmployeeId())) {
|
|
||||||
// 检查身份证号唯一性
|
|
||||||
LambdaQueryWrapper<CcdiEmployee> wrapper = new LambdaQueryWrapper<>();
|
|
||||||
wrapper.eq(CcdiEmployee::getIdCard, addDTO.getIdCard());
|
|
||||||
if (employeeMapper.selectCount(wrapper) > 0) {
|
|
||||||
throw new RuntimeException("该身份证号已存在");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证状态
|
|
||||||
if (!"0".equals(addDTO.getStatus()) && !"1".equals(addDTO.getStatus())) {
|
|
||||||
throw new RuntimeException("状态只能填写'在职'或'离职'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转换为VO对象
|
* 转换为VO对象
|
||||||
*/
|
*/
|
||||||
private CcdiEmployeeVO convertToVO(CcdiEmployee employee) {
|
public CcdiEmployeeVO convertToVO(CcdiEmployee employee) {
|
||||||
if (employee == null) {
|
if (employee == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -419,177 +239,11 @@ public class CcdiEmployeeServiceImpl implements ICcdiEmployeeService {
|
|||||||
return vo;
|
return vo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行导入逻辑
|
|
||||||
*/
|
|
||||||
@Transactional
|
|
||||||
private ImportResult doImport(List<CcdiEmployeeExcel> excelList, Boolean isUpdateSupport, String taskId) {
|
|
||||||
List<CcdiEmployee> newRecords = new ArrayList<>();
|
|
||||||
List<CcdiEmployee> updateRecords = new ArrayList<>();
|
|
||||||
List<ImportFailureVO> failures = new ArrayList<>();
|
|
||||||
|
|
||||||
// 批量查询已存在的柜员号
|
|
||||||
Set<Long> existingIds = getExistingEmployeeIds(excelList);
|
|
||||||
|
|
||||||
// 分类数据
|
|
||||||
for (int i = 0; i < excelList.size(); i++) {
|
|
||||||
CcdiEmployeeExcel excel = excelList.get(i);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 转换为AddDTO进行验证
|
|
||||||
CcdiEmployeeAddDTO addDTO = new CcdiEmployeeAddDTO();
|
|
||||||
BeanUtils.copyProperties(excel, addDTO);
|
|
||||||
|
|
||||||
// 验证数据(支持更新模式)
|
|
||||||
validateEmployeeData(addDTO, isUpdateSupport, existingIds);
|
|
||||||
|
|
||||||
CcdiEmployee employee = convertToEntity(excel);
|
|
||||||
|
|
||||||
if (existingIds.contains(excel.getEmployeeId())) {
|
|
||||||
if (isUpdateSupport) {
|
|
||||||
updateRecords.add(employee);
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException("柜员号已存在且未启用更新支持");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newRecords.add(employee);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新进度
|
|
||||||
int progress = (int) ((i + 1) * 100.0 / excelList.size());
|
|
||||||
updateImportProgress(taskId, progress);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
ImportFailureVO failure = new ImportFailureVO();
|
|
||||||
BeanUtils.copyProperties(excel, failure);
|
|
||||||
failure.setErrorMessage(e.getMessage());
|
|
||||||
failures.add(failure);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 批量插入新数据
|
|
||||||
if (!newRecords.isEmpty()) {
|
|
||||||
saveBatch(newRecords, 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 批量更新已有数据
|
|
||||||
if (!updateRecords.isEmpty() && isUpdateSupport) {
|
|
||||||
employeeMapper.insertOrUpdateBatch(updateRecords);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存失败记录到Redis
|
|
||||||
if (!failures.isEmpty()) {
|
|
||||||
String failuresKey = "import:employee:" + taskId + ":failures";
|
|
||||||
redisTemplate.opsForValue().set(failuresKey, failures, 7, TimeUnit.DAYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImportResult result = new ImportResult();
|
|
||||||
result.setTotalCount(excelList.size());
|
|
||||||
result.setSuccessCount(newRecords.size() + updateRecords.size());
|
|
||||||
result.setFailureCount(failures.size());
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量查询已存在的员工ID
|
|
||||||
*/
|
|
||||||
private Set<Long> getExistingEmployeeIds(List<CcdiEmployeeExcel> excelList) {
|
|
||||||
List<Long> employeeIds = excelList.stream()
|
|
||||||
.map(CcdiEmployeeExcel::getEmployeeId)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
if (employeeIds.isEmpty()) {
|
|
||||||
return Collections.emptySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<CcdiEmployee> existingEmployees = employeeMapper.selectBatchIds(employeeIds);
|
|
||||||
return existingEmployees.stream()
|
|
||||||
.map(CcdiEmployee::getEmployeeId)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为实体对象
|
|
||||||
*/
|
|
||||||
private CcdiEmployee convertToEntity(CcdiEmployeeExcel excel) {
|
|
||||||
CcdiEmployee employee = new CcdiEmployee();
|
|
||||||
BeanUtils.copyProperties(excel, employee);
|
|
||||||
return employee;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量保存
|
|
||||||
*/
|
|
||||||
private void saveBatch(List<CcdiEmployee> list, int batchSize) {
|
|
||||||
// 使用真正的批量插入,分批次执行以提高性能
|
|
||||||
for (int i = 0; i < list.size(); i += batchSize) {
|
|
||||||
int end = Math.min(i + batchSize, list.size());
|
|
||||||
List<CcdiEmployee> subList = list.subList(i, end);
|
|
||||||
employeeMapper.insertBatch(subList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新导入进度
|
|
||||||
*/
|
|
||||||
private void updateImportProgress(String taskId, Integer progress) {
|
|
||||||
String key = "import:employee:" + taskId;
|
|
||||||
redisTemplate.opsForHash().put(key, "progress", progress);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新导入状态
|
|
||||||
*/
|
|
||||||
private void updateImportStatus(String taskId, String status, ImportResult result, Long startTime) {
|
|
||||||
String key = "import:employee:" + taskId;
|
|
||||||
Map<String, Object> statusData = new HashMap<>();
|
|
||||||
statusData.put("status", status);
|
|
||||||
statusData.put("successCount", result.getSuccessCount());
|
|
||||||
statusData.put("failureCount", result.getFailureCount());
|
|
||||||
statusData.put("progress", 100);
|
|
||||||
statusData.put("endTime", System.currentTimeMillis());
|
|
||||||
|
|
||||||
if ("SUCCESS".equals(status)) {
|
|
||||||
statusData.put("message", "全部成功!共导入" + result.getTotalCount() + "条数据");
|
|
||||||
} else {
|
|
||||||
statusData.put("message", "成功" + result.getSuccessCount() + "条,失败" + result.getFailureCount() + "条");
|
|
||||||
}
|
|
||||||
|
|
||||||
redisTemplate.opsForHash().putAll(key, statusData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导入结果内部类
|
|
||||||
*/
|
|
||||||
private static class ImportResult {
|
|
||||||
private Integer totalCount;
|
|
||||||
private Integer successCount;
|
|
||||||
private Integer failureCount;
|
|
||||||
|
|
||||||
public Integer getTotalCount() {
|
|
||||||
return totalCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTotalCount(Integer totalCount) {
|
|
||||||
this.totalCount = totalCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getSuccessCount() {
|
|
||||||
return successCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSuccessCount(Integer successCount) {
|
|
||||||
this.successCount = successCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getFailureCount() {
|
|
||||||
return failureCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFailureCount(Integer failureCount) {
|
|
||||||
this.failureCount = failureCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
ORDER BY e.create_time DESC
|
ORDER BY e.create_time DESC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 批量插入或更新员工信息 -->
|
<!-- 批量插入或更新员工信息(只更新非null字段) -->
|
||||||
<insert id="insertOrUpdateBatch" parameterType="java.util.List">
|
<insert id="insertOrUpdateBatch" parameterType="java.util.List">
|
||||||
INSERT INTO ccdi_employee
|
INSERT INTO ccdi_employee
|
||||||
(employee_id, name, dept_id, id_card, phone, hire_date, status,
|
(employee_id, name, dept_id, id_card, phone, hire_date, status,
|
||||||
@@ -56,13 +56,12 @@
|
|||||||
#{item.createBy}, #{item.updateBy}, NOW())
|
#{item.createBy}, #{item.updateBy}, NOW())
|
||||||
</foreach>
|
</foreach>
|
||||||
ON DUPLICATE KEY UPDATE
|
ON DUPLICATE KEY UPDATE
|
||||||
name = VALUES(name),
|
name = COALESCE(VALUES(name), name),
|
||||||
dept_id = VALUES(dept_id),
|
dept_id = COALESCE(VALUES(dept_id), dept_id),
|
||||||
id_card = VALUES(id_card),
|
phone = COALESCE(VALUES(phone), phone),
|
||||||
phone = VALUES(phone),
|
hire_date = COALESCE(VALUES(hire_date), hire_date),
|
||||||
hire_date = VALUES(hire_date),
|
status = COALESCE(VALUES(status), status),
|
||||||
status = VALUES(status),
|
update_by = COALESCE(VALUES(update_by), update_by),
|
||||||
update_by = VALUES(update_by),
|
|
||||||
update_time = NOW()
|
update_time = NOW()
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user