当前位置: 首页 > article >正文

黑马天机学堂学习计划模块

核心功能

系统设计思路

​​​​​​​

代码分析

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);
}

http://www.kler.cn/a/502006.html

相关文章:

  • 【机器学习】主动学习-增加标签的操作方法-流式选择性采样(Stream-based selective sampling)
  • vue3+vite+ts集成第三方js
  • Vue.js组件开发-图片剪裁性能优化最佳方案实例
  • 初识@ffmpeg/ffmpeg库
  • ThreadLocal 的使用场景
  • 【airtest】自动化入门教程Poco元素定位
  • js:根据后端返回数据的最大值进行计算然后设置这个最大值为百分之百,其他的值除这个最大值
  • ThreeJs练习——载入外部模型
  • 【源码解析】Java NIO 包中的 HeapByteBuffer
  • C++—9、如何在Microsoft Visual Studio中调试C++
  • 性能测试工具Jmeter负载模拟
  • TPS61022 PFM的机制以及TPS61xxx转换器的PFM与PWM之间的负载阈值
  • 使用jquery的$.ajax提交带有FormData的post请求报错TypeError: Illegal invocation
  • 详解C#调用系统文件窗口:打开文件、保存文件和选择文件夹
  • 【Javaweb02】初探CSS:网页样式设计的入门指南
  • 《机器学习》——TF-IDF(关键词提取)
  • 如何用python实现语音输出
  • 积鼎科技:国产自主核反应堆流体仿真解决方案
  • 深度解析Linux中的调试器gdb/cgdb的使用
  • MySQL 16 章——变量、流程控制和游标
  • 青少年编程与数学 02-006 前端开发框架VUE 23课题、UI框架
  • huggingface/bert/transformer的模型默认下载路径以及自定义路径
  • 《使用 YOLOV8 和 KerasCV 进行高效目标检测》
  • 【机器学习案列】学生抑郁可视化及预测分析
  • 迁移WSL中的ext4.vhdx文件
  • MATLAB与Python中的快速傅里叶变换频谱分析