news 2026/4/2 13:28:57

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/3/27 13:39:22

17、探索 Linux 服务器替代方案及开源服务

探索 Linux 服务器替代方案及开源服务 在当今的 IT 领域,企业对于服务器系统和相关服务的选择至关重要。从成本效益、安全性到功能的多样性,每一个因素都影响着企业的决策。Linux 以其开源、灵活和稳定的特性,成为了替代传统 Windows 服务器的有力选择。下面将深入介绍 Lin…

作者头像 李华
网站建设 2026/3/28 9:10:45

24、深入了解瘦客户端计算与Linux桌面资源

深入了解瘦客户端计算与Linux桌面资源 在当今的计算领域,瘦客户端计算和Linux桌面系统正逐渐成为企业和个人用户关注的焦点。本文将深入探讨这两个方面的相关内容,包括瘦客户端计算的优势、Linux桌面迁移的考虑因素,以及丰富的Linux资源。 瘦客户端计算的优势 使用瘦客户…

作者头像 李华
网站建设 2026/4/1 14:10:43

Outfit字体终极教程:免费几何无衬线字体的完整使用指南

Outfit字体终极教程&#xff1a;免费几何无衬线字体的完整使用指南 【免费下载链接】Outfit-Fonts The most on-brand typeface 项目地址: https://gitcode.com/gh_mirrors/ou/Outfit-Fonts Outfit字体是一款专为现代数字设计而生的几何无衬线字体&#xff0c;作为品牌自…

作者头像 李华
网站建设 2026/3/29 14:33:32

31、开源技术在不同场景下的应用与成本效益分析

开源技术在不同场景下的应用与成本效益分析 在当今数字化时代,开源技术凭借其成本优势、灵活性和社区支持等特点,在各个领域得到了广泛应用。本文将通过几个实际案例,深入探讨开源技术在学校、政府和企业中的应用,以及它们所带来的显著效益。 志愿者助力特许学校节省开支…

作者头像 李华
网站建设 2026/3/30 23:06:32

IDM激活脚本终极指南:告别试用期烦恼,实现永久下载加速

IDM激活脚本终极指南&#xff1a;告别试用期烦恼&#xff0c;实现永久下载加速 【免费下载链接】IDM-Activation-Script IDM Activation & Trail Reset Script 项目地址: https://gitcode.com/gh_mirrors/id/IDM-Activation-Script 还在为IDM试用期结束而烦恼吗&…

作者头像 李华
网站建设 2026/3/31 1:23:58

F5-TTS移动端优化实战:让语音合成在手机上飞起来

F5-TTS移动端优化实战&#xff1a;让语音合成在手机上飞起来 【免费下载链接】F5-TTS Official code for "F5-TTS: A Fairytaler that Fakes Fluent and Faithful Speech with Flow Matching" 项目地址: https://gitcode.com/gh_mirrors/f5/F5-TTS 你是否曾经…

作者头像 李华