news 2026/4/23 17:30:45

1 验证码

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
1 验证码

1 验证码

1.1 功能概述

  1. 接口文档
url:GET /captcha
参数:无
返回:
{ "msg": "操作成功", "code": 200, "data": { "uuid": "b71fafb1a91b4961afb27372bd3af77c", "captcha": "data:image/png;base64,iVBORw0KGgoAAAA", "code": "nrew" } }
  1. 技术栈选用
使用Redis存储验证码,并使用一些工具包快速生成验证码。
验证码存储方案对比(为何放弃数据库、Cookie、Session)
1.数据库存储
  • 核心问题:验证码是高频、临时的轻量数据,数据库(如 MySQL)主打持久化存储,写入 / 读取需走磁盘 IO,性能远低于内存存储;且验证码有效期仅 2 分钟,频繁读写数据库会增加不必要的性能开销,还需额外写定时清理过期验证码的逻辑,徒增复杂度。
  • 简单总结:太重、太慢,没必要用持久化存储存临时验证码。
2.Cookie 存储
  • 核心问题:Cookie 存储在客户端浏览器,可被篡改、伪造,验证码是安全校验数据,存客户端完全无安全性;且 Cookie 有存储大小限制(约 4KB),虽验证码文本小,但违背 “安全数据服务端存储” 的原则。
  • 简单总结:不安全,数据能被客户端修改,失去验证码校验意义。
3.Session 存储
  • 核心问题:Session 基于服务器内存(或容器存储),分布式部署场景下(多台服务器),Session 无法共享,用户请求落到不同服务器时会校验失败;且 Session 默认过期时间较长(通常 30 分钟),手动设置 2 分钟过期需额外配置,还会占用服务器内存,服务器重启后 Session 丢失,验证码直接失效。
  • 简单总结:分布式环境不兼容,服务器重启易丢失,内存占用不灵活。
Redis 选用原因及简单介绍
1.为什么选 Redis
  • 高性能:基于内存读写,速度比数据库快几个量级,适配验证码高频读写场景;
  • 过期策略:原生支持设置 key 的过期时间,自动清理,无需手动维护;
  • 分布式友好:Redis 可独立部署,多台应用服务器都能访问,解决 Session 共享问题;
  • 轻量灵活:仅存储临时的验证码键值对,资源占用极低。
2.Redis 简单介绍
Redis 是一款内存型键值对数据库,主打高性能、高可用,支持字符串、哈希、列表等多种数据结构,常用作缓存、临时数据存储(如验证码、令牌);核心特点是 “快”(内存操作)、“灵活”(丰富的过期策略、数据结构),适配各类临时、高频访问的场景。
代码中用到的工具类 / 包介绍
1.SpecCaptcha(验证码生成)
作用:
  • 快速生成图片验证码(包含验证码文本 + 图片 Base64 编码),无需手动处理图片绘制、编码;
核心用法:
  • new SpecCaptcha(宽度, 高度, 验证码位数) 创建实例,text() 获取验证码文本,toBase64() 转为 Base64 编码(方便前端直接展示图片),具体示例见代码。
导入依赖:
<!-- 验证码 --> <dependency> <groupId>com.github.whvcse</groupId> <artifactId>easy-captcha</artifactId> <version>${captcha.version}</version> </dependency>
2.IdUtil(UUID 生成,通常是 Hutool 工具包)
作用
  • Hutool 工具包中的 ID 工具类,simpleUUID() 生成无横线的 UUID(如b71fafb1a91b4961afb27372bd3af77c),替代手动写 UUID 生成逻辑,简化代码;
优势:
  • 封装了各种 ID 生成规则(UUID、雪花 ID 等),开箱即用,避免重复造轮子。
导入依赖
<!--工具包--> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>${hutool.version}</version> </dependency>
3. RedisTemplate(Spring Data Redis)
作用:
  • Spring 框架封装的 Redis 操作模板,简化 Redis 的连接、读写操作;
核心用法:
  • opsForValue() 操作字符串类型数据,set(key, value, 过期时间, 时间单位) 存入带过期时间的键值对,无需手动处理 Redis 连接、序列化等底层逻辑。
导入依赖
<!--redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
yml配置文件
spring: redis: host: 127.0.0.1 port: 6379 database: 0
1.spring: redis:
  • 这是 Spring Boot 的 Redis 配置前缀,所有 Redis 相关配置都嵌套在这个层级下,是 Spring 框架约定的固定格式,框架会自动识别该前缀下的配置项并初始化 Redis 连接。
2.host: 127.0.0.1
  • Redis 服务器的 IP 地址:127.0.0.1表示连接本地的 Redis 服务(本机部署的 Redis);如果 Redis 部署在其他服务器,这里要改对应 IP(如192.168.1.100)。
3.port: 6379
  • Redis 服务的端口号:6379 是 Redis 的默认端口,若安装 Redis 时修改过端口(比如 6380),需对应修改这里。
4.database: 0
  • Redis 的数据库编号:
    • Redis 默认有 16 个逻辑数据库(编号 0-15),无需手动创建,通过编号区分不同用途的数据集;
    • 配置database: 0表示使用第 0 个数据库存储数据(如验证码的 uuid 和 code);
    • 作用:可按业务隔离数据(比如验证码用 0 库、用户令牌用 1 库),避免不同业务数据混在一起。
4. Result(自定义响应类)
作用:
  • 项目自定义的统一响应体类,保证接口返回格式统一(匹配文档的msg/code/data结构)。
实现
  • 对于Result类的的实现主要有两种方式。
实现方式
核心特点
继承 HashMap
基于 Map 结构,通过
put
方法动态添加字段,灵活但无类型约束,依赖键值对操作
泛型类(POJO)
固定字段(code/message/data 等),通过泛型约束数据类型,结构规范、类型安全
企业开发中统一响应体首选泛型 POJO 式 Result 类,核心原因是类型安全、结构规范、序列化稳定,适配绝大多数固定返回结构的业务场景(如验证码接口);继承 HashMap 的方式仅用于字段需动态增减的特殊临时场景,正式项目极少使用。
5.TimeUnit(java.util.concurrent)
作用
  • Java 并发包下的时间单位枚举类,用于明确指定时间单位(如秒、分钟、小时),配合 RedisTemplate 设置过期时间,避免 “硬编码数字 + 注释说明单位” 的不规范写法。
核心用法
  • 代码中120, TimeUnit.SECONDS表示 “120 秒”,RedisTemplate 会根据该枚举自动解析时间单位,确保过期时间的语义清晰、不易出错(比如不会把 120 秒误理解为 120 毫秒)。

1.2 代码实现

Result

package com.qcby.community_sp.util; import java.util.HashMap; public class Result extends HashMap<String,Object> { public static Result ok(){ Result result = new Result(); result.put("code", 200); result.put("msg", "操作成功"); return result; } public static Result error(String msg){ Result result = new Result(); result.put("code", 500); result.put("msg", msg); return result; } @Override public Result put(String key, Object value) { super.put(key, value); return this; } }

LoginController

package com.qcby.community_sp.controller; import cn.hutool.core.util.IdUtil; import cn.hutool.crypto.SecureUtil; import com.qcby.community_sp.util.Result; import com.wf.captcha.SpecCaptcha; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import java.util.HashMap; import java.util.concurrent.TimeUnit; //登录相关业务功能的Controller //统一回调方式,全部返回json到前端 @RestController public class LoginController { @Autowired private RedisTemplate redisTemplate; /** * 获取验证码 * @return */ @GetMapping("/captcha") public Result getCaptcha() { //生成一个验证码 SpecCaptcha specCaptcha = new SpecCaptcha(130,48,4); //获取工具类生成的验证码图片的验证码,并转成大写 String code = specCaptcha.text().toUpperCase(); //用uuid生成一个唯一的key(Redis里面的key),用来在Redis里面存取验证码 String uuid = IdUtil.simpleUUID(); //向Redis里面存数据 redisTemplate.opsForValue().set(uuid,code,120, TimeUnit.SECONDS); HashMap<String,String> res = new HashMap<>(); res.put("uuid",uuid); res.put("captcha",specCaptcha.toBase64()); res.put("code",code); return Result.ok().put("data",res); } }

RedisTemplate 中的 opsForValue () 介绍

  1. opsForValue () 核心定义
opsForValue() 是 RedisTemplate 针对 Redis 字符串(String)类型 数据的操作入口,核心用于操作「单键单值」的键值对结构(一个 key 对应一个 value),与 Java 中 Value 的具体数据类型无关,仅取决于 Redis 底层存储的数据结构类型。
  1. 核心判断逻辑
业务场景
对应 Redis 数据结构
RedisTemplate 操作入口
单键单值(如 uuid→验证码)
字符串(String)
opsForValue()
单键多字段(如 user→name/age)
哈希(Hash)
opsForHash()
有序可重复列表(如消息队列)
列表(List)
opsForList()
简单记:
  • 单值键值对 → 用 opsForValue ()
  • 多字段 / 多值结构 → 选 opsForHash ()/opsForList () 等对应方法
  1. Key 的类型说明
Redis 底层 Key 是字节数组,RedisTemplate 默认序列化为 String 类型;
实际开发中,Redis 的 Key 几乎都用 String(如 uuid),可读性、兼容性最优。
  1. Value 的类型说明
opsForValue().set(key, value) 中 Value 可传任意 Java 类型(String/Integer/ 自定义对象等),RedisTemplate 会自动序列化后存储,无需因 Value 类型切换 opsForXXX 方法。即:如果Value是HashMap或者List,用opsForValue()也可以,技术上可行,但是不规范。
  1. 代码场景对应
上面的验证码代码中,uuid(key)→ code(value) 是典型「单键单值」结构,因此用 opsForValue() 匹配 Redis String 类型,搭配 TimeUnit.SECONDS 设置 120 秒过期时间,是标准且规范的写法。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 14:16:19

28、开源软件许可与Linux桌面发行版全解析

开源软件许可与Linux桌面发行版全解析 在开源软件的世界里,许可证是规范软件使用、修改和分发的重要准则。同时,Linux作为开源操作系统的代表,其桌面发行版为用户提供了丰富多样的选择。 1. 伯克利软件发行许可(BSD) BSD许可最初用于将加州大学伯克利分校开发的软件放入…

作者头像 李华
网站建设 2026/4/23 14:15:32

基于ssm的商铺租赁管理系统(讲解+部署+文档)

商铺租赁管理系统的背景传统商铺租赁管理依赖纸质合同和人工操作&#xff0c;效率低下且易出错。随着商业地产规模扩大&#xff0c;手工记录租金、合同到期提醒、租户信息更新等问题日益凸显。数字化管理需求迫切&#xff0c;尤其在连锁商业或大型商业综合体场景中。技术选型意…

作者头像 李华
网站建设 2026/4/23 5:14:46

7、迈向 Linux 桌面迁移的全面指南

迈向 Linux 桌面迁移的全面指南 1. Linux 操作系统的优势与选择 在政府机构等场景中,每台设备多花费几百美元,累积起来可能意味着数千台利用率不高的计算机产生数百万美元的额外支出。而 Linux 操作系统具有很强的可移植性,能在多种硬件上运行,如 Intel、MIPS、ARM、Solar…

作者头像 李华
网站建设 2026/4/23 11:13:34

基于Django的在线考试与评估系统设计与实现

在线考试与评估系统的背景意义在线考试与评估系统基于Django框架开发&#xff0c;旨在解决传统纸质考试的局限性&#xff0c;提升考试管理的效率和公平性。该系统适用于教育机构、企业培训及认证考试等场景&#xff0c;具有广泛的应用前景。提升考试效率传统考试涉及试卷印刷、…

作者头像 李华
网站建设 2026/4/23 11:12:33

UltraVNC完全掌握指南:5个步骤让远程控制变得简单

UltraVNC完全掌握指南&#xff1a;5个步骤让远程控制变得简单 【免费下载链接】UltraVNC UltraVNC Server, UltraVNC Viewer and UltraVNC SC | Official repository: https://github.com/ultravnc/UltraVNC 项目地址: https://gitcode.com/gh_mirrors/ul/UltraVNC Ultr…

作者头像 李华
网站建设 2026/4/23 12:35:57

31、进程间通信(IPC)详解

进程间通信(IPC)详解 1. 进程间通信概述 进程间通信(IPC)是操作系统提供的一系列机制,用于实现同一系统内进程和线程之间的数据共享(如共享内存段)、信息与数据交换(如消息队列)以及对共享资源访问的同步(如信号量)。与基于网络的通信设施(如套接字和RPC接口)不…

作者头像 李华