基础业务与登录认证
# 基础业务与登录认证
# 拦截器与 AOP
- 拦截器只能拦截 Controller
- AOP 不仅可以拦截 Controller,还可以拦截业务逻辑层
- 用途之一:打印请求参数和返回结果
# 数据库准备
- MySQL 8.0
- 本地数据库 & 云数据库 二选一
推荐开发和生产部署都用云数据库,本次会介绍 Serverless 版数据库极大减少成本。
重点:专库专用,忌用 root
# 本地数据库准备
- 新增数据库
train - 新增用户
train,配置权限只能操作train数据库
可利用可视化工具创建使用(Navicat、DBeaver),SQL 预览如下:
CREATE USER `train`@`localhost` IDENTIFIED WITH caching_sha2_password;
GRANT Alter, Alter Routine, Create, Create Routine, Create Temporary Tables, Create View, Delete, Drop, Event, Execute, Grant Option, Index, Insert, Lock Tables, References, Select, Show View, Trigger, Update ON `chenmeng\_train`.* TO `train`@`localhost`;
2
3
# 云数据库的好处
- 免去环境搭建,版本任选
- 方便多台电脑协作开发
- 相当于雇了一帮运维
- 总结:花钱买时间
# 购买云数据库 RDS
阿里云官方小店可以买各种阿里云的产品,而且价格会比官方的便宜,非常适合新人。且官网购买时,没有最低配置的选择项,所以推荐在【阿里云官方小店】购买云产品。
地址: https://partner.aliyun.com/shop/1704506477397431 (opens new window)
正常购买的情况:
- 按年买比较划算,一年大概是四百多
学习专用,可以选择买 Serverless 版的 RDS:
- 按量计费,首月免费
- 关闭连接后,会暂停计费
# Serverless 版的 RDS
购买 Serverless 版的 RDS:
- 需配置白名单,设置可外网访问
- 配置专库专用
# 版本问题
为什么开发时,JDK 及各种框架都不建议用最新版本?
其中一个大原因,就是怕其依赖的第三方没有配套升级,导致不兼容。这也是为什么 JDK 1.8 还是主流版本,因为本身稳,第三方框架也稳。
SpringBoot 3 集成的 Mybatis 框架也必须是 3.0.0 版本或以上。
# Mybatis 生成器
注意规范:
- 开发规范:生成器生成的 4 个文件都不能手动修改
- 自定义 SQL 需要写到自己的 mapper 里,不能放在生成的 mapper 里
- 生成器只能生成单表增删改查
# 自定义异常类
为了区分业务异常和系统异常,需要增加自定义异常类。
# 详解雪花算法
12 bit - 序列号:同一毫秒时间戳下,可以生成 2^12 = 4096 个不重复 id
// todo
# 雪花算法问题
数据中心、机器 ID 怎么设置?
- 利用 Redis 自增序列
- 利用数据库,为每台机器分配 workerId,保存 ip 和 workerId 的关系
时钟回拨
- 机器时间是 3 点,北京时间是 2 点
- 此时需要把机器时间调回 2 点,那么 2 点 ~ 3 点的 ID 会重新再生成一遍
# 特点
全局唯一,有序增长,生成效率高。
# 短信验证码登录流程
两种短信攻击方式:
- 同一个手机号不断发短信
- 用不同的手机号不断发短信
解决办法:
- 获取验证码之前,使用图形验证码防止短信攻击
图形验证码的制作:
- 应该返回图片,而不是验证码字符串
提升用户体验:
- 第一次登录不需要输入图片验证码
- 如果第一次输入密码校验失败,就启用【图片验证码】
# 单点登录
# 两种单点登录实现方案
Redis + Token
- token 是指一个无意义的、随机的字符串
- 后端校验用户名密码之后,生成 token 后放入 Redis
- 前端将 token 放入 header(利用
store) - 其他页面请求校验时,从 header 获取 token,然后根据 token 到 Redis 获取数据进行判断,有数据则登录校验成功(主要是看 token 是否已失效)
JWT
- JWT 生成的 token 是有意义的
- 使用工具包来校验 token
# 操作细节
1、前端在用户登录之后保存登录信息
// 变量提交:保存登录信息, 即 token
store.commit("setMember", data.content);
2
2、修改 axios 全局拦截器
为请求 headers 增加 token,并返回配置:
axios.interceptors.request.use(function (config) {
console.log('请求参数:', config);
const _token = store.state.member.token;
if (_token) {
config.headers.token = _token;
console.log("请求headers增加token:", _token);
}
return config;
}, error => {
return Promise.reject(error);
});
2
3
4
5
6
7
8
9
10
11
# JWT 单点登录原理与存在的问题及解决方案
Hutool 对 JWT 的介绍:概述 (hutool.cn) (opens new window)
存在的问题分析:
token 被解密
- 加盐值(密钥),每个项目的盐值不能一样,避免一个项目被破解,全部项目都被破解
token 被拿到第三方使用
- 简单来说就是:自己的产品,被别人包了一个界面,做成他们收费的产品。(比如 ChatGPT 聊天机器人,外表包装成一个小程序,实际上是利用开发者设置的 token 去官网请求信息)
- 没啥好办法,只能使用限流(检测流量大的情况)
# 线程本地变量
方案:
- 首先,利用
拦截器在接口入口处拦截请求 - 然后,在
拦截器中获取会员信息,并放到线程本地变量 - 最后,就可以在 controller、service 直接从线程本地变量获取会员信息来使用了
其他方案:
- 可以在 controller 入口通过
request获得 header,进而获得 token 及会员信息 - 但这种方案实现起来比较麻烦,需要引入使用
request
# 批量生成功能
批量生成的功能一定要考虑几个问题:
- 能不能支持重复生成?
- 事务
重复生成的两种做法:
- 存在就跳过
- 先删除已有数据再插入(此项目用这个)
# 定时调度
# 为什么需要定时调度?
定时调度在企业级系统中非常重要,比如以下几个场景:
- 统计报表
- 功能补偿
- 不紧急的大批量任务
# 定时任务三大要素
- 执行的内容:功能逻辑
- 执行的策略:
cron表达式(从左到右,用空格隔开:秒 分 小时 月份中的日期 月份 星期中的日期 年份 —— 共 7 位) - 开关:开启定时任务
# 实现方案
SpringBoot 自带的定时任务和 Quartz 的不同
# SpringBoot 自带的定时任务
- 适合小项目,快速实现定时任务
- 需要开启定时任务注解
@EnableScheduling - 适合单体应用,不适合集群(增加分布式锁,可解决集群问题)
- 无法实时更改定时任务状态和策略
# Quartz
- 可并发执行
- 可加注解禁止并发执行:
@DisallowConcurrentExecution - 多节点场景下会轮询执行定时任务
并发执行:上一周期还没执行完,下一周期又开始了
# 时间字段问题
两个注解:@DateTimeFormat 和 @JsonFormat
注意:
GET请求中,请求体的时间字段不能用@JsonFormat,需要使用@DateTimeFormat- GET 请求的日期是拼接在 URL 里的,需要用 Spring 自带的
@DateTimeFormat(pattern="yyyy-MM-dd"),后端才能接收到参数
# 视图和存储过程
视图和存储过程在以前的项目中经常用到,因为依数据库内部的算力,就可以帮我们做很多复杂的功能,但因为会占用较多的数据库资源,所以逐渐淘汰了。服务端资源不够可以加机器,数据库就不好加了,所以数据库资源很珍贵,这也是为什么会有数据缓存。
视图依赖于计算,存储过程不好维护!