1.接口设计

1.1分析业务流程

分析业务可以从原型图开始,天机学堂的产品原型图如下:
用户端:https://lanhuapp.com/link/#/invite?sid=qx0Fy3fa 密码: ZsP3
管理端:https://lanhuapp.com/link/#/invite?sid=qx03viNU 密码: Ssml
code

2.接口设计

总设计接口
code
前4个接口为课上内容
后4个为作业

3.课表VO属性分析

code

4.导入实体类

  • 开发前需创建分支feature-lessons
  • 安装mybatisPlus插件
  • 在最上面的other设置数据库连接
    learning_lesson表
    1. 导入learning_lesson表 —-第二天资料
    2. 逆向生成代码
      code
    3. 导入2个枚举类
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      package com.tianji.learning.menu;

      import com.baomidou.mybatisplus.annotation.EnumValue;
      import com.fasterxml.jackson.annotation.JsonCreator;
      import com.fasterxml.jackson.annotation.JsonValue;
      import com.tianji.common.enums.BaseEnum;
      import lombok.Getter;

      @Getter
      public enum LessonStatus implements BaseEnum {
      NOT_BEGIN(0, "未学习"),
      LEARNING(1, "学习中"),
      FINISHED(2, "已学完"),
      EXPIRED(3, "已过期"),
      ;
      @JsonValue
      @EnumValue
      int value;
      String desc;

      LessonStatus(int value, String desc) {
      this.value = value;
      this.desc = desc;
      }

      @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
      public static LessonStatus of(Integer value){
      if (value == null) {
      return null;
      }
      for (LessonStatus status : values()) {
      if (status.equalsValue(value)) {
      return status;
      }
      }
      return null;
      }
      }

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      package com.tianji.learning.menu;

      import com.baomidou.mybatisplus.annotation.EnumValue;
      import com.fasterxml.jackson.annotation.JsonCreator;
      import com.fasterxml.jackson.annotation.JsonValue;
      import com.tianji.common.enums.BaseEnum;
      import lombok.Getter;

      @Getter
      public enum PlanStatus implements BaseEnum {
      NO_PLAN(0, "没有计划"),
      PLAN_RUNNING(1, "计划进行中"),
      ;
      @JsonValue
      @EnumValue
      int value;
      String desc;

      PlanStatus(int value, String desc) {
      this.value = value;
      this.desc = desc;
      }


      @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
      public static PlanStatus of(Integer value){
      if (value == null) {
      return null;
      }
      for (PlanStatus status : values()) {
      if (status.equalsValue(value)) {
      return status;
      }
      }
      return null;
      }
      }

    4. 修改PO
      • 把主键策略改为IdType.ASSIGN_ID
      • 把课程状态和学习计划状态改为对应的枚举类
    5. 导入VO
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      package com.tianji.learning.domain.vo;

      import com.tianji.learning.enums.LessonStatus;
      import com.tianji.learning.enums.PlanStatus;
      import io.swagger.annotations.ApiModel;
      import io.swagger.annotations.ApiModelProperty;
      import lombok.Data;

      import java.time.LocalDateTime;

      @Data
      @ApiModel(description = "课程表信息")
      public class LearningLessonVO {

      @ApiModelProperty("主键lessonId")
      private Long id;

      @ApiModelProperty("课程id")
      private Long courseId;

      @ApiModelProperty("课程名称")
      private String courseName;

      @ApiModelProperty("课程封面")
      private String courseCoverUrl;

      @ApiModelProperty("课程章节数量")
      private Integer sections;

      @ApiModelProperty("课程状态,0-未学习,1-学习中,2-已学完,3-已失效")
      private LessonStatus status;

      @ApiModelProperty("总已学习章节数")
      private Integer learnedSections;

      @ApiModelProperty("总已报名课程数")
      private Integer courseAmount;

      @ApiModelProperty("课程购买时间")
      private LocalDateTime createTime;

      @ApiModelProperty("课程过期时间,如果为null代表课程永久有效")
      private LocalDateTime expireTime;

      @ApiModelProperty("习计划状态,0-没有计划,1-计划进行中")
      private PlanStatus planStatus;

      @ApiModelProperty("计划的学习频率")
      private Integer weekFreq;

      @ApiModelProperty("最近学习的小节名")
      private String latestSectionName;

      @ApiModelProperty("最近学习的小节编号")
      private Integer latestSectionIndex;
      }

5.添加课程到我的课表

5.1需求分析

code

5.2接口定义

code
code
user_id 与 course_id 添加了联合唯一,从而使添加不会重复

5.3接口实现

  • 由于Exchange、RoutingKey都已经在tj-common中的MqConstants内定义好了,我们只需要定义消息监听器就可以了
  1. 创建LessonChangeListener监听器
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    package com.tianji.learning.mq;

    import com.tianji.api.dto.trade.OrderBasicDTO;
    import com.tianji.common.constants.MqConstants;
    import com.tianji.common.utils.CollUtils;
    import com.tianji.learning.service.ILearningLessonService;
    import lombok.RequiredArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.amqp.core.ExchangeTypes;
    import org.springframework.amqp.rabbit.annotation.Exchange;
    import org.springframework.amqp.rabbit.annotation.Queue;
    import org.springframework.amqp.rabbit.annotation.QueueBinding;
    import org.springframework.amqp.rabbit.annotation.RabbitListener;
    import org.springframework.stereotype.Component;

    @Slf4j
    @Component
    @RequiredArgsConstructor
    public class LessonChangeListener {

    private final ILearningLessonService lessonService;

    /**
    * 监听订单支付或课程报名的消息
    * @param order 订单信息
    */
    @RabbitListener(bindings = @QueueBinding(
    value = @Queue(value = "learning.lesson.pay.queue", durable = "true"),
    exchange = @Exchange(name = MqConstants.Exchange.ORDER_EXCHANGE, type = ExchangeTypes.TOPIC),
    key = MqConstants.Key.ORDER_PAY_KEY
    ))
    public void listenLessonPay(OrderBasicDTO order){
    // 1.校验
    if(order == null || order.getUserId() == null
    || CollUtils.isEmpty(order.getCourseIds())){
    log.error("接收到MQ消息有误,订单数据为空");
    //不要抛异常,否则会开启重试
    return;
    }
    // 2.调用service
    log.debug("监听到用户{}的订单{},需要添加课程{}到课表中", order.getUserId(), order.getOrderId(), order.getCourseIds());
    lessonService.addUserLessons(order.getUserId(), order.getCourseIds());
    }
    }
  2. 添加addUserLessons方法
  3. 实现LearningLessonServiceImpl
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    package com.tianji.learning.mq;

    import com.tianji.api.dto.trade.OrderBasicDTO;
    import com.tianji.common.constants.MqConstants;
    import com.tianji.common.utils.CollUtils;
    import com.tianji.learning.service.ILearningLessonService;
    import lombok.RequiredArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.amqp.core.ExchangeTypes;
    import org.springframework.amqp.rabbit.annotation.Exchange;
    import org.springframework.amqp.rabbit.annotation.Queue;
    import org.springframework.amqp.rabbit.annotation.QueueBinding;
    import org.springframework.amqp.rabbit.annotation.RabbitListener;
    import org.springframework.stereotype.Component;

    @Slf4j
    @Component
    @RequiredArgsConstructor
    public class LessonChangeListener {

    private final ILearningLessonService lessonService;

    /**
    * 监听订单支付或课程报名的消息
    * @param order 订单信息
    */
    @RabbitListener(bindings = @QueueBinding(
    value = @Queue(value = "learning.lesson.pay.queue", durable = "true"),
    exchange = @Exchange(name = MqConstants.Exchange.ORDER_EXCHANGE, type = ExchangeTypes.TOPIC),
    key = MqConstants.Key.ORDER_PAY_KEY
    ))
    public void listenLessonPay(OrderBasicDTO order){
    log.info("监听到用户{}的订单{},需要添加课程{}到课表中", order.getUserId(), order.getOrderId(), order.getCourseIds());
    // 1.校验
    if(order == null || order.getUserId() == null
    || CollUtils.isEmpty(order.getCourseIds())){
    log.error("接收到MQ消息有误,订单数据为空");
    //不要抛异常,否则会开启重试
    return;
    }
    // 2.调用service
    lessonService.addUserLessons(order.getUserId(), order.getCourseIds());
    }
    }

    5.4接口测试

  • 启动learn启动类
  • 点击添加java免费课程
  • 在控制台查看接收消息并在表中查看字段

    控制台没有输出
    通过trade模块的控制台发现是课程已过期

    • 解决方法:取消过期时间判断
      code
      修改表中的过期时间不知道为什么没有效果!!!!!