From 614c67653bd6e237eed6991aff5f7cb8f243e85f Mon Sep 17 00:00:00 2001 From: "hhb@hotmail.com" Date: Tue, 6 May 2025 17:47:03 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E6=9B=B4=E6=96=B0=E6=9D=83=E9=99=90?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/cn/teammodel/common/PK.java | 1 + .../admin/controller/TeacherController.java | 13 +- .../admin/service/TeacherService.java | 3 + .../impl/LaborEducationServiceImpl.java | 58 +++- .../service/impl/TeacherServiceImpl.java | 260 ++++++++++++++---- .../model/dto/admin/teacher/IdCodePair.java | 13 + .../model/dto/admin/teacher/TeacherDto.java | 3 + .../model/entity/teacher/PtTeacherInfo.java | 48 ++++ .../teammodel/model/vo/admin/GpTeacherVo.java | 1 + .../repository/PtTeacherRepository.java | 18 ++ .../teammodel/test/AsyncTeacherService.java | 148 ++++++++++ 11 files changed, 496 insertions(+), 70 deletions(-) create mode 100644 src/main/java/cn/teammodel/model/dto/admin/teacher/IdCodePair.java create mode 100644 src/main/java/cn/teammodel/model/entity/teacher/PtTeacherInfo.java create mode 100644 src/main/java/cn/teammodel/repository/PtTeacherRepository.java create mode 100644 src/main/java/cn/teammodel/test/AsyncTeacherService.java diff --git a/src/main/java/cn/teammodel/common/PK.java b/src/main/java/cn/teammodel/common/PK.java index 9e48736..486e5b3 100644 --- a/src/main/java/cn/teammodel/common/PK.java +++ b/src/main/java/cn/teammodel/common/PK.java @@ -35,6 +35,7 @@ public interface PK { String NEWS = "News-%s"; String CLASS_RESULT = "ExamClassResult-%s"; String EXAM = "Exam-%s"; + String PTTEACHER = "PtTeacher-%s"; /** * 构建分区键 diff --git a/src/main/java/cn/teammodel/controller/admin/controller/TeacherController.java b/src/main/java/cn/teammodel/controller/admin/controller/TeacherController.java index fd701c0..a88bb7f 100644 --- a/src/main/java/cn/teammodel/controller/admin/controller/TeacherController.java +++ b/src/main/java/cn/teammodel/controller/admin/controller/TeacherController.java @@ -79,5 +79,16 @@ public class TeacherController { return R.success(res); } - + @PostMapping("update") + @ApiOperation("更新教师信息") + public R update(@Valid @RequestBody TeacherDto teacherDto) { + teacherService.update(teacherDto); + return R.success("更新成功"); + } + @PostMapping("findIdentityByTmdId") + @ApiOperation("根据tmdId获取教师身份") + public R> findIdentityByTmdId(@Valid @RequestBody TeacherDto teacherDto) { + Map res = teacherService.findIdentityByTmdId(teacherDto); + return R.success(res); + } } diff --git a/src/main/java/cn/teammodel/controller/admin/service/TeacherService.java b/src/main/java/cn/teammodel/controller/admin/service/TeacherService.java index f5d3a30..808db13 100644 --- a/src/main/java/cn/teammodel/controller/admin/service/TeacherService.java +++ b/src/main/java/cn/teammodel/controller/admin/service/TeacherService.java @@ -2,6 +2,7 @@ package cn.teammodel.controller.admin.service; import cn.teammodel.model.dto.admin.teacher.GpTeacherDto; import cn.teammodel.model.dto.admin.teacher.TeacherDto; +import cn.teammodel.model.entity.teacher.PtTeacherInfo; import javax.servlet.http.HttpServletRequest; import java.util.LinkedHashMap; @@ -18,4 +19,6 @@ public interface TeacherService { Map getTeachingAndResearch(TeacherDto teacherDto, HttpServletRequest request); List>> getTeachingOfTeacher(TeacherDto teacherDto, HttpServletRequest request); Map getTeacherOfCapabilityAssessment(TeacherDto teacherDto, HttpServletRequest request); + void update (TeacherDto teacherDto); + Map findIdentityByTmdId(TeacherDto teacherDto); } diff --git a/src/main/java/cn/teammodel/controller/admin/service/impl/LaborEducationServiceImpl.java b/src/main/java/cn/teammodel/controller/admin/service/impl/LaborEducationServiceImpl.java index 946ac4f..03eea6e 100644 --- a/src/main/java/cn/teammodel/controller/admin/service/impl/LaborEducationServiceImpl.java +++ b/src/main/java/cn/teammodel/controller/admin/service/impl/LaborEducationServiceImpl.java @@ -211,13 +211,13 @@ public class LaborEducationServiceImpl implements LaborEducationService { classScoreRate = calculateKnowledgeScoreRateForClass(laborDto.getClassId(), examResults, knowledgeMap, appraise, point,res,request); } if (laborDto.getGrade() != null) { - gradeScoreRate = calculateKnowledgeScoreForGrade(laborDto.getGrade(), examResults, knowledgeMap,appraise, point,res,gradeAndClassVos); + gradeScoreRate = calculateKnowledgeScoreForGrade(laborDto.getGrade(), examResults, knowledgeMap,appraise, point,res,gradeAndClassVos,request); } - Map schoolScoreRate = calculateKnowledgeScoreForSchool(examResults, knowledgeMap,appraise, point,res,period,gradeAndClassVos); + Map schoolScoreRate = calculateKnowledgeScoreForSchool(examResults, knowledgeMap,appraise, point,res,period,gradeAndClassVos,request); resMap.put("gradeScoreRate", gradeScoreRate); resMap.put("classScoreRate", classScoreRate); resMap.put("schoolScoreRate", schoolScoreRate); - List> scores = calculateScoresWithDetails(res, appraise); + List> scores = calculateScoresWithDetails(res, appraise, request); List> students = combineScoresWithExamResults(scores,examResults,knowledgeMap,point,knowledgeBlockToPointsMap); resMap.put("scores", students); } @@ -455,7 +455,7 @@ public class LaborEducationServiceImpl implements LaborEducationService { } - public static List> calculateScoresWithDetails(List res, Appraise appraise) { + public static List> calculateScoresWithDetails(List res, Appraise appraise,HttpServletRequest request) { // 1. 构建知识点到知识块的映射 (一个知识块对应多个知识点) Map> knowledgeBlockToPointsMap = getKnowledgeBlockToPointsMap(appraise); @@ -482,10 +482,47 @@ public class LaborEducationServiceImpl implements LaborEducationService { Map> studentScores = new HashMap<>(); Map>> studentAppraises = new HashMap<>(); // 存储每个学生的评价记录 + // 将 classId 转换为 List + //获取res中的classId集合 + List classIds = res.stream() + .map(RecordVo::getClassId) + .distinct() + .collect(Collectors.toList()); + //List classIds = Collections.singletonList(classId); + GroupDto groupDto = new GroupDto(); + groupDto.setIds(classIds); + groupDto.setSchoolId(appraise.getSchoolId()); + String url = environment.getProperty("ies.server-url-group"); + Map groupId = GroupUtil.getGroupId(groupDto, new GroupUtil(environment), request, url); + List rGroupList = new ArrayList<>(); + List rMembers = new ArrayList<>(); + for (Map.Entry entry : groupId.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (key.equals("groups")) { + String jsonGroups = JSON.toJSONString(value); + rGroupList = JSON.parseObject(jsonGroups, new TypeReference>() {}); + } + if (key.equals("members")) { + String jsonGroups = JSON.toJSONString(value); + rMembers = JSON.parseObject(jsonGroups, new TypeReference>() {}); + } + } + for (RecordVo record : res) { String studentId = record.getTargetId(); // 学生 ID String studentName = record.getTargetName(); // 学生名称 - String className = record.getClassName(); // 班级名称 + String className = ""; + if (record.getClassName() == null) { + className = rGroupList.stream() + .filter(rGroupList1 -> rGroupList1.getId().equals(record.getClassId())) + .findFirst() + .map(RGroupList::getName) + .orElse("未知班级"); // 如果未找到则返回默认值 "未知班级" + }else { + className = record.getClassName(); + } + String appraiseName = record.getAppraiseName(); // 评价内容 boolean isPraise = record.isPraise(); // 是否为优点 @@ -830,7 +867,7 @@ public class LaborEducationServiceImpl implements LaborEducationService { } // 2. 获取班级所有学生的主观分数(次数) - List> subjectiveScoresList = calculateScoresWithDetails(res, appraise); + List> subjectiveScoresList = calculateScoresWithDetails(res, appraise,request); // 3. 将主观次数转换为0-100分数 Map> subjectiveScores = new HashMap<>(); @@ -1095,7 +1132,8 @@ public class LaborEducationServiceImpl implements LaborEducationService { Appraise appraise, Map> points, List res, - List gradeAndClassVos) { + List gradeAndClassVos, + HttpServletRequest request) { // 1. 获取年级所有班级的客观分数 Map> classScores = new HashMap<>(); @@ -1118,7 +1156,7 @@ public class LaborEducationServiceImpl implements LaborEducationService { .collect(Collectors.toList()); // 2. 获取年级所有学生的主观分数(次数) - List> subjectiveScoresList = calculateScoresWithDetails(res, appraise); + List> subjectiveScoresList = calculateScoresWithDetails(res, appraise,request); // 3. 将主观次数转换为0-100分数,并收集学生班级信息 Map> subjectiveScores = new HashMap<>(); @@ -1308,7 +1346,7 @@ public class LaborEducationServiceImpl implements LaborEducationService { Map> points, List res, List period, - List gradeAndClassVos) { + List gradeAndClassVos,HttpServletRequest request) { // 1. 初始化数据结构 Map> gradeScores = new HashMap<>(); @@ -1322,7 +1360,7 @@ public class LaborEducationServiceImpl implements LaborEducationService { int index = 0; for (String gradeId : gradeIds) { Map gradeResult = calculateKnowledgeScoreForGrade( - String.valueOf(index), examResults, knowledgeMap, appraise, points, res, gradeAndClassVos + String.valueOf(index), examResults, knowledgeMap, appraise, points, res, gradeAndClassVos,request ); // 2.1 提取年级平均分 diff --git a/src/main/java/cn/teammodel/controller/admin/service/impl/TeacherServiceImpl.java b/src/main/java/cn/teammodel/controller/admin/service/impl/TeacherServiceImpl.java index 9d6167d..9d023a3 100644 --- a/src/main/java/cn/teammodel/controller/admin/service/impl/TeacherServiceImpl.java +++ b/src/main/java/cn/teammodel/controller/admin/service/impl/TeacherServiceImpl.java @@ -5,20 +5,23 @@ import cn.teammodel.common.PK; import cn.teammodel.config.exception.ServiceException; import cn.teammodel.controller.admin.service.TeacherService; import cn.teammodel.model.dto.admin.teacher.GpTeacherDto; +import cn.teammodel.model.dto.admin.teacher.IdCodePair; import cn.teammodel.model.dto.admin.teacher.TeacherDto; import cn.teammodel.model.entity.User; import cn.teammodel.model.entity.common.GroupList; import cn.teammodel.model.entity.school.*; import cn.teammodel.model.entity.teacher.HonorInfo; +import cn.teammodel.model.entity.teacher.PtTeacherInfo; import cn.teammodel.model.vo.admin.GpTeacherVo; import cn.teammodel.model.vo.admin.SugVo; import cn.teammodel.model.vo.admin.TeacherGradeVo; import cn.teammodel.repository.*; import cn.teammodel.security.utils.SecurityUtil; +import cn.teammodel.test.AsyncTeacherService; import cn.teammodel.test.LessonRecordQueryService; import cn.teammodel.utils.GroupUtil; import cn.teammodel.utils.SchoolDateUtil; -import com.azure.cosmos.CosmosException; +import com.azure.cosmos.models.CosmosPatchOperations; import com.azure.spring.data.cosmos.core.query.CosmosPageRequest; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; @@ -26,11 +29,12 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; import org.springframework.core.env.Environment; import org.springframework.data.domain.Slice; -import org.springframework.data.domain.SliceImpl; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -39,6 +43,7 @@ import java.time.*; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.*; +import java.util.function.Function; import java.util.stream.Collectors; import static cn.teammodel.utils.SchoolDateUtil.calculateWeekNum; @@ -53,6 +58,8 @@ public class TeacherServiceImpl implements TeacherService { private SchoolRepository schoolRepository; @Resource private LessonRecordRepository lessonRecordRepository; + @Resource + private PtTeacherRepository ptTeacherRepository; /** * 学校试卷 */ @@ -63,16 +70,37 @@ public class TeacherServiceImpl implements TeacherService { */ @Resource private PaperTeacherRepository paperTeacherRepository; + + @Autowired + private AsyncTeacherService asyncTeacherService; @Autowired private Environment env; private static final double K = 0.08; // 衰减系数常量 + + // 引入缓存,需根据实际情况配置大小和过期时间 每次服务重启时 缓存会清空 + public static final Cache PT_TEACHER_CACHE = CacheBuilder.newBuilder() + .maximumSize(500) + .expireAfterWrite(8, TimeUnit.HOURS) + .build(); + + @Cacheable(value = "schoolGroupCache", key = "#code") + public List getCachedGroupLists(String code) { + return schoolGroupListRepository.findAllByCode("GroupList-" + code); + } + + @Cacheable(value = "TeacherCache", key = "#code") + public List getTeacherInfos(String code) { + return schoolTeacherRepository.findAllByCode("Teacher-" + code); + } + @Override public List> getTeacherList(TeacherDto teacherDto) { List> result = new ArrayList<>(); Map teacherCountMap = new HashMap<>(); Map groupCountMap = new HashMap<>(); - List groupLists = schoolGroupListRepository.findAllByCode("GroupList-" + teacherDto.getCode()); - List schoolTeachers = schoolTeacherRepository.findAllByCode("Teacher-" + teacherDto.getCode()); + String code = teacherDto.getCode(); + List groupLists = getCachedGroupLists(code); + List schoolTeachers = getTeacherInfos(code); teacherCountMap.put("教师总人数", schoolTeachers.size()); List school = schoolRepository.findBaseById(teacherDto.getCode()); List subjects = new ArrayList<>(); @@ -129,34 +157,29 @@ public class TeacherServiceImpl implements TeacherService { String url = env.getProperty("ies.server-url-get-teacher-all"); try { teachers = GroupUtil.getGroupId(teacherDto,new GroupUtil(env), request,url); - List teachersList = new ArrayList<>(); - for (Map.Entry entry : teachers.entrySet()) { - // 假设 entry.getValue() 返回的是 List> - List> mapList = (List>) entry.getValue(); - for (Map map : mapList) { - // 将 Map 转换为 GpTeacherVo 对象 - GpTeacherVo teacher = convertToGpTeacherVo(map); - teachersList.add(teacher); - } - } - List phones = new ArrayList<>(); - // 进一步处理 teachersList - for (GpTeacherVo teacher : teachersList) { - phones.add(teacher.getPhone()); - } + List teachersList = convertToGpTeacherVoList(teachers); + List phones = teachersList.stream().map(GpTeacherVo::getPhone).collect(Collectors.toList()); GpTeacherDto gpTeacherDto = new GpTeacherDto(); gpTeacherDto.setMobiles(phones); Map tBase = getTeacherBase(gpTeacherDto, request); - List gpTeachers = new ArrayList<>(); - for (Map.Entry entry : tBase.entrySet()) { - if (entry.getKey().equals("teachers")) { - List> dataList = (List>) entry.getValue(); - for (Map dataMap : dataList) { - GpTeacher gpTeacher = convertToGpTeacher(dataMap); - gpTeachers.add(gpTeacher); - } + List gpTeachers = convertToGpTeacherList(tBase); + // 优化1:使用Map加速查找 + Map phoneToGpTeacher = gpTeachers.stream() + .collect(Collectors.toMap( + gp -> gp.getMobile().toLowerCase(), + Function.identity() + )); + + // 处理教师信息 + teachersList.forEach(teacher -> { + String phoneKey = teacher.getPhone() != null ? teacher.getPhone().toLowerCase() : ""; + GpTeacher gpTeacher = phoneToGpTeacher.get(phoneKey); + if (gpTeacher != null) { + teacher.setGender(gpTeacher.getBasic() != null ? gpTeacher.getBasic().getGender() : ""); + teacher.setPracticeTime(gpTeacher.getPracticeTime() != null ? gpTeacher.getPracticeTime() : 0L); + teacher.setDegree(gpTeacher.getDegree() != null ? gpTeacher.getDegree() : ""); } - } + }); Map genderCount = gpTeachers.stream() .collect(Collectors.groupingBy(gpTeacher -> gpTeacher.getBasic().getGender(), Collectors.counting())); Map degreeCount = gpTeachers.stream() @@ -171,42 +194,13 @@ public class TeacherServiceImpl implements TeacherService { }else if (!genderCount.containsKey("M")){ genderCount.put("M",0L); } - /* Map genderMap = new HashMap<>(); - Map practiceMap = new HashMap<>(); - for (GpTeacher gpTeacher : gpTeachers) { - genderMap.put(gpTeacher.basic.name, gpTeacher.basic.gender); - practiceMap.put(gpTeacher.basic.name, gpTeacher.practiceTime); - }*/ - for (GpTeacherVo teacher : teachersList) { - for(GpTeacher gpTeacher : gpTeachers) { - if(StringUtils.isNotEmpty(teacher.phone) && teacher.phone.equalsIgnoreCase(gpTeacher.mobile)) { - if(gpTeacher.basic.gender != null) { - teacher.setGender(gpTeacher.basic.gender); - }else { - teacher.setGender(""); - } - if (gpTeacher.getPracticeTime() != null && gpTeacher.getPracticeTime() > 0) { - teacher.setPracticeTime(gpTeacher.getPracticeTime()); - }else { - teacher.setPracticeTime(0L); - } - if(gpTeacher.degree != null) { - teacher.setDegree(gpTeacher.degree); - }else { - teacher.setDegree(""); - } - break; - } - } - } - //teachers.put("practice", practiceCount); - //teachers.put("practiceMap", practiceMap); - //teachers.put("genderMap", genderMap); teachers.put("gender", genderCount); teachers.put("degree", degreeCount); teachers.put("info", teachersList); teachers.remove("teachers"); + List copyList = new ArrayList<>(teachersList); + asyncTeacherService.asyncSavePtTeacherInfos(Collections.unmodifiableList(copyList)); }catch (Exception e) { throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据转换错误"); @@ -215,6 +209,119 @@ public class TeacherServiceImpl implements TeacherService { return teachers; } + private List convertToGpTeacherVoList(Map teachers) { + List teachersList = new ArrayList<>(); + for (Map.Entry entry : teachers.entrySet()) { + List> mapList = (List>) entry.getValue(); + for (Map map : mapList) { + GpTeacherVo teacher = convertToGpTeacherVo(map); + teachersList.add(teacher); + } + } + return teachersList; + } + + private List convertToGpTeacherList(Map tBase) { + List gpTeachers = new ArrayList<>(); + for (Map.Entry entry : tBase.entrySet()) { + if (entry.getKey().equals("teachers")) { + List> dataList = (List>) entry.getValue(); + for (Map dataMap : dataList) { + GpTeacher gpTeacher = convertToGpTeacher(dataMap); + gpTeachers.add(gpTeacher); + } + } + } + return gpTeachers; + } + + + private void savePtTeacherInfosBatch(List teachersList) { + // 预加载版本号 + Map versionMap = loadExistingVersions(teachersList); + + List ptTeacherInfos = teachersList.stream() + .filter(t -> t.getId() != null) + .map(t -> convertToPtTeacherInfo(t, versionMap)) + .collect(Collectors.toList()); + + ptTeacherRepository.saveAll(ptTeacherInfos); + ptTeacherInfos.forEach(pt -> PT_TEACHER_CACHE.put(pt.getCode(), pt)); + } + + private Map loadExistingVersions(List teachersList) { + // 收集所有id和code组合 + List> idCodePairs = teachersList.stream() + .filter(t -> t.getId() != null) + .map(t -> Pair.of(t.getId(), "PtTeacher-" + t.getId())) + .collect(Collectors.toList()); + //将List> 转化为 List + List idAndCode = idCodePairs.stream() + .map(pair -> new IdCodePair(pair.getLeft(), pair.getRight())) + .collect(Collectors.toList()); + // 批量查询现有记录的版本号(需自定义Repository方法) + List existingList = ptTeacherRepository.findByIdCodePairs(idAndCode); + + // 转为Map + return existingList.stream() + .collect(Collectors.toMap( + PtTeacherInfo::getCode, + PtTeacherInfo::getVersion + )); + } + + + private PtTeacherInfo convertToPtTeacherInfo(GpTeacherVo teacher, Map versionMap) { + PtTeacherInfo ptTeacherInfo = new PtTeacherInfo(); + String code = "PtTeacher-" + teacher.getId(); + ptTeacherInfo.setPk("PtTeacher"); + ptTeacherInfo.setTtl(-1); + ptTeacherInfo.setCode(code); + ptTeacherInfo.setId(teacher.getId()); + ptTeacherInfo.setTmdId(teacher.getId()); + ptTeacherInfo.setName(teacher.getName()); + ptTeacherInfo.setPhone(teacher.getPhone()); + ptTeacherInfo.setEmail(teacher.getEmail()); + ptTeacherInfo.setPicture(teacher.getPicture()); + ptTeacherInfo.setIname(teacher.getIname()); + ptTeacherInfo.setJob(teacher.getJob()); + ptTeacherInfo.setSubjectIds(teacher.getSubjectIds()); + ptTeacherInfo.setSubjectNames(teacher.getSubjectNames()); + ptTeacherInfo.setRoles(teacher.getRoles()); + ptTeacherInfo.setGroups(teacher.getGroups()); + ptTeacherInfo.setNote(teacher.getNote()); + ptTeacherInfo.setDegree(teacher.getDegree()); + ptTeacherInfo.setPracticeTime(teacher.getPracticeTime()); + ptTeacherInfo.setGender(teacher.getGender()); + ptTeacherInfo.setGrade(teacher.getGrade()); + ptTeacherInfo.setPeriodId(teacher.getPeriodId()); + Integer currentVersion = versionMap.getOrDefault(code, 0); + + + // 从缓存中获取现有对象 + PtTeacherInfo existingPtTeacherInfo = PT_TEACHER_CACHE.getIfPresent(ptTeacherInfo.getCode()); + if (existingPtTeacherInfo != null) { + // 比较版本号,如果版本号相同则不需要更新 + if (Objects.equals(existingPtTeacherInfo.getVersion(), currentVersion)) { + return existingPtTeacherInfo; + } + } + //ptTeacherInfo.setVersion(currentVersion + 1); + + // 设置版本号 + ptTeacherInfo.setVersion(getNextVersion(ptTeacherInfo.getId(), ptTeacherInfo.getCode())); + + return ptTeacherInfo; + } + + private Integer getNextVersion(String id,String code) { + PtTeacherInfo existingPtTeacherInfo = ptTeacherRepository.findByIdAndCode(id,code); + if (existingPtTeacherInfo != null) { + return existingPtTeacherInfo.getVersion() + 1; + } + return 1; + } + private static @NotNull Map getStringIntegerMap(TeacherDto teacherDto, List gpTeachers) { Map practiceCount = new HashMap<>(); for (GpTeacher gpTeacher : gpTeachers) { @@ -1281,6 +1388,41 @@ public class TeacherServiceImpl implements TeacherService { return result; } + @Override + public void update(TeacherDto teacherDto) { + try { + String id = teacherDto.getTmdId(); + String code = String.format(PK.PTTEACHER, id); + PtTeacherInfo ptTeacherInfo = ptTeacherRepository.findByIdAndCode(id, code); + // 局部更新 + CosmosPatchOperations operations = CosmosPatchOperations.create(); + if (ptTeacherInfo != null) { + operations.set("/identity", teacherDto.getIdentity()); + } + ptTeacherRepository.save(id, PK.buildOf(PK.PTTEACHER, teacherDto.getTmdId()), PtTeacherInfo.class, operations); + } catch (Exception ex) { + throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据更新失败: " + ex.getMessage()); + } + } + + @Override + public Map findIdentityByTmdId(TeacherDto teacherDto) { + try { + String id = teacherDto.getTmdId(); + String code = String.format(PK.PTTEACHER, id); + PtTeacherInfo ptTeacherInfo = ptTeacherRepository.findByIdAndCode(id, code); + if (ptTeacherInfo != null) { + Map result = new HashMap<>(); + result.put("tmdId", id); + result.put("identity", ptTeacherInfo.getIdentity()); + return result; + } + } catch (Exception ex) { + throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据查询失败: " + ex.getMessage()); + } + return Collections.emptyMap(); + } + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); // 引入缓存,需根据实际情况配置大小和过期时间 每次服务重启时 缓存会清空 private static final Cache> REQUEST_CACHE = CacheBuilder.newBuilder() diff --git a/src/main/java/cn/teammodel/model/dto/admin/teacher/IdCodePair.java b/src/main/java/cn/teammodel/model/dto/admin/teacher/IdCodePair.java new file mode 100644 index 0000000..48db57a --- /dev/null +++ b/src/main/java/cn/teammodel/model/dto/admin/teacher/IdCodePair.java @@ -0,0 +1,13 @@ +package cn.teammodel.model.dto.admin.teacher; + +import lombok.Data; + +@Data +public class IdCodePair { + public String id; + public String code; + public IdCodePair(String id, String code) { + this.id = id; + this.code = code; + } +} diff --git a/src/main/java/cn/teammodel/model/dto/admin/teacher/TeacherDto.java b/src/main/java/cn/teammodel/model/dto/admin/teacher/TeacherDto.java index 88cf4dc..afd0e11 100644 --- a/src/main/java/cn/teammodel/model/dto/admin/teacher/TeacherDto.java +++ b/src/main/java/cn/teammodel/model/dto/admin/teacher/TeacherDto.java @@ -1,5 +1,6 @@ package cn.teammodel.model.dto.admin.teacher; +import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -27,4 +28,6 @@ public class TeacherDto { public String semesterId; public List duration = new ArrayList<>(); public List school_shortcode = new ArrayList<>(); + @JsonFormat(shape = JsonFormat.Shape.ARRAY) + public List identity = new ArrayList<>(); } diff --git a/src/main/java/cn/teammodel/model/entity/teacher/PtTeacherInfo.java b/src/main/java/cn/teammodel/model/entity/teacher/PtTeacherInfo.java new file mode 100644 index 0000000..705805f --- /dev/null +++ b/src/main/java/cn/teammodel/model/entity/teacher/PtTeacherInfo.java @@ -0,0 +1,48 @@ +package cn.teammodel.model.entity.teacher; + + +import cn.teammodel.model.entity.BaseItem; +import cn.teammodel.model.vo.admin.GpTeacherVo; +import com.azure.spring.data.cosmos.core.mapping.Container; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Container(containerName = "Teacher") +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class PtTeacherInfo extends BaseItem { + public String tmdId ; + public String name ; + public String pk ; + public Integer ttl ; + public String phone ; + public String email ; + public String picture ; + public String iname ; + public String job ; + public List subjectIds ; + public List subjectNames ; + public List roles; + public List groups; + public String note ; + public String degree; + public Long practiceTime ; + public String gender ; + public List grade; + public String periodId ; + //新增身份信息 + public List identity ; + public Integer version; // 添加版本控制字段 + @Data + public static class IdNameCode{ + public String id ; + public String name ; + public String code ; + public String picture ; + public String nickname ; + } +} diff --git a/src/main/java/cn/teammodel/model/vo/admin/GpTeacherVo.java b/src/main/java/cn/teammodel/model/vo/admin/GpTeacherVo.java index efd5d6b..83674a7 100644 --- a/src/main/java/cn/teammodel/model/vo/admin/GpTeacherVo.java +++ b/src/main/java/cn/teammodel/model/vo/admin/GpTeacherVo.java @@ -23,6 +23,7 @@ public class GpTeacherVo { public String gender ; public List grade; public String periodId ; + public Integer version = 1; @Data public static class IdNameCode{ public String id ; diff --git a/src/main/java/cn/teammodel/repository/PtTeacherRepository.java b/src/main/java/cn/teammodel/repository/PtTeacherRepository.java new file mode 100644 index 0000000..e499f4c --- /dev/null +++ b/src/main/java/cn/teammodel/repository/PtTeacherRepository.java @@ -0,0 +1,18 @@ +package cn.teammodel.repository; + +import cn.teammodel.model.dto.admin.teacher.IdCodePair; +import cn.teammodel.model.entity.teacher.PtTeacherInfo; +import com.azure.spring.data.cosmos.repository.CosmosRepository; +import com.azure.spring.data.cosmos.repository.Query; +import io.lettuce.core.dynamic.annotation.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface PtTeacherRepository extends CosmosRepository { + PtTeacherInfo findByIdAndCode(String id, String code); + + @Query(value = "SELECT * FROM c WHERE ARRAY_CONTAINS(@pairs, {id: c.id, code: c.code}, true) and c.pk = 'PtTeacher'") + List findByIdCodePairs(@Param("pairs") List pairs); +} diff --git a/src/main/java/cn/teammodel/test/AsyncTeacherService.java b/src/main/java/cn/teammodel/test/AsyncTeacherService.java new file mode 100644 index 0000000..15cb778 --- /dev/null +++ b/src/main/java/cn/teammodel/test/AsyncTeacherService.java @@ -0,0 +1,148 @@ +package cn.teammodel.test; + +import cn.teammodel.model.dto.admin.teacher.IdCodePair; +import cn.teammodel.model.entity.teacher.PtTeacherInfo; +import cn.teammodel.model.vo.admin.GpTeacherVo; +import cn.teammodel.repository.PtTeacherRepository; +import com.itextpdf.text.log.Logger; +import com.itextpdf.text.log.LoggerFactory; +import org.apache.commons.lang3.tuple.Pair; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static cn.teammodel.controller.admin.service.impl.TeacherServiceImpl.PT_TEACHER_CACHE; + +@Service +public class AsyncTeacherService { + private static final Logger log = LoggerFactory.getLogger(AsyncTeacherService.class); + + @Autowired + private PtTeacherRepository ptTeacherRepository; + + @Async + public void asyncSavePtTeacherInfos(List teachersList) { + try { + Map existingTeachers = loadExistingTeachers(teachersList); + + List updates = teachersList.stream() + .filter(t -> t.getId() != null) + .map(t -> convertToPtTeacherInfo(t, existingTeachers)) + .filter(Objects::nonNull) // 过滤掉未变更的记录 + .collect(Collectors.toList()); + + if (!updates.isEmpty()) { + ptTeacherRepository.saveAll(updates); + updates.forEach(pt -> PT_TEACHER_CACHE.put(pt.getCode(), pt)); + } + } catch (Exception e) { + log.error("Failed to save teacher info asynchronously", e); + } + } + + private Map loadExistingTeachers(List teachersList) { + List idAndCode = teachersList.stream() + .filter(t -> t.getId() != null) + .map(t -> new IdCodePair(t.getId(), "PtTeacher-" + t.getId())) + .collect(Collectors.toList()); + + List existingList = ptTeacherRepository.findByIdCodePairs(idAndCode); + + return existingList.stream() + .collect(Collectors.toMap( + PtTeacherInfo::getCode, + Function.identity() + )); + } + + private PtTeacherInfo convertToPtTeacherInfo(GpTeacherVo teacher, Map existingTeachers) { + + String code = "PtTeacher-" + teacher.getId(); + PtTeacherInfo existing = existingTeachers.get(code); + // 如果数据库无记录,直接创建新对象 + if (existing == null) { + return createNewPtTeacherInfo(teacher, code); + } + // 检查字段是否有变化 + boolean isChanged = !Objects.equals(existing.getName(), teacher.getName()) + || !Objects.equals(existing.getPhone(), teacher.getPhone()) + || !Objects.equals(existing.getDegree(), teacher.getDegree()) || + !Objects.equals(existing.getPracticeTime(), teacher.getPracticeTime()) || + !Objects.equals(existing.getGender(), teacher.getGender()) || + !Objects.equals(existing.getGrade(), teacher.getGrade()) || + !Objects.equals(existing.getPeriodId(), teacher.getPeriodId()); + + // 无变化则返回null,表示无需更新 + if (!isChanged) { + return null; + } + + PtTeacherInfo updated = new PtTeacherInfo(); + BeanUtils.copyProperties(existing, updated); + updated.setName(teacher.getName()); + updated.setPhone(teacher.getPhone()); + updated.setDegree(teacher.getDegree()); + updated.setPracticeTime(teacher.getPracticeTime()); + updated.setGender(teacher.getGender()); + updated.setGrade(teacher.getGrade()); + updated.setPeriodId(teacher.getPeriodId()); + updated.setVersion(getNextVersion(updated.getId(), updated.getCode())); + return updated; + + } + + private Integer getNextVersion(String id,String code) { + PtTeacherInfo existingPtTeacherInfo = ptTeacherRepository.findByIdAndCode(id,code); + if (existingPtTeacherInfo != null) { + return existingPtTeacherInfo.getVersion() + 1; + } + return 1; + } + + private PtTeacherInfo createNewPtTeacherInfo(GpTeacherVo teacher, String code) { + PtTeacherInfo ptTeacherInfo = new PtTeacherInfo(); + + // 固定值 + ptTeacherInfo.setPk("PtTeacher"); + ptTeacherInfo.setTtl(-1); + + // 基础信息映射 + ptTeacherInfo.setId(teacher.getId()); + ptTeacherInfo.setTmdId(teacher.getId()); + ptTeacherInfo.setCode(code); + ptTeacherInfo.setName(teacher.getName()); + ptTeacherInfo.setPhone(teacher.getPhone() != null ? teacher.getPhone() : ""); // 空值处理 + ptTeacherInfo.setEmail(teacher.getEmail() != null ? teacher.getEmail() : ""); + ptTeacherInfo.setPicture(teacher.getPicture()); + ptTeacherInfo.setIname(teacher.getIname()); + ptTeacherInfo.setJob(teacher.getJob()); + + // 学科与角色信息 + ptTeacherInfo.setSubjectIds(teacher.getSubjectIds() != null ? teacher.getSubjectIds() : Collections.emptyList()); + ptTeacherInfo.setSubjectNames(teacher.getSubjectNames() != null ? teacher.getSubjectNames() : Collections.emptyList()); + ptTeacherInfo.setRoles(teacher.getRoles() != null ? teacher.getRoles() : Collections.emptyList()); + ptTeacherInfo.setGroups(teacher.getGroups() != null ? teacher.getGroups() : Collections.emptyList()); + + // 其他业务字段 + ptTeacherInfo.setNote(teacher.getNote()); + ptTeacherInfo.setDegree(teacher.getDegree() != null ? teacher.getDegree() : ""); + ptTeacherInfo.setPracticeTime(teacher.getPracticeTime() != null ? teacher.getPracticeTime() : 0L); // 默认0 + ptTeacherInfo.setGender(teacher.getGender() != null ? teacher.getGender() : "U"); // 未知性别默认值 + ptTeacherInfo.setGrade(teacher.getGrade()); + ptTeacherInfo.setPeriodId(teacher.getPeriodId()); + + // 版本号初始化 + ptTeacherInfo.setVersion(1); + + return ptTeacherInfo; + } +}