day05-开发接口-学习记录和学习计划

1. 查询用户的课程学习记录

1.1 代码实现

Controller层:

package com.tianji.learning.controller;import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/*** <p>* 学习记录表 前端控制器* </p>** @author 孙克旭* @since 2024-12-06*/
@RestController
@RequestMapping("/learning-records")
@Api(tags = "学习记录的相关接口")
@RequiredArgsConstructor
public class LearningRecordController {private final ILearningRecordService recordService;@ApiOperation("查询指定课程的学习记录")@GetMapping("/course/{courseId}")public LearningLessonDTO queryLearningRecordByCourse(@ApiParam(value = "课程id", example = "2") @PathVariable("courseId") Long courseId) {return recordService.queryLearningRecordByCourse(courseId);}
}

Service层:

package com.tianji.learning.service.impl;import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;import java.util.List;/*** <p>* 学习记录表 服务实现类* </p>** @author 孙克旭* @since 2024-12-06*/
@Service
@RequiredArgsConstructor
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {private final ILearningLessonService lessonService;@Overridepublic LearningLessonDTO queryLearningRecordByCourse(Long courseId) {//1.获取用户idLong userId = UserContext.getUser();//2.查询课表LearningLesson lesson = lessonService.queryByUserIdAndCourseId(userId, courseId);if (lesson == null) {return null;}//3.查询学习记录List<LearningRecord> records = lambdaQuery().eq(LearningRecord::getLessonId, lesson.getId()).list();List<LearningRecordDTO> recordDTOS = BeanUtils.copyList(records, LearningRecordDTO.class);//4.封装结果LearningLessonDTO dto = new LearningLessonDTO();dto.setId(lesson.getId());dto.setLatestSectionId(lesson.getLatestSectionId());dto.setRecords(recordDTOS);return dto;}
}

2. 提交学习记录

2.1 业务流程

在这里插入图片描述

2.2 代码实现

Controller层:

    @ApiOperation("提交学习记录")@PostMappingpublic void addLearningRecord(@RequestBody LearningRecordFormDTO formDTO) {recordService.addLearningRecord(formDTO);}

Service层:

  @Override@Transactionalpublic void addLearningRecord(LearningRecordFormDTO recordDTO) {//1.获取用户idLong userId = UserContext.getUser();//2.处理学习记录boolean finished = false;if (recordDTO.getSectionType() == SectionType.VIDEO) {//2.1 处理视频finished = handleVideoRecord(userId, recordDTO);} else {//2.2 处理考试finished = handleExamRecord(userId, recordDTO);}//3. 处理课表数据handleLearningLessonsChanges(recordDTO, finished);}/*** 处理课表数据** @param recordDTO* @param finished*/private void handleLearningLessonsChanges(LearningRecordFormDTO recordDTO, boolean finished) {//1.查询课表LearningLesson lesson = lessonService.getById(recordDTO.getLessonId());if (lesson == null) {throw new BizIllegalException("课程不存在,无法更新数据!");}//2.判断是否有新的完成小节boolean allLearned = false;if (finished) {//3.如果有新的完成小节,则需要查询课程数据CourseFullInfoDTO cInfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);if (cInfo == null) {throw new BizIllegalException("课程不存在,无法更新数据!");}//4.比较课程是否全部学完:已学习小节》=课程总小节allLearned = lesson.getLearnedSections() + 1 >= cInfo.getSectionNum();}//5.更新课表lessonService.lambdaUpdate().set(lesson.getLearnedSections() == 0, LearningLesson::getStatus, LessonStatus.LEARNING.getValue()).set(allLearned, LearningLesson::getStatus, LessonStatus.FINISHED.getValue()).set(!finished, LearningLesson::getLatestSectionId, recordDTO.getSectionId()).set(!finished, LearningLesson::getLatestLearnTime, recordDTO.getCommitTime()).setSql(finished, "learned_sections=learned_sections+1").eq(LearningLesson::getId, lesson.getId()).update();}/*** 处理视频的学习记录** @param userId* @param recordDTO* @return*/private boolean handleVideoRecord(Long userId, LearningRecordFormDTO recordDTO) {//1.查询旧的学习记录LearningRecord old = lambdaQuery().eq(LearningRecord::getLessonId, recordDTO.getLessonId()).eq(LearningRecord::getSectionId, recordDTO.getSectionId()).one();//2.判断是否存在if (old == null) {//3.不存在,则新增//3.1 转换DTO为POLearningRecord record = BeanUtils.copyBean(recordDTO, LearningRecord.class);//3.2 填充数据record.setUserId(userId);//3.写入数据库boolean success = save(record);if (!success) {throw new DbException("新增学习失败!");}return false;}//4. 存在则更新//4.1 判断是否是第一次完成boolean finished = !old.getFinished() && recordDTO.getMoment() * 2 >= recordDTO.getDuration();//4.2 更新数据boolean success = lambdaUpdate().set(LearningRecord::getMoment, recordDTO.getMoment()).set(finished, LearningRecord::getFinished, true).set(finished, LearningRecord::getFinishTime, recordDTO.getCommitTime()).update();if (!success) {throw new DbException("新增学习失败!");}return finished;}/*** 处理考试的学习记录** @param userId* @param recordDTO* @return*/private boolean handleExamRecord(Long userId, LearningRecordFormDTO recordDTO) {//1.转换DTO为POLearningRecord record = BeanUtils.copyBean(recordDTO, LearningRecord.class);//2.填充数据record.setUserId(userId);record.setFinished(true);record.setFinishTime(recordDTO.getCommitTime());//3.写入数据库boolean success = save(record);if (!success) {throw new DbException("新增考试失败!");}return true;}

3. 创建学习计划

3.1 代码实现

Controller层:

    @PostMapping("/plans")@ApiOperation("创建学习计划") #实体类中属性有范围控制,所以使用@Valid注解public void createLearningPlans(@Valid @RequestBody LearningPlanDTO planDTO) {lessonService.createLearningPlans(planDTO.getCourseId(), planDTO.getFreq());}

Service层:

    @Overridepublic void createLearningPlans(Long courseId, Integer freq) {//1.获取当前用户Long userId = UserContext.getUser();//2.查询课表中的指定课程有关的数据LearningLesson lesson = queryByUserIdAndCourseId(userId, courseId);//课程信息为null会抛出异常AssertUtils.isNotNull(lesson, "课程信息不存在!");//3.修改数据LearningLesson l = new LearningLesson();l.setId(lesson.getId());l.setWeekFreq(freq);if (lesson.getPlanStatus() == PlanStatus.NO_PLAN) {l.setPlanStatus(PlanStatus.PLAN_RUNNING);}updateById(l);}

4. 查询学习计划

4.1 业务分析

在这里插入图片描述

4.2 代码实现

Controller层:

  @GetMapping("/plans")@ApiOperation("查询我的学习计划")public LearningPlanPageVO queryMyPlans(PageQuery query) {return lessonService.queryMyPlans(query);}

Service层:

 @Overridepublic LearningPlanPageVO queryMyPlans(PageQuery query) {LearningPlanPageVO result = new LearningPlanPageVO();//1. 获取当前登录用户Long userId = UserContext.getUser();//2. 获取本周起始时间LocalDate now = LocalDate.now();LocalDateTime begin = DateUtils.getWeekBeginTime(now);LocalDateTime end = DateUtils.getWeekEndTime(now);//3.查询总的统计数据//3.1.本周总的已学习小节数量Integer weekFinished = recordMapper.selectCount(new LambdaQueryWrapper<LearningRecord>().eq(LearningRecord::getUserId, userId).eq(LearningRecord::getFinished, true).eq(LearningRecord::getFinishTime, begin).lt(LearningRecord::getFinishTime, end));result.setWeekFinished(weekFinished);//3.2.本周总的计划学习小节数量Integer weekTotalPlan = getBaseMapper().queryTotalPlan(userId);result.setWeekTotalPlan(weekTotalPlan);//TODO  3.3.本周学习积分// 4.查询分页数据// 4.1.分页查询课表信息以及学习计划信息Page<LearningLesson> p = lambdaQuery().eq(LearningLesson::getUserId, userId).eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING).in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING).page(query.toMpPage("latest_learn_time", false));List<LearningLesson> records = p.getRecords();if (CollUtils.isEmpty(records)) {return result.emptyPage(p);}// 4.2.查询课表对应的课程信息Map<Long, CourseSimpleInfoDTO> cMap = queryCourseSimpleInfoList(records);// 4.3.统升每一个课程本周已学习小节数量List<IdAndNumDTO> list = recordMapper.countLearnedSections(userId, begin, end);Map<Long, Integer> countMap = IdAndNumDTO.toMap(list);// 4.4.组装数据V0List<LearningPlanVO> voList = new ArrayList<>(records.size());for (LearningLesson r : records) {//4.4.1 拷贝基础属性到voLearningPlanVO vo = BeanUtils.copyBean(r, LearningPlanVO.class);//4.4.2 填充课程详细信息CourseSimpleInfoDTO cInfo = cMap.get(r.getCourseId());if (cInfo != null) {vo.setCourseName(cInfo.getName());vo.setSections(cInfo.getSectionNum());}//4.4.3 每个课程的本周已学习小节数量vo.setWeekLearnedSections(countMap.getOrDefault(r.getId(), 0));voList.add(vo);}return result.pageInfo(p.getTotal(), p.getPages(), voList);}/*** 查询课程信息** @param records* @return*/private Map<Long, CourseSimpleInfoDTO> queryCourseSimpleInfoList(List<LearningLesson> records) {//3.1 获取课程idSet<Long> cIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());//3.2 查询课程信息List<CourseSimpleInfoDTO> cInfoList = courseClient.getSimpleInfoList(cIds);if (CollUtils.isEmpty(cInfoList)) {//课程不存在throw new BadRequestException("课程信息不存在!");}//3.3 把课程集合处理成Map,key是courseId,值是course本身Map<Long, CourseSimpleInfoDTO> cMap = cInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));return cMap;}

Mapper层:

LearningRecordMapper

package com.tianji.learning.mapper;import com.tianji.api.dto.IdAndNumDTO;
import com.tianji.learning.domain.po.LearningRecord;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.data.repository.query.Param;import java.time.LocalDateTime;
import java.util.List;/*** <p>* 学习记录表 Mapper 接口* </p>** @author 孙克旭* @since 2024-12-06*/
public interface LearningRecordMapper extends BaseMapper<LearningRecord> {/*** 统计用户每个课程学习的小节数量** @param userId* @param begin* @param end* @return*/List<IdAndNumDTO> countLearnedSections(@Param("userId") Long userId,@Param("begin") LocalDateTime begin,@Param("end") LocalDateTime end);
}<select id="countLearnedSections" resultType="com.tianji.api.dto.IdAndNumDTO">select lesson_id as id, count(1) as numfrom learning_recordwhere user_id = #{userId}and finished = 1and finish_time > #{begin}and finish_time < #{end}group by lesson_id</select>

LearningLessonMapper

package com.tianji.learning.mapper;import com.tianji.learning.domain.po.LearningLesson;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;/*** <p>* 学生课程表 Mapper 接口* </p>** @author 孙克旭* @since 2024-12-05*/
public interface LearningLessonMapper extends BaseMapper<LearningLesson> {/*** 查询本周总的学习计划** @param userId* @return*/Integer queryTotalPlan(Long userId);
}<select id="queryTotalPlan" resultType="java.lang.Integer">select sum(week_freq)from learning_lessonwhere user_id = #{userId}and plan_status = 1and status in (0, 1)</select>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/486959.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++】指针与智慧的邂逅:C++内存管理的诗意

文章目录 RAII 智能指针auto_ptrunique_ptr shared_ptr模拟实现定制删除器循环引用 和 weak_ptr RAII RAII&#xff08;Resource Acquisition Is Initialization&#xff09;是一种广泛应用于 C 等编程语言中的编程范式&#xff0c;它的核心思想是&#xff1a;资源的获取和释放…

Elasticsearch vs 向量数据库:寻找最佳混合检索方案

图片来自Shutterstock上的Bakhtiar Zein 多年来&#xff0c;以Elasticsearch为代表的基于全文检索的搜索方案&#xff0c;一直是搜索和推荐引擎等信息检索系统的默认选择。但传统的全文搜索只能提供基于关键字匹配的精确结果&#xff0c;例如找到包含特殊名词“Python3.9”的文…

探索ai一键生成PPT的未来

在当今快节奏的工作环境中&#xff0c;如何高效地完成PPT制作任务&#xff0c;已经成为了许多人追求的目标。无论是职场精英&#xff0c;还是创业者&#xff0c;每个人都希望通过智能工具来提高工作效率。而AI生成PPT&#xff0c;尤其是利用一些先进的自动生成PPT技术&#xff…

vue-router查漏补缺

一、动态路由匹配 1.带参数的动态路由匹配 import User from ./User.vue// 这些都会传递给 createRouter const routes [// 动态字段以冒号开始{ path: /users/:efg, component: User }, ]这种方式的路由会匹配到/users/abc或者/users/123,路径参数用冒号:表示&#xff0c;并…

013路由协议-OSPF

OSPF具有更适用于规模较大的网络环境&#xff0c;收敛更快速、依据带宽来计算路径成本等。 计算方式&#xff1a; 100M/当前端口的带宽 如果小于1就按照1来计算 例如&#xff1a; 当前端口的带宽是1.54M 路径成本 100/1.54 65 当前端口的带宽是 1000M 路径成本 100/100 0.…

快捷构建AI大模型,源码自取可直接运行

Node.js 和 WebSocket 实现一个基于kimi&#xff08;Moonshot 月之暗大模型&#xff09;的AI工具 前端&#xff1a;前端界面比较容易&#xff0c;只需要简单的额css js即可&#xff0c;本文使用vue作为作为demo。 后端&#xff1a;我java很垃圾&#xff0c;写不出好的代码&am…

探索云原生安全解决方案的未来

我们是否充分意识到云端所面临的网络安全威胁&#xff1f; 在当今互联互通的世界中&#xff0c;维护安全的环境至关重要。云的出现扩大了潜在威胁的范围&#xff0c;因为它催生了机器身份&#xff08;称为非人类身份 (NHI)&#xff09;及其秘密。随着组织越来越多地转向云原生…

关于利用 EtherNet/IP 转 Profinet 网关模块实现罗克韦尔变频器接入西门子 PLC 的配置范例

在现代工业自动化领域&#xff0c;不同品牌设备之间的通信兼容性问题一直是企业面临的挑战之一。某智能工厂为了优化生产流程&#xff0c;提高设备的协同工作效率&#xff0c;决定对其生产线上的控制系统进行升级改造。该生产线中&#xff0c;AB罗克韦尔PowerFlex变频器作为关键…

Ajax--实现检测用户名是否存在功能

&#xff08;一&#xff09;什么是Ajax Ajax&#xff08;Asynchronous Javascript And XML&#xff09; 翻译成中文就是“异步JavaScript和XML”&#xff0c;即使用JavaScript与服务器进行异步交互&#xff0c;传输的数据为XML。 AJAX还可以在浏览器实现局部刷新的效果&#xf…

【LC】160. 相交链表

题目描述&#xff1a; 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&…

算法设计1_分治

递归的概念 递归算法&#xff1a;一个直接或间接地调用自身的算法递归函数&#xff1a;使用函数自身给出定义的函数递归方程&#xff1a;对于递归算法&#xff0c;一般可把时间代价表示为一个递归方程解递归方程最常用的方法是进行递归扩展 阶乘函数 边界条件递归关系 n ! {…

基于yolov8的SAR影像目标检测系统,支持图像、视频和摄像实时检测【pytorch框架、python源码】

更多目标检测、图像分类识别、目标追踪等项目可看我主页其他文章 功能演示&#xff1a; 基于yolov8的SAR影像目标检测系统&#xff0c;支持图像、视频和摄像实时检测【pytorch框架、python源码】_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于yolov8的SAR影像目标…

uni-app 设置缓存过期时间【跨端开发系列】

&#x1f517; uniapp 跨端开发系列文章&#xff1a;&#x1f380;&#x1f380;&#x1f380; uni-app 组成和跨端原理 【跨端开发系列】 uni-app 各端差异注意事项 【跨端开发系列】uni-app 离线本地存储方案 【跨端开发系列】uni-app UI库、框架、组件选型指南 【跨端开…

复现论文:PromptTA: Prompt-driven Text Adapter for Source-freeDomain Generalization

github&#xff1a;zhanghr2001/PromptTA: Source-free Domain Generalization 论文&#xff1a;[2409.14163] PromptTA: Prompt-driven Text Adapter for Source-free Domain Generalization 自己标注&#xff1a;PromptTA: Prompt-driven Text Adapter for Source-free Domai…

Dos脚本中的start命令

0 Preface/Foreword 1 Start介绍 start是用来启动一个应用或者一个bat脚本文件。 1.1 %*传递参数 %*&#xff1a;表示运行命令时传入的所有参数。 1.2 %processor_architecture% 系统处理器架构&#xff0c;内置变量。 echo %processor_architecture% 1.3 示例 echo He…

HTML笔记()蜘蛛纸牌之卡牌拖拽

效果 代码 <!DOCTYPE html> <html><head><style>body{display: flex;justify-content: center;align-items: center;height: 100vh;background-color: #2b2b2b;position: relative;}.card{/*设置卡牌的外观*/width: 150px;height: 200px;background-…

基于SSM的线上考试系统的设计与实现(计算机毕业设计)+万字说明文档

系统合集跳转 源码获取链接 一、系统环境 运行环境: 最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。 IDE环境&#xff1a; Eclipse,Myeclipse,IDEA或者Spring Tool Suite都可以 tomcat环境&#xff1a; Tomcat 7.x,8.x,9.x版本均可 操作系统…

vue 封装全局方法及使用

1.找到项目中的utils定义js&#xff0c;这个js存放全局可使用的方法 2.去项目中main.js中引入注册 import publicFun from ./utils/test Vue.prototype.$publicFun publicFun;3.项目使用 ddd(){this.$publicFun.testwen()},

微信小程序中使用miniprogram-sm-crypto实现SM4加密攻略

在微信小程序开发过程中&#xff0c;数据安全至关重要。本文将为大家介绍如何在微信小程序中使用miniprogram-sm-crypto插件进行SM4加密&#xff0c;确保数据传输的安全性。 一、SM4加密简介 SM4是一种对称加密算法&#xff0c;由国家密码管理局发布&#xff0c;适用于商密领…

【论文阅读】相似误差订正方法在风电短期风速预报中的应用研究

文章目录 概述&#xff1a;摘要1. 引言2. 相似误差订正算法&#xff08;核心&#xff09;3. 订正实验3.1 相似因子选取3.2 相似样本数试验3.3 时间窗时长实验 4. 订正结果分析4.1 评估指标对比4.2 风速曲线对比4.3 分风速段订正效果评估4.4 风速频率统计 5. 结论与讨论 概述&am…