更改批量设置mealcard逻辑、导入数据加密、数据映射
This commit is contained in:
parent
2770ff5cf9
commit
49dddc4aaf
|
@ -32,6 +32,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Description: Controller基类
|
* @Description: Controller基类
|
||||||
|
@ -292,36 +293,142 @@ public class JeecgController<T, S extends IService<T>> {
|
||||||
* @param response
|
* @param response
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
// protected Result<?> importExcel(HttpServletRequest request, HttpServletResponse response, Class<T> clazz) {
|
||||||
|
// MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
|
||||||
|
// Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
|
||||||
|
// for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
|
||||||
|
// // 获取上传文件对象
|
||||||
|
// MultipartFile file = entity.getValue();
|
||||||
|
// ImportParams params = new ImportParams();
|
||||||
|
// params.setTitleRows(2);
|
||||||
|
// params.setHeadRows(1);
|
||||||
|
// params.setNeedSave(true);
|
||||||
|
// try {
|
||||||
|
// List<T> list = ExcelImportUtil.importExcel(file.getInputStream(), clazz, params);
|
||||||
|
// //update-begin-author:taoyan date:20190528 for:批量插入数据
|
||||||
|
// long start = System.currentTimeMillis();
|
||||||
|
// service.saveBatch(list);
|
||||||
|
// //400条 saveBatch消耗时间1592毫秒 循环插入消耗时间1947毫秒
|
||||||
|
// //1200条 saveBatch消耗时间3687毫秒 循环插入消耗时间5212毫秒
|
||||||
|
// log.info("消耗时间" + (System.currentTimeMillis() - start) + "毫秒");
|
||||||
|
// //update-end-author:taoyan date:20190528 for:批量插入数据
|
||||||
|
// return Result.ok("文件导入成功!数据行数:" + list.size());
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// //update-begin-author:taoyan date:20211124 for: 导入数据重复增加提示
|
||||||
|
// String msg = e.getMessage();
|
||||||
|
// log.error(msg, e);
|
||||||
|
// if(msg!=null && msg.indexOf("Duplicate entry")>=0){
|
||||||
|
// return Result.error("文件导入失败:有重复数据!");
|
||||||
|
// }else{
|
||||||
|
// return Result.error("文件导入失败:" + e.getMessage());
|
||||||
|
// }
|
||||||
|
// //update-end-author:taoyan date:20211124 for: 导入数据重复增加提示
|
||||||
|
// } finally {
|
||||||
|
// try {
|
||||||
|
// file.getInputStream().close();
|
||||||
|
// } catch (IOException e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return Result.error("文件导入失败!");
|
||||||
|
// }
|
||||||
protected Result<?> importExcel(HttpServletRequest request, HttpServletResponse response, Class<T> clazz) {
|
protected Result<?> importExcel(HttpServletRequest request, HttpServletResponse response, Class<T> clazz) {
|
||||||
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
|
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
|
||||||
Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
|
Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
|
||||||
|
|
||||||
for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
|
for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
|
||||||
// 获取上传文件对象
|
|
||||||
MultipartFile file = entity.getValue();
|
MultipartFile file = entity.getValue();
|
||||||
ImportParams params = new ImportParams();
|
ImportParams params = new ImportParams();
|
||||||
params.setTitleRows(2);
|
params.setTitleRows(2);
|
||||||
params.setHeadRows(1);
|
params.setHeadRows(1);
|
||||||
params.setNeedSave(true);
|
params.setNeedSave(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<T> list = ExcelImportUtil.importExcel(file.getInputStream(), clazz, params);
|
List<T> list = ExcelImportUtil.importExcel(file.getInputStream(), clazz, params);
|
||||||
//update-begin-author:taoyan date:20190528 for:批量插入数据
|
|
||||||
|
// === 加密敏感字段 ===
|
||||||
|
for (T item : list) {
|
||||||
|
try {
|
||||||
|
// 银行卡字段加密
|
||||||
|
Field pyCardField = null;
|
||||||
|
try {
|
||||||
|
pyCardField = item.getClass().getDeclaredField("pyCard");
|
||||||
|
} catch (NoSuchFieldException ignored) {}
|
||||||
|
if (pyCardField != null) {
|
||||||
|
pyCardField.setAccessible(true);
|
||||||
|
String value = (String) pyCardField.get(item);
|
||||||
|
if (value != null && !value.isEmpty()) {
|
||||||
|
String encryptedValue = JasyptUtil.encrypt(value, "bigdata");
|
||||||
|
pyCardField.set(item, encryptedValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 身份证字段加密
|
||||||
|
Field identityIdField = null;
|
||||||
|
try {
|
||||||
|
identityIdField = item.getClass().getDeclaredField("identityId");
|
||||||
|
} catch (NoSuchFieldException ignored) {}
|
||||||
|
if (identityIdField != null) {
|
||||||
|
identityIdField.setAccessible(true);
|
||||||
|
String value = (String) identityIdField.get(item);
|
||||||
|
if (value != null && !value.isEmpty()) {
|
||||||
|
String encryptedValue = JasyptUtil.encrypt(value, "bigdata");
|
||||||
|
identityIdField.set(item, encryptedValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 状态描述反向映射 =====
|
||||||
|
|
||||||
|
// 性别反向映射
|
||||||
|
applyReverseMapping(item, "sexDescription", "sex", StatusMappingUtil::reverseMapSex);
|
||||||
|
|
||||||
|
// 车辆状态反向映射
|
||||||
|
applyReverseMapping(item, "carStatusDescription", "carStatus", StatusMappingUtil::reverseMapCarStatus);
|
||||||
|
|
||||||
|
// 住宿状态反向映射
|
||||||
|
applyReverseMapping(item, "dormitoryStatusDescription", "dormitoryStatus", StatusMappingUtil::reverseMapDormitoryStatus);
|
||||||
|
|
||||||
|
// 一般状态反向映射
|
||||||
|
applyReverseMapping(item, "statusDescription", "status", StatusMappingUtil::reverseMapStatus);
|
||||||
|
|
||||||
|
// 宿舍名称反查 ID
|
||||||
|
// Field dormNameField = getField(item, "dormitoryName");
|
||||||
|
// Field dormIdField = getField(item, "dormitoryId");
|
||||||
|
// if (dormNameField != null && dormIdField != null) {
|
||||||
|
// String dormName = (String) dormNameField.get(item);
|
||||||
|
// if (dormName != null && !dormName.isEmpty()) {
|
||||||
|
// dormIdField.set(item, nameResolverService.getDormitoryId(dormName));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 组名称反查 ID
|
||||||
|
// Field groupNameField = getField(item, "groupName");
|
||||||
|
// Field groupIdField = getField(item, "groupId");
|
||||||
|
// if (groupNameField != null && groupIdField != null) {
|
||||||
|
// String groupName = (String) groupNameField.get(item);
|
||||||
|
// if (groupName != null && !groupName.isEmpty()) {
|
||||||
|
// groupIdField.set(item, nameResolverService.getGroupId(groupName));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new RuntimeException("加密字段处理失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
service.saveBatch(list);
|
service.saveBatch(list);
|
||||||
//400条 saveBatch消耗时间1592毫秒 循环插入消耗时间1947毫秒
|
|
||||||
//1200条 saveBatch消耗时间3687毫秒 循环插入消耗时间5212毫秒
|
|
||||||
log.info("消耗时间" + (System.currentTimeMillis() - start) + "毫秒");
|
log.info("消耗时间" + (System.currentTimeMillis() - start) + "毫秒");
|
||||||
//update-end-author:taoyan date:20190528 for:批量插入数据
|
|
||||||
return Result.ok("文件导入成功!数据行数:" + list.size());
|
return Result.ok("文件导入成功!数据行数:" + list.size());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
//update-begin-author:taoyan date:20211124 for: 导入数据重复增加提示
|
|
||||||
String msg = e.getMessage();
|
String msg = e.getMessage();
|
||||||
log.error(msg, e);
|
log.error(msg, e);
|
||||||
if(msg!=null && msg.indexOf("Duplicate entry")>=0){
|
if (msg != null && msg.contains("Duplicate entry")) {
|
||||||
return Result.error("文件导入失败:有重复数据!");
|
return Result.error("文件导入失败:有重复数据!");
|
||||||
}else{
|
} else {
|
||||||
return Result.error("文件导入失败:" + e.getMessage());
|
return Result.error("文件导入失败:" + msg);
|
||||||
}
|
}
|
||||||
//update-end-author:taoyan date:20211124 for: 导入数据重复增加提示
|
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
file.getInputStream().close();
|
file.getInputStream().close();
|
||||||
|
@ -332,4 +439,28 @@ public class JeecgController<T, S extends IService<T>> {
|
||||||
}
|
}
|
||||||
return Result.error("文件导入失败!");
|
return Result.error("文件导入失败!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Field getField(Object obj, String fieldName) {
|
||||||
|
try {
|
||||||
|
Field field = obj.getClass().getDeclaredField(fieldName);
|
||||||
|
field.setAccessible(true);
|
||||||
|
return field;
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyReverseMapping(Object item, String descFieldName, String codeFieldName, Function<String, Integer> mapper) throws IllegalAccessException {
|
||||||
|
Field descField = getField(item, descFieldName);
|
||||||
|
Field codeField = getField(item, codeFieldName);
|
||||||
|
if (descField != null && codeField != null) {
|
||||||
|
String desc = (String) descField.get(item);
|
||||||
|
if (desc != null && !desc.isEmpty()) {
|
||||||
|
Integer code = mapper.apply(desc);
|
||||||
|
codeField.set(item, code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,4 +3,8 @@ package org.jeecg.common.system.base.service;
|
||||||
public interface NameResolverService {
|
public interface NameResolverService {
|
||||||
String getDormitoryName(String dormitoryId);
|
String getDormitoryName(String dormitoryId);
|
||||||
String getGroupName(String groupId);
|
String getGroupName(String groupId);
|
||||||
|
|
||||||
|
Object getDormitoryId(String dormName);
|
||||||
|
|
||||||
|
Object getGroupId(String groupName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,4 +24,30 @@ public class StatusMappingUtil {
|
||||||
if (status == null) return "";
|
if (status == null) return "";
|
||||||
return status == 0 ? "已报到" : "未报到";
|
return status == 0 ? "已报到" : "未报到";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== 反向映射 =====
|
||||||
|
|
||||||
|
public static Integer reverseMapSex(String desc) {
|
||||||
|
if ("男".equals(desc)) return 0;
|
||||||
|
if ("女".equals(desc)) return 1;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer reverseMapCarStatus(String desc) {
|
||||||
|
if ("是".equals(desc)) return 1;
|
||||||
|
if ("否".equals(desc)) return 0;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer reverseMapDormitoryStatus(String desc) {
|
||||||
|
if ("是".equals(desc)) return 1;
|
||||||
|
if ("否".equals(desc)) return 0;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer reverseMapStatus(String desc) {
|
||||||
|
if ("已报到".equals(desc)) return 0;
|
||||||
|
if ("未报到".equals(desc)) return 1;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -412,18 +412,18 @@ public class CeesWaiTeacherServiceImpl extends ServiceImpl<CeesWaiTeacherMapper,
|
||||||
throw new IllegalArgumentException("max 参数类型错误");
|
throw new IllegalArgumentException("max 参数类型错误");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取所有已有的 mealCard,构建占用集合
|
// 获取所有已有的 mealCard 数据
|
||||||
List<CeesWaiTeacher> allTeachers = ceesWaiTeacherMapper.selectList(null);
|
List<CeesWaiTeacher> allTeachers = ceesWaiTeacherMapper.selectList(null);
|
||||||
Set<String> usedCards = allTeachers.stream()
|
Map<String, String> teacherIdToCard = allTeachers.stream()
|
||||||
.map(CeesWaiTeacher::getMealCard)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
|
|
||||||
// 获取已存在 mealCard 的用户 ID
|
|
||||||
Set<String> alreadyHasCardIds = allTeachers.stream()
|
|
||||||
.filter(t -> t.getMealCard() != null && !t.getMealCard().trim().isEmpty())
|
.filter(t -> t.getMealCard() != null && !t.getMealCard().trim().isEmpty())
|
||||||
.map(CeesWaiTeacher::getId)
|
.collect(Collectors.toMap(CeesWaiTeacher::getId, CeesWaiTeacher::getMealCard));
|
||||||
.collect(Collectors.toSet());
|
|
||||||
|
// 卡号 -> 人员ID 的映射,方便夺卡
|
||||||
|
Map<String, String> cardToTeacherId = allTeachers.stream()
|
||||||
|
.filter(t -> t.getMealCard() != null && !t.getMealCard().trim().isEmpty())
|
||||||
|
.collect(Collectors.toMap(CeesWaiTeacher::getMealCard, CeesWaiTeacher::getId));
|
||||||
|
|
||||||
|
Set<String> usedCards = new HashSet<>(cardToTeacherId.keySet());
|
||||||
|
|
||||||
int totalUpdatedLocal = 0;
|
int totalUpdatedLocal = 0;
|
||||||
List<String> failedIdsLocal = new ArrayList<>();
|
List<String> failedIdsLocal = new ArrayList<>();
|
||||||
|
@ -432,35 +432,44 @@ public class CeesWaiTeacherServiceImpl extends ServiceImpl<CeesWaiTeacherMapper,
|
||||||
int currentCard = min;
|
int currentCard = min;
|
||||||
|
|
||||||
for (String id : ids) {
|
for (String id : ids) {
|
||||||
// 如果用户已有 mealCard,跳过
|
|
||||||
if (alreadyHasCardIds.contains(id)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean assigned = false;
|
boolean assigned = false;
|
||||||
|
|
||||||
// 查找下一个未被占用的卡号
|
|
||||||
while (currentCard <= max) {
|
while (currentCard <= max) {
|
||||||
String formattedCard = String.format("%03d", currentCard);
|
String formattedCard = String.format("%03d", currentCard);
|
||||||
if (!usedCards.contains(formattedCard)) {
|
|
||||||
try {
|
|
||||||
LambdaUpdateWrapper<CeesWaiTeacher> updateWrapper = new LambdaUpdateWrapper<>();
|
|
||||||
updateWrapper.eq(CeesWaiTeacher::getId, id)
|
|
||||||
.set(CeesWaiTeacher::getMealCard, formattedCard);
|
|
||||||
|
|
||||||
int affectedRows = ceesWaiTeacherMapper.update(null, updateWrapper);
|
// 如果已被占用,则从原用户手中夺取
|
||||||
if (affectedRows > 0) {
|
if (usedCards.contains(formattedCard)) {
|
||||||
totalUpdatedLocal++;
|
String previousHolderId = cardToTeacherId.get(formattedCard);
|
||||||
usedCards.add(formattedCard);
|
if (!Objects.equals(previousHolderId, id)) {
|
||||||
assigned = true;
|
// 夺卡逻辑:把旧用户的卡号置空
|
||||||
}
|
LambdaUpdateWrapper<CeesWaiTeacher> clearWrapper = new LambdaUpdateWrapper<>();
|
||||||
} catch (Exception e) {
|
clearWrapper.eq(CeesWaiTeacher::getId, previousHolderId)
|
||||||
// 忽略异常,进入失败处理
|
.set(CeesWaiTeacher::getMealCard, null);
|
||||||
|
ceesWaiTeacherMapper.update(null, clearWrapper);
|
||||||
|
usedCards.remove(formattedCard);
|
||||||
|
cardToTeacherId.remove(formattedCard);
|
||||||
}
|
}
|
||||||
currentCard++;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 分配卡号给当前用户(无论其是否已有)
|
||||||
|
LambdaUpdateWrapper<CeesWaiTeacher> updateWrapper = new LambdaUpdateWrapper<>();
|
||||||
|
updateWrapper.eq(CeesWaiTeacher::getId, id)
|
||||||
|
.set(CeesWaiTeacher::getMealCard, formattedCard);
|
||||||
|
|
||||||
|
int affectedRows = ceesWaiTeacherMapper.update(null, updateWrapper);
|
||||||
|
if (affectedRows > 0) {
|
||||||
|
totalUpdatedLocal++;
|
||||||
|
usedCards.add(formattedCard);
|
||||||
|
cardToTeacherId.put(formattedCard, id);
|
||||||
|
assigned = true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 异常处理
|
||||||
|
}
|
||||||
|
|
||||||
currentCard++;
|
currentCard++;
|
||||||
|
break; // 成功或失败后跳出当前循环
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!assigned) {
|
if (!assigned) {
|
||||||
|
|
|
@ -32,4 +32,14 @@ public class NameResolverImpl implements NameResolverService {
|
||||||
CeesGroup group = groupService.getById(groupId);
|
CeesGroup group = groupService.getById(groupId);
|
||||||
return group != null ? group.getName() : "";
|
return group != null ? group.getName() : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getDormitoryId(String dormName) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getGroupId(String groupName) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue