代码实现:
1.查询我的课表代码实现:
1.先在controller层下的tj-learning服务的LearningLessonController进行方法与返回值定义。
@Api(tags = "我的课表相关接口")
@RestController
@RequestMapping("/lessons")
@RequiredArgsConstructor
public class LearningLessonController {
private final ILearningLessonService lessonService;
@ApiOperation("查询我的课表,排序字段 latest_learn_time:学习时间排序,create_time:购买时间排序")
@GetMapping("/page")
public PageDTO<LearningLessonVO> queryMyLessons(PageQuery query) {
return lessonService.queryMyLessons(query);
}
}
@Api用在类上注解声明这是一个接口集合
配合@ApiOperation用在方法上使用,声明当前方法的作用。
@RequiredArgsConstructor注解用来实现接口的自动注入
@RequestMapping("/lessons")用在类上,该类下所有路径都以这个为基础
@GetMapping("/page")用在方法是,这个方法的路径是/lessons/page
@RestController其核心作用是自动将控制器方法的返回值序列化为JSON/XML格式返回给客户端,无需额外添加@ResponseBody注解
用PageDTO<LearningLessonVO>集合接受查询到的课表信息。
2.在service接口里自动生成方法信息
PageDTO<LearningLessonVO> queryMyLessons(PageQuery query);
3.在ServiceImpl实现类里写具体的实现过程:
@Override
public PageDTO<LearningLessonVO> queryMyLessons(PageQuery query) {
// 1.获取当前登录用户
Long userId = UserContext.getUser();
// 2.分页查询
// select * from learning_lesson where user_id = #{userId} order by latest_learn_time limit 0, 5
Page<LearningLesson> page = lambdaQuery()
.eq(LearningLesson::getUserId, userId) // where user_id = #{userId}
.page(query.toMpPage("latest_learn_time", false));
List<LearningLesson> records = page.getRecords();
if (CollUtils.isEmpty(records)) {
return PageDTO.empty(page);
}
// 3.查询课程信息
Map<Long, CourseSimpleInfoDTO> cMap = queryCourseSimpleInfoList(records);
// 4.封装VO返回
List<LearningLessonVO> list = new ArrayList<>(records.size());
// 4.1.循环遍历,把LearningLesson转为VO
for (LearningLesson r : records) {
// 4.2.拷贝基础属性到vo
LearningLessonVO vo = BeanUtils.copyBean(r, LearningLessonVO.class);
// 4.3.获取课程信息,填充到vo
CourseSimpleInfoDTO cInfo = cMap.get(r.getCourseId());
vo.setCourseName(cInfo.getName());
vo.setCourseCoverUrl(cInfo.getCoverUrl());
vo.setSections(cInfo.getSectionNum());
list.add(vo);
}
return PageDTO.of(page, list);
}
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;
}
2.查询正在学习的课程
1.先在controller层下定义:
@GetMapping("/now")
@ApiOperation("查询我正在学习的课程")
public LearningLessonVO queryMyCurrentLesson() {
return lessonService.queryMyCurrentLesson();
}
2.然后是service的接口
LearningLessonVO queryMyCurrentLesson();
3.最后是实现类
private final CatalogueClient catalogueClient;
@Override
public LearningLessonVO queryMyCurrentLesson() {
// 1.获取当前登录的用户
Long userId = UserContext.getUser();
// 2.查询正在学习的课程 select * from xx where user_id = #{userId} AND status = 1 order by latest_learn_time limit 1
LearningLesson lesson = lambdaQuery()
.eq(LearningLesson::getUserId, userId)
.eq(LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
.orderByDesc(LearningLesson::getLatestLearnTime)
.last("limit 1")
.one();
if (lesson == null) {
return null;
}
// 3.拷贝PO基础属性到VO
LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);
// 4.查询课程信息
CourseFullInfoDTO cInfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
if (cInfo == null) {
throw new BadRequestException("课程不存在");
}
vo.setCourseName(cInfo.getName());
vo.setCourseCoverUrl(cInfo.getCoverUrl());
vo.setSections(cInfo.getSectionNum());
// 5.统计课表中的课程数量 select count(1) from xxx where user_id = #{userId}
Integer courseAmount = lambdaQuery()
.eq(LearningLesson::getUserId, userId)
.count();
vo.setCourseAmount(courseAmount);
// 6.查询小节信息
List<CataSimpleInfoDTO> cataInfos =
catalogueClient.batchQueryCatalogue(CollUtils.singletonList(lesson.getLatestSectionId()));
if (!CollUtils.isEmpty(cataInfos)) {
CataSimpleInfoDTO cataInfo = cataInfos.get(0);
vo.setLatestSectionName(cataInfo.getName());
vo.setLatestSectionIndex(cataInfo.getCIndex());
}
return vo;
}
作业代码实现
1.删除课表中课程
这个练习实际上是两部分,一个是退款通知,另一个才是删除课表中课程
1.先在mq包下的LessonChangeListener类里
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = "learning.lesson.refund.queue", durable = "true"),
exchange = @Exchange(name = MqConstants.Exchange.ORDER_EXCHANGE, type = ExchangeTypes.TOPIC),
key = MqConstants.Key.ORDER_REFUND_KEY
))
public void listenCourseRefund(OrderBasicDTO dto) {
//1.校验(健壮性处理)
if (dto == null || dto.getUserId() == null || CollUtils.isEmpty(dto.getCourseIds())) {
//数据有误,无需处理(不要抛异常,否则会开启重试)
log.error("listenCourseRefund接收到MQ消息有误,订单数据为空");
return;
}
//2.调用service,删除课程
log.debug("监听到用户{}的订单{}要退款,需要从课表中删除课程{}", dto.getUserId(), dto.getOrderId(), dto.getCourseIds());
lessonService.deleteCourseFromLesson(dto.getUserId(), dto.getCourseIds().get(0));
}
@RabbitListener标记一个方法作为 RabbitMQ 消息的消费者,使用@QueueBinding将队列、交换机和路由键绑定在一起,如果队列、交换机不存在,会自动创建,@Exchange定义交换机名称与类型,key指定绑定的路由规则。 先进行消息是否为空判断,如果为空写入日志。
service中自动创建类:
void deleteCourseFromLesson(Long userId, Long aLong);
serviceImpl类里实现:
public void deleteCourseFromLesson(Long userId, Long courseId) {
//1.判断当前登录用户id是否为null
//调用这个方法有两种情况:用户直接删除已失效的课程 -> 在controller中调用,没有获取用户id,只传了null值
// 用户退款后触发课表自动删除 -> 在listener中调用,直接获取了OrderBasicDTO中的用户id
//listenCourseRefund已有健壮性判断,这里目的是在直接删除已失效的课程时,获取用户id
if (userId == null) {
userId = UserContext.getUser();
}
//2.删除课程
//第一种写法:直接通过Wrappers.<LearningLesson>lambdaQuery()创建LambdaQueryWrapper对象,直接简洁
remove(Wrappers.<LearningLesson>lambdaQuery()
.eq(LearningLesson::getUserId, userId)
.eq(LearningLesson::getCourseId, courseId));
//第二种写法:先创建普通QueryWrapper对象,再通过.lambda()方法转换成LambdaQueryWrapper对象,多一次转换,冗余
// remove(new QueryWrapper<LearningLesson>().lambda()
// .eq(LearningLesson::getUserId, userId)
// .in(LearningLesson::getCourseId, courseId));
}
删除课程先判断用户id是否为null,删除课程通过lambdaQuery()方法,用它来判断当前用户id与课程id是否等于数据库里的。remove方法相当于实现了:
DELETE FROM learning_lesson WHERE user_id = ? AND course_id = ?
2.检查课程是否有效
在controller层里定义:
@ApiOperation("校验当前用户是否可以学习当前课程")
@GetMapping("/{courseId}/valid")
public Long isLessonValid(@PathVariable("courseId") Long courseId) {
return learningLessonService.isLessonValid(courseId);
}
service层里生成:
Long isLessonVaild(Long courseId);
serviceImpl快速生成基本方法,然后实现具体逻辑。
public Long isLessonValid(Long courseId) {
//1.获取当前登录用户id
Long userId = UserContext.getUser();
//2.查询当前用户的课表learning_lesson 条件:user_id course_id
LearningLesson lesson = lambdaQuery()
.eq(LearningLesson::getUserId, userId)
.eq(LearningLesson::getCourseId, courseId)
.one();//联合唯一索引,最多只能查出一条数据
if (lesson == null) {
return null;
}
//3.校验课程是否过期
LocalDateTime expireTime = lesson.getExpireTime();
LocalDateTime now = LocalDateTime.now();
if (now.isAfter(expireTime)) { //当前时间已经在过期时间之后,即过期
return null;
}
return lesson.getId();
}
步骤:先获取当前用户id,再查询用户的课表用lesson接收Select FROM learning_lesson WHERE user_id = ? AND course_id = ?查到的数据。最后先获取课程的过期时间与现在的时间进行对比,若当前时间在过期时间之后则过期。
3.查询用户课表中指定课程状态
原文档的请求路径是/ls/lessons/{courseId}。这里前面的/ls通过网关进行转发,所以实际代码只写/{courseId}就行
controller里定义方法名与返回信息
@ApiOperation("查询用户课表中指定课程状态")
@GetMapping("/{courseId}")
public LearningLessonVO queryLessonByCourseId(@PathVariable("courseId") Long courseId) {
return learningLessonService.queryLessonByCourseId(courseId);
}
快速生成service
LearningLessonVO queryLessonByCourseId(Long courseId);
ServiceImpl实现类里继续:
public LearningLessonVO queryLessonByCourseId(Long courseId) {
//1.获取当前登录用户id
Long userId = UserContext.getUser();
//2.查询当前用户的课表learning_lesson 条件:user_id course_id
LearningLesson lesson = lambdaQuery()
.eq(LearningLesson::getUserId, userId)
.eq(LearningLesson::getCourseId, courseId)
.one();//联合唯一索引,最多只能查出一条数据
if (lesson == null) {
return null;
}
//3.po转vo返回
LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);
return vo;
}
获取用户id,查询当前用户课表,把po转为vo进行返回。
4.统计课程的学习人数
controller层:
@ApiOperation("统计课程学习人数")
@GetMapping("/{courseId}/count")
public Integer countLearningLessonByCourse(@PathVariable("courseId") Long courseId){
return learningLessonService.countLearningLessonByCourse(courseId);
}
service层:
Integer countLearningLessonByCourse(Long courseId);
serviceImpl层:
@Override
public Integer countLearningLessonByCourse(Long courseId) {
//统计课程学习人数就不需要获取当前登录用户id了,因为统计的课程学习人数不需要区分用户
return lambdaQuery()
.eq(LearningLesson::getCourseId,courseId)
.in(LearningLesson::getStatus,
LessonStatus.NOT_BEGIN.getValue(),
LessonStatus.LEARNING.getValue(),
LessonStatus.FINISHED.getValue())
.count();
}
直接返回课程id相同的所有的NOT_BEGIN,LEARNING,FINISHED状态的用户数量和。
代码提交和分支合并
1.使用Git将修改的代码进行提交Commit。
2.将开发的功能分支合并到dev分支上,merge。
3.将本地的代码Push到远端,此时Jenkins就会进行自动构建。



1131

被折叠的 条评论
为什么被折叠?



