? 写在前面
我为什么要花时间去写这个笔记?
由于在学习该项目的过程中发现了原讲义存在的一些问题,所以该笔记基于「学成在线」微服务项目 PDF
讲义进行编写,并且投入了时间去优化了笔记的格式、代码的高亮、重点的标记等。
以及一些原讲义中所描述的一些知识点使我无法理解的内容,我会对这些内容的表达方式进行修改或者提出一些问题,并且用我自己所理解的一些想法去重新的解释这个问题。
总结一下原 PDF
讲义中已知的一些问题:
- 从
PDF
中复制出来的代码,部分特殊符号的编码有问题,并且不易被发现,例如横杠-
,从PDF直接复制出来的话是无法运行的。 - 有时候一些重复且简单的代码,我们需要直接从讲义中直接复制,而部分
PDF
编辑器复制出来的代码格式可能会变乱,且PDF中没有代码高亮,代码可阅读性差,并且复制出来时会有代码缩进错乱等问题。 - 部分内容是重点但在讲义中只是简单的描述,这并不方便我们后期回顾该课程的知识点,所以我在一些重点的内容上加上了更多的解释。
如有不足的地方,欢迎补充、填坑。
? 知识点概览
- 本章节将对【学成在线】项目的知识点进行回顾、总结、梳理。
目录
内容会比较多,小伙伴们可以根据目录进行按需查阅。
文章目录
- ? 写在前面
- 我为什么要花时间去写这个笔记?
- ? 知识点概览
- 目录
- 一、学成在线是一个什么样的项目?
- 0x01 项目背景
- 0x02 功能模块
- 0x03 技术架构
- 二、项目采用什么技术架构?
- 0x01 微服务技术栈
- 0x02 接口定义规范
- 0x03 微服务注册中心
- 0x04 微服务网关
- 0x05 项目使用Spring了吗?用了它的哪些东西?
- 0x06 项目中Spring Cloud是怎么使用的?
- 0x07 Spring Data JPA 和 MyBatis 为什么两个都用?具体怎么用的?
- 0x08 什么雪崩?如何解决?
- 0x09 视图层用什么技术实现?
- 0x0A 接口是怎么定义的?采用什么数据格式?
- 三、前端开发时具体流程是什么?
- 前端采用什么技术栈?
- 四、该项目当前完成了哪些功能
- 0x01 CMS页面管理
- GirdFS是什么?工作原理是什么?如何使用?
- MQ在本项目中是如何使用的?
- 页面发布的结果如何收集?
- 0x02 课程管理
- 为什么用多张表存储课程信息?
- 0x03 媒资管理
- 如何上传大文件?
- 如何进行视频处理?
- CDN 内容分发是什么?
- 0x04 搜索
- 0x05 图片服务器
- 使用FastDFS的好处是什么?
- 图片上传流程是怎么样的?
- FastDFS支持断点续传吗?
- 0x06 在线视频点播
- 五、项目一些常见的问题
- 0x01 认证授权如何实现?
- 0x02 事务是怎么控制的?分布式项目如何进行事务控制?
- 0x03 一个接口出现bug你是怎么进行调试的?
- 0x04 本项目中在线支付是如何实现的?遇到哪些问题
- 实现流程
- 一些问题
- 0x05 系统的异常是怎么处理的?
- 0x06 使用消息队列了吗?如何使用的?有哪些应用场景
- 0x07 你在开发中遇到什么问题?是怎么解决的
- 六、项目功能的整体的测试
- 0x01 准备工作
- 1)启动基础设施
- 2)启动所有服务,并且检查是否注册到的eureka中
- 3)启动前端工程
- 0x02 功能测试
- 1)页面静态化测试
- 测试过程中出现的一些问题
- 2)课程管理
- 3)媒资管理
- 4)课程信息搜索
- 5)在线点播
- 七、该项目待完善的地方
- 八、项目学习周期
- ? 认识作者
一、学成在线是一个什么样的项目?
0x01 项目背景
受互联网+概念的催化,当今中国在线教育市场的发展可谓是百花齐放、如火如荼。 按照市场领域细分为:学前教
育、K12教育、高等 育、留学教育、职业教育、语言教育、兴趣教育以及综合平台,其中,职业教育和语言教育
的市场优势突出。
学成在线借鉴了MOOC
(大型开放式网络课程,即MOOC(massive open online courses))的设计思想,是一
个提供IT职业课程在线学习的平台,它为即将和已经加入IT领域的技术人才提供在线学习服务,用户通过在线学
习、在线练习、在线考试等学习内容,最终掌握所学的IT技能,并能在工作中熟练应用。
当前市场的在线教育模式多种多样,包括:B2C
、C2C
、B2B2C
等业务模式,学成在线采用 B2B2C
业务模式,即向企业或个人提供在线教育平台和学生完成教学活动,市场上类似的平台有:网易云课堂、腾讯课堂等,学成在线的特点是IT职业课程在线教学。
0x02 功能模块
学成在线是一个在线教育平台,提供IT职业课程在线学习,平台包括:门户、学习中心、教学管理中心、系统管理
中心、社交系统等子系统。
项目的功能架构如下图:
门户是整个平台的入口,功能包括:
- 门户首页
- 注册/登录
- 课程搜索
- 职业规划
- 客服等
学习中心为用户提供在线学习服务,包括:
- 我的课程
- 视频点播
- 视频直播
- 在线考试
- 在线答疑
- 学习统计等功能
教学管理中心为教育机构或个人讲师提供教学管理功能,包括:
- 课程管理
- 媒资管理
- 考试管理
- 问答管理等功能
系统管理中心提供系统参数配置
- CMS
- 数据字典
- 分类管理等功能
0x03 技术架构
项目采用前后端分离的技术架构,前端采用vue.js构建,服务端采用 Spring Cloud Netflix
微服务架构,系统分为用户层、CDN
、负载均衡、前端UI、微服务层、数据层、接口层 及 DevOps
等部分组成,下图是完整的技术架构图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bps2L08P-1595704108260)(https://qnoss.codeyee.com/20200704_5b6u5pyN5YqhW+WtpuaIkOWcqOe6v10gZGF5MjAtMu+8mumhueebruaAu+e7kw==/image3.png)]
业务流程举例:
1、用户可以通过pc、手机等客户端访问系统进行在线学习。
2、 系统应用 CDN
技术,对一些 图片
、CSS样式文件
、视频
等资源从 CDN
调度访问。
3、所有的请求全部经过负载均衡器。
4、对于PC、H5等客户端请求,首先请求UI层,渲染用户界面。
5、客户端UI请求服务层获取进行具体的业务操作。
6、服务层将数据持久化到数据库
下图是技术架构简图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IlVMKOXu-1595704108263)(https://qnoss.codeyee.com/20200704_5b6u5pyN5YqhW+WtpuaIkOWcqOe6v10gZGF5MjAtMu+8mumhueebruaAu+e7kw==/image4.png)]
1、用户层,用户层描述了本系统所支持的客户端用户有哪些,本项目目前为各用户提供服务,包括H5、PC、Android和IOS等。
2、CDN
全称 Content Delivery Network
,即内容分发网络,本系统所有静态资源全部通过 CDN
加速来提高访问速度。系统静态资源包括:html页面、js文件、css文件、image图片、pdf和ppt及doc教学文档、video视频等
3、负载均衡 系统的CDN层、UI层、服务层及数据层均设置了负载均衡服务,系统采用LVS+Nginx实现负载均衡均
衡。
4、UI
层 UI层描述了系统向pc用户、app用户、h5用户提供的产品界面。本项目在 PC
和 H5
端采用vue.js+elementUI
实现。
5、微服务层将系统服务分类三类:前端服务、后端服务及系统服务。 前端服务:主要为学习用户提供学习服务。
后端服务:主要为管理用户提供教学管理服务。 系统服务:公共服务,为系统的所有微服务提供公共服务功能
6、外部系统接口 包括如下接口:
- 第三方登录接口,如QQ、微博、微信等。
- 支付宝、微信支付接口
- 短信接口 (阿里大于)
- 邮件接口,通过smpt邮件服务器对外发送电子邮件。
- 微信公众号
- 点播、直播。
OSS
存储- CDN,使用最阿里云CDN服务加速视频访问速度。
7、DevOps
提供了本系统开发、运营、维护支撑的系统,包括如下内容:
- Eureka 服务治理中心:提供服务治理服务,包括:服务注册、服务获取等。
- Docker 容器化部署服务:将本系统所有服务采用容器化部署方式。
- Maven 项目管理工具:提供管理项目所有的
Java
包依赖、项目工程打包服务。 - Git/GitLab 代码管理服务:提供
git
代码管理服务。 - Spring Boot Admin 服务健康监控:监控微服务的健康状态、会话数量、并发数等
二、项目采用什么技术架构?
0x01 微服务技术栈
所有微服务基于 Spring Boot
、Spring Cloud Netflix
构建
-
控制层
Spring MVC
、Spring Security Oauth2
、Swagger
-
业务层
事务控制:
Spring
任务处理:
Spring Task
数据缓存:
Spring Data Redis
消息队列:
Spring Rabbit Template
搜索:
Elasticsearch
-
持久层
操作 MySQL:
MyBatis
、Druid
连接池、Spring Data JPA
操作MongoDB:
Spring Data Mongodb
-
数据层
采用
MySQL
和MongoDb
存储数据,MySQL
存储用户、课程等系统核心信息,MongoDB
存储cms
、配置信息。等认证模块使用redis
储存用户的令牌信息
0x02 接口定义规范
项目架构设立接口层,接口层使用 swagger
注解描述接口的内容,接口定义规范如下:
请求
GET
请求时,前端请求 key/value 串,SpringMVC采用基本数据类型(String、Integer等)或自定义类型接收。POST
请求时,前端请Form
表单数据(application/x-www-form-urlencoded)和Json
数据(ContentType=application/json)、多部件类型数据(multipart/form-data),对于Json数据SpringMVC使用
@RequestBody
注解解析请求的json
数据。
响应
-
响应结果统一信息为:是否成功、操作代码、提示信息及自定义数据。
-
响应结果统一格式为
json
。
0x03 微服务注册中心
两台 Eureka Server
互相注册,组成高可用。
微服务向 Eureka Server
注册自己,并在远程调用时从微服务发现目标服务地址。
微服务远程调用采用客户端负载均衡技术,使用 Feign Client
。
0x04 微服务网关
网关的作用是负载均衡、路由转发、请求过虑等。
项目中网关与 Nginx
配合使用。
0x05 项目使用Spring了吗?用了它的哪些东西?
该项目是基于 Spring
进行构建的
1、所有的微服务开发采用 Spring Boot
开发
3、数据层使用Spring Data JPA、Spring Data MongoDB、Spring Data redis。
4、业务层使用Spring来控制本地事务,还使用了 Spring Task
任务调度框架、Spring AMQP
组件等。
5、控制层使用 SpringMVC、Sprnig Security Oauth2
。
6、微服务管理使用Spring Cloud的Eureka注册中心,微服务之间调用使用 Ribbon
和 Feign Client
完成。
7、使用 Zuul
网关完成微服务安全验证
0x06 项目中Spring Cloud是怎么使用的?
此问题通常是在回答了项目的技术架构后被问及,根据具体的使用Spring Cloud完成微服务开发的步骤来回答即可。
1、每个微服务使用 Spring Boot
开发,每个微服务工程包括了web、service、dao三层,这和开发一般的项目没有区别:
-
web 层使用Spring MVC实现,对外暴露API接口给前端调用。
-
service 层就是根据业务逻辑编写 JavaBean,并使用Spring的声明式事务控制方式来控制事务。
-
dao 层就是数据访问接口,来访问MySQL和Mongodb,访问MySQL使用
Spring Data JPA
和Mybatis
,访问mongodb
使用Spring data mongodb
。
2、微服务开发完成要向 Eureka
注册中心注册,以便被其它微服务查找和访问。
3、微服务与微服务之间使用 feign
来调用,feign Client
具有负载均衡的作用。只需要在接口上声明@FeignClient
注,Spring 底层会产生动态代理对象,使用 ribbon
客户端完成调用。
4、前端访问微服务需要通过网关,网关使用Nginx
和 Zuul
来实现,Nginx 是最前边的负载均衡,通过 Nginx 之后便到达了 Zuul,项目中 Zuul 的功能是过虑用户请求,判断用户身份,对于一些对外公开的微服务则需要经过 Zuul,直接通过 Nginx
负载均衡即可访问
0x07 Spring Data JPA 和 MyBatis 为什么两个都用?具体怎么用的?
此问题是考察对数据访问接口的使用程度。
项目中使用 Spring Data JPA
和 MyBatis
都是用来访问 MySQL
,但是它们的分工不同:
Spring Data JPA 是 Spring
提供的一套JPA接口,使用 Spring Data JPA 主要完成一些简单的增、删、改、查功能。
对于复杂的查询功能会使用 MyBatis
编写SQL语言来实现,因为使用 Spring Data JPA
来做一些复杂的查询是没有 MyBatis
方便的,Spring Data JPA 是面向的对象,而 MyBatis
直接面向 SQL
语句,并且复杂的 sql
操作使用原生的 sql 实现的话也便于后续的优化。
0x08 什么雪崩?如何解决?
容错保护是指微服务在执行过程中出现错误并从错误中恢复的能力。微服务容错性不好很容易导致雪崩效应,什么
是雪崩效应
微服务的雪崩效应表现在服务与服务之间调用,当其中一个服务无法提供服务可能导致其它服务也死掉,比如:单
点登录服务调用用户信息服务查询用户信息,由于用户信息服务无法提供服务导致单点登录服务一直等待,从而导
致用户登录、用户退出功能无法使用,像这样由一个服务所引起的一连串的多个服务无法提供服务即是微服务的雪
崩效应。
Spring Cloud Hystrix 是基于 Netflix
的开源框架 Hystrix
的整合,它实现了断路保护、线程隔离、信号隔离等容错功能。
什么是断路保护?
断路保护就类似家庭电路中的保险丝,当电路过载时保险丝会自动切断,保护整个电路的安全。微服务的断路保护
的工作原理是当请求微服务失败的数量达到一定比例时会切换为开路状态,当请求微服务时就直接返回结果不再请
求微服务,当保持开路状态一段时间后判断微服务是否可以正常请求,如果正常则切换到半开路状态,最后切换到
哪闭路状态。
具体的操作方法可以采用 Fallback,会每个FeignClient方法调用Fallback,当出现开路则调用Fallback方法返回错
误结果。
什么是线程隔离?
调用微服务使用不同的线程池,线程池之间互不影响,即使某个服务不可用也不影响其它服务的调用,比如:对商
品服务的调用使用一个线程池,对用户服务的调用使用另一个线程池,即使用户服务不可用也不影响商品服务的调
用。
0x09 视图层用什么技术实现?
此问题问的较模糊,没有问是客户端的视图还是服务端的视图,所以此问题不光是视图技术还是考察我们对前后端分离的理解。
1、视图层在前端和服务端都存在。
2、前端视图采用 vue.js
+ elementUI
产品界面。
3、服务端都是暴露的 rest
接口,统一用 json
展示数据。
0x0A 接口是怎么定义的?采用什么数据格式?
本问题考察前后端分离开发中接口定义技能。
1、接口定义
使用 SpringMVC
编写Controller
方法,对外暴露 Http
接口,在 Controller
方法上使用RequestMapping
、PostMapping
、GetMapping
等注解定义 Http
接口。
2、采用什么数据格式?
-
请求:
GET
请求时:前端请求key/value
串,SpringMVC
采用基本数据类型(String、Integer等)或自定义类型接收。POST
请求时:前端请Form
表单数据(application/x-www-form-urlencoded)和Json数据(ContentType=application/json)、多部件类型数据(multipart/form-data),对于Json
数据SpringMVC使用@RequestBody
注解解析请求的json数据。 -
响应:
统一响应
json
格式,json
格式数据SpringMVC
采用FastJson
解析为对象。非
json
格式数据SpringMVC
提供参数绑定的方法,将key/value
或Form-Data
数据转换为对象或基本数据类型的变量。
三、前端开发时具体流程是什么?
前后端分离开发模式在互联网公司最常见,特别是一些大型的互联网公司,但是一些传统的软件开发企业仍然是采用传统开发模式,此问题被问及是考察你有没有真正体会前端开发的好处。
1、前端与后端开发人员讨论确定接口。
接口讨论通过,形成接口文档 。
本项目专门设立一个 api
工程,在此工程定义接口,Spring Boot
集成 Swagger
,生成 Swagger
接口,前后端开发人员通过 html
查看接口文档的内容。
2、前端与后端开发人员按照接口文档进行开发。
开发过程中各自进行单元测试。
前端人员怎么进行单元测试?
前端人员可以通过一些工具生成一些模拟数据,比如:EasyMock
。
3、双方功能开发完成进行前后端联调。
阅读:https://github.com/phodal/fe/blob/master/chapters/chapter-13.md
前端采用什么技术栈?
前端工程大多为单页面应用(SPA),采用 vue.js
框架开发,搜索功能前端采用 nuxt.js
服务端渲染(SSR)框架开发。
技术栈包括:
名称 | 说明 |
---|---|
node.js | Node.js是一个事件驱动I/O服务端 JavaScript 环境,基于Google的 V8 引擎,V8引擎执行 Javascript 的速度非常快,性能非常好。 |
vue.js | 一套构建用户界面的渐进式框架。Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。 |
npm/cnpm | NPM是随同 NodeJS 一起安装的包管理工具,能解决NodeJS代码部署上的很多问题 |
webpack | Webpack 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。 |
axios | Axios 是一个基于 Promise 的 HTTP 库,可以用在浏览器和 node.js 中。 |
nuxt.js | Nuxt.js 是一个通过 Vue 用于服务端渲染的简单框架,灵感来自 Next.js |
element-ui | 一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库 |
四、该项目当前完成了哪些功能
0x01 CMS页面管理
CMS
(Content Management System)即内容管理系统,本项目对 CMS
系统的定位是对各各网站(子站点)页面的管理,本项目的CMS系统不去管理每个子网站的全部资源,比如:图片、CSS
、html
页面等,主要管理由于运营需要而经常变动的页面,从而满足根据运营需要快速开发、上线的需求。
功能包括:
- 站点管理,站点就是本项目各各子网站,站点信息包括:站点名称、站点域名、端口、服务器物理路径等
- 模板管理,由于要对页面进行静态化,使用
freemarker
引擎技术,所以需要定义模板。 - 页面管理,包括:页面添加、页面修改、页面删除等操作。
- 页面预览,对页面静态化,在浏览器预览页面静态化内容。
- 页面发布,将页面静态化后发布到所属站点服务器。
GirdFS是什么?工作原理是什么?如何使用?
是什么?为什么?怎么用?
GridFS
是 MongoDB
提供的用于持久化存储文件的模块,它可以作为分布式文件系统使用,CMS
子系统将页面文件、模板文件存储到 GridFS
中,由于本项目使用 MongoDB
,选用 GridFS
可以快速集成开发。
它的工作原理是:
在 GridFS
存储文件是将文件分块存储,文件会按照 256KB
的大小分割成多个块进行存储,GridFS
使用两个集合(collection)存储文件,一个集合是 chunks
, 用于存储文件的二进制数据;一个集合是 files
,用于存储文件的元数据信息(文件名称、块大小、上传时间等信息)。
从 GridFS
中读取文件要对文件的各个块进行组装、合并。
使用方法是:
使用 Spring data mongodb
包下提供的 GridFsTemplate
访问 GirdFS
。
gridFsTemplate.findone() 查询文件
gridFsTemplate.delete() 删除文件
gridFsTemplate.store()存储文件
MQ在本项目中是如何使用的?
1、平台包括多个站点,页面归属不同的站点,需求是发布一个页面应将该页面发布到所属站点的服务器上。
2、每个站点服务部署 CMS Client
程序,并与交换机绑定,绑定时指定站点 Id
为 routingKey
。指定站点id
为routingKey
就可以实现 cms client
只能接收到所属站点的页面发布消息。
3、页面发布程序向 MQ
发布消息时指定页面所属站点 Id
为 routingKey
,根据 routingKey
将消息发给指定的 CMS Client
。
页面发布的结果如何收集?
每次发布会在数据库记录发布日志,每个 CMS Client
完成页面发布会上报发布结果。
1、在站点管理中配置了每个站点的服务器信息
2、在每次发布页面时会记录发布日志(服务器ID、页面ID、页面名称、发布结果)
3、CMS Client
完成页面发布后会向数据库记录发布结果。
4、用户通过查询发布日志表的信息就可以知道每一次的发布结果(哪些服务器页面发布成功,哪些发布失败)
0x02 课程管理
为什么用多张表存储课程信息?
1、课程信息比较复杂,为了方便教学机构按步骤管理课程信息,并且也可以划分权限管理课程信息,将课程信息
管理功能分为多个表,如下
- 课程基本信息表
- 课程图片表
- 课程营销信息表
- 课程计划表等
2、将课程信息分开也是为了系统扩展需要,如果将课程所有信息存储在一张表中将不利于系统扩展。
0x03 媒资管理
每个教学机构都可以在媒资系统管理自己的教学资源,包括:视频、教案等文件。
媒资管理的主要管理对象是课程录播视频,包括:媒资文件的查询、视频上传、视频删除、视频处理等。
-
媒资查询:教学机构查询自己所拥有的媒体文件。
-
视频上传:将用户线下录制的教学视频上传到媒资系统。
-
视频处理:视频上传成功,系统自动对视频进行编码处理。
-
视频删除:如果该视频已不再使用,可以从媒资系统删除。
如何上传大文件?
前端使用 WebUploader
将文件分块,调用服务端分块上传接口来上传分块文件,分块上传完毕前端请求服务端进行合并,当上传过程中断再次进行上传时服务端判断分块是否已经上传,已经上传的分块不再重新上传。
如何进行视频处理?
如上图所示,Java
程序调用 ffmpeg
及流媒体程序员提供的视频处理类库(C程序)完成 avi
、mp4
视频转成 m3u8
格式的视频。
Java
程序使用Jdk提供的 Process Builder
调用 ffmpeg
及 C
程序进行视频处理。
Process Builder
可以调用第三方程序,在 java
程序运行时启动第三方程序进程。
视频处理完成,Java
程序捕获第三方程序的输出日志,解析出视频处理完成标记,更新视频处理状态为已完成。
CDN 内容分发是什么?
视频处理完成会在中心媒体服务器保存一份,另外通过 CDN
程序将视频发布到边缘媒体服务器,用户点播视频通
过 CDN
请求边缘媒体服务器中的视频,提高了视频播放速度。
具体使用的是第三方公司的 CDN
服务。
本项目中未实现CDN内容分发
0x04 搜索
项目中课程搜索采用 ElasticSearch
来完成。
实现方法是:
1、使用 Logstash
(logstash是ES下的一款开源软件,它能够同时 从多个来源采集数据、转换数据)将MySQL中的课程信息读取到 ES
中创建索引,使用IK分词器进行分词。
2、使用 Java High Level REST Client
完成搜索。
3、生产环境使用 ES
部署为集群。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ChvqdHqW-1595704108275)(https://qnoss.codeyee.com/20200704_5b6u5pyN5YqhW+WtpuaIkOWcqOe6v10gZGF5MjAtMu+8mumhueebruaAu+e7kw==/image16.png)]
0x05 图片服务器
本项目采用 FastDFS
分布式系统作为图片服务器。
FastDFS
是用 c
语言编写的一款开源的分布式文件系统,适合小文件的存储。
FastDFS 包括 Tracker server
和 Storage server
。客户端请求 Tracker server
进行文件上传、下载,通过 Tracker server
调度向 Storage server
完成文件上传和下载。
使用 FastDFS
官方提供的 Java API
实现。
图片服务使用 Nginx
作为代理服务器,对 Storage
上部署的 Nginx
完成负载均衡请求。
使用FastDFS的好处是什么?
FastDFS
相比其它的分布式文件系统它适用小文件存储,它不对文件进行分块存储,也不用对文件进行合并处理,所以性能比 GFS
、HDFS
等通用文件系统的性能要高。
图片上传流程是怎么样的?
时序图如下
执行流程如下:
1、管理员进入教学管理前端,点击上传图片
2、图片上传至文件系统服务,文件系统请求 fastDFS
上传文件
3、文件系统将文件信息入库,将文件信息存储到文件系统服务数据库中。
4、文件系统服务向前端返回文件上传结果,如果成功则包括文件的 Url
路径。
5、课程管理前端请求课程管理,进行保存课程图片信息到课程数据库。
6、课程管理服务将课程图片信息保存在课程数据库。
FastDFS支持断点续传吗?
FastDFS
支付断点续传,在 Api
中有 append_file1
方法就是用来实现断点续传的,本项目没有使用 FastDFS
的断点续传功能。
0x06 在线视频点播
本项目采用 HLS
技术实现视频点播。
1、使用 FFmpeg
对视频进行编码处理,生成 m3u8
文件及 ts
文件。
2、使用 Nginx
作为媒体服务器。
3、客户端使用 video.js
播放视频。
五、项目一些常见的问题
0x01 认证授权如何实现?
本项目采用 Spring security
+ Oauth2
完成用户认证及用户授权。认证授权流程如下:
1、用户请求认证服务完成身份认证。
2、认证服务下发用户 JTI
(身份令牌)和 JWT
令牌,拥有身份令牌表示身份合法,Jwt
令牌用于完成授权。
3、用户携带 jwt
令牌请求资源服务。
4、网关校验用户身份令牌的合法,不合法表示用户没有登录,如果合法则放行继续访问。
5、资源服务获取 jwt
令牌,根据 jwt
令牌完成授权,并放行用户访问指定的资源。
0x02 事务是怎么控制的?分布式项目如何进行事务控制?
此问题考察对事务的理解和应用程度。
1、在微服务中使用 Spring
声明式事务控制方式进行控制,在 Service
方法上添加 @Transctional
注解即可实现事务控制,它控制的是 MySQL
的本地事务。
2、项目中大量存在分布式事务控制,比如下单支付、课程发布等地址都用到了分布式事务。本项目实现分布式事务控制实现最终数据一致性,做法是:
a、将分布式事务拆分为多个本地事务。
b、提交事务前每个参与者要通过数据校验,和资源预留。
c、由消息队列去通知多个事务参与者完成本地事务的提交。
d、提交失败的本地事务会重试。
0x03 一个接口出现bug你是怎么进行调试的?
1、接口的开发需要前端和服务端共同调试,要仔细阅读测试人员反映的 bug
信息,判断这个 bug
是服务端的bug
还是前端的 bug
。通常服务接口开发完成会使用 postman
工具进行测试,测试没有问题再提交到 Git
或SVN
。
2、找到 bug
的出错点就可以根据 bug
信息进行修改。
3、修改完成需要前后端再次连调测试,按照测试人员提交的测试流程重新进行测试,测试通过将此 bug
置为已解决。
0x04 本项目中在线支付是如何实现的?遇到哪些问题
实现流程
1、系统中收费的课程需要用户在线支付,支付接口采用微信的扫码支付。
2、拿到需求后,确定使用微信支付,首先去阅读微信的接口文档,这里重点阅读统一下单、支付结果通知、支付
结果查询三个接口。
3、下载官方提供的 sdk
编写单元测试用例测试每个接口。测试时没有使用微信的沙箱测试,直接使用正式接口,我们将金额改的小一些进行测试。
4、单元测试通过后开发整个支付功能,最终集成测试通过。
一些问题
接口参数的签名问题,当时是因为自己没有仔细看接口文档导致少写一个必填参数一直报签名失败,随后将所有必填参数填写完成,最终解决问题。
本项目中还未实现在线支付功能,这里仅是提供一些实现的思路,需要后续自己完善
0x05 系统的异常是怎么处理的?
系统对异常的处理使用统一的异常处理流程。
1、自定义异常类型。
2、自定义错误代码及错误信息。
3、对于可预知的异常由程序员在代码中主动抛出自定义异常类型的异常,抛出异常时需要指定错误代码。
4、对于不可预知的异常(运行时异常)由 SpringMVC
统一捕获 Exception
类型的异常,由统一的异常捕获类来解析处理,并转换为与自定义异常类型一致的信息格式(错误代码+错误信息)。
5、可预知的异常及不可预知的运行时异常最终会采用统一的信息格式(错误代码+错误信息)来表示,最终也会随请求响应给客户端。
0x06 使用消息队列了吗?如何使用的?有哪些应用场景
项目使用 RabbitMQ
消息队列。
RabbitMQ
提供很多的工作模式,如下:
-
Work queues
-
Publish/Subscribe
-
Routing
-
Topics
-
Header
-
RPC
项目主要使用了 Routing
模式。
Routing
模式即路由模式,使用方法是:
1、每个消费者监听自己的队列,并且设置 routingkey
。
2、生产者将消息发给交换机,由交换机根据 routingkey
来转发消息到指定的队列。
有哪些应用场景?
1、任务异步处理。
将不需要同步处理的并且耗时长的操作由消息队列通知消息接收方进行异步处理。提高了应用程序的响应时间。
2、应用程序解耦合
MQ
相当于一个中介,生产方通过 MQ
与消费方交互,它将应用程序进行解耦合。
0x07 你在开发中遇到什么问题?是怎么解决的
此问题考察开发人员的问题描述及问题解决能力,可列举开发中实际的技术问题。
回答此问题要从两个方面来回答:
1、问题的描述
2、问题的解决方案
例子:
在处理订单时要用到定时任务,当时采用的是 Spring Task
来完成,由于一个订单服务会部署多个,多个订单服务同时去处理任务会造成任务被重复处理的情况,如何解决任务的重复处理。
解决:
采用乐观锁解决,在任务表中设置一个 version
字段记录版本号,取出任务记录同时拿到任务的版本号,执行前对任务进行锁定,具体的做法是执行 update
根据当前版本号将版本号加 1
,update
成功表示锁定任务成功,即可开始执行任务。
六、项目功能的整体的测试
0x01 准备工作
1)启动基础设施
- Mysql(本项目中用于储存课程管理相关数据)
- Redis(本项目中用于储存JWT令牌信息)
- MongoDB(本项目中用于储存页面信息、数据等)
- RabbitMQ(消息队列)
- ElasticSearch (提供数据索引的API)
- Logstash (将数据并且进行分词处理后发布到ES)
- Nginx(学成在线静态门户、各个服务的反向代理)
- FastDFS Tracker、FastDFS Storage (提供小文件储存服务,本项目中用于储存图片)
ElasticSearch
和 Logstash
使用windows
批处理启动(开发环境)其他服务均使用 windows
服务启动,启动效果如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZyokWdaG-1595704108280)(https://qnoss.codeyee.com/202020011722-w.png)]
ES启动脚本
@echo offsetlocal enabledelayedexpansion
setlocal enableextensionsSET params='%*':loop
FOR /F "usebackq tokens=1* delims= " %%A IN (!params!) DO (SET current=%%ASET params='%%B'SET silent=NIF "!current!" == "-s" (SET silent=Y)IF "!current!" == "--silent" (SET silent=Y)IF "!silent!" == "Y" (SET nopauseοnerrοr=Y) ELSE (IF "x!newparams!" NEQ "x" (SET newparams=!newparams! !current!) ELSE (SET newparams=!current!))IF "x!params!" NEQ "x" (GOTO loop)
)CALL "%~dp0elasticsearch-env.bat" || exit /b 1
IF ERRORLEVEL 1 (IF NOT DEFINED nopauseonerror (PAUSE)EXIT /B %ERRORLEVEL%
)set ES_JVM_OPTIONS=%ES_PATH_CONF%\jvm.options
@setlocal
for /F "usebackq delims=" %%a in (`CALL %JAVA% -cp "!ES_CLASSPATH!" "org.elasticsearch.tools.launchers.JvmOptionsParser" "!ES_JVM_OPTIONS!" ^|^| echo jvm_options_parser_failed`) do set JVM_OPTIONS=%%a
@endlocal & set "MAYBE_JVM_OPTIONS_PARSER_FAILED=%JVM_OPTIONS%" & set ES_JAVA_OPTS=%JVM_OPTIONS:${ES_TMPDIR}=!ES_TMPDIR!% %ES_JAVA_OPTS%if "%MAYBE_JVM_OPTIONS_PARSER_FAILED%" == "jvm_options_parser_failed" (exit /b 1
)cd /d "%ES_HOME%"
%JAVA% %ES_JAVA_OPTS% -Delasticsearch -Des.path.home="%ES_HOME%" -Des.path.conf="%ES_PATH_CONF%" -Des.distribution.flavor="%ES_DISTRIBUTION_FLAVOR%" -Des.distribution.type="%ES_DISTRIBUTION_TYPE%" -cp "%ES_CLASSPATH%" "org.elasticsearch.bootstrap.Elasticsearch" !newparams!endlocal
endlocal
exit /b %ERRORLEVEL%
Logstash 启动脚本
@title logstash i n teachplan_media_pub
logstash.bat -f ../config/mysql_course_media.conf --path.data=../data/teachplan_media/
2)启动所有服务,并且检查是否注册到的eureka中
Application | 服务描述 |
---|---|
XC-GOVERN-CENTER | Eureka服务注册中心,本项目中启动两个实例作为一主一从 |
XC-GOVERN-GATEWAY | Zuul网关 |
XC-SERVICE-BASE-FILESYSTEM | 文件系统服务,本项目中主要提供图片服务上传下载功能 |
XC-SERVICE-LEARNING | 学习中心服务,提供中心相关的API接口 |
XC-SERVICE-MANAGE-CMS | 站点CMS,提供网站页面静态化、制作、发布等相关API接口 |
XC-SERVICE-MANAGE-CMS-CLIENT | 站点CMS客户端,通过MQ接收页面发布的通知, |
XC-SERVICE-MANAGE-COURSE | 课程管理服务,提供课程管理相关的API |
XC-SERVICE-MANAGE-MEDIA | 课程媒资管理服务,提供课程媒体文件相关的API |
XC-SERVICE-MANAGE-MEDIA-PROCESSOR | 媒资处理服务,通过MQ接收视频处理通知,再调用第三方API来对媒资文件进行转码、分块等。 |
XC-SERVICE-MANAGE-ORDER | 订单管理服务,提供订单处理相关的API |
XC-SERVICE-SEARCH | 搜索服务,提供搜索相关的API |
XC-SERVICE-UCENTER | 用户中心服务,提供用户相关的API |
XC-SERVICE-UCENTER-AUTH | 统一认证中心服务,提供认证、授权相关操作的API |
在IDEA中启动服务,启动效果如下
所有服务成功的注册到 eureka
中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-101YNuj3-1595704108282)(https://qnoss.codeyee.com/202020011635-u.png)]
3)启动前端工程
- xc-ui-pc-portal (搜索门户前端)
- xc-ui-pc-sysmanage(站点CMS前端)
- xc-ui-pc-teach(课程管理前端)
- xc-ui-pc-leanring(用户学习中心前端)
启动效果如下
0x02 功能测试
1)页面静态化测试
访问cms前端 http://cms.xuecheng.com/#/cms/page/list
cms.xuecheng.com在hosts文件中指向本地,并且配置nginx虚拟主机
找到一个以往的页面,点击预览,效果如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZpCAmZEc-1595704108285)(https://qnoss.codeyee.com/202020022014-J)]
新增页面,填写页面数据,填写数据模型url,用于结合模板渲染页面
添加成功
预览效果如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n0drwTMN-1595704108287)(https://qnoss.codeyee.com/202020022019-v)]
编辑页面信息测试
删除测试
删除成功
测试过程中出现的一些问题
-
CMS接口无权限问题
问题描述:由于在之前的章节中没有对CMS前端做登录授权的相关配置,导致访问CMS页面时无法正常获取数据
解决方案:参考day18的 “四、前端集成认证授权” 章节进行配置。
-
课程预览无权限
问题描述:由于CMS在预览课程时候使用的是
window.open()
来访问预览页面,无法向header
传递认证信息解决方案:在
cms
服务和course
服务的ResourceServerConfig
分别放心/cms/preview/*
,/cms/config/getmodel/*
和/course/preview/model/*
的鉴权
2)课程管理
访问学成主站 http://www.xuecheng.com/
点击右上角登录,进入到登录页面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gEqvtETC-1595704108290)(https://qnoss.codeyee.com/202020022026-1)]
登录成功,主站右上角显示用户信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NB6H2561-1595704108291)(https://qnoss.codeyee.com/202020022029-N)]
登录成功后,用户的认证令牌信息储存到 redis
中
点击右上方的 “教学提供方” 进入到课程管理前端,点击我的课程,页面初始化前会访问 /course/list
接口获取该用户所属的所有课程信息,并且渲染到页面当中,效果如下
点击管理课程,测试更新课程信息
测试更换课程图片,删除原有图片并且上传
营销信息修改
添加课程计划测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-47JPCFBZ-1595704108295)(https://qnoss.codeyee.com/202020022046-q)]
预览课程
点击课程预览,生成预览链接
访问预览链接,效果如下
从效果图中可以看到,成功将我们的课程数据与课程模板相结合进行静态化渲染,得到最终的课程详情页面效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QSVbXPCS-1595704108297)(https://qnoss.codeyee.com/202020022048-p)]
课程发布
点击课程发布按钮
点击查看课程详情页面,会自动跳转到该课程的正式发布页面,跳转到的链接如下
http://www.xuecheng.com/course/detail/4028e58161bcf7f40161bcf8b77c0000.html
页面效果如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tciht4M9-1595704108298)(https://qnoss.codeyee.com/202020022111-P)]
课程重新发布后,课程发布信息的时间戳会被更新,logstash也会重新采集我们发布的课程数据并且添加到 ElasticSearch
的索引库当中
更新的 ES
索引库数据如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KCZeGMJq-1595704108300)(https://qnoss.codeyee.com/202020022113-8)]
3)媒资管理
上传视频文件测试,效果如下图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mbVjT2HP-1595704108301)(https://qnoss.codeyee.com/20200704_5b6u5pyN5YqhW+WtpuaIkOWcqOe6v10gZGF5MjAtMu+8mumhueebruaAu+e7kw==/image23.png)]
访问我的媒资,可以看到我们刚才上传的视频文件的相关信息,如下图
4)课程信息搜索
访问搜索门户页面 http://www.xuecheng.com/course/search 为了显示分页的效果,我们设置为每页显示两个结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A0esiztu-1595704108303)(https://qnoss.codeyee.com/202020032217-M)]
输入 cloud
关键字进行搜索,并且实现关键字高亮,效果如下
课程图片随意上传的,别较真哈哈
点击搜索结果进入该课程的课程详情页面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GhyxkqoK-1595704108304)(https://qnoss.codeyee.com/202020032221-0)]
5)在线点播
在课程的课程计划管理中,为某个课程计划关联我们刚才上传的视频,操作示例如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lk4m84yC-1595704108305)(https://qnoss.codeyee.com/202020032233-p)]
关联成功后,重新发布该课程信息
课程信息重新发布后,会更新该课程的时间戳,logstash
检索到时间戳的变化后会自动将更新后的课程信息到 ElasticSearch
的索引库中,如下图所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eFPnVw3a-1595704108306)(https://qnoss.codeyee.com/202020032240-L)]
自动更新课程计划信息
来到该课程的课程详情页面,点击 马上学习
进入到在线学习页面,点击目录中的课程计划,将会自动切换到课程计划节点对应的媒资内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XwmbkXKR-1595704108308)(https://qnoss.codeyee.com/202020032242-f)]
播放测试,推动进度条
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gfnVbTlz-1595704108309)(https://qnoss.codeyee.com/202020032242-F)]
七、该项目待完善的地方
已分散到每个章节的最后总结中,待整理汇总至此
欢迎各位小伙伴进行补充
八、项目学习周期
建议的每日投入的事件比例
? 认识作者
作者:? LCyee ,全干型代码?
自建博客:https://www.codeyee.com
记录学习以及项目开发过程中的笔记与心得,记录认知迭代的过程,分享想法与观点。
CSDN 博客:https://blog.csdn.net/codeyee
记录和分享一些开发过程中遇到的问题以及解决的思路。
欢迎加入微服务练习生的队伍,一起交流项目学习过程中的一些问题、分享学习心得等,不定期组织一起刷题、刷项目,共同见证成长。