天机学堂-2

代码实现:
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就会进行自动构建。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值