东林在线微课堂-我的课表相关

1.我的课表

准备阶段—业务流程

image-20240817204359442

准备阶段—字段分析

【主要涉及主键id,学员id和课程id也要记录[要考虑是谁学了什么课程]】

课表要记录的是用户的学习状态,所谓学习状态就是记录在学习哪个课程学习的进度如何。

  • 其中,谁在学习哪个课程,就是一种关系。也就是说课表就是用户和课程的中间关系表。因此一定要包含三个字段:

    • userId:用户id,也就是
    • courseId:课程id,也就是学的课程
    • id:唯一主键
  • 而学习进度,则是一些附加的功能字段,页面需要哪些功能就添加哪些字段即可:

  • status:课程学习状态。0-未学习,1-学习中,2-已学完,3-已过期

  • planStatus:学习计划状态,0-没有计划,1-计划进行中

  • weekFreq:计划的学习频率

  • learnedSections:已学习小节数量,【注意:课程总小节数、课程名称、封面等可由课程id查询得出,无需重复记录】

  • latestSectionId:最近一次学习的小节id,方便根据id查询最近学习的课程正在学第几节

  • latestLearnTime:最近一次学习时间,用于分页查询的排序:

  • createTime和expireTime,也就是课程加入时间和过期时间

准备阶段—ER图

image-20240817212711903

准备阶段—表结构

image-20240817205247815

image-20240817205028215

准备阶段—Mybatis-plus代码生成

参考我的Mybatis-plus笔记-代码生成步骤:

image-20240814151956565

准备阶段—状态枚举

image-20240814152152815

准备阶段—所有接口

image-20240813213435263

==具体实现==

1.支付/报名课程后添加课表

1.原型图

2.设计数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
create table learning_lesson
(
id bigint not null comment '主键'
primary key,
user_id bigint not null comment '学员id',
course_id bigint not null comment '课程id',
status tinyint default 0 null comment '课程状态,0-未学习,1-学习中,2-已学完,3-已失效',
week_freq tinyint null comment '每周学习频率,例如每周学习6小节,则频率为6',
plan_status tinyint default 0 not null comment '学习计划状态,0-没有计划,1-计划进行中',
learned_sections int default 0 not null comment '已学习小节数量',
latest_section_id bigint null comment '最近一次学习的小节id',
latest_learn_time datetime null comment '最近一次学习的时间',
create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
expire_time datetime not null comment '过期时间',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
constraint idx_user_id
unique (user_id, course_id)
)
comment '学生课程表' row_format = DYNAMIC;

image-20240815165857129

3.业务逻辑图

接下来,我们来分析一下添加课表逻辑的业务流程。首先来对比一下请求参数和数据库字段:

参数:

  • Long userId
  • List courseIds

数据表:

img

一个userId和一个courseId是learning_lesson表中的一条数据。而订单中一个用户可能购买多个课程。因此请求参数中的courseId集合就需要逐个处理,将来会有多条课表数据。

另外,可以发现参数中只有userId和courseId,表中的其它字段都需要我们想办法来组织:

  • status:课程状态,可以默认为0,代表未学习
  • week_freq:学习计划频率,可以为空,代表没有设置学习计划
  • plan_status:学习计划状态,默认为0,代表没有设置学习计划
  • learned_sections:已学习小节数,默认0,代表没有学习
  • latest_section_id:最近学习小节id,可以为空,代表最近没有学习任何小节
  • latest_learn_time:最近学习时间,可以为空,代表最近没有学习
  • create_time:创建时间,也就是当前时间
  • expire_time:过期时间,这个要结合课程来计算。每个课程都有自己的有效期(valid_duration),因此过期时间就是create_time加上课程的有效期
  • update_time:更新时间,默认当前时间,有数据库实时更新,不用管

可见在整张表中,需要我们在新增时处理的字段就剩下过期时间expire_time了。而要知道这个就必须根据courseId查询课程的信息,找到其中的课程有效期(valid_duration)。课程表结构如图:

image-20240817213419509

因此,我们要做的事情就是根据courseId集合查询课程信息,然后分别计算每个课程的有效期,组织多个LearingLesson的数据,形成集合。最终批量新增到数据库即可。

流程如图:

image-20240815212456046

其中消息发送者信息:

image-20240817211108395

4.接口分析

image-20240815212239468

5.具体实现

  • 1.数据库设计:

image-20240814145734802

  • 2.准备PO和枚举类:

image-20240814152152815

1
2
3
4
5
6
7
8
9
使用枚举类的优点:
1.类型安全:枚举提供了一种类型安全的方式来处理一组固定的常量。使用枚举可以确保status字段的值只限于预定义的四个选项,防止出现无效的值。【更安全】
2.代码可读性:枚举使得代码更易读,更易于维护。开发者可以很容易地理解每个枚举值的含义,而不需要去查看数据库字段的注释或文档。【易读】
3.减少错误:使用枚举可以减少因拼写错误或使用错误的整数值而导致的bug。【防止写错】
4.便于比较:枚举类型之间的比较可以直接使用==操作符,而不需要使用equals方法。【直接使用==对比】
5.可扩展性:如果未来需要添加更多的状态,枚举类可以很容易地进行扩展。【更容易扩展】
6.方法和属性:枚举类型可以包含字段、方法和构造函数,这使得你可以在枚举值上添加更多的行为和数据。
7.序列化:枚举类型默认实现了Serializable接口,这使得它们可以很容易地被序列化和反序列化。【搭配@JsonValue//序列化的时候转为响应值 @EnumValue //和数据库打交道时转为相对应值】
8.switch语句支持:枚举类型可以作为switch语句的合法变量类型,使得代码更加清晰。
  • 3.使用MybatisPlus生成其余基础代码:

image-20240814151956565

  • 4.设计MQ消费者信息

【我和课程下单统一OrderBasicDTO,主要传递orderId和courseID和userID以及完成时间】

image-20240815162011652

  • 5.具体逻辑

image-20240815162411566

6.具体难点和亮点

  • 问题一:课程过期时间怎么算?

    课程过期时间=课程加入课程时间(当前)+课程有效期(通过传入的courseId课程id远程调用课程微服务获取media_duration有效时间)

  • 问题二:如果这个人网络不好,重复下单怎么保证幂等性?

    1.我给(courseId,userId)创建唯一索引,保证幂等性

    image-20240815165221302

    2.我使用redis:进来的时候判断OrderId订单id是否有,有的话就重复,没有的话就存在redis[设置60s]

image-20240815165141761

  • 问题三:Id如何设计?

    分为分库和不分库情况:我考虑并发就分库,然后使用雪花算法【还有其他方法,在tk实习时候考虑的那个笔记里面】
    image-20240815170139617

参考本文:https://mp.weixin.qq.com/s/zQNfcpCbPoo4yQFJR7FpqQ

2.分页查询我的课表

1.原型图

image-20240817210643678

2.设计数据库

3.业务逻辑图

image-20240817210943970

肉眼可见的字段就包含:

  • 课程名称
  • 课程加入课表时间
  • 课程有效期结束时间
  • 课程状态
  • 课程已学习小节数
  • 课程总小节数
  • 课程是否创建了学习计划

还有一些字段是页面中没有的,但是可以从功能需要中推测出来,例如:

  • 课程id:因为我们点击卡片,需要跳转到对应课程页面,必须知道课程id
  • 课程封面:页面渲染时为了美观,一定会展示一个课程的封面图片
  • 学习计划频率:当用户点击修改学习计划时,需要回显目前的学习计划频率
  • 课表id,当前课程在课表中的对应id,当用户点击继续学习,或创建集合,需要根据课表来操作

4.接口分析

image-20240815211955503

5.具体实现

  • 1.controller层

image-20240815195224271

  • 2.service层

image-20240815195238771

  • 3.serviceImp层

image-20240815195504036

6.具体难点和亮点

  • 问题一:如何查询避免封装时候两次for循环

​ 使用courseList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c))转换为map,在后续直接取出来就行

3. 查看最近学习的课程(一门)

1.原型图

image-20240817204641999

2.设计数据库

learning_lesson

course

course_catalogue

image-20240815200109908

3.业务逻辑图

主要分为四个部分数据:

image-20240815210724100

4.接口分析

image-20240815200138868

5.具体实现

  • 1.controller层

image-20240815211536963

  • 2.service层

image-20240815211548167

  • 3.serviceimpl层

    image-20240815211458287

  • 4.mapper层

image-20240816150635247

6.具体难点和亮点

  • 问题一:什么是最近学习的一门课程【基本上围绕learning-lesson和course以及course-catalogue三个数据库表获取数据】

    可以在学习中心位置查看最近学习的一门课程,主要是通过userId用户id查询一条课程表信息;通过课程表信息的courseId课程id查询课程的具体信息;通过课程表信息的latest_section_id最近一次学习的小节名称远程调用课程学习微服务获取(通过latest_section_id查询course-catalogue表数据);通过userId用户id来count(*)获得数据

4.根据id查询某个课程学习状态

1.原型图

在课程详情页,课程展示有两种不同形式:

  • 对于未购买的课程:展示为立刻购买或加入购物车

img

  • 对于已经购买的课程:展示为马上学习,并且显示学习的进度、有效期

img

2.设计数据库

3.业务逻辑图

image-20240816144647955

4.接口分析

image-20240816144722047

5.具体实现

  • 1.controller层

image-20240816151331705

  • 2.service层

image-20240816151336910

  • 3.serviceimpl层

image-20240816151452627

  • 4.mapper层

image-20240816151350430

6.具体难点和亮点

  • 问题一:查询课表的课程还是课程表的信息?

​ ①根据courseId和UserId(两者是唯一索引,能保证只有得到一条数据)查询课表得到公共数据,针对课程具体信息要传入courseId课程id远程调用查询

5.删除课表中的课程

1.原型图

image-20240816164422835

2.设计数据库

3.业务逻辑图

删除课表中的课程有两种场景:

  • ①用户直接删除已失效的课程【比较简单】
  • ②用户退款后触发课表自动删除【涉及发送MQ消息给learning-service服务】

现在那边退款成功之后增加步骤4[发送消息,我需要负责接受消息]

image-20240816162139654

4.接口分析

这里我们可以按照Restful的规范来定义这个删除接口:

  • 请求方式:删除业务的请求方式都是DELETE
  • 请求路径:一般是资源名 + 标示,这里删除的是课表中的课程,因此:/ls/lessons/{courseId}
  • 请求参数:自然是路径中传递的课程id
  • 返回值:无

5.具体实现

  • 1.controller层

image-20240816160647290

  • 2.service层

    image-20240816163813941

  • 3.serviceimpl层

image-20240816160731775

image-20240816163833033

  • 4.mapper层

image-20240816160747311

  • 5.learning-service微服务接收MQ消息

image-20240816164326102

6.具体难点和亮点

  • 问题一:删除的有哪几种情况?

    ①根据用户下单,然后取消报名的时候发送MQ消息给learning-service微服务告知删除

    ②已经学习了很久,课程失效了就直接根据情况删除

6.检查课程是否有效

1.原型图

2.设计数据库

3.业务逻辑图

这是一个微服务内部接口,当用户学习课程时,可能需要播放课程视频。此时提供视频播放功能的媒资系统就需要校验用户是否有播放视频的资格。所以,开发媒资服务(tj-media)的同事就请你提供这样一个接口。

用户要想有播放视频的资格,那就必须满足两个条件:

  • 用户课表中是否有该课程
  • 课程状态是否是有效的状态(未过期)

image-20240816165647909

4.接口分析

image-20240816164643768

5.具体实现

  • 1.controller层

image-20240816165802260

  • 2.service层

image-20240816165837661

  • 3.serviceimpl层

image-20240816165901892

  • 4.mapper层

image-20240816165912431

6.具体难点和亮点

  • 问题一:如何判断课程是否有效

    就是①判断课表是否有这个课程,②这个课程的expire过期时间是否失效了,没办法学了

7.统计课程的学习人数

1.原型图

课程微服务中需要统计每个课程的报名人数,同样是一个内部调用接口,在tj-api模块中已经定义好了:

1
2
3
4
5
6
7
/**
* 统计课程学习人数
* @param courseId 课程id
* @return 学习人数
*/
@GetMapping("/lessons/{courseId}/count")
Integer countLearningLessonByCourse(@PathVariable("courseId") Long courseId);

2.设计数据库

3.业务逻辑图

4.接口分析

这里我们可以按照Restful的规范来定义这个统计接口:

  • 请求方式:删除业务的请求方式都是GET
  • 请求路径:一般是资源名 + 标示,这里删除的是课表中的课程,因此:/lessons/{courseId}
  • 请求参数:自然是路径中传递的课程id
  • 返回值:Integer学习人数

5.具体实现

  • 1.controller层

image-20240816173242686

  • 2.service层

image-20240816173248999

  • 3.serviceimpl层

image-20240816173314799

  • 4.mapper层

image-20240816173300519

6.具体难点和亮点

  • 问题一:sql怎么写?怎么统计

    1
    2
    3
    select count(user_id) 
    from learning_lesson
    where course_id=xx 【根据课程id分类】

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. 1.我的课表
    1. 1.1. 准备阶段—业务流程
    2. 1.2. 准备阶段—字段分析
    3. 1.3. 准备阶段—ER图
    4. 1.4. 准备阶段—表结构
    5. 1.5. 准备阶段—Mybatis-plus代码生成
    6. 1.6. 准备阶段—状态枚举
    7. 1.7. 准备阶段—所有接口
  2. 2. ==具体实现==
  3. 3. 1.支付/报名课程后添加课表
    1. 3.1. 1.原型图
    2. 3.2. 2.设计数据库
    3. 3.3. 3.业务逻辑图
    4. 3.4. 4.接口分析
    5. 3.5. 5.具体实现
    6. 3.6. 6.具体难点和亮点
  4. 4. 2.分页查询我的课表
    1. 4.1. 1.原型图
    2. 4.2. 2.设计数据库
    3. 4.3. 3.业务逻辑图
    4. 4.4. 4.接口分析
    5. 4.5. 5.具体实现
    6. 4.6. 6.具体难点和亮点
  5. 5. 3. 查看最近学习的课程(一门)
    1. 5.1. 1.原型图
    2. 5.2. 2.设计数据库
    3. 5.3. 3.业务逻辑图
    4. 5.4. 4.接口分析
    5. 5.5. 5.具体实现
    6. 5.6. 6.具体难点和亮点
  6. 6. 4.根据id查询某个课程学习状态
    1. 6.1. 1.原型图
    2. 6.2. 2.设计数据库
    3. 6.3. 3.业务逻辑图
    4. 6.4. 4.接口分析
    5. 6.5. 5.具体实现
    6. 6.6. 6.具体难点和亮点
  7. 7. 5.删除课表中的课程
    1. 7.1. 1.原型图
    2. 7.2. 2.设计数据库
    3. 7.3. 3.业务逻辑图
    4. 7.4. 4.接口分析
    5. 7.5. 5.具体实现
    6. 7.6. 6.具体难点和亮点
  8. 8. 6.检查课程是否有效
    1. 8.1. 1.原型图
    2. 8.2. 2.设计数据库
    3. 8.3. 3.业务逻辑图
    4. 8.4. 4.接口分析
    5. 8.5. 5.具体实现
    6. 8.6. 6.具体难点和亮点
  9. 9. 7.统计课程的学习人数
    1. 9.1. 1.原型图
    2. 9.2. 2.设计数据库
    3. 9.3. 3.业务逻辑图
    4. 9.4. 4.接口分析
    5. 9.5. 5.具体实现
    6. 9.6. 6.具体难点和亮点
,