This commit is contained in:
2026-08-14 12:19:17 +08:00
parent 7a549c87c6
commit ce0812211c
20 changed files with 260 additions and 279 deletions
@@ -4,6 +4,7 @@ import com.yunhai.bschclassmanage.Repository.SchInfoRepository;
import com.yunhai.bschclassmanage.entity.SchInfo;
import com.yunhai.bschclassmanage.enums.NodeType;
import com.yunhai.bschclassmanage.model.tool.BaseGroup;
import com.yunhai.bschclassmanage.model.tool.SyncGroupDTO;
import com.yunhai.bschclassmanage.service.ISyncGroupService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -19,7 +20,7 @@ public class SyncGroupService implements ISyncGroupService {
private SchInfoRepository schInfoRepository;
public void syncAddOrUpdate(BaseGroup group) {
public void syncAddOrUpdate(SyncGroupDTO group) {
//学校组 年级组 班级组
if(group.getType().equals(NodeType.SCHOOL.getId())){
@@ -37,7 +38,7 @@ public class SyncGroupService implements ISyncGroupService {
}
public void addOrUpdateSchool(BaseGroup group)
public void addOrUpdateSchool(SyncGroupDTO group)
{
Optional<SchInfo> schOpt=schInfoRepository.findBySchId(group.getId());
if(schOpt.isPresent()){
@@ -1,33 +1,31 @@
package com.yunhai.bschclassmanage.service.impl.sync;
import com.yunhai.bschclassmanage.Repository.SchInfoRepository;
import com.yunhai.bschclassmanage.Repository.SchStudentRepository;
import com.yunhai.bschclassmanage.Repository.SchTeacherGroupRepository;
import com.yunhai.bschclassmanage.Repository.SchTeacherRepository;
import com.yunhai.bschclassmanage.entity.SchInfo;
import com.yunhai.bschclassmanage.entity.SchStudent;
import com.yunhai.bschclassmanage.entity.SchTeacher;
import com.yunhai.bschclassmanage.entity.SchTeacherGroup;
import com.yunhai.bschclassmanage.enums.NodeType;
import com.yunhai.bschclassmanage.enums.StuAbnormalStatus;
import com.yunhai.bschclassmanage.enums.TransferStatus;
import com.yunhai.bschclassmanage.enums.UserRole;
import com.yunhai.bschclassmanage.model.tool.BaseGroup;
import com.yunhai.bschclassmanage.model.tool.BaseUser;
import com.yunhai.bschclassmanage.model.tool.DeleteUser;
import com.yunhai.bschclassmanage.service.ISchTeacherService;
import com.yunhai.bschclassmanage.model.tool.SyncUserDTO;
import com.yunhai.bschclassmanage.model.tool.SyncUserGroupDTO;
import com.yunhai.bschclassmanage.model.tool.SyncUserRoleDTO;
import com.yunhai.bschclassmanage.service.ISyncUserService;
import com.yunhai.bschclassmanage.service.impl.student.SchStudentCacheService;
import com.yunhai.bschclassmanage.service.impl.teacher.SchTeacherCacheService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@Slf4j
@Service
public class SyncUserService implements ISyncUserService {
@@ -47,18 +45,25 @@ public class SyncUserService implements ISyncUserService {
private SchTeacherCacheService schTeacherCacheService;
// ==================== 同步入口 ====================
@Override
@Transactional(rollbackFor = Exception.class)
public void syncAddOrUpdate(List<BaseUser> userList) {
public void syncAddOrUpdate(List<SyncUserDTO> userList) {
if (userList == null || userList.isEmpty()) return;
// 按角色分组
List<BaseUser> syncStudentList = new ArrayList<>();
List<BaseUser> syncTeacherList = new ArrayList<>();
// 按角色分组(每个用户只遍历一次 roleList)
List<SyncUserDTO> syncStudentList = new ArrayList<>();
List<SyncUserDTO> syncTeacherList = new ArrayList<>();
for (BaseUser user : userList) {
if (isStudent(user)) syncStudentList.add(user);
if (isTeacher(user)) syncTeacherList.add(user);
for (SyncUserDTO user : userList) {
Set<Integer> roleIds = collectRoleIds(user);
if (isStudent(roleIds)) {
syncStudentList.add(user);
} else if (isTeacher(roleIds)) {
syncTeacherList.add(user);
} else {
log.error("用户:{} 角色不符合同步要求!", user.getAccount());
}
}
Date now = new Date();
@@ -71,124 +76,112 @@ public class SyncUserService implements ISyncUserService {
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteUser(List<DeleteUser> deleteUserList) {
if (deleteUserList == null || deleteUserList.isEmpty()) return;
// 提取所有 userId
List<Integer> allUserIds = deleteUserList.stream()
.map(DeleteUser::getUserId)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
if (allUserIds.isEmpty()) return;
// ---------- 1. 物理删除学生 ----------
List<DeleteUser> studentDeletes = deleteUserList.stream()
// 过滤出有效的 (userId, groupId) 条目,仅计算一次
List<DeleteUser> validDeletes = deleteUserList.stream()
.filter(du -> du.getUserId() != null && du.getGroupId() != null)
.collect(Collectors.toList());
if (!studentDeletes.isEmpty()) {
// 批量查询学生
List<SchStudent> allStudents = schStudentRepository.findByStuIdIn(allUserIds);
Map<String, SchStudent> studentMap = allStudents.stream()
.collect(Collectors.toMap(
s -> buildStudentKey(s.getStuId(), s.getGroupId()),
Function.identity()
));
List<SchStudent> toDelete = new ArrayList<>();
for (DeleteUser du : studentDeletes) {
String key = buildStudentKey(du.getUserId(), du.getGroupId());
SchStudent stu = studentMap.get(key);
if (stu != null) {
toDelete.add(stu);
if (validDeletes.isEmpty()) return;
List<Integer> allUserIds = validDeletes.stream()
.map(DeleteUser::getUserId)
.distinct()
.collect(Collectors.toList());
// ---------- 1. 物理删除学生 ----------
List<SchStudent> toDeleteStudents = new ArrayList<>();
Map<String, SchStudent> studentMap = schStudentRepository.findByStuIdIn(allUserIds).stream()
.collect(Collectors.toMap(
s -> buildStudentKey(s.getStuId(), s.getGroupId()),
Function.identity()
));
for (DeleteUser du : validDeletes) {
SchStudent stu = studentMap.get(buildStudentKey(du.getUserId(), du.getGroupId()));
if (stu != null) {
toDeleteStudents.add(stu);
}
}
if (!toDeleteStudents.isEmpty()) {
// 按 (schId, classId) 去重后清除缓存
Map<Integer, Set<Integer>> classKeys = new HashMap<>();
for (SchStudent stu : toDeleteStudents) {
if (stu.getSchId() != null && stu.getGroupId() != null) {
classKeys.computeIfAbsent(stu.getSchId(), k -> new HashSet<>()).add(stu.getGroupId());
}
}
if (!toDelete.isEmpty()) {
// 先清除缓存(需要 schId,可从学生实体获取或查询)
for (SchStudent stu : toDelete) {
// 假设 SchStudent 有 schId 字段,若没有则需通过 groupId 查询
Integer schId = stu.getSchId(); // 若没有,调用 service 查询
if (schId != null) {
schStudentCacheService.clearClassStudentCache(schId, stu.getGroupId());
}
}
// 物理删除
schStudentRepository.deleteAll(toDelete);
}
classKeys.forEach((schId, classIds) -> schStudentCacheService.clearClassStudentCaches(schId, classIds));
schStudentRepository.deleteAll(toDeleteStudents);
}
// ---------- 2. 物理删除教师分组(不删教师主体) ----------
List<DeleteUser> teacherDeletes = deleteUserList.stream()
.filter(du -> du.getUserId() != null && du.getGroupId() != null)
.collect(Collectors.toList());
if (!teacherDeletes.isEmpty()) {
// 查询所有涉及的分组
List<SchTeacherGroup> allGroups = schTeacherGroupRepository.findByTeaIdIn(allUserIds);
Map<String, SchTeacherGroup> groupMap = allGroups.stream()
.collect(Collectors.toMap(
g -> buildTeacherGroupKey(g.getTeaId(), g.getGroupId()),
Function.identity()
));
List<SchTeacherGroup> toDeleteGroups = new ArrayList<>();
for (DeleteUser du : teacherDeletes) {
String key = buildTeacherGroupKey(du.getUserId(), du.getGroupId());
SchTeacherGroup group = groupMap.get(key);
if (group != null) {
toDeleteGroups.add(group);
}
}
if (!toDeleteGroups.isEmpty()) {
// 按学校维度分组,用于缓存清除和剩余分组检查
Map<Integer, List<SchTeacherGroup>> groupsBySchool = toDeleteGroups.stream()
.collect(Collectors.groupingBy(SchTeacherGroup::getSchId));
// 先清除缓存(针对每个分组所属学校)
for (SchTeacherGroup group : toDeleteGroups) {
schTeacherCacheService.clearTeacherCache(group.getSchId());
}
// 物理删除分组
schTeacherGroupRepository.deleteAll(toDeleteGroups);
// 同一 (teaId, groupId) 可能跨多所学校,用 List 收集避免重复键被丢弃
Map<String, List<SchTeacherGroup>> groupMap = schTeacherGroupRepository.findByTeaIdIn(allUserIds).stream()
.collect(Collectors.groupingBy(g -> buildTeacherGroupKey(g.getTeaId(), g.getGroupId())));
List<SchTeacherGroup> toDeleteGroups = new ArrayList<>();
for (DeleteUser du : validDeletes) {
List<SchTeacherGroup> groups = groupMap.get(buildTeacherGroupKey(du.getUserId(), du.getGroupId()));
if (groups != null) {
toDeleteGroups.addAll(groups);
}
}
if (!toDeleteGroups.isEmpty()) {
// 按学校维度去重后清除缓存
Set<Integer> schIds = toDeleteGroups.stream()
.map(SchTeacherGroup::getSchId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
schTeacherCacheService.clearTeacherCaches(schIds);
schTeacherGroupRepository.deleteAll(toDeleteGroups);
}
}
// ==================== 角色判断 ====================
private boolean isStudent(BaseUser user) {
if (user.getRoleList() == null) return false;
/**
* 提取用户的角色 id 集合(去重、过滤空值),每个用户仅遍历一次。
*/
private Set<Integer> collectRoleIds(SyncUserDTO user) {
if (user.getRoleList() == null) return Collections.emptySet();
return user.getRoleList().stream()
.anyMatch(r -> r.getRoleId() != null && r.getRoleId().equals(UserRole.STU_USER.getValue()));
.filter(Objects::nonNull)
.map(SyncUserRoleDTO::getRoleId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
}
private boolean isTeacher(BaseUser user) {
if (user.getRoleList() == null) return false;
return user.getRoleList().stream()
.anyMatch(r -> r.getRoleId() != null &&
(r.getRoleId().equals(UserRole.TEACHER_USER.getValue()) ||
r.getRoleId().equals(UserRole.SCH_LEADER_USER.getValue())));
private boolean isStudent(Set<Integer> roleIds) {
return roleIds.contains(UserRole.STU_USER.getValue());
}
private boolean isTeacher(Set<Integer> roleIds) {
return roleIds.contains(UserRole.TEACHER_USER.getValue())
|| roleIds.contains(UserRole.SCH_LEADER_USER.getValue());
}
// ==================== 学生同步 ====================
private void syncStudents(List<BaseUser> studentUsers, Date now) {
List<Integer> stuIds = studentUsers.stream().map(BaseUser::getId).distinct().collect(Collectors.toList());
private void syncStudents(List<SyncUserDTO> studentUsers, Date now) {
List<Integer> stuIds = studentUsers.stream().map(SyncUserDTO::getId).distinct().collect(Collectors.toList());
// 已有学生记录 (stuId, groupId) -> SchStudent
Map<String, SchStudent> studentMap = schStudentRepository.findByStuIdIn(stuIds)
.stream()
Map<String, SchStudent> studentMap = schStudentRepository.findByStuIdIn(stuIds).stream()
.collect(Collectors.toMap(
s -> buildStudentKey(s.getStuId(), s.getGroupId()),
Function.identity()
));
List<SchStudent> saveList = new ArrayList<>();
// 受影响班级缓存键 (schId -> classId 集合),用于同步后失效
Map<Integer, Set<Integer>> classKeys = new HashMap<>();
for (BaseUser user : studentUsers) {
for (SyncUserDTO user : studentUsers) {
if (user.getGroups() == null) continue;
for (BaseUser.GroupInfo group : user.getGroups()) {
for (SyncUserGroupDTO group : user.getGroups()) {
Integer groupId = group.getGroupId();
Integer schId = group.getSchoolId();
if (groupId == null || schId == null) continue;
@@ -201,21 +194,18 @@ public class SyncUserService implements ISyncUserService {
student = createStudent(user, group, now);
}
saveList.add(student);
classKeys.computeIfAbsent(schId, k -> new HashSet<>()).add(groupId);
}
}
if (!saveList.isEmpty()) {
schStudentRepository.saveAll(saveList);
// 缓存:将学生加入班级缓存(Set结构)
// for (SchStudent stu : saveList) {
// if (stu.getSchId() != null && stu.getGroupId() != null) {
// schStudentCacheService.addClassStudentCache(stu.getSchId(), stu.getGroupId(), stu.getStuId());
// }
// }
// 同步后使受影响班级的学生缓存失效,避免读到旧数据
classKeys.forEach((schId, classIds) -> schStudentCacheService.clearClassStudentCaches(schId, classIds));
}
}
private void updateStudent(SchStudent student, BaseUser user, BaseUser.GroupInfo group, Date now) {
private void updateStudent(SchStudent student, SyncUserDTO user, SyncUserGroupDTO group, Date now) {
student.setAccount(user.getAccount());
student.setName(user.getName());
student.setGender(user.getGender());
@@ -228,7 +218,7 @@ public class SyncUserService implements ISyncUserService {
student.setUpdateDate(now);
}
private SchStudent createStudent(BaseUser user, BaseUser.GroupInfo group, Date now) {
private SchStudent createStudent(SyncUserDTO user, SyncUserGroupDTO group, Date now) {
SchStudent student = new SchStudent();
student.setStuId(user.getId());
student.setAccount(user.getAccount());
@@ -248,17 +238,16 @@ public class SyncUserService implements ISyncUserService {
}
// ==================== 教师同步 ====================
private void syncTeachers(List<BaseUser> teacherUsers, Date now) {
List<Integer> teaIds = teacherUsers.stream().map(BaseUser::getId).distinct().collect(Collectors.toList());
private void syncTeachers(List<SyncUserDTO> teacherUsers, Date now) {
List<Integer> teaIds = teacherUsers.stream().map(SyncUserDTO::getId).distinct().collect(Collectors.toList());
// 教师主体(唯一)
Map<Integer, SchTeacher> teacherMap = schTeacherRepository.findByTeaIdIn(teaIds)
.stream()
Map<Integer, SchTeacher> teacherMap = schTeacherRepository.findByTeaIdIn(teaIds).stream()
.collect(Collectors.toMap(SchTeacher::getTeaId, Function.identity()));
// 教师分组 (teaId, groupId, schId) -> SchTeacherGroup
Map<String, SchTeacherGroup> groupMap = schTeacherGroupRepository.findByTeaIdIn(teaIds)
.stream()
Map<String, SchTeacherGroup> groupMap = schTeacherGroupRepository.findByTeaIdIn(teaIds).stream()
.collect(Collectors.toMap(
g -> buildTeacherGroupKeyWithSchId(g.getTeaId(), g.getGroupId(), g.getSchId()),
Function.identity()
@@ -266,8 +255,10 @@ public class SyncUserService implements ISyncUserService {
List<SchTeacher> saveTeacherList = new ArrayList<>();
List<SchTeacherGroup> saveGroupList = new ArrayList<>();
// 受影响学校缓存键,用于同步后失效
Set<Integer> schIds = new HashSet<>();
for (BaseUser user : teacherUsers) {
for (SyncUserDTO user : teacherUsers) {
// 教师主体(只存一条)
SchTeacher teacher = teacherMap.get(user.getId());
if (teacher != null) {
@@ -279,7 +270,7 @@ public class SyncUserService implements ISyncUserService {
// 教师分组(遍历 groups)
if (user.getGroups() == null) continue;
for (BaseUser.GroupInfo group : user.getGroups()) {
for (SyncUserGroupDTO group : user.getGroups()) {
Integer groupId = group.getGroupId();
Integer schId = group.getSchoolId();
if (groupId == null || schId == null) continue;
@@ -293,6 +284,7 @@ public class SyncUserService implements ISyncUserService {
tg = createTeacherGroup(user, group, now);
}
saveGroupList.add(tg);
schIds.add(schId);
}
}
@@ -301,18 +293,14 @@ public class SyncUserService implements ISyncUserService {
}
if (!saveGroupList.isEmpty()) {
schTeacherGroupRepository.saveAll(saveGroupList);
// // 缓存:更新教师缓存(学校维度)
// // 为简单起见,清除每个涉及的学校缓存,然后重新添加该学校所有教师(但这里我们只添加本次更新的教师,因为Set可重复)
// // 更稳健:清除后重建,但为了减少数据库查询,我们使用 add 方法
// for (SchTeacherGroup g : saveGroupList) {
// if (g.getSchId() != null) {
// schTeacherCacheService.addSchoolTeacherCache(g.getSchId(), g.getTeaId());
// }
// }
}
// 同步后使受影响学校的教师缓存失效
if (!schIds.isEmpty()) {
schTeacherCacheService.clearTeacherCaches(schIds);
}
}
private void updateTeacher(SchTeacher teacher, BaseUser user, Date now) {
private void updateTeacher(SchTeacher teacher, SyncUserDTO user, Date now) {
teacher.setAccount(user.getAccount());
teacher.setName(user.getName());
teacher.setGender(user.getGender());
@@ -322,7 +310,7 @@ public class SyncUserService implements ISyncUserService {
teacher.setUpdateDate(now);
}
private SchTeacher createTeacher(BaseUser user, Date now) {
private SchTeacher createTeacher(SyncUserDTO user, Date now) {
SchTeacher teacher = new SchTeacher();
teacher.setTeaId(user.getId());
teacher.setAccount(user.getAccount());
@@ -336,7 +324,7 @@ public class SyncUserService implements ISyncUserService {
return teacher;
}
private SchTeacherGroup createTeacherGroup(BaseUser user, BaseUser.GroupInfo group, Date now) {
private SchTeacherGroup createTeacherGroup(SyncUserDTO user, SyncUserGroupDTO group, Date now) {
SchTeacherGroup tg = new SchTeacherGroup();
tg.setTeaId(user.getId());
tg.setGroupId(group.getGroupId());
@@ -346,6 +334,7 @@ public class SyncUserService implements ISyncUserService {
}
// ==================== 辅助键生成 ====================
private String buildStudentKey(Integer stuId, Integer groupId) {
return stuId + "_" + groupId;
}