实际项目开发:Spring集成Redis,并实现短信登录功能

redis新手,学了几种基本数据类型,却不知道怎么使用?
总是一边学一边忘?
学会了Redis的大多数使用命令,却不知道如何在项目中使用?
本文将从实际出发,为大家解决这些问题。
我是蚊子码农,欢迎各位的点赞、关注和收藏,有了你们的激励,我会带来更好的作品。

一、环境准备

从环境出发。

第一,基础环境:
  1. JDK版本:JDK1.8。
  2. 构建工具:Maven。
  3. 开发工具:IDEA。
  4. 基础依赖:SpringBoot通用依赖。
  5. 前后端验证机制:JWT令牌机制【如果是Token,可以看成一样;如果是cookie或session,则需要按情况改变】
第二,个人环境:
  1. Redis环境(操作系统):Windows10
  2. 使用的Redis客户端:lettuce

二、在pom文件导入Redis的相关依赖、配置Redis相关信息

注意:本文的基础,是已经安装好Redis,并且学会启动Redis服务器的用户。
简要安装步骤:来到Redis官网,按照版本下载—》解压Redis的压缩包到某个目录—》在这个解压包里,找到redis-server.exe打开服务器。【这个方法的好处是,不用配置系统变量,当然,也不能随时随地通过CMD命令启动Redis】

        <!--    redis的依赖    -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.11.1</version>

完成依赖的导入后,需要配置appliacation.yml文件的配置信息。
这个信息和MySQL非常类似,如下:

  redis:
    host: 127.0.0.1 # 服务器的IP地址
    port: 6379 # 默认端口号
    # 默认密码是null,如果设定密码则修改
    password: 
	# lettuce客户端
    lettuce:
      # 连接池的配置信息,和线程池类似
      pool:
        max-active: 8   # 最大连接数,负数表示无限制
        max-wait: -1    # 最大阻塞等待时间,负数则表示无限制
        max-idle: 8     # 连接池最大空闲连接

三、写Redis操作的通用类RedisUtil【基于StringRedisTemplate类】

在Spring集成Redis的项目中,通常可以使用RedisTemplate和StringRedisTemplate来操作Redis。
RedisTemplate<K, V>,是一个泛型类,允许很多种结构,灵活性很高。
而StringRedisTemplate<String, String>,继承自RedisTemplate,只允许字符串对字符串的映射,相对来说灵活性较差,但是开发字符串结构的业务,非常方便高效。
本文的短信验证机制,只需要String对String即可,因此,使用StringRedisTemplate开发。
工具类代码如下,本质只有读、写两个操作:

// 可以写接口和实现类,来充分解耦,本文不解耦
@Component
public class RedisUtil {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    // 向Redis中,设定验证码【手机号映射code的方式】
    public void redisSetCode(String phone, String code){
	// 设定手机号、验证码、5分钟的过期时间【最后的参数,是时间单位】
        stringRedisTemplate.opsForValue().set(phone, code, 60 * 5, TimeUnit.SECONDS);
    }
    
    // 从Redis中得到验证码,如果返回null,表示没有这个phone,在此不做验证
    public String redisGetCode(String phone){
        return stringRedisTemplate.opsForValue().get(phone);
    }
}

四、短信登陆功能的开发步骤

短信登录验证是市面上最火的登录验证方式之一。
从B/S的交互角度来看,它一共有4步:

第一,用户输入手机号,并向服务器发送请求。
第二,服务器验证手机号有效性,生成验证码,并将验证码返回客户端。
第三,用户输入手机号、验证码,并向服务器发送请求。
第四,服务器验证二者的对应关系和有效性,返回结果。

我们可以发现,这个验证机制的关键只有2个,手机号、验证码。
二者有一对一的关系,为了保证安全,验证码还必须有过期策略。因此,在没有其它业务逻辑的情况下,可以使用redis方便地完成这个功能。
不使用MySQL的原因:该验证机制较为简单,使用MySQL却需要建立一张难以变化的表,很不值得,加上访问速度也没有Redis快。
本文面向后端用户,所以前端的开发流程在此不说明,我们重点关注以下步骤:

第一,得到手机号。

这一步,需要做至少3件事:

  1. 手机号有效性检测【判断数据库有没有这个人(如果该验证机制,不允许使用手机号注册的话)】
  2. 生成验证码
  3. 将验证码写进Redis
  4. 注:借用短信API将验证码发给用户。【这一步不好写】
第二,得到手机号、验证码

需要做2件事:

  1. 判断手机号与验证码是否对应
  2. 如果对应,返回个人信息;如果不对应,报错。

五、后端得到手机号

在开发前,我们要保证,前端传来的手机号没有异常。【在本文不判断手机号null的情况】

第一步,搜索数据库,查找有没有这个人

说明:这一步可以省略,可以直接返回验证码,等到用户拿到验证码后,再从数据库拿数据判断,这样可以节省一点后端资源。【不过,用户使用起来是比较难受的,所以建议先判断】
判断的代码比较简单,在此不说明。

第二步,生成验证码

这个业务,可能需要各种复用,干脆写成一个工具类。
代码如下:

public class GeneCodeUtil {
    // 验证码的范围,如果想使用复杂字符,可以写i、g、a、b等
    public static final String VERIFY_CODES = "1234567890";

	// 验证码生成函数,指定验证码的位数【比如4位验证码:1234、5144】
    public static String CodeGenerate(int verifySize){
        String sources = VERIFY_CODES;
        int codesLen = sources.length();
		// 以当前的毫秒数为种子,生成随机数
        Random rand = new Random(System.currentTimeMillis());
	
		// 使用StringBuilder结构存储数据
        StringBuilder sb = new StringBuilder(verifySize);
        for(int i = 0; i < verifySize; i++){
        	// 添加到sb里
            sb.append(sources.charAt(rand.nextInt(codesLen-1)));
        }
        return sb.toString();
    }
}
第三,将手机号、验证码写入Redis数据库。

由于我们已经写好了Redis的工具类,在此调用工具类的set方法即可。
下面的代码,是手机号发送的业务逻辑:
下面的一些类,比较简单,就不分开讲解了,我都在第一次使用时,做了说明

	// 验证有效性,生成验证码,写入Redis数据库
    @PostMapping("/login")
    public CodeDTO loginGenerateCode(@RequestBody PhoneCodeDTO phoneCodeDTO){
    	// CodeDTO类:包含通用的返回信息、返回状态码;比如【1,验证码成功发送】
		// PhoneCodeDTO类:包含验证码、手机号,为了方便接收前端的数据,现在验证码属性为null

        String phone = phoneCodeDTO.getPhone();        
		// 查找有没有这个人
        String tempPhone = new String(phone);
        // Public类:一个数据类,不重要
        LambdaQueryWrapper<Public> publicLambdaQueryWrapper = new LambdaQueryWrapper<>();
        publicLambdaQueryWrapper.eq(Public::getPubNum,Long.parseLong(tempPhone));
		// 得到这个人
        Public pub = publicService.getOne(publicLambdaQueryWrapper);
		// 空表示没有,说明失败
        if(pub == null){
        	// codeFail:返回CodeDTO的对象,输入的数据,即为返回信息
            return CodeDTO.codeFail("不存在此用户");
        }

		// codeRedisAndSend:send函数做了2件事。。1.生成验证码;2.写入Redis服务器
        codeRedisAndSend.send(phone);
		// 可以在这里,写一些代码,调用信息发送API,将信息发送给用户

		// codeSuccess:返回CodeDTO对象,输入的数据为返回信息
        return CodeDTO.codeSuccess("验证码发送成功");
    }

六、阶段效果演示

使用Postman,发送请求给服务器
不存在用户时:
用户不存在时的展示
将该用户添加到数据库表中后:
验证码成功发布

七、后端拿到验证码、手机号

其实业务逻辑比较简单,所以直接看代码即可。

 	// 请求URL
    @RequestMapping("/codeLogin")
	// 效验验证码,如果有这个人,返回这个人的数据,JWT令牌
    public PublicDataDTO loginByCode(@RequestBody PhoneCodeDTO phoneCodeDTO){
        // PublicDataDTO类:包含用户信息、JWT令牌及一些附带信息
        // PhoneCodeDTO类:包含验证码、手机号信息
        
        String phone = phoneCodeDTO.getPhone();
		// 判断手机号、验证码是否对应,getCode方法是从Redis服务器拿到验证码
        if( phoneCodeDTO.getCode().equals(codeRedisAndSend.getCode(phone)) ){
             LambdaQueryWrapper<Public> publicLambdaQueryWrapper = new LambdaQueryWrapper<>();
             publicLambdaQueryWrapper.eq(Public::getPubNum,Long.parseLong(phone));
			// 得到此人信息
             Public pub = publicService.getOne(publicLambdaQueryWrapper);

			// getPublicDataDTO方法:返回一个PublicDataDTO对象
			// JWT令牌是JWT工具类生成的,传给前端,用作后续效验
             return PublicDataDTO.getPublicDataDTO(pub);
         }

		// 不相同,则返回null
         return PublicDataDTO.getPublicDataDTO(null);
    }

八、效果演示

同样使用Postman作为演示,假设我们知道验证码是1666
那么,输入错误的验证码:
错误验证码
我们输入正确的验证码
正确验证码

九、结语

我是蚊子码农,如有补充或者疑问,欢迎在评论区留言。个人的知识体系可能没有那么完善,希望各位多多指正,谢谢大家。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/736575.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TikTok账号运营:静态住宅IP为什么可以防封?

静态住宅IP代理服务是一种提供稳定、静态IP地址并可隐藏用户真实IP地址的网络代理服务。此类代理服务通常使用高速光纤网络来提供稳定、高速的互联网体验。与动态IP代理相比&#xff0c;静态住宅IP代理的IP地址更稳定&#xff0c;被封的可能性更小&#xff0c;因此更受用户欢迎…

JAVA学习过程中遇到的问题

前言 记录学习过程中遇见的各种问题。希望对你有帮助。 目录 前言 1、新建maven项目时&#xff0c;archetype项目骨架加载慢 2、maven的pop.xml添加依赖项无法检测到 3、java: 无效的目标发行版: 20 4、idea添加maven依赖太慢 5、CTRLCV复制粘贴太慢 6、Swagger写接口文…

20240621日志:大模型压缩-从闭源大模型蒸馏

目录 1. 核心内容2. 方法2.1 先验估计2.2 后验估计2.3 目标函数 3. 交叉熵损失函数与Kullback-Leibler&#xff08;KL&#xff09;损失函数 location&#xff1a;beijing 涉及知识&#xff1a;大模型压缩、知识蒸馏 Fig. 1 大模型压缩-知识蒸馏 1. 核心内容 本文提出在一个贝…

(Amazing!) 通过 vfox 在 Windows 上安装管理多个 Erlang/OTP 和 Elixir 的版本

大概一个多月前, 我写了篇关于如何使用跨平台版本管理工具 vfox 在 Linux 系统下安装管理多个 Erlang/OTP 版本的文章 -> 通过 vfox 安装管理多版本 Erlang 和 Elixir. 文章使用的示范操作系统是 Ubuntu 20.04 Linux 操作系统. 最近 vfox-erlang 和 vfox-elixir 插件的最新…

如何关闭软件开机自启,提升电脑开机速度?

如何关闭软件开机自启&#xff0c;提升电脑开机速度&#xff1f;大家知道&#xff0c;很多软件在安装时默认都会设置为开机自动启动。但是&#xff0c;有很多软件在我们开机之后并不是马上需要用到的&#xff0c;开机启动的软件过多会导致电脑开机变慢。那么&#xff0c;如何关…

xshell使用vi命令:bash:vim:command not found

你们好&#xff0c;我是金金金。 场景 此时我通过xshell客户端连接到了远程的虚拟机。想用vi命令编辑一个文件时&#xff0c;显示&#xff1a;bash: vim: command not found 排查 看报错提示就可以知道&#xff0c;没找到vim命令 解决 使用包管理器 apt 来安装 vim 更新你的软…

springboot+vue+mybatis旅游管理+PPT+论文+讲解+售后

随着人民生活水平的提高,旅游业已经越来越大众化,而旅游业的核心是信息,不论是对旅游管理部门、对旅游企业,或是对旅游者而言,有效的获取旅游信息,都显得特别重要.旅游管理系统将使旅游相关信息管理工作规范化、信息化、程序化,提供旅游景点、旅游线路,旅游新闻等服务本文以jsp…

ubuntu18.0.4安装gradio踩坑记

Collecting pandas (from gradio) Downloading http://mirrors.cloud.aliyuncs.com/pypi/packages/c3/e2/00cacecafbab071c787019f00ad84ca3185952f6bb9bca9550ed83870d4d/pandas-1.1.5-cp36-cp36m-manylinux1_x86_64.whl (9.5MB) 100% |████████████████…

Python学习打卡:day14

day14 笔记来源于&#xff1a;黑马程序员python教程&#xff0c;8天python从入门到精通&#xff0c;学python看这套就够了 目录 day14102、封装三大特性对用户隐藏的属性和行为私有成员使用私有成员 103、封装的课后习题104、继承单继承多继承 105、复写父类成员和调用父类成…

神经网络学习3-卷积层

膨胀卷积&#xff0c;也被称为空洞卷积或扩张卷积&#xff0c;是一种特殊的卷积运算&#xff0c;它在标准卷积的基础上引入了一个额外的超参数&#xff0c;即膨胀率&#xff08;dilation rate&#xff09;。这个超参数决定了在卷积核的元素之间插入多少额外的空间。通过这种方式…

图解注意力

图解注意力 Part #2: The Illustrated Self-Attention 在文章前面的部分&#xff0c;我们展示了这张图片来展示自注意力被应用于正在处理单词"it"的一层中&#xff1a; 在本节中&#xff0c;我们将看看这是如何完成的。请注意&#xff0c;我们将以一种试图理解单…

Linux系统编程--软/硬连接

真正找到磁盘上文件的并不是文件名&#xff0c;而是inode。 其实在linux中可以让多个文件名对应于同一个inode。 命令&#xff1a; 软连接&#xff1a;ln -s 原文件名 新文件名 硬链接&#xff1a;ln 原文件名 新文件名 删除链接文件&#xff1a;unlink 文件名执行上面两条命令…

linux 简单使用 sftp 和 lftp命令

目录 一. 环境准备二. sftp命令连接到SFTP服务器三. lftp命令3.1 连接FTP和SFTP服务器3.2 将文件从sftp服务器下载到本地指定目录 四. 通过WinSCP命令行从SFTP服务器获取文件到Windows 一. 环境准备 ⏹在安卓手机上下载个MiXplorer&#xff0c;用作SFTP和FTP服务器 官网: htt…

MySQL数据库(一):数据库介绍与安装

在嵌入式开发中&#xff0c;数据库的重要性体现在高效的数据存储和管理、数据持久化、复杂查询和处理、数据同步和共享、安全性和可扩展性。常见嵌入式数据库包括SQLite、MySQL、LevelDB等&#xff0c;应用于智能家居、工业控制、车载系统和物联网设备&#xff0c;提升了系统功…

网络编程篇:HTTP协议

一.预备知识 在客户端访问服务端时&#xff0c;要用ipport&#xff0c;但是在日常用户访问服务端的时候&#xff0c;并不会直接使用ip&#xff0c;而是使用域名&#xff0c;比如&#xff1a;百度(www.baidu,com)。 …

深度学习11-13

1.神经元的个数对结果的影响&#xff1a; &#xff08;http://cs.stanford.edu/people/karpathy/convnetjs/demo/classify2d.html&#xff09; &#xff08;1&#xff09;神经元3个的时候 &#xff08;2&#xff09;神经元是10个的时候 神经元个数越多&#xff0c;可能会产生…

在C++中,构造器(Builder)模式的思考(《C++20设计模式》及常规设计模式对比)

文章目录 一、前言二、为什么需要Builder Pattern,Builder Pattern到底解决了什么实际问题&#xff1f;为什么不用set()方法&#xff1f;2.1 初学者有那些对象的属性初始化方法呢&#xff1f;2.1.1 构造函数的弊端2.1.1.1 对于属性的初始化只能是固定的顺序 2.1.2 用set()函数初…

在线随机密码生成工具

对于运维工作&#xff0c;经常需要生产随机密码&#xff0c;这里介绍一款在线生成密码工具&#xff0c;支持配置密码组合类型&#xff0c;如数字、字母大小写、特殊字符等&#xff0c;还能排除某些特殊字符。 在线随机密码生成工具 https://tool.hiofd.com/random-string-gen…

SCI一区级 | Matlab实现BO-Transformer-LSTM多变量时间序列预测

SCI一区级 | Matlab实现BO-Transformer-LSTM多变量时间序列预测 目录 SCI一区级 | Matlab实现BO-Transformer-LSTM多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.【SCI一区级】Matlab实现BO-Transformer-LSTM多变量时间序列预测&#xff0c;贝叶斯…

嵌入式中逻辑分析仪与示波器的基本原理

大家好,今天主要给大家分享一下,嵌入式中如何使用逻辑分析仪和示波器的方法,希望对大家有所帮助。 https://dreamsourcelab.cn/ 第一:什么是逻辑分析仪 是否遇到使用示波器分析数字电路的冏境:深度不够,时间太短,无法抓到想要的波形,没有协议内容解析? 逻辑分析仪…