关于项目的一些完善功能
文章目录
- 一、登录加密机制
- 二、文件上传功能
- 三、验证码功能
- 四、分页查询功能
- 五、自动获取学号功能
一、登录加密机制
-
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类型)。
- 遍历链表,若存在