学号
This commit is contained in:
@@ -45,6 +45,11 @@ public interface SchStudentRepository extends JpaRepository<SchStudent, Integer>
|
|||||||
|
|
||||||
boolean existsBySchIdAndClassIdAndNameAndIdNot(Integer schId,Integer classId, String name, Integer id);
|
boolean existsBySchIdAndClassIdAndNameAndIdNot(Integer schId,Integer classId, String name, Integer id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断同一班级内是否已存在相同学号的学生(排除自身,用于学号导入时的重复校验)
|
||||||
|
*/
|
||||||
|
boolean existsBySchIdAndClassIdAndStuClassNoAndIdNot(Integer schId, Integer classId, String stuClassNo, Integer id);
|
||||||
|
|
||||||
@Modifying(clearAutomatically = true)
|
@Modifying(clearAutomatically = true)
|
||||||
@Query("UPDATE SchStudent s SET s.classId = :newClassId, s.groupId = :newClassId, s.updateDate = :updateDate, s.updateUserId = :updateUserId WHERE s.id IN (:ids) AND s.schId = :schId")
|
@Query("UPDATE SchStudent s SET s.classId = :newClassId, s.groupId = :newClassId, s.updateDate = :updateDate, s.updateUserId = :updateUserId WHERE s.id IN (:ids) AND s.schId = :schId")
|
||||||
int batchUpdateClassId(@Param("ids") List<Integer> ids,
|
int batchUpdateClassId(@Param("ids") List<Integer> ids,
|
||||||
|
|||||||
+84
-10
@@ -346,6 +346,47 @@ public class SchStudentImportService {
|
|||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验学号导入数据中的重复项(账号、学号)
|
||||||
|
* @param importList 导入数据列表
|
||||||
|
* @return 错误信息列表
|
||||||
|
*/
|
||||||
|
private List<String> validateClassNoDuplicates(List<StudentClassNoExcelColumn> importList) {
|
||||||
|
List<String> errors = new ArrayList<>();
|
||||||
|
|
||||||
|
// 1. 校验 "账号" 在本次导入中是否重复(避免同一学生被重复处理)
|
||||||
|
Map<String, Long> accountCountMap = importList.stream()
|
||||||
|
.filter(dto -> StringUtils.isNotBlank(dto.getAccount()))
|
||||||
|
.collect(Collectors.groupingBy(
|
||||||
|
dto -> dto.getAccount(),
|
||||||
|
Collectors.counting()
|
||||||
|
));
|
||||||
|
|
||||||
|
accountCountMap.entrySet().stream()
|
||||||
|
.filter(entry -> entry.getValue() > 1)
|
||||||
|
.forEach(entry -> errors.add(
|
||||||
|
String.format("账号 '%s' 在表格中出现了 %d 次,请检查并去重",
|
||||||
|
entry.getKey(), entry.getValue())
|
||||||
|
));
|
||||||
|
|
||||||
|
// 2. 校验 "学号" 在本次导入中是否重复
|
||||||
|
Map<String, Long> classNoCountMap = importList.stream()
|
||||||
|
.filter(dto -> StringUtils.isNotBlank(dto.getClazzNo()))
|
||||||
|
.collect(Collectors.groupingBy(
|
||||||
|
dto -> dto.getClazzNo(),
|
||||||
|
Collectors.counting()
|
||||||
|
));
|
||||||
|
|
||||||
|
classNoCountMap.entrySet().stream()
|
||||||
|
.filter(entry -> entry.getValue() > 1)
|
||||||
|
.forEach(entry -> errors.add(
|
||||||
|
String.format("学号 '%s' 在表格中出现了 %d 次,请检查并去重",
|
||||||
|
entry.getKey(), entry.getValue())
|
||||||
|
));
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void studentClassNoTemplate(HttpServletResponse response,
|
public void studentClassNoTemplate(HttpServletResponse response,
|
||||||
Integer schId,Integer systemId,Integer gradeId,Integer classId){
|
Integer schId,Integer systemId,Integer gradeId,Integer classId){
|
||||||
@@ -419,9 +460,17 @@ public class SchStudentImportService {
|
|||||||
throw new DException("上传的 Excel 中没有有效数据行,请检查后重新上传!");
|
throw new DException("上传的 Excel 中没有有效数据行,请检查后重新上传!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Excel数据重复验证(账号、学号)
|
||||||
|
{
|
||||||
|
List<String> validateDuplicatesMsgs = validateClassNoDuplicates(list);
|
||||||
|
if (validateDuplicatesMsgs.size() > 0) {
|
||||||
|
errorMsgArr.add(new ErrorExcelColumn(0, "数据重复", String.join("\r\n", validateDuplicatesMsgs)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 4. 业务校验与转换
|
// 4. 业务校验与转换
|
||||||
List<SchStudent> saveStudentList = new ArrayList<>();
|
List<SchStudent> saveStudentList = new ArrayList<>();
|
||||||
int currentRow = params.getTitleRows() + params.getHeadRows() ; // 从第2行开始
|
int currentRow = params.getTitleRows() + params.getHeadRows() + 1; // 第一行数据从第2行开始
|
||||||
|
|
||||||
for (StudentClassNoExcelColumn item : list) {
|
for (StudentClassNoExcelColumn item : list) {
|
||||||
// Excel数据验证
|
// Excel数据验证
|
||||||
@@ -429,6 +478,7 @@ public class SchStudentImportService {
|
|||||||
List<String> validateMsgs = ValidationUtil.validateMsgs(item);
|
List<String> validateMsgs = ValidationUtil.validateMsgs(item);
|
||||||
if (validateMsgs.size() > 0) {
|
if (validateMsgs.size() > 0) {
|
||||||
errorMsgArr.add(new ErrorExcelColumn(currentRow, "导入规则", String.join("\r\n", validateMsgs)));
|
errorMsgArr.add(new ErrorExcelColumn(currentRow, "导入规则", String.join("\r\n", validateMsgs)));
|
||||||
|
currentRow++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -438,17 +488,22 @@ public class SchStudentImportService {
|
|||||||
{
|
{
|
||||||
Optional<SchStudent> accountOpt = schStudentRepository.findByAccount(item.getAccount());
|
Optional<SchStudent> accountOpt = schStudentRepository.findByAccount(item.getAccount());
|
||||||
if (accountOpt.isPresent()) {
|
if (accountOpt.isPresent()) {
|
||||||
if (!accountOpt.get().getSchId().equals(schId) && accountOpt.get().getTransferStatus().equals(TransferStatus.IN)) {
|
SchStudent existing = accountOpt.get();
|
||||||
|
// 跨校防护(空安全):账号属于其他学校时一律拒绝,避免修改其他学校的学生数据
|
||||||
|
if (!schId.equals(existing.getSchId())) {
|
||||||
|
String schoolName = existing.getSchId() == null ? "未知学校"
|
||||||
|
: comSchTreeService.getSchoolName(existing.getSchId());
|
||||||
errorMsgArr.add(new ErrorExcelColumn(currentRow, item.getStuName(),
|
errorMsgArr.add(new ErrorExcelColumn(currentRow, item.getStuName(),
|
||||||
"禁止将" + comSchTreeService.getSchoolName(accountOpt.get().getSchId()) + "正常学生导入!"));
|
"禁止将" + schoolName + "学生导入!"));
|
||||||
|
currentRow++;
|
||||||
continue;
|
continue;
|
||||||
} else {
|
|
||||||
BeanUtils.copyProperties(accountOpt.get(), stu);
|
|
||||||
stu.setUpdateDate(now);
|
|
||||||
stu.setUpdateUserId(userId);
|
|
||||||
}
|
}
|
||||||
|
BeanUtils.copyProperties(existing, stu);
|
||||||
|
stu.setUpdateDate(now);
|
||||||
|
stu.setUpdateUserId(userId);
|
||||||
} else {
|
} else {
|
||||||
errorMsgArr.add(new ErrorExcelColumn(currentRow, item.getAccount(),item.getStuName()+"学生账号未找到!"));
|
errorMsgArr.add(new ErrorExcelColumn(currentRow, item.getAccount(),item.getStuName()+"学生账号未找到!"));
|
||||||
|
currentRow++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -465,10 +520,12 @@ public class SchStudentImportService {
|
|||||||
gradeId2 = gradeIdOpt.get();
|
gradeId2 = gradeIdOpt.get();
|
||||||
if(gradeId!=null&&!gradeId2.equals(gradeId)){
|
if(gradeId!=null&&!gradeId2.equals(gradeId)){
|
||||||
errorMsgArr.add(new ErrorExcelColumn(currentRow, item.getGradeName(), StudentExcelColumn.GRADE_NAME + "参数年级与模板年级不一致!"));
|
errorMsgArr.add(new ErrorExcelColumn(currentRow, item.getGradeName(), StudentExcelColumn.GRADE_NAME + "参数年级与模板年级不一致!"));
|
||||||
|
currentRow++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
errorMsgArr.add(new ErrorExcelColumn(currentRow, item.getGradeName(), StudentExcelColumn.GRADE_NAME + "不存在!"));
|
errorMsgArr.add(new ErrorExcelColumn(currentRow, item.getGradeName(), StudentExcelColumn.GRADE_NAME + "不存在!"));
|
||||||
|
currentRow++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -482,20 +539,35 @@ public class SchStudentImportService {
|
|||||||
if(classId!=null){
|
if(classId!=null){
|
||||||
if(!schClassOpt.get().getClassId().equals(classId)){
|
if(!schClassOpt.get().getClassId().equals(classId)){
|
||||||
errorMsgArr.add(new ErrorExcelColumn(currentRow, item.getClazzName(), StudentExcelColumn.CLAZZ_NAME + "参数班级与模板班级不一致!"));
|
errorMsgArr.add(new ErrorExcelColumn(currentRow, item.getClazzName(), StudentExcelColumn.CLAZZ_NAME + "参数班级与模板班级不一致!"));
|
||||||
|
currentRow++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// 学生当前班级必须与模板班级一致,避免改错其他班级学生的学号
|
||||||
|
if (!Objects.equals(stu.getClassId(), schClassOpt.get().getClassId())) {
|
||||||
|
errorMsgArr.add(new ErrorExcelColumn(currentRow, item.getClazzName(), "学生当前班级与模板班级不一致!"));
|
||||||
|
currentRow++;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
errorMsgArr.add(new ErrorExcelColumn(currentRow, item.getClazzName(), StudentExcelColumn.CLAZZ_NAME + "不存在!"));
|
errorMsgArr.add(new ErrorExcelColumn(currentRow, item.getClazzName(), StudentExcelColumn.CLAZZ_NAME + "不存在!"));
|
||||||
|
currentRow++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 学号
|
// 学号(为空时保留原学号,避免误清空)
|
||||||
{
|
{
|
||||||
stu.setStuClassNo(item.getClazzNo());
|
|
||||||
if (StringUtils.isNotBlank(item.getClazzNo())) {
|
if (StringUtils.isNotBlank(item.getClazzNo())) {
|
||||||
|
// 同班级内学号重复校验(排除学生自身)
|
||||||
|
boolean classNoExists = schStudentRepository.existsBySchIdAndClassIdAndStuClassNoAndIdNot(
|
||||||
|
schId, stu.getClassId(), item.getClazzNo(), stu.getId());
|
||||||
|
if (classNoExists) {
|
||||||
|
errorMsgArr.add(new ErrorExcelColumn(currentRow, item.getClazzNo(), "该班级已存在相同学号的学生!"));
|
||||||
|
currentRow++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
stu.setStuClassNo(item.getClazzNo());
|
||||||
try {
|
try {
|
||||||
String digits = item.getClazzNo().replaceAll("\\D+", "");
|
String digits = item.getClazzNo().replaceAll("\\D+", "");
|
||||||
if (StringUtils.isNotBlank(digits)) {
|
if (StringUtils.isNotBlank(digits)) {
|
||||||
@@ -507,6 +579,8 @@ public class SchStudentImportService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
saveStudentList.add(stu);
|
saveStudentList.add(stu);
|
||||||
|
classIds.add(stu.getClassId());
|
||||||
|
currentRow++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. 若有错误,抛出异常(携带明细)
|
// 5. 若有错误,抛出异常(携带明细)
|
||||||
|
|||||||
+7
-2
@@ -450,7 +450,7 @@ public class SchStudentLogService {
|
|||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
List<OperationLogRecord> logs = new ArrayList<>();
|
List<OperationLogRecord> logs = new ArrayList<>();
|
||||||
for (SchStudent stu : saveStudentList) {
|
for (SchStudent stu : saveStudentList) {
|
||||||
String content = "";
|
String content;
|
||||||
Optional<SchClass> schClassOpt = schClassList.stream()
|
Optional<SchClass> schClassOpt = schClassList.stream()
|
||||||
.filter(s -> s.getClassId().equals(stu.getClassId()))
|
.filter(s -> s.getClassId().equals(stu.getClassId()))
|
||||||
.findFirst();
|
.findFirst();
|
||||||
@@ -461,8 +461,12 @@ public class SchStudentLogService {
|
|||||||
.map(SelectIntVO::getName)
|
.map(SelectIntVO::getName)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse("未知年级");
|
.orElse("未知年级");
|
||||||
content = "导入学生[" + stu.getName() + "]学号["+stu.getStuClassNo()+"]】成功,用户信息:"
|
content = "导入学生[" + stu.getName() + "]学号[" + stu.getStuClassNo() + "]成功,用户信息:"
|
||||||
|
+ JSON.toJSONString(stu, NO_PWD_FILTER)
|
||||||
+ ",所在年级班级:" + gradeName + schClassOpt.get().getName();
|
+ ",所在年级班级:" + gradeName + schClassOpt.get().getName();
|
||||||
|
} else {
|
||||||
|
content = "导入学生[" + stu.getName() + "]学号[" + stu.getStuClassNo() + "]成功,用户信息:"
|
||||||
|
+ JSON.toJSONString(stu, NO_PWD_FILTER) + ",班级:未知";
|
||||||
}
|
}
|
||||||
OperationLogRecord log = logService.buildLogRecord(user, MODULE_STUDENT, content, now);
|
OperationLogRecord log = logService.buildLogRecord(user, MODULE_STUDENT, content, now);
|
||||||
logs.add(log);
|
logs.add(log);
|
||||||
@@ -470,6 +474,7 @@ public class SchStudentLogService {
|
|||||||
if (!logs.isEmpty()) {
|
if (!logs.isEmpty()) {
|
||||||
logService.saveAllLogAsync(logs);
|
logService.saveAllLogAsync(logs);
|
||||||
}
|
}
|
||||||
|
log.debug("操作人:{},学生学号导入日志成功: {}", user.getUserName(), JSON.toJSONString(saveStudentList, NO_PWD_FILTER));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("操作人:" + user.getUserName() + ",学生学号导入日志失败: {}", e.getMessage(), e);
|
log.error("操作人:" + user.getUserName() + ",学生学号导入日志失败: {}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user