SpringBoot + Redis + Mysql + Swagger + 七牛云
-
Swagger接口文档
-
统一异常处理,捕获Controller层的异常
-
登录拦截器,对指定接口进行拦截 从redis中获取token以及用户信息,判断是否登录
-
登录拦截器从redis获取到用户,放入到ThreadLocal中,方便在请求内部获取用户信息,减少了用户信息远程查询次数
-
登录拦截器中使用完ThreadLocal做了value的删除,防止了内存泄漏
-
JWT + redis token令牌登录方式,登录用户做了缓存, 灵活控制用户的过期(提掉线)【token令牌登录方式,访问认证速度快,session共享,安全性】【redis做了令牌和用户信息的管理 1.进一步增加了安全性 2.登录用户做了缓存,灵活控制用户的过期时间】
-
对接七牛云对象存储,做了CND加速, 图片上传到七牛云,降低服务器访问压力
-
查看文章详情,阅读数量增加 扔到线程池中执行,不影响主业务逻辑(对当前主业务流程无影响的操作,放入线程池中执行) 【查看完文章之后,本应该直接返回数据了,这时候做了一个更新操作,更新时加写锁,阻塞其他的读操作,性能就会比较低,更新 增加了此次接口的 耗时 如果一旦更新出问题,不能影响 查看文章的操作】
-
线程安全 文章详情 (1)先查询出来文章 (2)更新阅读数扔到线程池中 (3)更新阅读数量 update 文章表 set view_count = oldValue+1 where id = ? and view_count = oldValue
-
统一缓存处理,自定义缓存注解 + AOP,想要缓存的接口直接加上注解
-
统一日志处理,自定义日志注解 + AOP 记录日志(记录了 module、operation、请求方法名参数、请求ip地址、接口执行时间)
-
RequestContextHodler Spring提供的工具获取request对象, 比如说日志切面需要获取request对象
获取request 请求工具类 RequestContextHolder 是Spirng提供的一个用来暴漏Request对象的工具,利用RequestContextHolder,可以在一个请求线程中获取到Request,避免了Request从投传到尾的情况
-
DO对象转换为VO对象 copy copyList
-
Dockerfile构建镜像,Nginx + Docker 部署
-
使用MQ解决缓存不一致问题,修改文章后,缓存中的数据和数据库中不一致,采用先更后删,修改文件-->更新数据库-->发送消息到MQ中-->删除缓存
使用mq解决缓存不一致问题
修改文章后,能够保证最终一致性
删除文章列表缓存、更新查看某个文章的缓存
部署:加上/api区分 前端的访问与后端的访问
- Long类型id 太长传到前端 无法识别
- FROM_UNIXTIME 查询月份用 %c 而不是 %m(月份小于10为 01, 02, 03...)
-
首页-文章列表
瀑布流展示,分页查询(第几页+每页大小)
注解 加入Redis缓存
按时间倒排
-
首页-最热标签
标签对应的文章数量多
文章标签表 按照标签分组-->按照文章排序
-
首页-最新文章
按照时间排序
注解 加入Redis缓存
-
首页-文章归档
查询xxx年xxx月文章数量
时间戳 --> 函数 --> year、month
按照year、month 分组 查询分组后的数量
-
首页-最热文章
观看数量最多
注解 加入Redis缓存
-
文章详情
查询文章 -> 文章内容 and 一级评论、二级评论
更新阅读数量 ---> 扔到线程池中
-
文章分类
查看所有文章分类
-
文章标签
查看所有标签
-
查看特定分类
分类详细信息
相应分类文章列表 --> 复用文章列表接口,加入分类查询参数
-
查看特定标签
标签详细信息
相应标签文章列表 --> 复用文章列表接口,加入标签查询参数
-
查看特定归档
相应归档文章列表 --> 复用文章列表接口,加入归档(year、month)查询参数
-
登录
验证参数合法性
数据库中验证
生成token
存入redis 缓存token和用户信息
-
注册
验证参数合法性
数据库中验证
生成token
存入redis 缓存token和用户信息
-
注销
redis 中删除token
-
写文章
上传图片接口 --> 上传到七牛云
查询文章分类 --> 发表时选分类
查询文章标签 --> 发表时选标签
加入到登录拦截器
-
评论
封装评论信息
更新文章表评论数量
-
登录用户信息做缓存,一些必须登录的接口放入到登录拦截器当中,判断用户是否登录,(顺便放入ThreadLocal中,在请求线程中,随时获取登录的用户,做了线程隔离,减少远程数据库查询次数)
-
灵活控制用户过期时间,注销功能,jwt是保存在客户端,服务端无法控制
-
进一步增加了安全性,jwt中不能存放敏感信息,jwt数据载荷部分可以存放用户的id,,做用户验证的时候,(reids中key为token,value为用户信息), 用token从缓存中获取用户信息进行验证
用一个类标注 @ControllerAdvice 注解,对加了@Controller注解的方法进行拦截处理(AOP), 然后在方法上边标注@ExceptionHandler 表示要处理什么样的异常
阅读数量与主业务逻辑分隔开,将不影响主业务逻辑放入到线程池中执行
查看完文章之后,本应该直接返回数据了,这时候做了一个更新操作,更新时加写锁,阻塞其他的读操作,性能就会比较低,更新 增加了此次接口的 耗时 如果一旦更新出问题,不能影响 查看文章的操作
首先定义了一个 日志注解,然后定义一个切面类,切点就是我们的缓存注解,在通知中记录请求方法名、请求参数、请求接口耗时、请求ip等,任何加了缓存注解的方法都会加入我们的通知逻辑。
自定义一个缓存注解,然后利用SpringAOP面向切面编程,加了缓存注解的接口,会先去缓存中查找,如果缓存中不存在或者缓存过期,那么再执行接口的业务逻辑去数据库中查询。
当修改文章之后,数据库中的数据更新了,但是缓存中缓存了我们的文章列表,缓存中的数据还是旧的数据,这样会出现用户更新文章之后显示的文章列表中还是旧的数据,出现了缓存不一致问题。
采用了先更后删的解决方案,利用MQ解决,MQ解耦,更新文章,然后发送一条消息到MQ中,由服务消费者进行处理,删除缓存。
可以,但是不好。一旦删除缓存失败还是会导致我们的缓存不一致问题,利用MQ呢,可以失败重试。。。。// 之后添加
前端Nginx + 后端jar包运行
前端Nginx + 后端构建Docker镜像运行
后端的服务非常多:Mysql、Redis、RabbitMQ、SpringBoot镜像
未解决:vue项目部署在nginx非根目录,图片资源访问出错