文章目录
一、登录加密机制
-
CodeVO设计
- 作用:作为前后端加密交互的媒介,包含
code(随机加密密钥)、currentTime(生成时间戳)、minute(有效时长,单位:分钟,如10分钟)。 - 生成逻辑:后端通过
java.util.Random生成随机数作为code,结合当前时间戳和预设有效时长创建CodeVO对象,存入HttpSession(键为固定标识如LOGIN_CODE),同时返回给前端。
- 作用:作为前后端加密交互的媒介,包含
-
前端加密流程
- 前端通过GET请求获取CodeVO,提取
code.code存入全局变量key。 - 编写加密函数
encoding(str, key):采用对称加密算法(如AES),以key为密钥对明文账号(userID)和密码(pwd)加密,加密后通过POST请求提交给后端。
- 前端通过GET请求获取CodeVO,提取
-
后端解密与验证
- 解密工具:
MyUtil.encoding(str, -code),其中-code为解密密钥(与前端加密密钥对应),对前端传来的加密字符串解密得到明文。 - 会话校验:从
HttpSession中提取之前存储的CodeVO,验证currentTime是否在有效时长内(通过currentTime + minute*60*1000 >= 系统当前时间戳判断),失效则返回"加密信息过期"。 - 登录成功后:调用
session.removeAttribute("LOGIN_CODE")清除会话中的CodeVO,避免重复使用。
- 解密工具:
二、文件上传功能
-
前端实现
- 页面添加
<input type="file" id="fileUpload">组件,编写文件选择监听函数,通过FormData对象封装文件数据,使用axios.post发送multipart/form-data类型请求(设置Content-Type: multipart/form-data)。
- 页面添加
-
后端处理流程
- Controller层:定义接收方法,使用
@RequestParam("file") MultipartFile file接收文件。 - 存储逻辑:
- 指定服务器存储路径(如
/upload/files/),确保路径存在(通过File.mkdirs()创建多级目录)。 - 生成唯一文件名(如
UUID + 原文件后缀),避免重名覆盖。 - 调用
file.transferTo(new File(存储路径 + 唯一文件名))完成存储,返回完整文件路径(如/upload/files/uuid_filename.jpg)给前端。
- 指定服务器存储路径(如
- 异常处理:捕获文件过大(通过
spring.servlet.multipart.max-file-size配置限制)、格式错误等异常,返回友好提示。
- Controller层:定义接收方法,使用
三、验证码功能
-
验证码VO设计
- 定义
CaptchaVO,包含code(验证码字符串,如4位数字字母组合)、expireTime(过期时间戳)。
- 定义
-
后端生成与存储
- 生成逻辑:使用
Random生成随机验证码(可结合BufferedImage生成图片验证码,此处以字符串为例),设置过期时间(如5分钟),创建CaptchaVO对象,存入HttpSession(键为CAPTCHA_CODE),返回给前端。
- 生成逻辑:使用
-
验证流程
- 前端:用户输入验证码后,随登录请求一同提交
userInputCode。 - 后端:
- 从会话中获取CaptchaVO,若不存在则返回"验证码已过期"。
- 比对
userInputCode与captchaVO.code(忽略大小写),不一致则返回"验证码错误"。 - 验证通过后清除会话中的验证码,避免重复使用。
- 前端:用户输入验证码后,随登录请求一同提交
四、分页查询功能
-
核心类与工具
PageInfo:包含page(当前页码)、size(每页条数)、pages(总页数)、rows(当前页数据列表)、total(总条数)、uuid(查询唯一标识)。QueryPools:静态工具类,内部维护HashMap<String, PageInfo>(键为uuid,值为分页数据),提供:put(String uuid, PageInfo pageInfo):存储分页数据。getPage(PageInfo pageInfo):通过pageInfo中的uuid从HashMap获取数据,填充到pageInfo并返回。
-
实现流程
- Mapper层:修改
getAllStu方法,添加start(起始索引,(page-1)*size)和size参数,SQL为select * from studentinfo limit #{start}, #{size};新增countAllStu方法查询总条数(select count(*) from studentinfo)。 - Service层:
- 计算总条数
total = countAllStu(),总页数pages = (total + size - 1) / size。 - 查询当前页数据
rows = getAllStu(start, size),封装为PageInfo对象。
- 计算总条数
- Controller层:
- 首次查询:生成uuid(如
UUID.randomUUID().toString()),存入PageInfo,调用Service获取数据后通过QueryPools.put(uuid, pageInfo)存储。 - 非首次查询:从前端接收包含uuid的PageInfo,调用
QueryPools.getPage(pageInfo)获取完整分页数据并返回。
- 首次查询:生成uuid(如
- Mapper层:修改
五、自动获取学号功能
-
学号池设计
XHPools:单例模式,内部维护链表结构Node(属性:sno(学号)、next(下一个节点)、sessionID(会话标识)),以及max(当前最大学号数值)。- 初始化:调用Mapper层
getMaxSno()获取数据库中最大学号(如20230001),解析数值部分(20230001→20230001)赋值给max。
-
学号分配逻辑
- 遍历链表,若存在
sessionID与当前会话ID一致的节点,返回该节点的sno(保持会话内学号不变)。 - 若不存在,则
max++,拼接学号前缀(如"2023")生成新学号(如20230002),创建新Node插入链表,返回新学号。 - Mapper层方法:
select max(sno) from student(需处理学号为字符串的情况,如提取数字部分转换为Long类型)。
- 遍历链表,若存在