核心功能
系统设计思路
代码分析
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; // 纳秒时间戳
@Override
public 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);
}