1、项目总体描述
在线教育平台采用了B2C商业模块,基于微服务架构,采用前后端分离的方式进行开发
2、功能模块
基于前后台的模式开发,前台系统是给使用这个平台进行学习的用户,后台系统是给管理员使用的
涉及到的功能模块:
前台:
- 首页信息展示
- 课程列表和详情
- 课程支付
- 课程视频播放
- 名师列表和详情:基本课程列表和详情
- 登录和注册
后台:
- 讲师管理
- 课程分类管理
- 课程管理
- 网站数据统计分析
- 权限管理
3、项目涉及的技术
根据前端技术和后端技术分开说
后端:
- SpringBoot
- SpringCloud(Nacos,Feign,Hystrix,gateway)
- Mybatis-plus
- redis
- Spring Security
- Swagger
- EasyExcel
前端:
- vue
- element-ui
- NUXT
- babel
第三方技术:
- 阿里云短信服务
- 阿里云OSS存储服务
- 阿里云视频点播服务
- 微信登录
- 微信支付
4、功能模块详细
前台:
-
首页信息展示
首页信息包括banner,热门课程,热门名师
- banner是每次取时间最近的前两个图
- 热门课程是根据销量取前8个课程
- 热门名师都是id查询4个讲师
因为首页的访问量最大,所以把数据放入redis中缓存,具体使用方法是在需要的模块中的配置文件里配置redis,在需要缓存的方法上加上
@Cacheable
注解 -
名师列表和详情
- 名师列表就是条件分页查询,分别用
QueryWrapper
和Page
封装 - 名师详情是点击某一个讲师,根据讲师的id查询讲师的信息,以及他讲授的课程
- 名师列表就是条件分页查询,分别用
-
课程列表和详情
- 课程列表就是复杂条件分页查询,分别用
QueryWrapper
和Page
封装 - 课程详情是点击课程,进入课程详情页面
包含课程基本信息,分类,讲师,课程大纲
- 课程列表就是复杂条件分页查询,分别用
-
课程视频播放
在详情页可以直接点击小节观看课程
整合了阿里云视频点播服务
-
可以直接拿播放地址播放视频
-
可以拿播放凭证+视频id播放视频(用的是这种方式)
拿阿里云的access_id和access_secret和视频的id可以拿到播放凭证,传给前端,就可以创建播放器组件观看视频
-
-
课程支付
课程分为免费课程和付费课程,付费课程需要进行支付才能进行观看,使用微信扫码支付
涉及订单表和支付表两张表
-
点击‘立即购买’,生成订单,跳转到订单详情页面
根据课程id(前端传入)和用户id(用户发的请求的header里有token里面有id)生成订单,还需要额外的信息通过这两个id分别去两个表里查,生成的订单加到订单表里
-
点击确定‘去支付’,生成二维码
设置支付的参数(公司的appid,订单编号等),使用HTTPClient工具请求微信提供的固定地址,返回信息包含了支付二维码的url等信息,传给前端
-
查询支付状态,成功后,显示支付成功
查询支付状态跟上面一样,也是设置参数并请求地址,得到的结果里有订单状态
成功后,向支付表中添加,并把订单表中该订单的状态改为1怎么知道用户是否支付了这门课?
点击页面详情的时候,后端同步调用查询订单表,如果有数据而且订单状态是已支付,那就是可以看,返回给前端这个信息
-
-
登录和注册
-
注册:输入手机号+密码,获取验证码,输入验证码后成功注册
使用到了阿里云的短信服务,这个不能自己申请,是去云市场买的,按照他给的api写代码就可以
输入手机号后,点击获取验证码,后端会生成一个验证码,以手机号-验证码的形式存在redis里,设置过期时间比如5分钟,当用户得到验证码后输入,判断用户输入的和redis中的是否一样,如果一样就向用户表中添加新数据
-
登录
实现单点登录SSO,通过OAuth2+JWT,分别对应扫码登录和账号密码登录
1)手机号+密码
输入手机和密码之后,按照手机号去数据库中查询,如果加密后的密码是一样的,说明登陆成功,返回JWT,将返回的jwt放入cookie中,再次请求的时候,从前端拦截一下,如果cookie中有token的话,把token放入用户的请求头header中,跳转到首页,调后端接口从token中的到用户信息,显示在首页上
2)微信扫码
主要是是用了OAuth2的开放间系统授权,微信授权给我们的这个网站
具体获取扫描人的信息的过程:扫描人扫描后,会得到一个临时票据,拿着这个临时票据去请求一个微信的固定地址,会得到两个值access_token(访问凭证)和open_id(微信号),拿着这两个值再去请求一个固定地址,返回一个json串,就能得到扫描人的头像和昵称等信息
涉及到的技术:用httpclient发送请求,用json工具解析字符串得到对应的信息
-
退出
不涉及后端,直接前端把cookie移除就可以了
-
后台:
-
讲师管理
分两个模块
-
讲师列表:讲师的条件分页查询,删除和修改(根据id)
-
讲师增加:增加,除了基础的信息之外还上传了老师的头像。
主要原因是没有自己的服务器,类似图像视频等资源没有地方放,所以使用了阿里云OSS对象存储服务,放在了阿里云上,这样外界也可以访问到
1)将阿里云上传文件的api集成到系统中,service签名为
String upload(MultipartFile file)
,返回上传后的url2)主要看阿里云的文档的文件流传输,大概流程是根据access_key和access_secret等信息新建ossClient对象,通过这个client上传文件,返回上传后的url,存入teacher表中的头像中
-
-
课程分类管理
分为两个模块
-
课程分类列表:课程列表的展示,有两级分类,以树形的结构显示(后端封装成两级的对象)
-
课程分类添加:读取excel表格添加分类,使用EasyExcel工具
需求就是将下图excel中的形式转化为下下图中数据库的形式
1)建立与Excel表格对应的实体类2)一个监听器类listener,重写invoke函数用来一行行读取excel中的内容,读的时候调service一行一行往数据库里添加,这里一个注意点,easyExcel不能交给spring管理,所以不能自动注入service,解决方式是将service作为参数直接传进来
- 课程管理
edu_course,存课程基本信息
edu_course_description,存课程简介
edu_chapter,存课程的章节
edu_video,课程小节表,存课程的章节里面的小节的信息
edu_teacher,edu_subject一共6张表
表与表之间的关系
效果
分两个模块:
-
课程列表:基本同前面模块的列表,课程的删改查
-
课程添加:分为三个步骤
1)编辑课程基本信息:包括名称、简介(单独一张表)、价格、讲师(下拉框)、分类(下拉框,一二级联动的)等,涉及到两张表
-
表单初始化的时候,前端会实现调用后端接口查询一级分类和讲师列表,选择一级列表后会查询二级列表
-
编辑完信息之后点击保存并下一步,这个时候分别向课程表和课程简介表中增加课程信息,由于课程和课程描述是一对一的,所以可以用同一个主键,先向课程表里添加,查询得到添加的主键后,再向描述表中添加,注意描述表的主键生成策略要改
-
课程的状态默认为未发布
2)编辑课程大纲:
-
对章节进行增删改,操作后直接向数据库中同步
-
章节里可以添加小节,删除小节,操作后直接向数据库中同步
-
添加小节的时候需要上传视频,涉及到微服务远程调用,和阿里云视频点播服务
-
阿里云视频点播的上传和删除和oss服务基本一致
3)确认课程信息:包括一系列信息,用一个sql语句将这些任务都做一个回显。点击确认发布的时候,将该课程的状态改为已发布
-
- 网站数据统计分析
-
统计某段时间内网站的注册人数
去用户表中统计注册日期为某一天的数目,即可得到注册人数
主要是引入定时任务,加启动类上加注解
@EnableScheduling
,在对应方法上加@Scheduled(cron 表达式)
-
图表显示:前端使用ECharts,后端查询数据库返回日期json数组和数量json数组
-
权限管理
主要是针对后台系统,思路是基于token的认证和授权
分两个部分
- 认证流程
1)用户输入用户名和密码,去数据库中查用户是否合法,以及相应的权限
2)将用户的权限以用户名-权限列表的方法存入redis
3)将用户名等信息生成jwt,返回给前端
4)前端拿到jwt放到cookie里,再请求的时候把cookie中的token放入请求头header中
5)再次请求的时候从header中取出token,解析出用户名,在redis中查询,如果有的话就是已登录的
6)授予相应的权限
代码执行流程
- 认证流程
-
授权流程
spring security是个过滤器链,在认证的时候在SecurityContextHolder中保存了当前登录的用户信息,其中就包括对应的权限,鉴权的时候会从SecurityContextHolder取出用户的权限,如果当前没有当前访问的这个资源的权限的话,就不放行1)限制访问资源所需要的权限
-
配置类里开启权限注解
@EnableGlobalMethodSecurity(prePostEnabled = true)
,在相应的资源(controller)上使用@PreAuthorize("hasRole('xxxx')")
-
也可以在配置类中,将请求的路径赋予一定的权限
在访问相应的URL的时候,会执行hasRole()这个方法,然后查询实现了UserDetails接口的那个类中的属性authorities,只要authorities中包含"xxxx",则该用户就可以访问这个URL,否则会报错,提示权限不足
2)分配权限
在实现了UserDetails类里要重写一个方法,将表示权限的字符串封装成相应的权限类
-
-
认证时登陆成功的处理
在认证过滤器中重写
successfulAuthentication
方法,返回统一响应结构,里面封装我们生成的jwt字符串 -
认证时登陆失败的处理
在认证过滤器中重写
unsuccessfulAuthentication
方法,返回统一响应结构 -
登出时的处理
继承LogoutHandler类,重写logout方法,方法内将用户信息在redis中移除。将这个登出类配置到spring security中
-
未授权的处理
写AuthenticationEntryPoint的继承子类,重写commence方法,方法内返回统一响应格式
将写好的处理配置给spring security
-
权限不够的处理
写AccessDeniedHandler 的继承子类,重写commence方法,方法内返回统一响应格式
将写好的处理配置给spring security
5、一些技术详细
- 微服务
服务发现——Netflix Eureka (Nacos)
服务调用——Netflix Feign
熔断器——Netflix Hystrix
服务网关——Spring Cloud GateWay
分布式配置——Spring Cloud Config (Nacos)
消息总线 —— Spring Cloud Bus (Nacos)
-
注册中心使用阿里的Nacos
原理:生产者消费者,分别都在注册中心注册,之后相互调用,注册的东西本质上就是ip地址和端口号
-
服务调用使用原生的Feign
过程:只需要创建一个接口并用注解方式配置它,即可完成服务提供方的接口绑定
功能就是可以像调用本地方法一样调用远程的方法
-
熔断器Hystrix
一个容错机制,调用前先确认一下服务是否可用,如果不可用的话就不允许调用,可用就放行
-
网关gateway
这里主要是使用网关的请求分发的功能
负载均衡:当同一服务是部署在集群上的时候,gateway会自动的帮我们做到平均分配请求,不需要像nginx一样做额外配置
跨域问题:网关可以解决跨域问题,不需要在controller上加@CrossOrigin了,在网关模块写一个配置类即可
过滤器:设置什么样的请求可以访问或者不可以访问
-
配置中心Nacos
当同一服务以集群的方式部署的时候,每个服务器上都有对应的同一个配置文件,当配置文件需要改动的时候,就得都跟着改,为了解决这个问题,使用配置中心统一管理配置文件,只需要一份就够了
用法:
1)在nacos中新建配置,注意命名方式,配置内容直接复制原服务里的配置内容
2)在服务里面添加依赖
3)在服务里创建bootstrap.properties配置文件,里面配置配置中心的地址,这样就配置完成了 -
统一异常处理
类上加
@ControllerAdvice
类内的方法上加
@ExceptionHandler(xxx.class)