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;
@Override
public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {
//1.获取用户id
Long 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("提交学习记录")
@PostMapping
public void addLearningRecord(@RequestBody LearningRecordFormDTO formDTO) {
recordService.addLearningRecord(formDTO);
}
Service层:
@Override
@Transactional
public void addLearningRecord(LearningRecordFormDTO recordDTO) {
//1.获取用户id
Long 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为PO
LearningRecord 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为PO
LearningRecord 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层:
@Override
public 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层:
@Override
public 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.组装数据V0
List<LearningPlanVO> voList = new ArrayList<>(records.size());
for (LearningLesson r : records) {
//4.4.1 拷贝基础属性到vo
LearningPlanVO 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 获取课程id
Set<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 num
from learning_record
where user_id = #{userId}
and finished = 1
and 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_lesson
where user_id = #{userId}
and plan_status = 1
and status in (0, 1)
</select>