核心功能
系统设计思路
代码分析
1. 学习记录管理
• 存储学习记录到 Redis:
利用 Redis 缓存学习记录,减少频繁的数据库访问。
public void writeRecordCache(LearningRecord record) {String key = String.format("LEARNING:RECORD:%d", record.getLessonId());redisTemplate.opsForHash().put(key, record.getSectionId().toString(), JsonUtils.toJsonStr(record));redisTemplate.expire(key, Duration.ofMinutes(30)); // 设置缓存有效期
}
• 从 Redis 查询学习记录:
如果缓存中存在学习记录,直接返回;否则查询数据库。
public LearningRecord readRecordCache(Long lessonId, Long sectionId) {String key = String.format("LEARNING:RECORD:%d", lessonId);Object recordData = redisTemplate.opsForHash().get(key, sectionId.toString());return recordData == null ? null : JsonUtils.parse(recordData.toString(), LearningRecord.class);
}
• 定时持久化学习记录:
使用延迟任务模块,将学习记录从 Redis 同步到数据库。
public void persistLearningRecords() {List<LearningRecord> records = getAllCachedRecords();for (LearningRecord record : records) {learningRecordMapper.upsert(record);}
}
2. 延迟任务模块
• 延迟任务定义:
每个任务封装了学习记录及延迟时间。
public class DelayTask<D> implements Delayed {private D data;private long deadline; // 纳秒时间戳@Overridepublic long getDelay(TimeUnit unit) {return unit.convert(deadline - System.nanoTime(), TimeUnit.NANOSECONDS);}
}
• 延迟队列的处理:
任务到达延迟时间后,从队列中取出并处理。
public void handleDelayTasks() {while (true) {try {DelayTask<RecordTaskData> task = queue.take();persistLearningRecords(task.getData()); // 持久化记录} catch (InterruptedException e) {Thread.currentThread().interrupt();}}
}
3. 积分与排行榜管理
• 积分记录管理
public void addPoints(Long userId, Long courseId, int points) {PointsRecord record = new PointsRecord();record.setUserId(userId);record.setCourseId(courseId);record.setPoints(points);record.setCreateTime(LocalDateTime.now());pointsRecordMapper.insert(record);
}
• 每日积分统计:
public List<PointsStatisticsVO> queryMyPointsToday(Long userId) {LocalDate today = LocalDate.now();return pointsRecordMapper.findByUserIdAndDate(userId, today);
}
• 动态表名的排行榜:
通过 MyBatis 的 DynamicTableNameInnerInterceptor 实现动态表名替换。
map.put("points_board", (sql, tableName) -> {String seasonId = getCurrentSeason();return tableName + "_" + seasonId; // 动态拼接表名
});
4. 互动问答模块
• 提问功能:
public void saveQuestion(QuestionFormDTO questionDTO) {Question question = new Question();question.setContent(questionDTO.getContent());question.setUserId(questionDTO.getUserId());question.setCourseId(questionDTO.getCourseId());question.setCreateTime(LocalDateTime.now());questionMapper.insert(question);
}
• 管理员隐藏问题:
public void hiddenQuestionAdmin(Long id, Boolean hidden) {Question question = questionMapper.selectById(id);question.setHidden(hidden);questionMapper.updateById(question);
}
• 点赞功能:
使用 Redis 实现快速计数,同时支持异步更新到数据库。
public void likeQuestion(Long questionId, Long userId) {String redisKey = String.format("QUESTION:LIKE:%d", questionId);redisTemplate.opsForSet().add(redisKey, userId.toString());
}
5. Redis 缓存机制
• 学习记录缓存:
redisTemplate.opsForHash().put("LEARNING:RECORD:123", "section_456", recordData);
redisTemplate.expire("LEARNING:RECORD:123", Duration.ofMinutes(30));
• 签到记录缓存:
redisTemplate.opsForValue().set("SIGN:USER:123:2025-01-09", true, Duration.ofDays(1));
6. 动态表名管理
• 配置 MyBatis 的动态表名拦截器:
@Bean
public DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor() {Map<String, TableNameHandler> map = new HashMap<>();map.put("points_board", (sql, tableName) -> {String seasonId = getCurrentSeason();return tableName + "_" + seasonId;});return new DynamicTableNameInnerInterceptor(map);
}