From c8d0584f11c0b644f82588b7e69b8bf8a13967af Mon Sep 17 00:00:00 2001 From: cat-shark <1716967236@qq.com> Date: Mon, 3 Aug 2026 23:08:08 +0800 Subject: [PATCH 1/4] =?UTF-8?q?docs:=20=E8=A1=A5=E5=85=85=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E6=8F=90=E7=A4=BA=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AGENTS.md b/AGENTS.md index 4fabb83..417d8de 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -73,6 +73,7 @@ lpt-be/src/main/java/com/guo/learningprogresstracker/ - 业务错误:`CommonResult.error(msg)`,code=400,HTTP 200。 - 未登录:`GlobalExceptionHandler.handleNotLogin()`,HTTP 401 + code=401。 - 参数校验失败:`MethodArgumentNotValidException`,code=400。 +- 用户可见错误文案必须口语化、可理解,避免“无法生成”“不存在”等技术化表述;技术细节写入日志。例如无学习报告时应提示“这个任务还没开始学习哦,学习后产生学习报告后再来吧”,而不是“没有学习报告,无法生成思维导图”。 ## DTO 转换 From 5b6f7d6a2a62de2761f9558036fa33467f4ab7a8 Mon Sep 17 00:00:00 2001 From: cat-shark <1716967236@qq.com> Date: Mon, 3 Aug 2026 23:08:14 +0800 Subject: [PATCH 2/4] =?UTF-8?q?refactor:=20=E9=A6=96=E9=A1=B5feed=E4=BB=85?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E6=AE=8B=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReviewController.java | 2 +- .../dto/ReviewFeedItem.java | 2 +- .../service/ReviewService.java | 2 +- .../service/impl/ReviewServiceImpl.java | 29 +++++++++---------- .../service/impl/ReviewServiceImplTest.java | 20 ++++--------- 5 files changed, 23 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/guo/learningprogresstracker/controller/ReviewController.java b/src/main/java/com/guo/learningprogresstracker/controller/ReviewController.java index fd97df8..189eb02 100644 --- a/src/main/java/com/guo/learningprogresstracker/controller/ReviewController.java +++ b/src/main/java/com/guo/learningprogresstracker/controller/ReviewController.java @@ -35,7 +35,7 @@ public class ReviewController { private final StandardMindMapService standardMindMapService; /** - * 获取复习 feed,合并报告和残片按时间倒序 + * 获取复习 feed,仅返回学习残片(首页滚动条使用) */ @GetMapping("/feed") public CommonResult> getReviewFeed( diff --git a/src/main/java/com/guo/learningprogresstracker/dto/ReviewFeedItem.java b/src/main/java/com/guo/learningprogresstracker/dto/ReviewFeedItem.java index e21bfbe..8d5dfd8 100644 --- a/src/main/java/com/guo/learningprogresstracker/dto/ReviewFeedItem.java +++ b/src/main/java/com/guo/learningprogresstracker/dto/ReviewFeedItem.java @@ -5,7 +5,7 @@ import lombok.Data; import java.time.LocalDateTime; /** - * 复习滚动 feed 条目,合并展示学习报告和残片 + * 复习滚动 feed 条目;首页仅使用残片,任务详情仍可同时包含报告和残片 */ @Data public class ReviewFeedItem { diff --git a/src/main/java/com/guo/learningprogresstracker/service/ReviewService.java b/src/main/java/com/guo/learningprogresstracker/service/ReviewService.java index bef4704..0059254 100644 --- a/src/main/java/com/guo/learningprogresstracker/service/ReviewService.java +++ b/src/main/java/com/guo/learningprogresstracker/service/ReviewService.java @@ -14,7 +14,7 @@ import java.util.List; public interface ReviewService { /** - * 获取复习 feed 列表,合并报告和残片按时间倒序 + * 获取复习 feed 列表,仅返回学习残片并按时间倒序 */ List getReviewFeed(int limit, String mode); diff --git a/src/main/java/com/guo/learningprogresstracker/service/impl/ReviewServiceImpl.java b/src/main/java/com/guo/learningprogresstracker/service/impl/ReviewServiceImpl.java index 9f574db..4240174 100644 --- a/src/main/java/com/guo/learningprogresstracker/service/impl/ReviewServiceImpl.java +++ b/src/main/java/com/guo/learningprogresstracker/service/impl/ReviewServiceImpl.java @@ -16,6 +16,7 @@ import com.guo.learningprogresstracker.mapper.StudySessionsMapper; import com.guo.learningprogresstracker.mapper.TasksMapper; import com.guo.learningprogresstracker.service.ReviewService; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; @@ -29,6 +30,7 @@ import java.util.stream.Stream; /** * 复习模块 Service 实现 */ +@Slf4j @Service @RequiredArgsConstructor public class ReviewServiceImpl implements ReviewService { @@ -53,13 +55,6 @@ public class ReviewServiceImpl implements ReviewService { } boolean random = RANDOM_MODE.equalsIgnoreCase(mode); - List reports = random - ? studyReportsMapper.selectList(Wrappers.lambdaQuery() - .last("ORDER BY RAND() LIMIT " + safeLimit)) - : studyReportsMapper.selectList(Wrappers.lambdaQuery() - .orderByDesc(StudyReportsEntity::getCreatedTime) - .last("LIMIT " + safeLimit)); - List fragments = random ? studyReportFragmentsMapper.selectList(Wrappers.lambdaQuery() .last("ORDER BY RAND() LIMIT " + safeLimit)) @@ -67,7 +62,7 @@ public class ReviewServiceImpl implements ReviewService { .orderByDesc(StudyReportFragmentsEntity::getCreatedTime) .last("LIMIT " + safeLimit)); - List items = mergeAndConvert(reports, fragments); + List items = mergeAndConvert(List.of(), fragments); if (random) { Collections.shuffle(items); } @@ -82,14 +77,11 @@ public class ReviewServiceImpl implements ReviewService { private List getSmartFeed(int safeLimit) { int candidateLimit = Math.min(safeLimit * SMART_CANDIDATE_MULTIPLIER, 500); - List reports = studyReportsMapper.selectList( - Wrappers.lambdaQuery() - .last("ORDER BY RAND() LIMIT " + candidateLimit)); List fragments = studyReportFragmentsMapper.selectList( Wrappers.lambdaQuery() .last("ORDER BY RAND() LIMIT " + candidateLimit)); - List candidates = mergeAndConvert(reports, fragments); + List candidates = mergeAndConvert(List.of(), fragments); if (candidates.size() <= safeLimit) { Collections.shuffle(candidates); return candidates; @@ -224,13 +216,19 @@ public class ReviewServiceImpl implements ReviewService { @Override public StudyReportsEntity getReportDetail(int id) throws NotFindEntitiesException { return Optional.ofNullable(studyReportsMapper.selectById(id)) - .orElseThrow(() -> new NotFindEntitiesException("学习报告[" + id + "]不存在")); + .orElseThrow(() -> { + log.warn("学习报告[{}]不存在", id); + return new NotFindEntitiesException("这份学习报告不存在或已被删除"); + }); } @Override public StudyReportFragmentsEntity getFragmentDetail(int id) throws NotFindEntitiesException { return Optional.ofNullable(studyReportFragmentsMapper.selectById(id)) - .orElseThrow(() -> new NotFindEntitiesException("学习残片[" + id + "]不存在")); + .orElseThrow(() -> { + log.warn("学习残片[{}]不存在", id); + return new NotFindEntitiesException("这条学习残片不存在或已被删除"); + }); } /** @@ -321,7 +319,8 @@ public class ReviewServiceImpl implements ReviewService { private void ensureTaskExists(String taskNum) throws NotFindEntitiesException { if (!StringUtils.hasText(taskNum) || !tasksMapper.exists( Wrappers.lambdaQuery().eq(TaskEntity::getTaskNum, taskNum))) { - throw new NotFindEntitiesException("任务[" + taskNum + "]不存在"); + log.warn("任务[{}]不存在", taskNum); + throw new NotFindEntitiesException("这个任务不存在或已被删除"); } } diff --git a/src/test/java/com/guo/learningprogresstracker/service/impl/ReviewServiceImplTest.java b/src/test/java/com/guo/learningprogresstracker/service/impl/ReviewServiceImplTest.java index c2fed13..bf5573d 100644 --- a/src/test/java/com/guo/learningprogresstracker/service/impl/ReviewServiceImplTest.java +++ b/src/test/java/com/guo/learningprogresstracker/service/impl/ReviewServiceImplTest.java @@ -62,13 +62,13 @@ class ReviewServiceImplTest { void getReviewFeed_smartMode_prefersLowRecallRatioContent() { LocalDateTime now = LocalDateTime.now(); - StudyReportsEntity oldLowMastery = new StudyReportsEntity(); + StudyReportFragmentsEntity oldLowMastery = new StudyReportFragmentsEntity(); oldLowMastery.setId(1); oldLowMastery.setSessionNum("S_LOW"); oldLowMastery.setContent("很久没复习且掌握度低"); oldLowMastery.setCreatedTime(now.minusDays(60)); - StudyReportsEntity freshHighMastery = new StudyReportsEntity(); + StudyReportFragmentsEntity freshHighMastery = new StudyReportFragmentsEntity(); freshHighMastery.setId(2); freshHighMastery.setSessionNum("S_HIGH"); freshHighMastery.setContent("刚学完且掌握度高"); @@ -93,8 +93,7 @@ class ReviewServiceImplTest { highRatioRecord.setRecallRatio(1.0); highRatioRecord.setCreatedTime(now); - when(studyReportsMapper.selectList(any())).thenReturn(List.of(oldLowMastery, freshHighMastery)); - when(studyReportFragmentsMapper.selectList(any())).thenReturn(List.of()); + when(studyReportFragmentsMapper.selectList(any())).thenReturn(List.of(oldLowMastery, freshHighMastery)); when(studySessionsMapper.selectList(any())).thenReturn(List.of(sessionLow, sessionHigh)); when(tasksMapper.selectList(any())).thenReturn(List.of(taskLow, taskHigh)); when(reviewRecallRecordMapper.selectList(any())).thenReturn(List.of(highRatioRecord)); @@ -116,15 +115,9 @@ class ReviewServiceImplTest { } @Test - void getReviewFeed_shouldApplyFinalLimitAfterMerge() { - StudyReportsEntity report = new StudyReportsEntity(); - report.setId(1); - report.setSessionNum("S1"); - report.setContent("report"); - report.setCreatedTime(LocalDateTime.now()); - + void getReviewFeed_shouldReturnFragmentsOnly() { StudyReportFragmentsEntity fragment = new StudyReportFragmentsEntity(); - fragment.setId(2); + fragment.setId(1); fragment.setSessionNum("S1"); fragment.setContent("fragment"); fragment.setCreatedTime(LocalDateTime.now().minusMinutes(1)); @@ -137,7 +130,6 @@ class ReviewServiceImplTest { task.setTaskNum("T1"); task.setTaskName("Task"); - when(studyReportsMapper.selectList(any())).thenReturn(List.of(report)); when(studyReportFragmentsMapper.selectList(any())).thenReturn(List.of(fragment)); when(studySessionsMapper.selectList(any())).thenReturn(List.of(session)); when(tasksMapper.selectList(any())).thenReturn(List.of(task)); @@ -145,7 +137,7 @@ class ReviewServiceImplTest { List items = reviewService.getReviewFeed(1, "recent"); assertEquals(1, items.size()); - assertEquals("REPORT", items.get(0).getSourceType()); + assertEquals("FRAGMENT", items.get(0).getSourceType()); assertEquals("Task", items.get(0).getTaskName()); } From b434520eff35779a84529ad5912324ba25963c10 Mon Sep 17 00:00:00 2001 From: cat-shark <1716967236@qq.com> Date: Mon, 3 Aug 2026 23:08:19 +0800 Subject: [PATCH 3/4] =?UTF-8?q?refactor:=20=E6=A0=87=E5=87=86=E5=AF=BC?= =?UTF-8?q?=E5=9B=BE=E4=BB=85=E4=BD=BF=E7=94=A8=E6=8A=A5=E5=91=8A=E7=94=9F?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/ReviewStandardMindMapEntity.java | 2 +- .../service/MindMapAiClient.java | 5 +- .../service/impl/AiServiceClient.java | 7 ++- .../service/impl/BuiltinMindMapGenerator.java | 48 +++++-------------- .../service/impl/RemoteAiMindMapClient.java | 13 ++--- .../impl/StandardMindMapServiceImpl.java | 38 ++++++++------- .../impl/StandardMindMapServiceImplTest.java | 4 +- 7 files changed, 42 insertions(+), 75 deletions(-) diff --git a/src/main/java/com/guo/learningprogresstracker/entity/ReviewStandardMindMapEntity.java b/src/main/java/com/guo/learningprogresstracker/entity/ReviewStandardMindMapEntity.java index 18c2702..d3ae711 100644 --- a/src/main/java/com/guo/learningprogresstracker/entity/ReviewStandardMindMapEntity.java +++ b/src/main/java/com/guo/learningprogresstracker/entity/ReviewStandardMindMapEntity.java @@ -10,7 +10,7 @@ import java.io.Serializable; import java.time.LocalDateTime; /** - * 任务标准思维导图:由内置规则或 AI 从学习报告/残片生成,用户可修改 + * 任务标准思维导图:由内置规则或 AI 从学习报告生成,用户可修改 */ @TableName(value = "review_standard_mind_maps") @Data diff --git a/src/main/java/com/guo/learningprogresstracker/service/MindMapAiClient.java b/src/main/java/com/guo/learningprogresstracker/service/MindMapAiClient.java index dd8c25e..032324c 100644 --- a/src/main/java/com/guo/learningprogresstracker/service/MindMapAiClient.java +++ b/src/main/java/com/guo/learningprogresstracker/service/MindMapAiClient.java @@ -1,6 +1,5 @@ package com.guo.learningprogresstracker.service; -import com.guo.learningprogresstracker.entity.StudyReportFragmentsEntity; import com.guo.learningprogresstracker.entity.StudyReportsEntity; import com.guo.learningprogresstracker.entity.TaskApplicationEntity; import com.guo.learningprogresstracker.entity.TaskEntity; @@ -25,15 +24,13 @@ public interface MindMapAiClient { * 根据学习数据生成标准思维导图根节点 * * @param task 学习任务 - * @param reports 该任务的全部学习报告 - * @param fragments 该任务的全部学习残片 + * @param reports 该任务的全部学习报告 * @param applications 该任务的应用场景(可选) * @param clientHint 前端已有的大纲文本(可选,用于 AI 续写而非全量生成) * @return 标准思维导图的根节点;若无可生成数据则返回 {@link Optional#empty()} */ Optional generate(TaskEntity task, List reports, - List fragments, List applications, String clientHint); diff --git a/src/main/java/com/guo/learningprogresstracker/service/impl/AiServiceClient.java b/src/main/java/com/guo/learningprogresstracker/service/impl/AiServiceClient.java index 7f2dd74..433fb90 100644 --- a/src/main/java/com/guo/learningprogresstracker/service/impl/AiServiceClient.java +++ b/src/main/java/com/guo/learningprogresstracker/service/impl/AiServiceClient.java @@ -82,10 +82,10 @@ public class AiServiceClient { } /** - * 调用 lpt-ai 从学习数据生成思维导图大纲。 + * 调用 lpt-ai 从学习报告生成思维导图大纲。 */ public Optional generateMindMap(String taskName, String taskDescription, - List reports, List fragments) { + List reports) { if (!isConfigured()) { return Optional.empty(); } @@ -93,8 +93,7 @@ public class AiServiceClient { Map params = Map.of( "taskName", taskName, "taskDescription", taskDescription != null ? taskDescription : "", - "reports", reports != null ? reports : List.of(), - "fragments", fragments != null ? fragments : List.of() + "reports", reports != null ? reports : List.of() ); Optional result = submitAndWait("generate-mind-map", params); diff --git a/src/main/java/com/guo/learningprogresstracker/service/impl/BuiltinMindMapGenerator.java b/src/main/java/com/guo/learningprogresstracker/service/impl/BuiltinMindMapGenerator.java index e6be4a9..a0c030a 100644 --- a/src/main/java/com/guo/learningprogresstracker/service/impl/BuiltinMindMapGenerator.java +++ b/src/main/java/com/guo/learningprogresstracker/service/impl/BuiltinMindMapGenerator.java @@ -1,6 +1,5 @@ package com.guo.learningprogresstracker.service.impl; -import com.guo.learningprogresstracker.entity.StudyReportFragmentsEntity; import com.guo.learningprogresstracker.entity.StudyReportsEntity; import com.guo.learningprogresstracker.entity.TaskApplicationEntity; import com.guo.learningprogresstracker.entity.TaskEntity; @@ -16,12 +15,12 @@ import java.util.*; import java.util.stream.Collectors; /** - * 内置规则引擎:从学习报告和残片提取关键词并组织为树形思维导图。 + * 内置规则引擎:从学习报告提取内容并组织为树形思维导图。 *

规则策略:

*
    *
  1. 根节点 = 任务名称
  2. *
  3. 一级分支 = 按会话(日期+报告摘要)分组
  4. - *
  5. 二级分支 = 该会话下的残片标题
  6. + *
  7. 二级分支 = 该会话下的报告
  8. *
  9. 附加分支"应用场景" = 任务应用场景(如有)
  10. *
  11. 去重:标准化后标题对比,合并内容相似的节点
  12. *
  13. 引用追溯:每个节点携带 sourceType / sourceId
  14. @@ -46,10 +45,9 @@ public class BuiltinMindMapGenerator implements MindMapAiClient { @Override public Optional generate(TaskEntity task, List reports, - List fragments, List applications, String clientHint) { - if (reports.isEmpty() && fragments.isEmpty()) { + if (reports == null || reports.isEmpty()) { return Optional.empty(); } @@ -58,34 +56,21 @@ public class BuiltinMindMapGenerator implements MindMapAiClient { // 按 session 分组 Map> reportsBySession = reports.stream() + .filter(r -> r.getSessionNum() != null) .collect(Collectors.groupingBy(StudyReportsEntity::getSessionNum)); - Map> fragmentsBySession = fragments.stream() - .collect(Collectors.groupingBy(StudyReportFragmentsEntity::getSessionNum)); - // 合并所有 session - Set allSessions = new LinkedHashSet<>(); - allSessions.addAll(reportsBySession.keySet()); - allSessions.addAll(fragmentsBySession.keySet()); + for (Map.Entry> entry : reportsBySession.entrySet()) { + List sessReports = entry.getValue(); - for (String sessionNum : allSessions) { - List sessReports = reportsBySession.getOrDefault(sessionNum, List.of()); - List sessFragments = fragmentsBySession.getOrDefault(sessionNum, List.of()); - - // 会话分支标题:取第一条报告的前 60 字作为摘要,或直接写"学习记录" - String sessionTitle; - if (!sessReports.isEmpty()) { - String firstReport = sessReports.get(0).getContent(); - sessionTitle = truncate(firstReport, MAX_TITLE_LENGTH); - if (sessReports.get(0).getCreatedTime() != null) { - sessionTitle = formatDate(sessReports.get(0).getCreatedTime()) + " " + sessionTitle; - } - } else { - sessionTitle = "学习记录 " + (sessFragments.isEmpty() ? "" : formatDate(sessFragments.get(0).getCreatedTime())); + // 会话分支标题:取第一条报告的前 60 字作为摘要 + StudyReportsEntity firstReport = sessReports.get(0); + String sessionTitle = truncate(firstReport.getContent(), MAX_TITLE_LENGTH); + if (firstReport.getCreatedTime() != null) { + sessionTitle = formatDate(firstReport.getCreatedTime()) + " " + sessionTitle; } MindMapNode sessionNode = new MindMapNode(sessionTitle); - // 报告作为子节点 for (StudyReportsEntity report : sessReports) { String content = report.getContent(); if (content == null || content.isBlank()) continue; @@ -96,17 +81,6 @@ public class BuiltinMindMapGenerator implements MindMapAiClient { sessionNode.getChildren().add(reportNode); } - // 残片作为子节点 - for (StudyReportFragmentsEntity frag : sessFragments) { - String content = frag.getContent(); - if (content == null || content.isBlank()) continue; - MindMapNode fragNode = new MindMapNode(truncate(content, MAX_TITLE_LENGTH)); - fragNode.setNotes(content); - fragNode.setSourceType("FRAGMENT"); - fragNode.setSourceId(frag.getId()); - sessionNode.getChildren().add(fragNode); - } - root.getChildren().add(sessionNode); } diff --git a/src/main/java/com/guo/learningprogresstracker/service/impl/RemoteAiMindMapClient.java b/src/main/java/com/guo/learningprogresstracker/service/impl/RemoteAiMindMapClient.java index 9de5dc9..20b92a5 100644 --- a/src/main/java/com/guo/learningprogresstracker/service/impl/RemoteAiMindMapClient.java +++ b/src/main/java/com/guo/learningprogresstracker/service/impl/RemoteAiMindMapClient.java @@ -1,6 +1,5 @@ package com.guo.learningprogresstracker.service.impl; -import com.guo.learningprogresstracker.entity.StudyReportFragmentsEntity; import com.guo.learningprogresstracker.entity.StudyReportsEntity; import com.guo.learningprogresstracker.entity.TaskApplicationEntity; import com.guo.learningprogresstracker.entity.TaskEntity; @@ -40,32 +39,26 @@ public class RemoteAiMindMapClient implements MindMapAiClient { @Override public Optional generate(TaskEntity task, List reports, - List fragments, List applications, String clientHint) { if (!isAvailable()) { return Optional.empty(); } - // 提取报告和残片的内容文本 + // 提取学习报告的内容文本 List reportTexts = reports.stream() .map(StudyReportsEntity::getContent) .filter(c -> c != null && !c.isBlank()) .collect(Collectors.toList()); - List fragmentTexts = fragments.stream() - .map(StudyReportFragmentsEntity::getContent) - .filter(c -> c != null && !c.isBlank()) - .collect(Collectors.toList()); - if (reportTexts.isEmpty() && fragmentTexts.isEmpty()) { + if (reportTexts.isEmpty()) { return Optional.empty(); } Optional optOutline = aiServiceClient.generateMindMap( task.getTaskName(), task.getTaskDescription(), - reportTexts, - fragmentTexts + reportTexts ); if (optOutline.isEmpty() || optOutline.get().isBlank()) { diff --git a/src/main/java/com/guo/learningprogresstracker/service/impl/StandardMindMapServiceImpl.java b/src/main/java/com/guo/learningprogresstracker/service/impl/StandardMindMapServiceImpl.java index ae9fdc9..acf8157 100644 --- a/src/main/java/com/guo/learningprogresstracker/service/impl/StandardMindMapServiceImpl.java +++ b/src/main/java/com/guo/learningprogresstracker/service/impl/StandardMindMapServiceImpl.java @@ -36,7 +36,6 @@ public class StandardMindMapServiceImpl implements StandardMindMapService { private final ReviewRecallRecordMapper recallRecordMapper; private final TasksMapper tasksMapper; private final StudyReportsMapper studyReportsMapper; - private final StudyReportFragmentsMapper studyReportFragmentsMapper; private final TaskApplicationMapper taskApplicationMapper; private final StudySessionsMapper studySessionsMapper; @@ -86,7 +85,8 @@ public class StandardMindMapServiceImpl implements StandardMindMapService { ensureTaskExists(taskNum); ReviewStandardMindMapEntity existing = queryByTaskNum(taskNum); if (existing == null) { - throw new NotFindEntitiesException("标准思维导图尚不存在,无法增量更新"); + log.warn("任务[{}]标准思维导图尚不存在,无法增量更新", taskNum); + throw new NotFindEntitiesException("还没有生成过标准思维导图,请先完整生成一次哦"); } // 防并发生成 AtomicBoolean lock = generatingTasks.computeIfAbsent(taskNum, k -> new AtomicBoolean(false)); @@ -201,7 +201,8 @@ public class StandardMindMapServiceImpl implements StandardMindMapService { try { resultJson = objectMapper.writeValueAsString(result); } catch (Exception e) { - throw new OperationFailedException("对比结果序列化失败"); + log.error("任务[{}]对比结果序列化失败", taskNum, e); + throw new OperationFailedException("对比结果解析失败了,请稍后再试"); } // 5. 保存回忆记录 @@ -405,7 +406,10 @@ public class StandardMindMapServiceImpl implements StandardMindMapService { @Override public ReviewRecallRecordEntity getRecallRecord(Integer recordId) throws NotFindEntitiesException { return Optional.ofNullable(recallRecordMapper.selectById(recordId)) - .orElseThrow(() -> new NotFindEntitiesException("回忆记录[" + recordId + "]不存在")); + .orElseThrow(() -> { + log.warn("回忆记录[{}]不存在", recordId); + return new NotFindEntitiesException("这条回忆记录不存在或已被删除"); + }); } // ============ 内部方法 ============ @@ -415,7 +419,8 @@ public class StandardMindMapServiceImpl implements StandardMindMapService { Wrappers.lambdaQuery().eq(TaskEntity::getTaskNum, taskNum).last("LIMIT 1")); if (task == null) { - throw new OperationFailedException("任务[" + taskNum + "]不存在"); + log.warn("任务[{}]不存在,无法生成思维导图", taskNum); + throw new OperationFailedException("这个任务不存在或已被删除"); } // 收集学习数据 @@ -428,14 +433,12 @@ public class StandardMindMapServiceImpl implements StandardMindMapService { List reports = sessionNums.isEmpty() ? List.of() : studyReportsMapper.selectList(Wrappers.lambdaQuery() .in(StudyReportsEntity::getSessionNum, sessionNums)); - List fragments = sessionNums.isEmpty() ? List.of() - : studyReportFragmentsMapper.selectList(Wrappers.lambdaQuery() - .in(StudyReportFragmentsEntity::getSessionNum, sessionNums)); List applications = taskApplicationMapper.selectList( Wrappers.lambdaQuery().eq(TaskApplicationEntity::getTaskNum, taskNum)); - if (reports.isEmpty() && fragments.isEmpty()) { - throw new OperationFailedException("任务[" + taskNum + "]没有学习报告或残片,无法生成思维导图"); + if (reports.isEmpty()) { + log.warn("任务[{}]没有学习报告,无法生成思维导图", taskNum); + throw new OperationFailedException("这个任务还没开始学习哦,学习后产生学习报告后再来吧"); } // 优先选 AI 客户端(非 BUILTIN),其次内置生成器 @@ -445,10 +448,11 @@ public class StandardMindMapServiceImpl implements StandardMindMapService { .orElse(null); if (client == null) { - throw new OperationFailedException("没有可用的思维导图生成器"); + log.warn("任务[{}]没有可用的思维导图生成器", taskNum); + throw new OperationFailedException("思维导图暂时生成不了,请稍后再试"); } - Optional optRoot = client.generate(task, reports, fragments, applications, null); + Optional optRoot = client.generate(task, reports, applications, null); // AI 生成失败时尝试降级到内置生成器 if (optRoot.isEmpty() && !"BUILTIN".equals(client.generatorName())) { log.info("AI 思维导图生成失败,降级到内置生成器"); @@ -456,11 +460,12 @@ public class StandardMindMapServiceImpl implements StandardMindMapService { .filter(c -> "BUILTIN".equals(c.generatorName()) && c.isAvailable()) .findFirst().orElse(null); if (fallback != null) { - optRoot = fallback.generate(task, reports, fragments, applications, null); + optRoot = fallback.generate(task, reports, applications, null); } } if (optRoot.isEmpty()) { - throw new OperationFailedException("思维导图生成失败"); + log.warn("任务[{}]思维导图生成失败,已尝试全部生成器", taskNum); + throw new OperationFailedException("思维导图生成失败了,请稍后再试"); } MindMapNode root = optRoot.get(); @@ -483,7 +488,7 @@ public class StandardMindMapServiceImpl implements StandardMindMapService { entity.setGenerator(client.generatorName()); entity.setGeneratorVersion("1.0"); entity.setSourceReportCount(reports.size()); - entity.setSourceFragmentCount(fragments.size()); + entity.setSourceFragmentCount(0); entity.setGeneratedTime(LocalDateTime.now()); if (create) { @@ -497,7 +502,8 @@ public class StandardMindMapServiceImpl implements StandardMindMapService { private void ensureTaskExists(String taskNum) throws NotFindEntitiesException { if (!StringUtils.hasText(taskNum) || !tasksMapper.exists( Wrappers.lambdaQuery().eq(TaskEntity::getTaskNum, taskNum))) { - throw new NotFindEntitiesException("任务[" + taskNum + "]不存在"); + log.warn("任务[{}]不存在", taskNum); + throw new NotFindEntitiesException("这个任务不存在或已被删除"); } } diff --git a/src/test/java/com/guo/learningprogresstracker/service/impl/StandardMindMapServiceImplTest.java b/src/test/java/com/guo/learningprogresstracker/service/impl/StandardMindMapServiceImplTest.java index 58cbcaf..8548442 100644 --- a/src/test/java/com/guo/learningprogresstracker/service/impl/StandardMindMapServiceImplTest.java +++ b/src/test/java/com/guo/learningprogresstracker/service/impl/StandardMindMapServiceImplTest.java @@ -36,8 +36,6 @@ class StandardMindMapServiceImplTest { @Mock private StudyReportsMapper studyReportsMapper; @Mock - private StudyReportFragmentsMapper studyReportFragmentsMapper; - @Mock private TaskApplicationMapper taskApplicationMapper; @Mock private StudySessionsMapper studySessionsMapper; @@ -189,7 +187,7 @@ class StandardMindMapServiceImplTest { private StandardMindMapServiceImpl createService() { StandardMindMapServiceImpl s = new StandardMindMapServiceImpl( standardMindMapMapper, recallRecordMapper, - tasksMapper, studyReportsMapper, studyReportFragmentsMapper, + tasksMapper, studyReportsMapper, taskApplicationMapper, studySessionsMapper, List.of(mockAiClient), objectMapper, aiServiceClient); return s; From 6678c2b8c0d1552364097e0bedf59b27584f21c2 Mon Sep 17 00:00:00 2001 From: cat-shark <1716967236@qq.com> Date: Mon, 3 Aug 2026 23:08:26 +0800 Subject: [PATCH 4/4] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=8F=AF=E8=A7=81=E9=94=99=E8=AF=AF=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/GlobalExceptionHandler.java | 12 +++++- .../controller/StudySessionController.java | 2 +- .../controller/TaskController.java | 4 +- .../dto/request/CreateFragmentsRequest.java | 2 +- .../request/CreateTaskApplicationRequest.java | 2 +- .../dto/request/EndedStudySessionRequest.java | 2 +- .../dto/request/RecallCompareRequest.java | 2 +- .../dto/request/TaskRequest.java | 38 +++++++++--------- .../dto/request/UpdateFragmentsRequest.java | 2 +- .../request/UpdateStandardMindMapRequest.java | 2 +- .../request/UpdateTaskApplicationRequest.java | 2 +- .../dto/request/UpsertExpectationRequest.java | 2 +- .../impl/StudyExpectationsServiceImpl.java | 5 ++- .../impl/StudyReportFragmentsServiceImpl.java | 8 +++- .../impl/StudySessionsServiceImpl.java | 40 +++++++++++++------ .../service/impl/TasksServiceImpl.java | 16 ++++++-- 16 files changed, 91 insertions(+), 50 deletions(-) diff --git a/src/main/java/com/guo/learningprogresstracker/common/GlobalExceptionHandler.java b/src/main/java/com/guo/learningprogresstracker/common/GlobalExceptionHandler.java index b3eba3f..2914a63 100644 --- a/src/main/java/com/guo/learningprogresstracker/common/GlobalExceptionHandler.java +++ b/src/main/java/com/guo/learningprogresstracker/common/GlobalExceptionHandler.java @@ -5,6 +5,7 @@ import com.guo.learningprogresstracker.entity.CommonResult; import com.guo.learningprogresstracker.exception.AppException; import com.guo.learningprogresstracker.exception.ErrorParameterException; import com.guo.learningprogresstracker.exception.NotFindEntitiesException; +import com.guo.learningprogresstracker.exception.OperationFailedException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; @@ -21,16 +22,25 @@ public class GlobalExceptionHandler { @ExceptionHandler({ErrorParameterException.class}) public CommonResult errorParameterException(ErrorParameterException ex) { + log.warn("参数异常: {}", ex.getMessage(), ex); return CommonResult.error(ex.getMessage()); } @ExceptionHandler({NotFindEntitiesException.class}) public CommonResult notFindEntitiesException(NotFindEntitiesException ex) { + log.warn("数据不存在: {}", ex.getMessage(), ex); + return CommonResult.error(ex.getMessage()); + } + + @ExceptionHandler({OperationFailedException.class}) + public CommonResult operationFailedException(OperationFailedException ex) { + log.warn("操作失败: {}", ex.getMessage(), ex); return CommonResult.error(ex.getMessage()); } @ExceptionHandler({AppException.class}) public CommonResult AppException(AppException ex) { + log.error("业务异常: {}", ex.getMessage(), ex); return CommonResult.serverError(ex.getMessage()); } @@ -49,7 +59,7 @@ public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public CommonResult Exception(Exception ex) { log.error("系统异常", ex); - return CommonResult.error(ex.getMessage()); + return CommonResult.error("操作没有成功,请稍后再试"); } } diff --git a/src/main/java/com/guo/learningprogresstracker/controller/StudySessionController.java b/src/main/java/com/guo/learningprogresstracker/controller/StudySessionController.java index d0b5bda..1a228d2 100644 --- a/src/main/java/com/guo/learningprogresstracker/controller/StudySessionController.java +++ b/src/main/java/com/guo/learningprogresstracker/controller/StudySessionController.java @@ -57,7 +57,7 @@ public class StudySessionController { * 通过sessionNum获取一个【学习会话】 */ @GetMapping("/{sessionNum}") - public CommonResult getStudySessionBySessionNum(@NotEmpty(message = "sessionNum不可为空") @PathVariable String sessionNum) throws ErrorParameterException { + public CommonResult getStudySessionBySessionNum(@NotEmpty(message = "请提供学习会话编号") @PathVariable String sessionNum) throws ErrorParameterException { // 通过 service 层获取,包含归属校验 StudySessionResponse response = studySessionsServiceImpl.getStudySessionBySessionNum(sessionNum); return CommonResult.success(response); diff --git a/src/main/java/com/guo/learningprogresstracker/controller/TaskController.java b/src/main/java/com/guo/learningprogresstracker/controller/TaskController.java index 67d263b..82219ec 100644 --- a/src/main/java/com/guo/learningprogresstracker/controller/TaskController.java +++ b/src/main/java/com/guo/learningprogresstracker/controller/TaskController.java @@ -132,7 +132,7 @@ public class TaskController { * 开始或继续一个【学习会话】 */ @GetMapping("/{taskNum}/study-sessions/start-or-continue") - public CommonResult startOrContinueStudySession(@NotEmpty(message = "taskNum不可为空") + public CommonResult startOrContinueStudySession(@NotEmpty(message = "请提供任务编号") @PathVariable String taskNum) throws NotFindEntitiesException, ServiceException { StudySessionResponse response = studySessionsServiceImpl.startOrContinueStudySession(taskNum); return CommonResult.success(response); @@ -143,7 +143,7 @@ public class TaskController { * 通过学习任务num获取该任务的未结束会话 */ @GetMapping("/{taskNum}/not-ended-study-session") - public CommonResult getNotEndedStudySessionByTaskNum(@NotEmpty(message = "taskNum不可为空") + public CommonResult getNotEndedStudySessionByTaskNum(@NotEmpty(message = "请提供任务编号") @PathVariable String taskNum) throws ErrorParameterException { StudySessionResponse response = studySessionsServiceImpl.getNotEndedStudySessionByTaskNum(taskNum); return CommonResult.success(response); diff --git a/src/main/java/com/guo/learningprogresstracker/dto/request/CreateFragmentsRequest.java b/src/main/java/com/guo/learningprogresstracker/dto/request/CreateFragmentsRequest.java index 53756b9..891a72c 100644 --- a/src/main/java/com/guo/learningprogresstracker/dto/request/CreateFragmentsRequest.java +++ b/src/main/java/com/guo/learningprogresstracker/dto/request/CreateFragmentsRequest.java @@ -16,6 +16,6 @@ public class CreateFragmentsRequest { /** * 残片内容,学习内容的描述 */ - @NotBlank(message = "啊?无字天书?") + @NotBlank(message = "请填写学习内容") private String content; } diff --git a/src/main/java/com/guo/learningprogresstracker/dto/request/CreateTaskApplicationRequest.java b/src/main/java/com/guo/learningprogresstracker/dto/request/CreateTaskApplicationRequest.java index b66c360..808926b 100644 --- a/src/main/java/com/guo/learningprogresstracker/dto/request/CreateTaskApplicationRequest.java +++ b/src/main/java/com/guo/learningprogresstracker/dto/request/CreateTaskApplicationRequest.java @@ -8,7 +8,7 @@ public class CreateTaskApplicationRequest { private String taskNum; - @NotBlank(message = "应用项目标题不可为空") + @NotBlank(message = "请填写应用项目标题") private String title; private String description; diff --git a/src/main/java/com/guo/learningprogresstracker/dto/request/EndedStudySessionRequest.java b/src/main/java/com/guo/learningprogresstracker/dto/request/EndedStudySessionRequest.java index dcff657..1e7313e 100644 --- a/src/main/java/com/guo/learningprogresstracker/dto/request/EndedStudySessionRequest.java +++ b/src/main/java/com/guo/learningprogresstracker/dto/request/EndedStudySessionRequest.java @@ -8,6 +8,6 @@ import lombok.Data; */ @Data public class EndedStudySessionRequest { - @NotBlank(message = "啊?搞无字天书是吧?报告内容不可为空") + @NotBlank(message = "请填写学习报告内容") private String content; } diff --git a/src/main/java/com/guo/learningprogresstracker/dto/request/RecallCompareRequest.java b/src/main/java/com/guo/learningprogresstracker/dto/request/RecallCompareRequest.java index a9e88a8..960b43e 100644 --- a/src/main/java/com/guo/learningprogresstracker/dto/request/RecallCompareRequest.java +++ b/src/main/java/com/guo/learningprogresstracker/dto/request/RecallCompareRequest.java @@ -9,7 +9,7 @@ import lombok.Data; @Data public class RecallCompareRequest { - @NotBlank(message = "回忆大纲不可为空") + @NotBlank(message = "请先填写回忆大纲") private String recallOutline; /** 复习起点节点路径(以 / 分隔),null 为任务维度 */ diff --git a/src/main/java/com/guo/learningprogresstracker/dto/request/TaskRequest.java b/src/main/java/com/guo/learningprogresstracker/dto/request/TaskRequest.java index f35b696..2ae83f1 100644 --- a/src/main/java/com/guo/learningprogresstracker/dto/request/TaskRequest.java +++ b/src/main/java/com/guo/learningprogresstracker/dto/request/TaskRequest.java @@ -15,16 +15,16 @@ import lombok.Data; public class TaskRequest { public interface Create{} - @Null(message = "创建时不可指定任务ID",groups = Ops.CreateG.class) - @NotNull(message = "更新时必须指定任务ID",groups = Ops.UpdateG.class) + @Null(message = "创建任务时不需要填写任务编号",groups = Ops.CreateG.class) + @NotNull(message = "缺少要更新的任务信息,请刷新后重试",groups = Ops.UpdateG.class) private Integer id; /** * 学习任务的名称 */ - @NotEmpty(message = "必须指定非空的任务名称", groups = Ops.CreateG.class) + @NotEmpty(message = "请填写任务名称", groups = Ops.CreateG.class) private String taskName; - @NotEmpty(message = "必须指定非空的任务描述", groups = Ops.CreateG.class) + @NotEmpty(message = "请填写任务描述", groups = Ops.CreateG.class) private String taskDescription; /** @@ -35,41 +35,41 @@ public class TaskRequest { /** * 用户设置的任务紧急性 */ - @NotNull(message = "必须指定【任务紧急性】指标", groups = Ops.CreateG.class) - @Min(value = 0,message = "urgency参数值必须大于等于0") - @Max(value = 5,message = "urgency参数值必须小于等于5") + @NotNull(message = "请设置任务紧急性", groups = Ops.CreateG.class) + @Min(value = 0,message = "任务紧急性不能小于 0") + @Max(value = 5,message = "任务紧急性不能大于 5") private Integer urgency; /** * 用户设置的任务重要性 */ - @NotNull(message = "必须指定【任务重要性】指标", groups = Ops.CreateG.class) - @Min(value = 0,message = "importance参数值必须大于等于0") - @Max(value = 5,message = "importance参数值必须小于等于5") + @NotNull(message = "请设置任务重要性", groups = Ops.CreateG.class) + @Min(value = 0,message = "任务重要性不能小于 0") + @Max(value = 5,message = "任务重要性不能大于 5") private Integer importance; /** * 任务的内容难度 */ - @NotNull(message = "必须指定【内容难度】指标", groups = Ops.CreateG.class) - @Min(value = 0,message = "contentDifficulty参数值必须大于等于0") - @Max(value = 5,message = "contentDifficulty参数值必须小于等于5") + @NotNull(message = "请设置内容难度", groups = Ops.CreateG.class) + @Min(value = 0,message = "内容难度不能小于 0") + @Max(value = 5,message = "内容难度不能大于 5") private Integer contentDifficulty; /** * 任务的未来价值 */ - @NotNull(message = "必须指定【未来价值】指标", groups = Ops.CreateG.class) - @Min(value = 0,message = "futureValue参数值必须大于等于0") - @Max(value = 5,message = "futureValue参数值必须小于等于5") + @NotNull(message = "请设置未来价值", groups = Ops.CreateG.class) + @Min(value = 0,message = "未来价值不能小于 0") + @Max(value = 5,message = "未来价值不能大于 5") private Integer futureValue; /** * 用户对任务的主观优先级 */ - @NotNull(message = "必须指定【主观优先级】指标", groups = Ops.CreateG.class) - @Min(value = 0,message = "subjectivePriority参数值必须大于等于0") - @Max(value = 5,message = "subjectivePriority参数值必须小于等于5") + @NotNull(message = "请设置主观优先级", groups = Ops.CreateG.class) + @Min(value = 0,message = "主观优先级不能小于 0") + @Max(value = 5,message = "主观优先级不能大于 5") private Integer subjectivePriority; } diff --git a/src/main/java/com/guo/learningprogresstracker/dto/request/UpdateFragmentsRequest.java b/src/main/java/com/guo/learningprogresstracker/dto/request/UpdateFragmentsRequest.java index 37acce3..c60273f 100644 --- a/src/main/java/com/guo/learningprogresstracker/dto/request/UpdateFragmentsRequest.java +++ b/src/main/java/com/guo/learningprogresstracker/dto/request/UpdateFragmentsRequest.java @@ -11,6 +11,6 @@ public class UpdateFragmentsRequest { /** * 残片内容,学习内容的描述 */ - @NotBlank(message = "啊?无字天书?") + @NotBlank(message = "请填写学习内容") private String content; } diff --git a/src/main/java/com/guo/learningprogresstracker/dto/request/UpdateStandardMindMapRequest.java b/src/main/java/com/guo/learningprogresstracker/dto/request/UpdateStandardMindMapRequest.java index bff71f0..4551912 100644 --- a/src/main/java/com/guo/learningprogresstracker/dto/request/UpdateStandardMindMapRequest.java +++ b/src/main/java/com/guo/learningprogresstracker/dto/request/UpdateStandardMindMapRequest.java @@ -9,6 +9,6 @@ import lombok.Data; @Data public class UpdateStandardMindMapRequest { - @NotBlank(message = "思维导图大纲不可为空") + @NotBlank(message = "请填写思维导图大纲") private String outline; } diff --git a/src/main/java/com/guo/learningprogresstracker/dto/request/UpdateTaskApplicationRequest.java b/src/main/java/com/guo/learningprogresstracker/dto/request/UpdateTaskApplicationRequest.java index 17ae893..0aa336e 100644 --- a/src/main/java/com/guo/learningprogresstracker/dto/request/UpdateTaskApplicationRequest.java +++ b/src/main/java/com/guo/learningprogresstracker/dto/request/UpdateTaskApplicationRequest.java @@ -6,7 +6,7 @@ import lombok.Data; @Data public class UpdateTaskApplicationRequest { - @NotBlank(message = "应用项目标题不可为空") + @NotBlank(message = "请填写应用项目标题") private String title; private String description; diff --git a/src/main/java/com/guo/learningprogresstracker/dto/request/UpsertExpectationRequest.java b/src/main/java/com/guo/learningprogresstracker/dto/request/UpsertExpectationRequest.java index f70cc3e..733bb65 100644 --- a/src/main/java/com/guo/learningprogresstracker/dto/request/UpsertExpectationRequest.java +++ b/src/main/java/com/guo/learningprogresstracker/dto/request/UpsertExpectationRequest.java @@ -9,6 +9,6 @@ import lombok.Data; @Data public class UpsertExpectationRequest { - @NotBlank(message = "学习预期不可为空") + @NotBlank(message = "请填写学习预期") private String description; } diff --git a/src/main/java/com/guo/learningprogresstracker/service/impl/StudyExpectationsServiceImpl.java b/src/main/java/com/guo/learningprogresstracker/service/impl/StudyExpectationsServiceImpl.java index b77b8b4..692a79e 100644 --- a/src/main/java/com/guo/learningprogresstracker/service/impl/StudyExpectationsServiceImpl.java +++ b/src/main/java/com/guo/learningprogresstracker/service/impl/StudyExpectationsServiceImpl.java @@ -8,11 +8,13 @@ import com.guo.learningprogresstracker.mapper.StudyExpectationsMapper; import com.guo.learningprogresstracker.mapper.StudySessionsMapper; import com.guo.learningprogresstracker.service.StudyExpectationsService; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; /** * 学习预期服务实现 */ +@Slf4j @Service @RequiredArgsConstructor public class StudyExpectationsServiceImpl implements StudyExpectationsService { @@ -26,7 +28,8 @@ public class StudyExpectationsServiceImpl implements StudyExpectationsService { Wrappers.lambdaQuery() .eq(StudySessionsEntity::getSessionNum, sessionNum)); if (!sessionExists) { - throw new ErrorParameterException("学习会话[" + sessionNum + "]不存在"); + log.warn("学习会话[{}]不存在", sessionNum); + throw new ErrorParameterException("这次学习会话不存在或已结束"); } StudyExpectationsEntity existing = getBySessionNum(sessionNum); diff --git a/src/main/java/com/guo/learningprogresstracker/service/impl/StudyReportFragmentsServiceImpl.java b/src/main/java/com/guo/learningprogresstracker/service/impl/StudyReportFragmentsServiceImpl.java index 5378613..3c3a83a 100644 --- a/src/main/java/com/guo/learningprogresstracker/service/impl/StudyReportFragmentsServiceImpl.java +++ b/src/main/java/com/guo/learningprogresstracker/service/impl/StudyReportFragmentsServiceImpl.java @@ -12,6 +12,7 @@ import com.guo.learningprogresstracker.mapper.StudySessionsMapper; import com.guo.learningprogresstracker.service.StudyReportFragmentsService; import com.guo.learningprogresstracker.mapper.StudyReportFragmentsMapper; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -20,6 +21,7 @@ import java.util.List; /** * 针对表【study_report_fragments(记录学习过程中的学习内容报告残片)】的数据库操作Service实现 */ +@Slf4j @Service @RequiredArgsConstructor public class StudyReportFragmentsServiceImpl extends ServiceImpl @@ -35,7 +37,8 @@ public class StudyReportFragmentsServiceImpl extends ServiceImpl new NotFindEntitiesException(String.format("[%s]不存在", taskNum))); + .orElseThrow(() -> { + log.warn("[{}]不存在", taskNum); + return new NotFindEntitiesException("这个任务不存在或已被删除"); + }); StudySessionsEntity session = this.getOneOpt(Wrappers.lambdaQuery() .eq(StudySessionsEntity::getTaskNum, taskNum) @@ -88,10 +91,10 @@ public class StudySessionsServiceImpl extends ServiceImpl new ErrorParameterException("会话[" + sessionNum + "]不存在")); + .orElseThrow(() -> sessionNotFound(sessionNum)); if (StudySessionStateEnum.PAUSED.name().equals(studySessionsEntity.getSessionState())) { log.error("会话[" + studySessionsEntity.getSessionNum() + "]重复暂停"); - throw new ErrorParameterException("会话[" + sessionNum + "]已经暂停,请勿重复暂停!"); + throw new ErrorParameterException("这次学习会话已经暂停了,不用重复暂停哦"); } studySessionsEntity.calculatePointerPosition(); studySessionsEntity.pausedStudySession(endTime); @@ -104,7 +107,7 @@ public class StudySessionsServiceImpl extends ServiceImpl new ErrorParameterException("会话[" + sessionNum + "]不存在")); + .orElseThrow(() -> sessionNotFound(sessionNum)); boolean wasOngoing = StudySessionStateEnum.ONGOING.name().equals(studySessionsEntity.getSessionState()); studySessionsEntity.endedStudySession(); this.updateById(studySessionsEntity); @@ -122,9 +125,12 @@ public class StudySessionsServiceImpl extends ServiceImpl new ErrorParameterException("任务[" + taskNum + "]不存在")); + .orElseThrow(() -> taskNotFound(taskNum)); StudySessionsDto dto = Optional.ofNullable(studyReportsMapper.getNotEndedStudySessionDtoByTaskNum(taskNum)) - .orElseThrow(() -> new ErrorParameterException("任务[" + taskNum + "]不存在进行中或暂停中的会话")); + .orElseThrow(() -> { + log.warn("任务[{}]不存在进行中或暂停中的会话", taskNum); + return new ErrorParameterException("这个任务当前没有进行中或已暂停的学习会话"); + }); return StudySessionConvert.MAPPER.toStudySessionResponse(dto); } @@ -136,7 +142,7 @@ public class StudySessionsServiceImpl extends ServiceImpl new ErrorParameterException("会话[" + sessionNum + "]不存在")); + .orElseThrow(() -> sessionNotFound(sessionNum)); if (StudySessionStateEnum.ONGOING.name().equals(studySessionsEntity.getSessionState())) { log.error("会话[" + studySessionsEntity.getSessionNum() + "]重复开始"); - throw new ErrorParameterException("会话[" + sessionNum + "]已经开始,请勿重复开始!"); + throw new ErrorParameterException("这次学习会话已经开始了,不用重复开始哦"); } else if (StudySessionStateEnum.ENDED.name().equals(studySessionsEntity.getSessionState())) { log.error("会话[" + studySessionsEntity.getSessionNum() + "]处于结束状态,不可开始该会话!"); - throw new ErrorParameterException("会话[" + sessionNum + "]处于结束状态,不可开始该会话!"); + throw new ErrorParameterException("这次学习会话已经结束,无法再次开始"); } studySessionsEntity.continueStudySession(); this.updateById(studySessionsEntity); @@ -163,7 +169,7 @@ public class StudySessionsServiceImpl extends ServiceImpl new ErrorParameterException("会话[" + sessionNum + "]不存在")); + .orElseThrow(() -> sessionNotFound(sessionNum)); return StudySessionConvert.MAPPER.toStudySessionResponse(session); } @@ -174,7 +180,7 @@ public class StudySessionsServiceImpl extends ServiceImpl new ErrorParameterException("会话[" + sessionNum + "]不存在")); + .orElseThrow(() -> sessionNotFound(sessionNum)); ArrayList fragments = getAllFragments(sessionNum); if (fragments.isEmpty()) { @@ -262,4 +268,14 @@ public class StudySessionsServiceImpl extends ServiceImpl if (this.exists(Wrappers.lambdaQuery(TaskEntity.class) .eq(TaskEntity::getTaskName, task.getTaskName()))) { - throw new ErrorParameterException(String.format("任务名[%s]重复", task.getTaskName())); + log.warn("任务名[{}]重复", task.getTaskName()); + throw new ErrorParameterException("已经有同名任务了,换个任务名称吧"); } task.setTaskNum(GenerateNumTool.generateNum("TASK")); @@ -132,7 +133,10 @@ public class TasksServiceImpl extends ServiceImpl @Override public TaskApplicationEntity updateApplication(Integer id, UpdateTaskApplicationRequest request) throws NotFindEntitiesException { TaskApplicationEntity existing = Optional.ofNullable(taskApplicationMapper.selectById(id)) - .orElseThrow(() -> new NotFindEntitiesException("应用场景[" + id + "]不存在")); + .orElseThrow(() -> { + log.warn("应用场景[{}]不存在", id); + return new NotFindEntitiesException("这个应用场景不存在或已被删除"); + }); existing.setTitle(request.getTitle()); existing.setDescription(request.getDescription()); existing.setResourceUrl(request.getResourceUrl()); @@ -144,14 +148,18 @@ public class TasksServiceImpl extends ServiceImpl @Override public void deleteApplication(Integer id) throws NotFindEntitiesException { TaskApplicationEntity existing = Optional.ofNullable(taskApplicationMapper.selectById(id)) - .orElseThrow(() -> new NotFindEntitiesException("应用场景[" + id + "]不存在")); + .orElseThrow(() -> { + log.warn("应用场景[{}]不存在", id); + return new NotFindEntitiesException("这个应用场景不存在或已被删除"); + }); taskApplicationMapper.deleteById(existing.getId()); } private void ensureTaskExists(String taskNum) throws NotFindEntitiesException { if (!StringUtils.hasText(taskNum) || !tasksMapper.exists( Wrappers.lambdaQuery().eq(TaskEntity::getTaskNum, taskNum))) { - throw new NotFindEntitiesException("任务[" + taskNum + "]不存在"); + log.warn("任务[{}]不存在", taskNum); + throw new NotFindEntitiesException("这个任务不存在或已被删除"); } }