文章目录
总述
项目包结构
一个项目中清晰明了的项目包结构,可以反映出开发人员的基本开发素质,以及是否对项目有一个清晰明确的开发思路。
从这个项目中,我们可以学到以下几点:
具体结构说明
可以看到包的层次非常的清晰明了,各个部分的作用非常的清晰,毫不含糊,方便后续人员的开发和维护。
当然这个项目设计到的技术栈还是很简单,因此项目结构还不是很复杂。
DTO:Data Transfer Object数据传输对象
可以将PO中的部分属性抽取出来,就形成了DTO。
比如一张表中有100个字段,那么对应的PO就会有100个属性。但是界面上只会显示10个字段,客户端用WEB service来获取数据,没有必要把整个PO对象传递到客户端,这样也不会服务端表结构。到达客户端以后,如果用这个对象来对应界面显示,那此时它的身份就转为VO(View Object)。
//OneSubjectDto
//用于表示一级分类
@Data
public class OneSubjectDto {
private String id;//一级分类id
private String title;//一级分类名称
//一级分类所有的二级分类
private List<TwoSubjectDto> children = new ArrayList<>();
}
//TwoSubjectDto
//用于表示二级分类
@Data
public class TwoSubjectDto {
private String id;//二级分类id
private String title;//二级分类名称
}
MyBatis-Plus的用法
这里涉及到的主要是封装查询条件,然后使用baseMapper
中的方法进行增删改查,不得不说这样很方便,避免了很多重复性的劳动。大大减少了工作量。
BaseMapper
Insert
//插入一条记录
int insert(T entity);
参数说明
T | entity | 实体对象 |
Delete
// 根据entity条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 删除(根据ID批量删除)
int deleteBatchIds(@Param(Constants.CPLLECTION)Collection<? extends Serializable> idList);
// 根据
selectPage
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
根据entity条件,查询全部记录(并翻页)
@Param:page,分页查询条件
@Param:queryWrapper 实体对象封装操作类(可以为null)
selectList
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
根据entity条件,查询全部记录
@param:queryWrapper 实体对象封装操作类(可以为null)
selectCount
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
根据wrapper条件,查询记录总数
@param:queryWrapper 实体对象
selectOne
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
根据entity条件,查询一条记录
@param queryWrapper 实体对象
selectById
T selectById(Serializable id);
根据 ID查询
@param id 主键ID
deleteById
int deleteById(Serializable id);
根据ID删除
@param id 主键ID
delete
int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
根据entity条件,删除记录
@param queryWrapper实体对象封装操作类
insert
int insert(T entity);
插入一条记录
@param entity 实体对象
IService
Save
//插入一条记录(选择字段,策略插入)
boolean save(T entity);
//插入(批量)
boolean saveBatch(Collection<T> entityList);
//插入(批量)
boolean saveBatch(Collection<T> entityList, int bathcSize);
参数说明
类型 | 参数名 | 描述 |
---|---|---|
T | entity | 实体对象 |
Collection | entityList | 实体对象集合 |
int | batchSize | 插入批次数量 |
SaveOrUpdate
// TableId 注解存在更新记录,否插入一条记录
boolean saveOrUpdate(T entity);
// 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);
// 批量修改插入
boolean saveOrUpdateBatch(Coolection<T> entityList);
// 批量修改插入
boolean saveOrUpdateBatch(Coolection<T> entityList, int batchSize);
参数说明
T | entity | 实体对象 |
Wrapper | updateWrapper | 实体对象封装操作类UpdateWrapper |
Collection | entityList | 实体对象集合 |
int | batchSize | 插入批次数量 |
Remove
// 根据entity条件,删除记录
boolean remove(Wrapper<T> queryWrapper);
// 根据ID删除
boolean removeById(Serializable id);
// 根据columnMap条件,删除记录
boolean removeByMap(Map<String, Object> columnMap);
// 删除(根据ID 批量删除)
boolean remvoeByIds(Coolection<? extends Serializable> idList);
类型 | 参数名 | 描述 |
---|---|---|
Wrapper | queryWrapper | 实体包装类QueryWrapper |
Serializable | id | 主键ID |
Map<String,Object> | columnMap | 表字段map对象 |
Collection<? extends Serializable> | idList | 主键ID列表 |
Update
//根据 UpdateWrapper条件,更新记录 需要设置sqlset
boolean update(Wrapper<T> updateWrapper);
// 根据whereEntity条件,更新记录
boolean update(T entity, Wrapper<T> updateWrapper);
// 根据ID选择修改
boolean updateById(T entity);
// 根据ID批量更新
boolean updateBatchById(Collection<T> entityList);
// 根据ID批量更新
boolean updateBatchById(Collection<T> entityList, int batchSize);
参数说明
Wrapper<T> | updateWrapper | 实体对象封装操作类UpdateWrapper |
T | entity | 实体对象 |
Collection<T> | entityList | 实体对象集合 |
int | batchSize | 更新批次数量 |
Get
// 根据ID查询
T getById(Serializable id);
// 根据Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);
// 根据Wrapper,查询一条记录
T getOne(Wrapper<T> querWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
Serilizable | id | 主键ID |
Wrapper<T> | querWrapper | 实体对象封装操作类QueryWrapper |
boolean | throwEx | 有多个result是否抛出异常 |
T | entity | 实体对象 |
Function<? super Object,V> | mapper | 转换函数 |
list
// 查询所有
List<T> list();
// 查询列表
List<T> list(Wrapper<T> queryWrapper);
// 查询(根据ID批量查询)
Collection<T> listByIds(Collection<? extends Serializable> idList);
// 查询所有列表
List<Map<String,Object>> listMaps();
// 查询列表
List<Map<String,Object>> listMaps(Wrapper<T> queryWrapper);
// 查询全部记录
List<Object> listObjs();
//查询全部记录
<V> List<V> listObjs(Function<? super Object ,V> mapper);
// 根据Wrapper条件,查询全部记录
List<Object> listObjs(Wrapper<T> queryWrapper);
// 根据Wrapper条件,查询全部记录
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? ssuper Object, V> mapper);
参数说明
Wrapper<T> | queryWrapper | 实体对象封装操作类QueryWrapper |
Collection<? extends Serilizable> | idList | 主键ID列表 |
Map<?String,object> | columnMap | 表字段map对象 |
Function<? super Object,V> | mapper | 转换函数 |
Page
//无条件分页查询
IPage<T> page(IPage<T> page);
//条件分页查询
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
//无条件分页查询
IPage<Map<String,Object>> pageMaps(IPage<T> page);
//条件分页查询
IPage<Map<String,Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);
参数说明
IPage<T> | page | 翻页对象 |
Wrapper | queryWrapper | 实体对象封装操作类QueryWrapper |
Count
//查询总记录数
int count();
//根据Wrapper条件,查询总记录数
int count(Wrapper<T> queryWrapper);
参数说明
Wrapper<T> | queryWrapper | 实体对象封装操作类 QueryWrapper |
Chain
query
//链式查询 普通
QueryChainMapper<T> query();
//链式查询 lambda式。注意:不支持Kotlin
LambdaQueryChainWrapper<T> lambdaQuery();
//示例:
query().eq("column",value).one();
lambdaQuery().eq(Entity::getId,value).list();
update
//链式更改 普通
UpdateChainWrapper<T> update();
//链式更改 lambda式。注意:不支持Kotlin
LambdaUpdateChainWrapper<T> lambdaUpdate();
//示例:
update().eq("column",value).remove();
lambdaUpdate().eq(Entity::getId,value).update(entity);
day02
测试查询所有讲师功能
//1查询所有讲师功能
@GetMapping
public R getAllTeacherList(){
//调用service的方法
List<EduTeacher> list = eduTeacherService.list(null);
//return list;
return R.ok().data("items",list);
}
逻辑删除讲师功能实现
在entity
包的EduTeacher
类中的isDeleted
字段上加上@TableLogic
,表示逻辑删除,这是Mybatis-plus的注解。·
还需要在配置类EduServiceConfig
中加上逻辑删除的插件
@EnableTransactionManagement
@Configuration
@MapperScan("com.online.edu.eduservice.mapper")
public class EduServiceConfig {
/**
* 逻辑删除插件
* */
@Bean
public ISqlInjector sqlInjector(){
return new LogicSqlInjector();
}
}
//2逻辑删除讲师
@DeleteMapping("{id}")
public boolean deleteTeacherById(@PathVariable("id") String id){
boolean b = eduTeacherService.removeById(id);
return b;
统一返回数据结果
{
"success": 布尔,//响应是否成功
"code": 数字,//响应码
"message": 字符串,//返回消息
"data": HashMap //返回数据,放在键值对中
}
简单分页查询功能
还需要配置分页插件,具体来说,在EduServiceConfig.java
中添加分页插件
/**
* 分页插件
* */
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
//3 分页查询讲师列表的方法
@GetMapping("pageList/{page}/{limit}")
public R getPageTeacherList(@PathVariable("page") Long page, @PathVariable("limit") Long limit){
//创建page对象,传递两个参数
Page<EduTeacher> pageTeacher = new Page<>(page,limit);
//调用方法实现分页查询
eduTeacherService.page(pageTeacher, null);
//从pageTeacher对象里面获取分页数据
Long total = pageTeacher.getTotal();
List<EduTeacher> records = pageTeacher.getRecords();
return R.ok().data("total",total).data("items",records);
}
day03
统一异常处理
统一日志处理
day04
讲师管理前端开发(添加路由)
找到模板的router
文件夹下的index.js
文件,添加新的路由即可。
例如,仿照example
示例,添加讲师管理
路由
{
path: '/teacher',
component: Layout,
redirect: '/teacher/list',
name: '讲师管理',
meta: { title: '讲师管理', icon: 'example' },
children: [
{
path: 'list',
name: '讲师列表',
component: () => import('@/views/table/index'),
meta: { title: '讲师列表', icon: 'table' }
},
{
path: 'save',
name: '添加讲师',
component: () => import('@/views/tree/index'),
meta: { title: '添加讲师', icon: 'tree' }
}
]
},
{
path: '/example1',
component: Layout,
redirect: '/example/table',
name: 'Example1',
meta: { title: 'Example1', icon: 'example' },
children: [
{
path: 'table1',
name: 'Table1',
component: () => import('@/views/table/index'),
meta: { title: 'Table1', icon: 'table' }
},
{
path: 'tree1',
name: 'Tree1',
component: () => import('@/views/tree/index'),
meta: { title: 'Tree', icon: 'tree' }
}
]
},
1、把讲师管理前后端整合
(1)讲师列表
第一步:添加路由,到src--router--index.js
添加路由
第二步:创建路由配置页面views/edu/teacher/index
第三步:在src--api
文件夹里面创建teacher.js
文件,定义列表请求后端路径
第四步:在views/edu/teacher/index
页面中编写核心代码
- 列表页面
- 分页部分
- 条件查询部分
使用element-ui组件实现的
(2)讲师删除
第一步:页面 views/edu/teacher/index
,添加每条记录有删除按钮
第二步:点击删除按钮,触发事件,传递讲师id,@click="removeDataById(scope.row.id)"
第三步:编写删除的方法,添加确认框,调用具体的方法实现删除
2、跨域问题
(1)如果访问协议、ip地址、端口号,有一个是不一样的,就是跨域
(2)解决:nginx、httpclient、添加到controller注解@CrossOrigin
3、把登录改造到本地
(1)看easymock返回的数据,自己写方法也返回相同的数据
(2)在自己controller里面编写两个方法,login和info
(3)在前端修改api
里面的login.js
修改为自己路径
因为请求本地路径,把config里面
dev.env.js
修改为本地ip和端口号
讲师管理前端开发(修改讲师功能实现1)
讲师管理前端开发(路由变化bug解决)
前端首先写函数观测路由变化
watch: {
$route(to, from) {
console.log('watch $route')
this.init()
}
},
created () {
this.init()
},
methods: {
init() {
//在页面加载之前,判断路由里面是否有id值
//如果有id值,调用方法根据id查询
//从路由里面获取值
if(this.$route.params && this.$route.params.id) {//修改数据回显
const id = this.$route.params.id
//调用方法根据id查询
this.getTeacherById(id)
} else {//添加
//表单数据清空
this.teacher = { ...defaultForm }
}
},
day05
阿里云oss介绍和测试
(1)上传功能
-
原始写法
- 上传表单要求:post提交、表单有文件上传项目并且name属性
<input type="file name="file"/>
- 设置form表单属性
enctype="multipart/form-data"
- 使用
fileupload
组件实现上传
- 上传表单要求:post提交、表单有文件上传项目并且name属性
-
springmvc写法
- 在controller中使用对象获取上传文件
MultipartFile
- 在controller中使用对象获取上传文件
后端代码开发(nginx基本配置)
讲师头像上传(前端上传组件整合和测试)
<!-- 讲师头像:TODO -->
<!-- 讲师头像 -->
<el-form-item label="讲师头像">
<!-- 头衔缩略图 -->
<pan-thumb :image="teacher.avatar"/>
<!-- 文件上传按钮 -->
<el-button type="primary" icon="el-icon-upload" @click="imagecropperShow=true">更换头像
</el-button>
<!--
v-show:是否显示上传组件
:key:类似于id,如果一个页面多个图片上传控件,可以做区分
:url:后台上传的url地址
@close:关闭上传组件
@crop-upload-success:上传成功后的回调 -->
<image-cropper
v-show="imagecropperShow"
:width="300"
:height="300"
:key="imagecropperKey"
:url="BASE_API+'/eduservice/oss/upload'"
field="file"
@close="close"
@crop-upload-success="cropSuccess"/>
</el-form-item>
//声明使用的额外组件
components: {ImageCropper,PanThumb},
data() {
return {//设置teacher对象初始值
BASE_API: process.env.BASE_API, // 接口API地址
imagecropperShow:false,
imagecropperKey:0,
teacher: defaultForm
}
},
//cropSuccess函数
cropSuccess(data) {
console.log(data)
this.imagecropperShow = false
//获取后台返回图片地址,显示到页面中
this.teacher.avatar = data.imgurl
//重新加载上传组件
this.imagecropperKey = this.imagecropperKey + 1
},
课程相关表结构的分析
day06
poi导入分类信息(添加分类)
- 实现后端
- 使用代码生成器生成分类相关代码
- 在项目中引入poi依赖
- 在controller创建方法实现功能
- 在controller调用service方法
(1)获取文件输入流
(2)创建workbook,传入输入流
(3)根据workbook获取sheet
(4)获取最后一行数据索引int lastRowNum = sheet.getLastRowNum();
(5)遍历每一行数据,从第二行开始遍历,得到每一行数据
(6)获取每一行数据的第一列
(7)获取每一行第一列中的值
(8)判断获取第一列中的值(一级分类名称)在数据表是否存在相同的一级分类名称- 根据一级分类名称和
parent_id
值0进行判断
(9)如果数据库表不存在相同的一级分类,进行添加,如果已经存在不添加 - 把一级分类id获取到,为了后面二级分类做准备
(10)获取每一行第二列中的值
(11)判断第二列中的值(二级分类)在数据库表是否存在相同的二级分类名称 - 根据二级分类名称和
parent_id
进行判断
(12)如果数据库表不存在相同的二级分类,进行添加,如果已经存在不添加。
- 根据一级分类名称和
poi导入分类信息(初步实现添加一级分类)
day07
发布课程流程
发布课程(添加课程信息分类下拉列表)
day08
- 分类删除
- 分类添加
- 发布课程
- 添加课程基本信息
添加课程基本信息完善
(1)课程分类二级联动
// 获取选择一级分类的id值
//根据一级分类id值,获取下面的所有二级分类
//1 遍历所有一级分类集合
//2 获取每个一级分类
//3 判断value值和遍历出来的每个一级分类id值是否一样,
//如果一样,获取下面二级分类,是child
(2)整合文本编辑器
- 为了课程简介显示更丰富的内容,比如图片,文字有颜色
- 按照笔记过程整合出来就可以了
- 文本编辑器图片存储没有使用服务器,而是对图片使用base64编码
(3)课程封面上传
- 把课程封面上传到阿里云oss里面
课程基本信息修改
(1)课程基本信息数据回显
- 实现课程大纲页面上一步效果
- 根据课程id查询课程信息,做数据回显
- 后端代码:根据课程id查询课程详细信息
(2)修改课程基本信息
前端分类数据回显底层分析
day09
1、删除课程功能(删除课程、删除章节、删除小节)
(1)第一步 根据课程id删除章节
(2)第二步 根据课程id删除小节
(3)第三步 根据课程id删除描述
删除章节、小节和描述,不需要返回值判断,可以没有数据
(4)第四步 根据课程id删除课程本身
2、编写课程大纲
(1)查询课程大纲列表
大纲包干课程里面章节和课程里面小节
章节和小节信息可以根据课程id查询
第一步:创建两个dto实体类,用于数据封装
(1)课程章节
(2)课程小节
发布课程
根据课程id查询信息sql语句编写
/*
根据课程id查询课程信息
课程名称、课程价格、课程封面
课程描述
课程所属讲师名称
课程一级分类和二级分类
*/
select c.title,c.price,c.cover,cd.description,et.name,s1.title as onelevel,s2.title as twolevel
from edu_course c LEFT outer join edu_course_description cd on c.id = cd.id
LEFT outer join edu_teacher et on c.teacher_id= et.id
LEFT outer join edu_subject s1 on c.subject_parent_id=s1.id
LEFT outer join edu_subject s2 on c.subject_id=s2.id
where c.id='18'
day10
nacos注册
今日内容:
1、实现课程最终发布功能
(1)在第二步点击下一步,跳转到课程最终发布页面,在最终发布页面中,显示课程的详细信息
根据课程id查询课程详细信息
因为显示课程详细信息包含很多内容,所以查询的时候包含很多张表数据
编写一条sql语句,使用sql语句查询出课程详细信息
如何解决?
第一种做法:把xml配置文件放到resources里面,不建议这样做
第二种做法:推荐做法,进行配置实现,通过配置实现,通过配置让maven加载xml配置文件
第一个地方,在项目pom.xml文件中进行配置
第二个地方,在项目springboot的配置文件中进行相应的配置
mybatis-plus.mapper-locations=classpath:com/online/edu/eduservice/mapper/xml/*.xml
(2)点击最终发布,修改课程状态是已经发布状态
修改课程状态,字段status值修改为Normal
发布课程过程总结(问题和细节)
(1)填写课程基本信息的时候
课程所属类型做二级联动
二级联动实现过程:显示所有的一级分类,二级分类默认没有数据,点击某个一级分类的时候,才显示对应的二级分类。
点击某个一级分类的时候,下拉列表触发的事件是change事件
整合文本编辑器
上传功能如何实现的:没有上传服务器,不是真正上传,把文件进行base64编码,编码数据进行存储
这种上传方式优点:如果文件比较小,使用这种方式效率高
(2)添加课程大纲信息的时候
dto封装思想
(3)课程最终发布
查询多张表,自己写sql语句
maven默认不会加载java文件夹下面的配置文件,通过配置可以让maven加载配置文件
day11
今天内容
1、添加小节(视频操作)
(1)上传视频到阿里云服务器
使用阿里云实现上传视频到阿里云服务器中,需要引入依赖
这个依赖从maven仓库下载不到,需要手动把依赖安装到本地仓库中
第一种方式:使用命令(推荐)
- 打开cmd窗口,进入依赖所在文件夹下
- 输入命令
mvn install:install-file -DgroupId=com.aliyun -DartifactId=aliyun-sdk-vod-upload -Dversion=1.4.7 -Dpackaging=jar -Dfile=aliyun-java-vod-upload-1.4.7.jar
第二种方式:直接在仓库创建文件夹
*** 写测试类,测试上传视频到阿里云服务器操作
(2)删除视频(删除阿里云里面视频)
(3)整合阿里云视频播放器
配置nginx
server {
listen 9001;
server_name localhost;
location ~ /eduservice/ {
proxy_pass http://localhost:8001;
}
location ~ /vidservice/ {
proxy_pass http://localhost:8002;
}
}
- 在前端页面中,添加小节时候,上传视频
- 413 nginx上传大小限制问题。client_max_body_size 1024m;
- 上传之后,在文件后面有×,点击×实现删除阿里云云端视频文件
2、统计分析功能需求分析
(1)springcloud里面服务注册和服务发现
(2)图表工具echarts(柱状图,饼状图等)
(3)统计每一天有多少注册人数
day12
内容介绍
JWT令牌
整合阿里云短信服务
申请模板
申请签名
1、springcloud组件服务注册和服务发现
可以让不同的服务之间实现通信,每间隔30秒实现周期性的轮询
2、删除小节,同时删除对应的阿里云视频
第一节 搭建注册中心
第二节 把eduservice和vidservice注册到注册中心里面
第三节 在eduservice中调用vidservice的删除视频方法
在调用端eduservice,引入依赖,启动类上添加注解
创建接口,使用注解指定找哪个服务 @FeignClient(“xueyuan-vidservice”)
接口中定义调用的方法,写调用vidservice里面的路径
特别注意,@PathVariable后面必须加上变量的名称
@DeleteMapping("/vidservice/vod/{videoId}")
public R removeVideoAliyunId(@PathVariable("videoId") String videoId);
3、删除课程,不仅删除小节,还要把小节里面阿里云视频删除
(1)删除课程的时候,因为里面有很多的章节,每个章节有很多小节,每个小节中都会有视频。因此一个课程会有很多个视频
4、统计分析功能实现(一部分)
Redis缓存
由于首页数据变化不是很频繁,而且首页访问量相对较大,所以有必要把首页接口数据缓存到redis缓存中,减少数据库压力和提高访问速度。
Spring Boot缓存注解
缓存@Cacheable
根据方法对其返回结果进行缓存,下次请求时,如果缓存存在,则直接读取缓存数据返回;如果缓存数据不存在,则执行方法,并把返回的结果存入缓存中。一般用在查询方法上。
属性/方法名 | 解释 |
---|---|
value | 缓存名,必填,它指定了你的缓存存放在哪块命名空间 |
cacheNames | 与value差不多,二选一即可 |
key | 可选属性,可以使用SpEL标签自定义缓存的key |
缓存@CachePut
使用该注解的方法,每次都会执行,并将结果存入指定的缓存中。其它方法可以直接从响应的缓存中读取缓存数据,而不需要再去查询数据库。一般用在新增方法上。
查看源码,属性值如下:
属性/方法名 | 解释 |
---|---|
value | 缓存名,必填,它指定了你的缓存存放在哪块命名空间 |
cacheNames | 与value差不多,二选一即可 |
key | 可选属性,可以使用SpEL标签自定义缓存的key |
缓存@CacheEvict
使用该注解标志的方法,会清空指定的缓存。一般用在更新或者删除方法上。
查看源码,属性值如下:
属性/方法名 | 解释 |
---|---|
value | 缓存名,必填,它指定了你的缓存存放在哪块命名空间 |
cacheNames | 与value差不多,二选一即可 |
key | 可选属性,可以使用SpEL标签自定义缓存的key |
allEntries | 是否情况所有缓存,默认为false。如果指定为true,则方法调用后将立即清空所有的缓存 |
beforeInvocation | 是否在方法执行前就清空,默认为false。如果指定为true,则再方法执行前就会清空 |
day14
- 前台系统中讲师列表整合
- 前台系统中讲师详情整合
- 实现前台系统中课程列表
- 实现前台系统中课程详情
- 整合阿里云视频播放器课程播放
- 在线教育优化
(1)首页面优化
在线教育首页面,包含幻灯片和课程列表和讲师列表
把首页这些信息放到缓存里面,放到redis里面
redis缺点
第一类重要的数据(财务类)
第二类经常修改的数据
如何把数据放到redis里面,实现过程?
首先获取数据肯定查询redis,看redis里面是否有数据
如果redis里面有数据,直接返回
如果redis没有数据,查询数据库,把数据库数据放到redis里面
(2)页面静态化
(3)消息队列应用场景(mq)activemq
- 项目后台删除课程的同时,删除视频
- 删除课程的时候,再删除阿里云视频,删除阿里云视频放到消息队列里面,直接返回删除成功
- 删除速度快,让消息队列慢慢去删除阿里云视频
消息队列缺点:
要求操作实时性高
课程评论
day15
今天内容:
1、实现微信扫描登录
第一步 生成微信扫描登录的二维码
第二步 扫描生成二维码,回调操作,登录过程
2、jwt
3、OAuth2
微信登录流程
day16
定时任务
day17
数据同步
权限管理需求
day18
Spring Security