springboot实现邮箱验证码功能
引言
邮箱验证码是一个常见的功能,常用于邮箱绑定、修改密码等操作上,这里我演示一下如何使用springboot实现验证码的发送功能;
这里用qq邮箱进行演示,其他都差不多;
准备工作
首先要在设置->账户中开启邮箱POP3/SMTP服务:
开启成功后会获取一个授权码,记住该授权码:
初步准备完成;
代码实现
引入依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId>
</dependency>
application.yml中配置:
spring:mail:host: smtp.qq.comusername: 邮箱号@qq.com # 发件人邮箱password: 授权码 # 邮箱授权码default-encoding: UTF-8
下面就是controller、service了
controller
@PostMapping("/code")
public BaseResponse<String> sendMessageToEmail(@RequestParam("email") String email) {if (StringUtils.isAnyBlank(email)) {throw new BusinessException(StatusCode.NULL_ERROR, "邮箱为空");}// 校验邮箱RegExpUtil.regExpVerify(RegExpUtil.emailRegExp, email, "邮箱格式错误");// 从redis中查看有没有该邮箱的验证码String verifyCode = (String) redisTemplate.opsForValue().get(RedisKey.EMAIL_CODE + email);if (!StringUtils.isAnyBlank(verifyCode)) {throw new BusinessException(StatusCode.SUCCESS, "验证码已发送=>" + verifyCode);}// 如果redis没有该手机号验证码,则获取验证码并发送短信verifyCode = RandomSmsNumUtils.getSixBitRandom(); // 获取六位验证码emailService.sendMessageToEmail(verifyCode, email);// 将该验证码存入redisredisTemplate.opsForValue().set(RedisKey.EMAIL_CODE + email,verifyCode,EMAIL_EXPIRED_TIME,TimeUnit.MINUTES);return ResultUtils.success("发送成功");
}
大致流程就是:校验邮箱->查redis判断邮件是否已发送->未发送则发送验证码->将发送的验证码存入redis
接下来是service,网上有很多发送的就是简单的文本验证码,类似这样的:
就是一个纯文本,不好看,所以接下来直接实现一个html模板email,如图:
html的解析可以用springboot自带的thymeleaf,引入依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
然后再resources文件下创建templates文件夹,创建一个html文件作为邮件模板:
该模板内容如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>邮箱验证码</title><style>table {width: 700px;margin: 0 auto;}#top {width: 700px;border-bottom: 1px solid #ccc;margin: 0 auto 30px;}#top table {font: 12px Tahoma, Arial, 宋体;height: 40px;}#content {width: 680px;padding: 0 10px;margin: 0 auto;}#content_top {line-height: 1.5;font-size: 14px;margin-bottom: 25px;color: #4d4d4d;}#content_top strong {display: block;margin-bottom: 15px;}#content_top strong span {color: #f60;font-size: 16px;}#verificationCode {color: #f60;font-size: 24px;}#content_bottom {margin-bottom: 30px;}#content_bottom small {display: block;margin-bottom: 20px;font-size: 12px;color: #747474;}#bottom {width: 700px;margin: 0 auto;}#bottom div {padding: 10px 10px 0;border-top: 1px solid #ccc;color: #747474;margin-bottom: 20px;line-height: 1.3em;font-size: 12px;}#content_top strong span {font-size: 18px;color: #FE4F70;}#sign {text-align: right;font-size: 18px;color: #FE4F70;font-weight: bold;}#verificationCode {height: 100px;width: 680px;text-align: center;margin: 30px 0;}#verificationCode div {height: 100px;width: 680px;}.button {color: #FE4F70;margin-left: 10px;height: 80px;width: 80px;resize: none;font-size: 42px;border: none;outline: none;padding: 10px 15px;background: #ededed;text-align: center;border-radius: 17px;box-shadow: 6px 6px 12px #cccccc,-6px -6px 12px #ffffff;}.button:hover {box-shadow: inset 6px 6px 4px #d1d1d1,inset -6px -6px 4px #ffffff;}</style>
</head>
<body>
<table><tbody><tr><td><div id="top"><table><tbody><tr><td></td></tr></tbody></table></div><div id="content"><div id="content_top"><strong>尊敬的用户,您好!</strong><strong>您正在使用验证码校验,请在5分钟内填写如下验证码,如非本人操作请忽略该邮件</strong><div id="verificationCode"><button class="button" th:each="a:${verifyCode}">[[${a}]]</button></div></div><div id="content_bottom"><small>注意:此操作可能会修改您的密码、登录邮箱或绑定手机。如非本人操作,请及时登录并修改密码以保证帐户安全<br>(工作人员不会向你索取此验证码,请勿泄漏!)</small></div></div><div id="bottom"><div><p>此为系统邮件,请勿回复<br>请保管好您的邮箱,避免账号被他人盗用</p>
<!-- <p id="sign">——POLAR官方</p>--></div></div></td></tr></tbody>
</table>
</body>
模板参考文章:传送门
接下来就是编写service了:
@Service("emailService")
public class EmailServiceImpl implements EmailService {@Resourceprivate JavaMailSender javaMailSender;@Resourceprivate TemplateEngine templateEngine;@Value("${spring.mail.username}")private String username;@Overridepublic void sendMessageToEmail(String verifyCode, String email) {Context context = new Context(); // 引入Template的Context// 设置模板中的变量(分割验证码)context.setVariable("verifyCode", Arrays.asList(verifyCode.split("")));// 第一个参数为模板的名称(html不用写全路径)String process = templateEngine.process("EmailVerificationCode.html", context); // 这里不用写全路径MimeMessage mimeMessage = javaMailSender.createMimeMessage();try {MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);helper.setSubject("【POLAR】验证码"); // 邮件的标题helper.setFrom(username); // 发送者helper.setTo(email); // 接收者helper.setSentDate(new Date()); // 时间helper.setText(process, true); // 第二个参数true表示这是一个html文本} catch (MessagingException e) {throw new BusinessException(StatusCode.SYSTEM_ERROR, "邮件发送异常");}javaMailSender.send(mimeMessage);}
}
这就完成整体逻辑的编写了,接下来测试一下:
接收到的邮件:
查看redis:
至此所有功能完成;
相关文章:

springboot实现邮箱验证码功能
引言 邮箱验证码是一个常见的功能,常用于邮箱绑定、修改密码等操作上,这里我演示一下如何使用springboot实现验证码的发送功能; 这里用qq邮箱进行演示,其他都差不多; 准备工作 首先要在设置->账户中开启邮箱POP…...

Java 进阶(5) Java IO流
⼀、File类 概念:代表物理盘符中的⼀个⽂件或者⽂件夹。 常见方法: 方法名 描述 createNewFile() 创建⼀个新文件。 mkdir() 创建⼀个新⽬录。 delete() 删除⽂件或空⽬录。 exists() 判断File对象所对象所代表的对象是否存在。 getAbsolute…...

“终于我从字节离职了...“一个年薪40W的测试工程师的自白...
”我递上了我的辞职信,不是因为公司给的不多,也不是因为公司待我不好,但是我觉得,我每天看中我憔悴的面容,每天晚上拖着疲惫的身体躺在床上,我都不知道人生的意义,是赚钱吗?是为了更…...

设计模式之策略模式(C++)
作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 一、策略模式是什么? 策略模式是一种行为型的软件设计模式,针对某个行为,在不同的应用场景下&…...

从工厂普工到Python女程序员,聊聊这一路我是如何逆袭的?
我来聊聊我是如何从一名工厂普工,到国外程序员的过程,这里面充满了坎坷。过去我的工作是在工厂的流水线上,我负责检测电池的正负极。现如今我每天从早上6:20起床,6点四五十分出发到地铁站,7:40到公司。我会给自己准备一…...
全国青少年信息素养大赛2023年python·选做题模拟二卷
目录 打印真题文章进行做题: 全国青少年电子信息智能创新大赛 python选做题模拟二卷 一、单选题 1. numbers = [1, 11, 111, 9], 运行numbers.sort() 后,运行numbers.reverse() numbers会变成?( )...

分布式事务Seata原理
Seata 是一款开源的分布式事务解决方案,致力于提供高性能与简单易用的分布式事务服务,为用户提供了 AT、TCC、SAGA 和 XA 几种不同的事务模式。Seata AT模式是基于XA事务演进而来,需要数据库支持。AT 模式的特点就是对业务无入侵式࿰…...

用ChatGPT怎么赚钱?普通人用这5个方法也能赚到生活费
ChatGPT在互联网火得一塌糊涂,因为它可以帮很多人解决问题。比如:帮编辑人员写文章,还可以替代程序员写代码,帮策划人员写文案策划等等。ChatGPT这么厉害,能否用它来赚钱呢?今天和大家分享用ChatGPT赚钱的5…...

( “树” 之 DFS) 110. 平衡二叉树 ——【Leetcode每日一题】
110. 平衡二叉树 给定一个二叉树,判断它是否是高度平衡的二叉树。 本题中,一棵高度平衡二叉树定义为: 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。 示例 1: 输入:root [3,9,20,null,null,15,7] …...

nvm软件使用-同一个环境下控制多个不同node版本
1.使用场景 nvm是一个用于管理Node.js版本的工具,它可以让你在同一台机器上安装和切换不同的Node.js版本。使用nvm的好处有以下几点: 1.1.nvm可以让你轻松地测试你的代码在不同的Node.js版本下的兼容性和性能,避免因为版本差异导致的问题。…...
连续两个南航的研究生面试出了从来没出现过的问题,本科和研究生都是计算机专业的,竟然说static是不可更改的。
最近面试人数有点多,面试有点频繁,因此发现了一些学生普遍会发生的错误,可以说是很离谱。 因为做了十多年的面试官,无论是大中小厂的面试,还是社招、校招。 从来没有遇到过这样的情况,而且发生在两个南航…...
How to install nacos/nacos-server:v2.1.2-slim with docker
今天给大家介绍一下如何基于Docker的nacos/nacos-server:v2.1.2-slim镜像安装nacos 1、Data Source 我们需要从nacos的github官网下载nacos 2.12发布包 nacos-server-2.1.2.tar.gznacos-server-2.1.2.zip 这里以nacos-server-2.1.2.tar.gz为例来介绍,解压后我们…...

Rust社区引发舆论危机,问题到底出在哪儿?
围绕开源的法律问题,讨论焦点往往集中在开源许可证、软件著作权等方面,商标的讨论却极少引人关注。事实上,关于开源软件以及开源软件的衍生产品的商标使用情况往往处于某种灰色地带。 最近,Rust基金会正在就更新的商标政策征求反馈…...
C++算法恢复训练之归并排序
归并排序(Merge Sort)是一种基于分治思想的排序算法,它将待排序数组分成两个子数组,然后对这两个子数组分别进行排序,最后将两个已排序的子数组合并成一个有序数组。归并排序是一种稳定的排序算法,具体体现…...
使用Process Explorer和Clumsy工具定位软件高CPU占用问题
目录 1、问题描述 2、使用Process Explorer初步找到CPU占用高的原因 3、使用Clumsy工具在公司内网环境复现了问题...

为何巴菲特和马斯克站在了一起?
股神巴菲特虽然非常传奇,但是马斯克对其并不感冒。马斯克曾经在一档电视节目中表示,实业才是王道,埋怨金融业抢走太多人才和精英,暗指巴菲特为年轻人做了错误示范。当然,巴菲特的投资非常厉害,但也有失手的…...

企业数字化转型全是坑?这几篇数字化转型成功案例,减少70%损失
这篇给大家整理了200企业数字化转型案例合集,涵盖了制造、建筑、教育、零售、互联网等10行业的大中小型企业数字化转型思路,希望对大家有所帮助。 案例全部整合在这篇文章中,点击即可查看>>数字化干货资料合集! 01 首先&…...

13.Java面向对象----嵌套类
Java面向对象—嵌套类、内部类、匿名类 一、static静态 在《Java编程思想》有这样一段话: “static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来…...
Redis数据迁移过程,使用jedis客户端发送命令,需要注意string和byte类型的命令,如果使用的转换字符编码不一致,会导致丢数据
1.了解String与byte之间存在的字符编码映射规则(java为例) string与byte来回转换,需要指定一样字符编码规则 详细原因请参考:关于Java中bytes到String的转换-阿里云开发者社区 简单来说 (1)string和by…...
第六章 IA-32指令类型
IA-32指令类型1、传送指令1.1、常用传送指令1.1.1、通用数据传送指令1.2、传送指令执行过程2、定点算术运算指令2.1、常用定点运算指令2.2、加法运算的底层实现举例2.3、加法指令和乘法指令举例3、按位运算指令3.1、逻辑运算和移位运算3.2、按位运算指令举例4、控制转移指令4.1…...

UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
flow_controllers
关键点: 流控制器类型: 同步(Sync):发布操作会阻塞,直到数据被确认发送。异步(Async):发布操作非阻塞,数据发送由后台线程处理。纯同步(PureSync…...

CTF show 数学不及格
拿到题目先查一下壳,看一下信息 发现是一个ELF文件,64位的 用IDA Pro 64 打开这个文件 然后点击F5进行伪代码转换 可以看到有五个if判断,第一个argc ! 5这个判断并没有起太大作用,主要是下面四个if判断 根据题目…...
从零手写Java版本的LSM Tree (一):LSM Tree 概述
🔥 推荐一个高质量的Java LSM Tree开源项目! https://github.com/brianxiadong/java-lsm-tree java-lsm-tree 是一个从零实现的Log-Structured Merge Tree,专为高并发写入场景设计。 核心亮点: ⚡ 极致性能:写入速度超…...

二维数组 行列混淆区分 js
二维数组定义 行 row:是“横着的一整行” 列 column:是“竖着的一整列” 在 JavaScript 里访问二维数组 grid[i][j] 表示 第i行第j列的元素 let grid [[1, 2, 3], // 第0行[4, 5, 6], // 第1行[7, 8, 9] // 第2行 ];// grid[i][j] 表示 第i行第j列的…...
Ansible+Zabbix-agent2快速实现对多主机监控
ansible Ansible 是一款开源的自动化工具,用于配置管理(Configuration Management)、应用部署(Application Deployment)、任务自动化(Task Automation)和编排(Orchestration…...

Modbus转ETHERNET IP网关:快速冷却系统的智能化升级密钥
现代工业自动化系统中,无锡耐特森Modbus转Ethernet IP网关MCN-EN3001扮演着至关重要的角色。通过这一技术,传统的串行通讯协议Modbus得以在更高速、更稳定的以太网环境中运行,为快速冷却系统等关键设施的自动化控制提供了强有力的支撑。快速冷…...