导入同步修改
This commit is contained in:
@@ -184,6 +184,14 @@ public class SchStudentController extends BaseController {
|
||||
ruleList.add(rule);
|
||||
}
|
||||
|
||||
{
|
||||
ImportRuleExcelColumn rule = new ImportRuleExcelColumn();
|
||||
rule.setRuleItem("密码");
|
||||
rule.setDescription("验证规则");
|
||||
rule.setContent("长度 8-32;必须同时包含字母、数字、符号;不允许出现连续自然数序列(如 1234、6789)。");
|
||||
ruleList.add(rule);
|
||||
}
|
||||
|
||||
ExportParams params1 = new ExportParams("学生导入",comSchTreeService.getSchoolName(schId));
|
||||
|
||||
Map<String, Object> sheet1 = new HashMap<>();
|
||||
|
||||
@@ -47,4 +47,11 @@ public class SyncUserController {
|
||||
List<SyncUserDTO> userList = OtherUtil.jsonParseList(jsonString, SyncUserDTO.class);
|
||||
syncUserService.syncAddOrUpdate(userList,true);
|
||||
}
|
||||
|
||||
@SyncOpLog(SyncDataType.SYNC_MOVE_USER)
|
||||
@PostMapping("moveUser")
|
||||
public void SyncMoveUser(@RequestBody String jsonString) {
|
||||
List<SyncUserDTO> userList = OtherUtil.jsonParseList(jsonString, SyncUserDTO.class);
|
||||
syncUserService.syncAddOrUpdate(userList,true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ public enum SyncDataType
|
||||
SYNC_ADD_USER("Sync-AddUser","添加用户"),
|
||||
SYNC_EDIT_USER("Sync-UpdateUser","编辑用户"),
|
||||
SYNC_DELETE_USER("Sync-DeleteUser","删除用户"),
|
||||
SYNC_MOVE_USER("Sync-MoveUser","用户移组"),
|
||||
SYNC_USER("Sync-SyncUser","全量用户"),
|
||||
|
||||
//推送
|
||||
@@ -34,7 +35,12 @@ public enum SyncDataType
|
||||
|
||||
SEND_ADD_STUDENT("Send-AddStudent","添加学生"),
|
||||
SEND_EDIT_STUDENT("Send-UpdateStudent","编辑学生"),
|
||||
SEND_DELETE_STUDENT("Send-DeleteStudent","删除学生");
|
||||
SEND_DELETE_STUDENT("Send-DeleteStudent","删除学生"),
|
||||
|
||||
SEND_MOVE_TEACHER("Send-MoveTeacher","教师移组"),
|
||||
SEND_MOVE_STUDENT("Send-MoveStudent","学生调班"),
|
||||
SEND_BATCH_TEACHER("Send-BatchAddTeacher","批量添加教师"),
|
||||
SEND_BATCH_STUDENT("Send-BatchAddStudent","批量添加学生");
|
||||
|
||||
private String key;
|
||||
private String name;
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
package com.yunhai.bschclassmanage.model.dto;
|
||||
|
||||
import com.yunhai.bschclassmanage.entity.SchStudent;
|
||||
import com.yunhai.bschclassmanage.model.vo.SchStudentVO;
|
||||
import com.yunhai.bschclassmanage.validation.PasswordCheckable;
|
||||
import com.yunhai.bschclassmanage.validation.PasswordValidation;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
public class SchStudentDTO extends SchStudentVO {
|
||||
@PasswordValidation
|
||||
public class SchStudentDTO extends SchStudent implements PasswordCheckable {
|
||||
|
||||
private String pwd;
|
||||
/** 密码校验见类级 @PasswordValidation:新增(id为null或<=0)必填且校验强度;更新(id>0)时密码为空跳过、非空则同样校验强度 */
|
||||
private String pwd;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.yunhai.bschclassmanage.model.dto;
|
||||
|
||||
import com.yunhai.bschclassmanage.entity.SchTeacher;
|
||||
import com.yunhai.bschclassmanage.validation.PasswordCheckable;
|
||||
import com.yunhai.bschclassmanage.validation.PasswordValidation;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
@@ -8,19 +10,20 @@ import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SchTeacherDTO extends SchTeacher {
|
||||
@PasswordValidation
|
||||
public class SchTeacherDTO extends SchTeacher implements PasswordCheckable {
|
||||
|
||||
@NotNull(message = "组ID不能为空")
|
||||
@Min(value = 1, message = "至少选择一个组")
|
||||
private Integer groupId;
|
||||
|
||||
private String pwd;
|
||||
/** 密码校验见类级 @PasswordValidation:新增(id为null或<=0)必填且校验强度;更新(id>0)时密码为空跳过、非空则同样校验强度 */
|
||||
private String pwd;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.yunhai.bschclassmanage.model.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Data
|
||||
public class SendMoveGroupUserDTO {
|
||||
@NotNull(message = "请选择移动教师")
|
||||
private Integer userId;
|
||||
@NotNull(message = "请选择移动组")
|
||||
private Integer groupId;
|
||||
}
|
||||
@@ -5,8 +5,7 @@ import com.yunhai.bschclassmanage.entity.SchTeacher;
|
||||
import com.yunhai.bschclassmanage.enums.NodeType;
|
||||
import com.yunhai.bschclassmanage.model.dto.SchStudentDTO;
|
||||
import com.yunhai.bschclassmanage.model.dto.SchTeacherDTO;
|
||||
import com.yunhai.bschclassmanage.model.tool.DeleteUser;
|
||||
import com.yunhai.bschclassmanage.model.tool.SyncUserDTO;
|
||||
import com.yunhai.bschclassmanage.model.dto.SendMoveGroupUserDTO;
|
||||
import com.yunhai.platform.utils.model.BoaGroup;
|
||||
import com.yunhai.platform.utils.model.BoaUser;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -35,4 +34,18 @@ public interface ISendUserBaseService {
|
||||
void deleteTeachers(List<Integer> userIds,Integer groupId,Integer schId);
|
||||
|
||||
void deleteStudents(List<Integer> userIds,Integer groupId,Integer schId);
|
||||
|
||||
/** 导入失败回滚:删除已推送成功的学生平台账号(syncedList 与 groupIds 按下标一一对应) */
|
||||
void rollbackSyncedStudents(List<BoaUser> syncedList, List<Integer> groupIds, Integer schId);
|
||||
|
||||
/** 导入失败回滚:删除已推送成功的教师平台账号(syncedList 与 groupIds 按下标一一对应) */
|
||||
void rollbackSyncedTeachers(List<BoaUser> syncedList, List<Integer> groupIds, Integer schId);
|
||||
|
||||
void moveTeacherToGroup(List<SendMoveGroupUserDTO> teacherList, Integer schId);
|
||||
|
||||
void moveStudentToGroup(List<Integer> stuIds,Integer classId,Integer schId);
|
||||
|
||||
List<BoaUser> batchAddStudent(List<SchStudentDTO> stuList);
|
||||
|
||||
List<BoaUser> batchAddTeacher(List<SchTeacherDTO> teacherList);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import com.yunhai.bschclassmanage.utils.UserContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
@@ -90,8 +89,8 @@ public class SchStudentService implements ISchStudentService {
|
||||
@OperationLog(module = LogModule.STUDENT)
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void saveStudent(UserContext.UserInfo user, SchStudentDTO entityVO) {
|
||||
infoService.saveStudent(user, entityVO);
|
||||
public void saveStudent(UserContext.UserInfo user, SchStudentDTO entityDTO) {
|
||||
infoService.saveStudent(user, entityDTO);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
|
||||
+120
-23
@@ -6,13 +6,13 @@ import com.yunhai.bschclassmanage.enums.NodeType;
|
||||
import com.yunhai.bschclassmanage.enums.UserRole;
|
||||
import com.yunhai.bschclassmanage.annotation.SyncOpLog;
|
||||
import com.yunhai.bschclassmanage.enums.SyncDataType;
|
||||
import com.yunhai.bschclassmanage.model.dto.SchStudentDTO;
|
||||
import com.yunhai.bschclassmanage.model.dto.SchTeacherDTO;
|
||||
import com.yunhai.bschclassmanage.model.dto.SendMoveGroupUserDTO;
|
||||
import com.yunhai.bschclassmanage.service.IComSchTreeService;
|
||||
import com.yunhai.bschclassmanage.service.ISendUserBaseService;
|
||||
import com.yunhai.platform.openapi.client.YschBaseOpenApi;
|
||||
import com.yunhai.platform.openapi.model.SysGroupMoveRequest;
|
||||
import com.yunhai.platform.openapi.model.SysGroupRequest;
|
||||
import com.yunhai.platform.openapi.model.SysUserGroupDeleteItem;
|
||||
import com.yunhai.platform.openapi.model.SysUserRequest;
|
||||
import com.yunhai.platform.openapi.model.*;
|
||||
import com.yunhai.platform.utils.exception.DException;
|
||||
import com.yunhai.platform.utils.model.BoaGroup;
|
||||
import com.yunhai.platform.utils.model.BoaUser;
|
||||
@@ -181,23 +181,120 @@ public class SendUserBaseService implements ISendUserBaseService {
|
||||
}
|
||||
}
|
||||
|
||||
// public void moveTeachertToGroup(List<SchTeacherDTO> teacherList){
|
||||
// for (SchTeacherDTO teacher :teacherList) {
|
||||
// SysUserMoveRequest move=new SysUserMoveRequest();
|
||||
// move.setUserId();
|
||||
// move.setGroupId();
|
||||
// move.setSchoolId();
|
||||
// YschBaseOpenApi.moveUserToGroup(teacher.getTeaId(),teacher.getGroupId());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public void moveStudentToGroup(List<SchTeacherDTO> teacherList){
|
||||
// for (SchTeacherDTO teacher :teacherList) {
|
||||
// SysUserMoveRequest move=new SysUserMoveRequest();
|
||||
// move.setUserId();
|
||||
// move.setGroupId();
|
||||
// move.setSchoolId();
|
||||
// YschBaseOpenApi.moveUserToGroup(teacher.getTeaId(),teacher.getGroupId());
|
||||
// }
|
||||
// }
|
||||
/**
|
||||
* 导入失败回滚:删除已成功推送到平台的学生账号,避免孤儿账号。
|
||||
* syncedList 与 groupIds 按下标一一对应(groupId 取自主组 classId)。
|
||||
*/
|
||||
public void rollbackSyncedStudents(List<BoaUser> syncedList, List<Integer> groupIds, Integer schId) {
|
||||
if (syncedList == null || syncedList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
int n = Math.min(syncedList.size(), groupIds == null ? 0 : groupIds.size());
|
||||
for (int i = 0; i < n; i++) {
|
||||
BoaUser boaUser = syncedList.get(i);
|
||||
if (boaUser == null) {
|
||||
continue;
|
||||
}
|
||||
Integer groupId = groupIds.get(i);
|
||||
if (groupId != null) {
|
||||
deleteStudents(Collections.singletonList(boaUser.getId()), groupId, schId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入失败回滚:删除已成功推送到平台的教师账号,避免孤儿账号。
|
||||
* syncedList 与 groupIds 按下标一一对应(groupId 取自主组)。
|
||||
*/
|
||||
public void rollbackSyncedTeachers(List<BoaUser> syncedList, List<Integer> groupIds, Integer schId) {
|
||||
if (syncedList == null || syncedList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
int n = Math.min(syncedList.size(), groupIds == null ? 0 : groupIds.size());
|
||||
for (int i = 0; i < n; i++) {
|
||||
BoaUser boaUser = syncedList.get(i);
|
||||
if (boaUser == null) {
|
||||
continue;
|
||||
}
|
||||
Integer groupId = groupIds.get(i);
|
||||
if (groupId != null) {
|
||||
deleteTeachers(Collections.singletonList(boaUser.getId()), groupId, schId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//移动教师
|
||||
@SyncOpLog(SyncDataType.SEND_MOVE_TEACHER)
|
||||
public void moveTeacherToGroup(List<SendMoveGroupUserDTO> teacherList,Integer schId){
|
||||
for (SendMoveGroupUserDTO teacher :teacherList) {
|
||||
SysUserMoveRequest move=new SysUserMoveRequest();
|
||||
move.setUserId(teacher.getUserId());
|
||||
move.setGroupId(teacher.getGroupId());
|
||||
YschBaseOpenApi.moveUserToGroup(move);
|
||||
}
|
||||
}
|
||||
|
||||
//学生调班
|
||||
@SyncOpLog(SyncDataType.SEND_MOVE_STUDENT)
|
||||
public void moveStudentToGroup(List<Integer> stuIds,Integer classId,Integer schId){
|
||||
for (Integer stuId :stuIds) {
|
||||
SysUserMoveRequest move=new SysUserMoveRequest();
|
||||
move.setUserId(stuId);
|
||||
move.setGroupId(classId);
|
||||
move.setSchoolId(schId);
|
||||
YschBaseOpenApi.moveUserToGroup(move);
|
||||
}
|
||||
}
|
||||
|
||||
@SyncOpLog(SyncDataType.SEND_BATCH_STUDENT)
|
||||
public List<BoaUser> batchAddStudent(List<SchStudentDTO> stuList){
|
||||
if (stuList == null || stuList.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<SysUserRequest> requests = new ArrayList<>();
|
||||
for (SchStudentDTO stu : stuList) {
|
||||
SysUserRequest sysUser = new SysUserRequest();
|
||||
sysUser.setAccount(stu.getAccount());
|
||||
sysUser.setRealName(stu.getName());
|
||||
sysUser.setGender(stu.getGender());
|
||||
sysUser.setIdcard(stu.getIdCard());
|
||||
sysUser.setGroupId(stu.getGroupId());
|
||||
sysUser.setRoles(Arrays.asList(UserRole.STU_USER.getValue()));
|
||||
String pwd = stu.getPwd();
|
||||
if (StringUtils.isNotBlank(pwd)) {
|
||||
sysUser.setPassword(pwd);
|
||||
sysUser.setConfirmPassword(pwd);
|
||||
}
|
||||
requests.add(sysUser);
|
||||
}
|
||||
return YschBaseOpenApi.batchAddUsers(requests);
|
||||
}
|
||||
|
||||
@SyncOpLog(SyncDataType.SEND_BATCH_TEACHER)
|
||||
public List<BoaUser> batchAddTeacher(List<SchTeacherDTO> teacherList)
|
||||
{
|
||||
if (teacherList == null || teacherList.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<SysUserRequest> requests = new ArrayList<>();
|
||||
for (SchTeacherDTO teacher : teacherList) {
|
||||
SysUserRequest sysUser = new SysUserRequest();
|
||||
sysUser.setAccount(teacher.getAccount());
|
||||
sysUser.setRealName(teacher.getName());
|
||||
sysUser.setGender(teacher.getGender());
|
||||
sysUser.setIdcard(teacher.getIdCard());
|
||||
sysUser.setPhone(teacher.getTel());
|
||||
sysUser.setGroupId(teacher.getGroupId());
|
||||
sysUser.setRoles(Arrays.asList(UserRole.TEACHER_USER.getValue()));
|
||||
String pwd = teacher.getPwd();
|
||||
if (StringUtils.isNotBlank(pwd)) {
|
||||
sysUser.setPassword(pwd);
|
||||
sysUser.setConfirmPassword(pwd);
|
||||
}
|
||||
requests.add(sysUser);
|
||||
}
|
||||
return YschBaseOpenApi.batchAddUsers(requests);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+42
-14
@@ -12,6 +12,7 @@ import com.yunhai.bschclassmanage.enums.StuAbnormalStatus;
|
||||
import com.yunhai.bschclassmanage.enums.TransferStatus;
|
||||
import com.yunhai.bschclassmanage.enums.UserGender;
|
||||
import com.yunhai.bschclassmanage.enums.UserStatus;
|
||||
import com.yunhai.bschclassmanage.model.dto.SchStudentDTO;
|
||||
import com.yunhai.bschclassmanage.model.excel.ErrorExcelColumn;
|
||||
import com.yunhai.bschclassmanage.model.excel.StudentClassNoExcelColumn;
|
||||
import com.yunhai.bschclassmanage.model.excel.StudentExcelColumn;
|
||||
@@ -20,10 +21,13 @@ import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||
import com.yunhai.bschclassmanage.service.IBaseSchsystemGradeService;
|
||||
import com.yunhai.bschclassmanage.service.IComSchTreeService;
|
||||
import com.yunhai.bschclassmanage.service.ISchClassService;
|
||||
import com.yunhai.bschclassmanage.service.ISendUserBaseService;
|
||||
import com.yunhai.bschclassmanage.utils.EasyPoiUtils;
|
||||
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||
import com.yunhai.bschclassmanage.utils.ValidateUtil;
|
||||
import com.yunhai.bschclassmanage.utils.ValidationUtil;
|
||||
import com.yunhai.platform.openapi.client.YschBaseOpenApi;
|
||||
import com.yunhai.platform.utils.model.BoaUser;
|
||||
import com.yunhai.platform.utils.exception.DException;
|
||||
import com.yunhai.platform.utils.exception.ErrorCode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -59,6 +63,10 @@ public class SchStudentImportService {
|
||||
@Autowired
|
||||
private IComSchTreeService comSchTreeService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private ISendUserBaseService sendUserBaseService;
|
||||
|
||||
@Autowired
|
||||
private SchStudentCacheService cacheService;
|
||||
|
||||
@@ -77,6 +85,9 @@ public class SchStudentImportService {
|
||||
Integer userId = user.getUserId();
|
||||
|
||||
Date now = new Date();
|
||||
// 提到 try 外,供 catch 回滚时访问
|
||||
List<SchStudentDTO> saveStudentList = new ArrayList<>();
|
||||
List<BoaUser> syncStudentList = null;
|
||||
// 使用 try-with-resources 确保流关闭
|
||||
try (InputStream is = file.getInputStream()) {
|
||||
// 1. 加载基础数据(放在 try 内,若加载失败也回滚)
|
||||
@@ -109,7 +120,6 @@ public class SchStudentImportService {
|
||||
}
|
||||
|
||||
// 4. 业务校验与转换
|
||||
List<SchStudent> saveStudentList = new ArrayList<>();
|
||||
int currentRow = params.getTitleRows() + params.getHeadRows() + 1; // 从第3行开始
|
||||
|
||||
for (StudentExcelColumn item : list) {
|
||||
@@ -122,8 +132,7 @@ public class SchStudentImportService {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
SchStudent stu = new SchStudent();
|
||||
|
||||
SchStudentDTO stu = new SchStudentDTO();
|
||||
// 账号
|
||||
{
|
||||
Optional<SchStudent> accountOpt = schStudentRepository.findByAccount(item.getAccount());
|
||||
@@ -133,10 +142,12 @@ public class SchStudentImportService {
|
||||
"禁止将" + comSchTreeService.getSchoolName(accountOpt.get().getSchId()) + "正常学生导入!"));
|
||||
continue;
|
||||
} else {
|
||||
BeanUtils.copyProperties(accountOpt.get(), stu);
|
||||
stu.setUpdateDate(now);
|
||||
stu.setUpdateUserId(userId);
|
||||
oldClassId = accountOpt.get().getClassId();
|
||||
errorMsgArr.add(new ErrorExcelColumn(currentRow, item.getStuName(),"学生账号已存在!"));
|
||||
continue;
|
||||
// BeanUtils.copyProperties(accountOpt.get(), stu);
|
||||
// stu.setUpdateDate(now);
|
||||
// stu.setUpdateUserId(userId);
|
||||
// oldClassId = accountOpt.get().getClassId();
|
||||
}
|
||||
} else {
|
||||
stu.setId(0);
|
||||
@@ -190,7 +201,7 @@ public class SchStudentImportService {
|
||||
}
|
||||
|
||||
// 密码(暂时忽略,或可设置默认密码,但原代码无处理)
|
||||
|
||||
stu.setPwd(item.getPassword());
|
||||
// 身份证
|
||||
if (StringUtils.isNotBlank(item.getIdCard())) {
|
||||
if (!ValidateUtil.isValidIdCard(item.getIdCard())) {
|
||||
@@ -250,19 +261,36 @@ public class SchStudentImportService {
|
||||
throw new DException(ErrorCode.CUSTOM,"导入失败,请检查错误列表",errorMsgArr);
|
||||
}
|
||||
|
||||
// 6. 批量保存
|
||||
schStudentRepository.saveAll(saveStudentList);
|
||||
// 6. 先推送平台用户(返回平台用户ID),顺序与 saveStudentList 一致
|
||||
syncStudentList = sendUserBaseService.batchAddStudent(saveStudentList);
|
||||
// 按顺序回填平台用户ID(stuId),batchAddUsers 返回顺序与传入一致
|
||||
for (int i = 0; i < saveStudentList.size(); i++) {
|
||||
if (i < syncStudentList.size() && syncStudentList.get(i) != null) {
|
||||
saveStudentList.get(i).setStuId(syncStudentList.get(i).getId());
|
||||
}
|
||||
}
|
||||
|
||||
// 7. 异步记录导入日志
|
||||
logService.importLogs(user, saveStudentList, gradeList, schClassList);
|
||||
// 7. DTO 不能直接传给 saveAll(泛型不变性:List<SchStudentDTO> 非 List<SchStudent>),转实体并保留已回填的 stuId
|
||||
List<SchStudent> studentEntities = saveStudentList.stream().map(dto -> {
|
||||
SchStudent s = new SchStudent();
|
||||
BeanUtils.copyProperties(dto, s);
|
||||
return s;
|
||||
}).collect(Collectors.toList());
|
||||
List<SchStudent> savedStudentList = schStudentRepository.saveAll(studentEntities);
|
||||
|
||||
// 8. 清除受影响的班级缓存
|
||||
// 8. 异步记录导入日志
|
||||
logService.importLogs(user, savedStudentList, gradeList, schClassList);
|
||||
|
||||
// 9. 清除受影响的班级缓存
|
||||
cacheService.clearClassStudentCaches(schId, classIds);
|
||||
|
||||
} catch (DException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
// 其他所有未预期的异常(包括数据库、IO等)
|
||||
// 导入失败:回滚已成功推送到平台的学生账号,避免孤儿账号
|
||||
List<Integer> groupIds = saveStudentList.stream()
|
||||
.map(SchStudentDTO::getGroupId).collect(Collectors.toList());
|
||||
sendUserBaseService.rollbackSyncedStudents(syncStudentList, groupIds, schId);
|
||||
log.error("导入班级学生时发生系统异常,操作人:" + user.getUserName(), e);
|
||||
throw new DException(ErrorCode.INTERNAL_SERVER_ERROR,"导入失败,请联系管理员",null,e);
|
||||
}
|
||||
|
||||
+13
-4
@@ -1,6 +1,7 @@
|
||||
package com.yunhai.bschclassmanage.service.impl.student;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.SimplePropertyPreFilter;
|
||||
import com.yunhai.bschclassmanage.Repository.SchClassRepository;
|
||||
import com.yunhai.bschclassmanage.entity.OperationLogRecord;
|
||||
import com.yunhai.bschclassmanage.entity.SchClass;
|
||||
@@ -8,6 +9,7 @@ import com.yunhai.bschclassmanage.entity.SchStudent;
|
||||
import com.yunhai.bschclassmanage.enums.StuAbnormalStatus;
|
||||
import com.yunhai.bschclassmanage.enums.TransferStatus;
|
||||
import com.yunhai.bschclassmanage.model.constant.LogModule;
|
||||
import com.yunhai.bschclassmanage.model.dto.SchStudentDTO;
|
||||
import com.yunhai.bschclassmanage.model.vo.BaseSchClassVO;
|
||||
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||
import com.yunhai.bschclassmanage.service.IBaseSchsystemGradeService;
|
||||
@@ -37,6 +39,13 @@ public class SchStudentLogService {
|
||||
@Autowired
|
||||
private ILogService logService;
|
||||
|
||||
/** 学生对象序列化时排除敏感字段(密码),防止明文进入日志内容/调试日志 */
|
||||
private static final SimplePropertyPreFilter NO_PWD_FILTER = new SimplePropertyPreFilter();
|
||||
|
||||
static {
|
||||
NO_PWD_FILTER.getExcludes().add("pwd");
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private ISchClassService schClassService;
|
||||
|
||||
@@ -387,7 +396,7 @@ public class SchStudentLogService {
|
||||
if (!logRecords.isEmpty()) {
|
||||
logService.saveAllLogAsync(logRecords);
|
||||
}
|
||||
log.debug("操作人:{},删除学生日志:{}", user.getUserName(), JSON.toJSONString(students));
|
||||
log.debug("操作人:{},删除学生日志:{}", user.getUserName(), JSON.toJSONString(students, NO_PWD_FILTER));
|
||||
} catch (Exception e) {
|
||||
log.error("记录批量删除学生日志失败", e);
|
||||
}
|
||||
@@ -414,10 +423,10 @@ public class SchStudentLogService {
|
||||
.map(SelectIntVO::getName)
|
||||
.findFirst()
|
||||
.orElse("未知年级");
|
||||
content = "导入学生[" + stu.getName() + "]成功,用户信息:" + JSON.toJSONString(stu)
|
||||
content = "导入学生[" + stu.getName() + "]成功,用户信息:" + JSON.toJSONString(stu, NO_PWD_FILTER)
|
||||
+ ",所在年级班级:" + gradeName + schClassOpt.get().getName();
|
||||
} else {
|
||||
content = "导入学生[" + stu.getName() + "]成功,用户信息:" + JSON.toJSONString(stu) + ",班级:未知";
|
||||
content = "导入学生[" + stu.getName() + "]成功,用户信息:" + JSON.toJSONString(stu, NO_PWD_FILTER) + ",班级:未知";
|
||||
}
|
||||
OperationLogRecord log = logService.buildLogRecord(user, MODULE_STUDENT, content, now);
|
||||
logs.add(log);
|
||||
@@ -425,7 +434,7 @@ public class SchStudentLogService {
|
||||
if (!logs.isEmpty()) {
|
||||
logService.saveAllLogAsync(logs);
|
||||
}
|
||||
log.debug("操作人:{},学生导入日志成功: {}", user.getUserName(), JSON.toJSONString(saveStudentList));
|
||||
log.debug("操作人:{},学生导入日志成功: {}", user.getUserName(), JSON.toJSONString(saveStudentList, NO_PWD_FILTER));
|
||||
} catch (Exception e) {
|
||||
log.error("操作人:" + user.getUserName() + ",学生导入日志失败: {}", e.getMessage(), e);
|
||||
}
|
||||
|
||||
+6
@@ -5,6 +5,7 @@ import com.yunhai.bschclassmanage.Repository.SchStudentRepository;
|
||||
import com.yunhai.bschclassmanage.entity.SchStudent;
|
||||
import com.yunhai.bschclassmanage.enums.TransferStatus;
|
||||
import com.yunhai.bschclassmanage.model.dto.StuTransferClassDTO;
|
||||
import com.yunhai.bschclassmanage.service.ISendUserBaseService;
|
||||
import com.yunhai.bschclassmanage.utils.RedisConstants;
|
||||
import com.yunhai.bschclassmanage.utils.RedisUtil;
|
||||
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||
@@ -34,6 +35,9 @@ public class SchStudentTransferService {
|
||||
@Autowired
|
||||
private SchStudentCacheService cacheService;
|
||||
|
||||
@Autowired
|
||||
private ISendUserBaseService sendUserBaseService;
|
||||
|
||||
@Autowired
|
||||
private SchStudentLogService logService;
|
||||
|
||||
@@ -93,6 +97,8 @@ public class SchStudentTransferService {
|
||||
// 清除缓存(新旧班级都要清除)
|
||||
cacheService.clearClassStudentCaches(schId, affectedClassIds);
|
||||
|
||||
sendUserBaseService.moveStudentToGroup(model.getStuIds(),model.getTransferClassId(),schId);
|
||||
|
||||
// 异步记录操作日志
|
||||
logService.transferClassLogs(user, students, targetClassId, affectedClassIds);
|
||||
}
|
||||
|
||||
+48
-8
@@ -9,15 +9,18 @@ import com.yunhai.bschclassmanage.entity.SchTeacherGroup;
|
||||
import com.yunhai.bschclassmanage.enums.TransferStatus;
|
||||
import com.yunhai.bschclassmanage.enums.UserGender;
|
||||
import com.yunhai.bschclassmanage.enums.UserStatus;
|
||||
import com.yunhai.bschclassmanage.model.dto.SchTeacherDTO;
|
||||
import com.yunhai.bschclassmanage.model.excel.ErrorExcelColumn;
|
||||
import com.yunhai.bschclassmanage.model.excel.TeacherExcelColumn;
|
||||
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||
import com.yunhai.bschclassmanage.service.IComSchTreeService;
|
||||
import com.yunhai.bschclassmanage.service.ISendUserBaseService;
|
||||
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||
import com.yunhai.bschclassmanage.utils.ValidateUtil;
|
||||
import com.yunhai.bschclassmanage.utils.ValidationUtil;
|
||||
import com.yunhai.platform.utils.exception.DException;
|
||||
import com.yunhai.platform.utils.exception.ErrorCode;
|
||||
import com.yunhai.platform.utils.model.BoaUser;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
@@ -44,6 +47,10 @@ public class SchTeacherImportService {
|
||||
@Autowired
|
||||
private IComSchTreeService comSchTreeService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private ISendUserBaseService sendUserBaseService;
|
||||
|
||||
@Autowired
|
||||
private SchTeacherCacheService cacheService;
|
||||
|
||||
@@ -59,6 +66,9 @@ public class SchTeacherImportService {
|
||||
Integer userId = user.getUserId();
|
||||
|
||||
Date now = new Date();
|
||||
// 提到 try 外,供 catch 回滚时访问
|
||||
List<SchTeacherDTO> teachers = new ArrayList<>();
|
||||
List<BoaUser> syncTeacherList = null;
|
||||
try {
|
||||
List<SelectIntVO> teaGroupNameList = comSchTreeService.getTeaGroupNameList(schId, null);
|
||||
List<TeacherExcelColumn> list = ExcelImportUtil.importExcel(file.getInputStream(), TeacherExcelColumn.class, params);
|
||||
@@ -69,10 +79,9 @@ public class SchTeacherImportService {
|
||||
|
||||
List<SchTeacher> teachersByAccounts = getTeachersByAccounts(accountList);
|
||||
List<SchTeacher> schTeacherList = cacheService.getSchTeacherList(schId);
|
||||
List<SchTeacher> teachers = new ArrayList<>();
|
||||
int rows = 0;
|
||||
for (TeacherExcelColumn item : list) {
|
||||
SchTeacher teacher = new SchTeacher();
|
||||
SchTeacherDTO teacher = new SchTeacherDTO();
|
||||
List<SchTeacherGroup> teacherGroupList = new ArrayList<>();
|
||||
|
||||
rows += 2;
|
||||
@@ -85,14 +94,17 @@ public class SchTeacherImportService {
|
||||
}
|
||||
Optional<SchTeacher> schTeacherOpt = teachersByAccounts.stream().filter(s -> s.getAccount().equals(item.getAccount())).findFirst();
|
||||
if (schTeacherOpt.isPresent()) {
|
||||
BeanUtils.copyProperties(schTeacherOpt.get(), teacher);
|
||||
teacher.setUpdateDate(now);
|
||||
teacher.setUpdateUserId(userId);
|
||||
// BeanUtils.copyProperties(schTeacherOpt.get(), teacher);
|
||||
// teacher.setUpdateDate(now);
|
||||
// teacher.setUpdateUserId(userId);
|
||||
errorMsgArr.add(new ErrorExcelColumn(rows, item.getAccount(), TeacherExcelColumn.ACCOUNT + "教师已存在!"));
|
||||
continue;
|
||||
} else {
|
||||
teacher.setCreateDate(now);
|
||||
teacher.setCreateUserId(userId);
|
||||
teacher.setAccount(item.getAccount());
|
||||
teacher.setStatus(UserStatus.NORMAL.getId());
|
||||
teacher.setPwd(item.getPassword());
|
||||
}
|
||||
}
|
||||
//姓名
|
||||
@@ -133,6 +145,10 @@ public class SchTeacherImportService {
|
||||
teacherGroupList.add(teacherGroup);
|
||||
}
|
||||
teacher.setGroupList(teacherGroupList);
|
||||
// 主组取第一个组(DTO.groupId 有 @NotNull/@Min 校验,平台推送 batchAddTeacher 也需要主组)
|
||||
if (!teacherGroupList.isEmpty()) {
|
||||
teacher.setGroupId(teacherGroupList.get(0).getGroupId());
|
||||
}
|
||||
}
|
||||
//身份证
|
||||
{
|
||||
@@ -190,13 +206,30 @@ public class SchTeacherImportService {
|
||||
throw new DException(ErrorCode.CUSTOM,"导入失败,请检查错误列表",errorMsgArr);
|
||||
}
|
||||
|
||||
List<SchTeacher> saveList = schTeacherRepository.saveAll(teachers);
|
||||
// 推送平台用户:必须用原 DTO 列表(含 pwd);saveAll 返回的实体不含密码
|
||||
syncTeacherList = sendUserBaseService.batchAddTeacher(teachers);
|
||||
// 按顺序回填平台用户ID(batchAddUsers 返回顺序与传入一致)
|
||||
for (int i = 0; i < teachers.size(); i++) {
|
||||
if (i < syncTeacherList.size() && syncTeacherList.get(i) != null) {
|
||||
teachers.get(i).setTeaId(syncTeacherList.get(i).getId());
|
||||
}
|
||||
}
|
||||
|
||||
// DTO 不能直接传给 saveAll(泛型不变性:List<SchTeacherDTO> 非 List<SchTeacher>),需转实体并保留已回填的 teaId/groupList
|
||||
List<SchTeacher> teacherEntities = teachers.stream().map(dto -> {
|
||||
SchTeacher t = new SchTeacher();
|
||||
BeanUtils.copyProperties(dto, t);
|
||||
return t;
|
||||
}).collect(Collectors.toList());
|
||||
List<SchTeacher> saveList = schTeacherRepository.saveAll(teacherEntities);
|
||||
|
||||
|
||||
|
||||
List<SchTeacherGroup> schTeacherGroupList = new ArrayList<>();
|
||||
for (SchTeacher teacher : saveList) {
|
||||
teacher.setTeaId(teacher.getId());
|
||||
// teaId 已是平台推送返回的用户ID(batchAddTeacher 已回填),勿用本地 id 覆盖
|
||||
for (SchTeacherGroup group : teacher.getGroupList()) {
|
||||
group.setTeaId(teacher.getId());
|
||||
group.setTeaId(teacher.getTeaId());
|
||||
}
|
||||
schTeacherGroupList.addAll(teacher.getGroupList());
|
||||
}
|
||||
@@ -213,9 +246,16 @@ public class SchTeacherImportService {
|
||||
|
||||
// 清除缓存
|
||||
cacheService.clearTeacherCache(schId);
|
||||
|
||||
|
||||
|
||||
} catch (DException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
// 导入失败:回滚已成功推送到平台的教师账号,避免孤儿账号
|
||||
List<Integer> groupIds = teachers.stream()
|
||||
.map(SchTeacherDTO::getGroupId).collect(Collectors.toList());
|
||||
sendUserBaseService.rollbackSyncedTeachers(syncTeacherList, groupIds, schId);
|
||||
log.error("操作人:" + user.getUserName() + ",导入教师日志失败: {}", e.getMessage(), e);
|
||||
throw new DException("导入失败,请联系管理员! </br> 错误详情: </br>" + e.getMessage());
|
||||
}
|
||||
|
||||
+16
@@ -6,9 +6,11 @@ import com.yunhai.bschclassmanage.Repository.SchTeacherRepository;
|
||||
import com.yunhai.bschclassmanage.entity.SchTeacher;
|
||||
import com.yunhai.bschclassmanage.entity.SchTeacherGroup;
|
||||
import com.yunhai.bschclassmanage.enums.TransferStatus;
|
||||
import com.yunhai.bschclassmanage.model.dto.SendMoveGroupUserDTO;
|
||||
import com.yunhai.bschclassmanage.model.dto.TeaTransferGroupDTO;
|
||||
import com.yunhai.bschclassmanage.model.dto.TeaTransferInGroupDTO;
|
||||
import com.yunhai.bschclassmanage.service.IComSchTreeService;
|
||||
import com.yunhai.bschclassmanage.service.ISendUserBaseService;
|
||||
import com.yunhai.bschclassmanage.utils.OtherUtil;
|
||||
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||
import com.yunhai.platform.utils.exception.DException;
|
||||
@@ -42,6 +44,9 @@ public class SchTeacherRelationService {
|
||||
@Autowired
|
||||
private SchTeacherCacheService cacheService;
|
||||
|
||||
@Autowired
|
||||
private ISendUserBaseService sendUserBaseService;
|
||||
|
||||
@Autowired
|
||||
private SchTeacherLogService logService; // 异步日志
|
||||
|
||||
@@ -256,6 +261,17 @@ public class SchTeacherRelationService {
|
||||
schTeacherGroupRepository.saveAll(newRelations);
|
||||
}
|
||||
|
||||
List<SendMoveGroupUserDTO> teacherList = newRelations.stream()
|
||||
.map(rel -> {
|
||||
SendMoveGroupUserDTO dto = new SendMoveGroupUserDTO();
|
||||
dto.setUserId(rel.getTeaId());
|
||||
dto.setGroupId(rel.getGroupId());
|
||||
return dto;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
sendUserBaseService.moveTeacherToGroup(teacherList,schId);
|
||||
|
||||
// 清除缓存
|
||||
cacheService.clearTeacherCache(schId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user