SpringBoot + Vue3邮件验证码功能的实现

后端

  • SpringBoot
  • maven
  • mysql
  • IDEA

后端负责编写邮件发送的接口逻辑,具体流程如下:

  • 引入相关依赖
  • 配置邮箱信息
  • 编写邮件发送服务接口
  • OK

引入依赖

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-mail -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
    <version>2.6.7</version>
</dependency>

配置邮箱信息

首先要明白一点,我们实现邮件发送需要一个用来发送邮件到目标用户邮箱里的邮箱,因此,这一步必不可少,也是最主要的一点。关于邮箱配置的具体信息在我的论文一篇文章中已经做过详细的操作说明,为了节省时间,这里就不再拿出来赘述了,建议参考文档CSDN文章 开发必会:SpringBoot邮件集成图文详解

通过你的努力阅读,相信邮箱相关的配置已经做好了,那么现在我们需要将邮箱的信息配置到项目的配置文件application.yml/properties中,参考如下:

  # 配置邮箱
  mail:
    host: smtp.163.com
    username: ilikexff@163.com
    password: 这里放你上面配置好的邮件密码或者授权码
    default-encoding: UTF-8
    protocol: smtp
    port: 465
    properties:
      mail:
        smtp:
          auth: true
          socketFactory:
            class: javax.net.ssl.SSLSocketFactory
            port: 465
          ssl:
            enable: true
          starttls:
            enable: true
            required: true

配置关注做好之后,开始着手开发邮件发送的服务接口;


编写邮件发送服务接口

基本流程:

  1. 编写邮件发送接口;
  2. 编写接口实现
  3. 编写controller层
  4. 接口基本测试
  5. 完成开发

编写服务层的接口,接口代码如下:

/**
 * ===================我亦无它================================
 * project name: big-event
 * author: 八尺妖剑
 * date: 2024/3/31
 * blog: https://www.ilikexff.cn/
 * description 邮件发送接口
 * ====================唯手熟尔===============================
 **/

package cn.ilikexff.service;

import javax.mail.MessagingException;

/**
 * 邮件发送接口
 */
public interface EmailSendService {
    /**
     * 发送普通文本邮件
     * @param to 收件人地址
     * @param subject 邮件主题
     * @param content 邮件内容
     * @param cc 抄送地址
     */
    void sendSimpleMail(String to,String subject,String content,String... cc);

    /**
     * 发送HTML邮件
     * @param to 收件人地址
     * @param subject 邮件主题
     * @param content 邮件内容
     * @param cc 抄送地址
     */
    void sendHtmlMail(String to,String subject,String content,String... cc);

    /**
     * 发送带附件的邮件
     * @param to 收件人
     * @param subject 邮件主题
     * @param content 邮件内容
     * @param filePath 附件地址
     * @param cc 抄送地址
     * @throws MessagingException 邮件发送异常
     */
    void sendAttachmentsMail(String to, String subject, String content, String filePath, String... cc) throws MessagingException;


    /**
     * 发送正文中有静态资源的邮件
     * @param to 收件人地址
     * @param subject 邮件主题
     * @param content 邮件内容
     * @param rscPath 静态资源地址
     * @param rscId 静态资源ID
     * @param cc 抄送地址
     * @throws MessagingException 发送异常
     */
    void sendResourceMail(String to, String subject, String content, String rscPath, String rscId, String... cc) throws MessagingException;


}

关于邮件发送的一些具体信息,如果你看过上面的文章,配合这里每个方法详细的注释,聪明的你应该不用我再过多解释了吧,那么继续实现该接口;

/**
 * ===================我亦无它================================
 * project name: big-event
 * author: 八尺妖剑
 * date: 2024/3/31
 * blog: https://www.ilikexff.cn/
 * description 邮件发送接口的实现
 * ====================唯手熟尔===============================
 **/

package cn.ilikexff.service.impl;

import cn.hutool.core.util.ArrayUtil;
import cn.ilikexff.service.EmailSendService;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import java.io.File;

/**
 * 对邮件发送接口的实现
 */

@Service
public class EmailSendServiceImpl implements EmailSendService {
    @Autowired
    private JavaMailSender mailSender;
    @Value("${speing.mail.username}")
    private String from;


    /**
     * 实现普通文本邮件发送
     * @param to 收件人地址
     * @param subject 邮件主题
     * @param content 邮件内容
     * @param cc 抄送地址
     */
    @Override
    public void sendSimpleMail(String to, String subject, String content, String... cc) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(from);
        message.setTo(to);
        message.setSubject(subject);
        message.setText(content);
        if(ArrayUtil.isNotEmpty(cc)){
            message.setCc(cc);
        }
        mailSender.send(message);
    }

    /**
     * 实现发送HTML类型邮件
     * @param to 收件人地址
     * @param subject 邮件主题
     * @param content 邮件内容
     * @param cc 抄送地址
     */
    @Override
    public void sendHtmlMail(String to, String subject, String content, String... cc) throws MessagingException {

        MimeMessage message;
        message = mailSender.createMimeMessage();
        MimeMessageHelper helper;
        helper = new MimeMessageHelper(message, true);
        helper.setFrom(from);
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(content,true);
        if(ArrayUtil.isNotEmpty(cc)){
            helper.setCc(cc);
        }
        mailSender.send(message);
    }

    /**
     * 实现发送带附件的邮件
     * @param to 收件人
     * @param subject 邮件主题
     * @param content 邮件内容
     * @param filePath 附件地址
     * @param cc 抄送地址
     * @throws MessagingException
     */
    @Override
    public void sendAttachmentsMail(String to, String subject, String content, String filePath, String... cc) throws MessagingException {
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setFrom(from);
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(content);
        if(ArrayUtil.isNotEmpty(cc)){
            helper.setCc(cc);
        }
        FileSystemResource file = new FileSystemResource(new File(filePath));
        String fileName = filePath.substring(filePath.lastIndexOf(File.separator)+1);
        helper.addAttachment(fileName, file);
        mailSender.send(message);
    }

    /**
     * 实现发送正文中有静态资源的邮件
     * @param to 收件人地址
     * @param subject 邮件主题
     * @param content 邮件内容
     * @param rscPath 静态资源地址
     * @param rscId 静态资源ID
     * @param cc 抄送地址
     * @throws MessagingException
     */
    @Override
    public void sendResourceMail(String to, String subject, String content, String rscPath, String rscId, String... cc) throws MessagingException {
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setFrom(from);
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(content, true);
        if (ArrayUtil.isNotEmpty(cc)) {
            helper.setCc(cc);
        }
        FileSystemResource res = new FileSystemResource(new File(rscPath));
        helper.addInline(rscId, res);
        mailSender.send(message);
    }
}

其中,下面的代码是将我们在配置文件中配置好的邮箱的用户名,也就是邮件的发送者注入到该类中,方便后面的方法使用。

@Value("${spring.mail.username}")
private String from;

接下来就是接口的编写了,新建一个controller,内容如下:

    /**
 * Handles the request to send an email verification code.
 * <p>
 * This method generates a random numeric verification code using a utility class,
 * stores the code in Redis with a specified expiration time, and sends the code to the
 * provided email address. The verification code is intended for use in registration or
 * other verification processes.
 * 
 * @param email The target email address to which the verification code will be sent.
 * @return A {@link Result} object containing the generated verification code and a success status.
 */
@GetMapping("/email/code")
public Result sendEmailCode(String email) {
    // 调用工具类生成指定长度的随机验证码
    String code = VerificationUtil.generateNumberCaptcha(6);
    // 将验证码存入redis并指定有效期,单位:秒
    ValueOperations<String, String> operation = stringRedisTemplate.opsForValue();
    operation.set("code",code,30, TimeUnit.SECONDS);
    // 发送验证码
    emailSendService.sendSimpleMail(email,"注册验证码","你的注册验证码为:"+code);
    return Result.success(code,0);
}

由于这里使用了redis保存验证码有效信息,因此需要引入对应的依赖:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

下面是生成随机验证码的工具类:

/**
 * ===================我亦无它================================
 * project name: big-event
 * author: 八尺妖剑
 * date: 2024/3/31
 * blog: https://www.ilikexff.cn/
 * description 邮件验证码生成工具类
 * ====================唯手熟尔===============================
 **/

package cn.ilikexff.utils;
import java.util.Random;
public class VerificationUtil {
    /**
     * Generates a numeric captcha of a specified length.
     * This method creates a string composed of random digits, where the length of the string
     * is determined by the input parameter.
     * @param length The length of the captcha to generate. Must be a positive integer.
     * @return A string representing the generated numeric captcha.
     */
    public static String generateNumberCaptcha(int length) {
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            sb.append(random.nextInt(10));
        }
        return sb.toString();
    }
}

上面代码中用到的依赖注入:

private final EmailSendService emailSendService;
private final StringRedisTemplate stringRedisTemplate;

/**
 * 使用指定的邮件发送服务和Redis模板构造EmailSendController的实例。
 * 该构造函数允许对EmailSendService和StringRedisTemplate进行依赖注入,
 * 使得控制器能够发送邮件并与Redis进行交互,如存储验证码等操作。
 * @param emailSendService 用于发送邮件的服务。
 * @param stringRedisTemplate 用于字符串操作的Redis模板,此处用于存储验证码。
 */
public EmailSendController(EmailSendService emailSendService, StringRedisTemplate stringRedisTemplate) {
    this.emailSendService = emailSendService;
    this.stringRedisTemplate = stringRedisTemplate;
}

接口测试

测试工具postman

image-20240331124251806

至此,关于邮件验证码的后端部分就先告一段落,接下来使用Vue3写好前端页面,再回过头来进行前后端的联调,确保核心功能正常;


前端

  • Vue3
  • Element-Plus
  • WebStorm
  • JavaScript

编写表单

这个项目本来是没有注册验证码这个需求的,为了更好的演示效果,简单修改了以下原来的表单,修改后的页面如下:

image-20240331163500154

页面有了,接下来就是请求后端的接口,实现点击 获取验证码 按钮发送邮件验证码,为了实现点击之后进入倒计时禁用,这里采用v-if组件来实现,下面是核心代码:

image-20240331163700724


倒计时处理

其中的JavaScript部分如下:

const sms = reactive({
  disabled: false, // 按钮禁用状态
  total: 10, // 倒计时间隔:秒
  count: 0
})
// 邮件验证码,这段你可以忽略,根据自己得项目情况来,这个就是调用后端获取验证码的请求
const sendEmail = async () =>{
  console.log("函数被调用...")
  timerHandler()
  let result =  await sendEmailCodeService(registerData.value.email);
  console.log("邮箱:"+registerData.value.email)
  ElMessage.success("验证码已发送,请注意查收!");
}

// 倒计时实现
const timerHandler = () => {
  sms.count = sms.total
  sms.disabled = true

  let timer = setInterval(() => {
    if (sms.count > 1 && sms.count <= sms.total) {
      sms.count--
    } else {
      sms.disabled = false
      clearInterval(timer)
    }
  }, 1000)
}

差不多就是这样了,当我们点击【获取验证码】之后,该按钮会进入禁用状态并且倒计时提示,效果如下:

image-20240331164130631

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

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

相关文章

基于FreeRTOS系统的STM32简易遥控器设计

项目说明 该项目是一个基于FreeRTOS系统的Stm32遥控器设计。使用该项目主要是自己学习FreeRTOS的使用&#xff0c;以及模块化编程的思想。这个项目应该长期会有更新。 项目开源 github:https://github.com/snqx-lqh/Stm32RemoteControl gitee:https://gitee.com/snqx-lqh/S…

conda 创建 python3.10.12 环境

conda 创建 python3.10.12 环境 介绍使用前置条件&#xff1a;安装 conda配置环境变量验证 Conda 安装结果创建环境&#xff1a;python激活 Anaconda 环境 验证 Python 版本。 介绍 Conda是一个开源的包管理和环境管理系统&#xff0c;由Continuum Analytics公司开发。它可以安…

【InternLM 实战营第二期笔记】InternLM1.8B浦语大模型趣味 Demo

体验环境 平台&#xff1a;InternStudio GPU&#xff1a;10% 配置基础环境 studio-conda -o internlm-base -t demo 与 studio-conda 等效的配置方案 conda create -n demo python3.10 -y conda activate demo conda install pytorch2.0.1 torchvision0.15.2 torchaudio2…

使用MySQL和PHP创建一个公告板

目录 一、创建表 二、制作首页&#xff08;创建主题以及显示列表&#xff09; 三、制作各个主题的页面&#xff08;输入回帖和显示列表&#xff09; 四、制作消息的查询界面 五、制作读取数据库信息的原始文件 六、制作数据重置页面 七、效果图 八、问题 1、目前无法处…

轻量应用服务器16核32G28M腾讯云租用优惠价格4224元15个月

腾讯云16核32G服务器租用价格4224元15个月&#xff0c;买一年送3个月&#xff0c;配置为&#xff1a;轻量16核32G28M、380GB SSD盘、6000GB月流量、28M带宽&#xff0c;腾讯云优惠活动 yunfuwuqiba.com/go/txy 活动链接打开如下图&#xff1a; 腾讯云16核32G服务器租用价格 腾讯…

三栏布局——面试/笔试题

目录 三栏布局(两端指定宽度&#xff0c;中间自适应)三栏布局(平均分布) 三栏布局(两端指定宽度&#xff0c;中间自适应) 只介绍简单的写法&#xff0c;圣杯布局之类的比较复杂&#xff0c;实际上越简单越好&#xff0c;所以复杂的就不介绍了 flex布局 <!DOCTYPE html>…

vultr ubuntu 服务器远程桌面安装及连接

一. 概述 vultr 上开启一个linux服务器&#xff0c;都是以终端形式给出的&#xff0c;默认不带 ui 桌面的&#xff0c;那其实对于想使用服务器上浏览器时的情形不是很好。那有没有方法在远程服务器安装桌面&#xff0c;然后原程使用呢&#xff1f;至少ubuntu的服务器是有的&am…

HTTP/1.1、HTTP/2、HTTP/3 演变(计算机网络)

HTTP/1.1 相比 HTTP/1.0 提高了什么性能&#xff1f; HTTP/1.1 相比 HTTP/1.0 性能上的改进&#xff1a; 使用长连接改善了短连接造成的性能开销。支持管道网络传输&#xff0c;只要第一个请求发出去了&#xff0c;不必等其回来&#xff0c;就可以发第二个请求出去&#xff0c…

数据库----数据类型正确选择

mysql支持的数据类型&#xff1a; 数值型&#xff0c;如INT&#xff0c;BIGINT&#xff0c;FLOAT和decimal 日期和时间类型&#xff0c;如DATE,TIME和TIMESTAMP等 字符串类型&#xff0c;如VARCHAR,CHAR和BLOB 空间数据类型&#xff0c;如GEOMETRY&#xff0c;POINT和POLYGON J…

解决创建springboot项目时,无法选中java8的问题

主要原因是springboot3.0.0以上版本需要jdk17. 问题描述&#xff1a; 解决办法&#xff1a; 在Server url上点击齿轮&#xff0c;把http://start.springboot.io/更改为https://start.aliyun.com/ 效果如下

速通汇编(三)寄存器及汇编mul、div指令

一&#xff0c;寄存器及标志 AH&ALAX(accumulator)&#xff1a;累加寄存器BH&BLBX(base)&#xff1a;基址寄存器CH&CLCX(count)&#xff1a;计数寄存器DH&DLDX(data)&#xff1a;数据寄存器SP(Stack Pointer)&#xff1a;堆栈指针寄存器BP(Base Pointer)&#…

C#调用FreeSpire.Office读取word数据的基本用法

FreeSpire.Office是Spire.Office的免费版本&#xff0c;后者支持全面、复杂的office文件操作功能&#xff0c;包括文件格式转换、文档操作、文档打印等&#xff0c;详细介绍见下图及参考文献1。本文学习FreeSpire.Office的基本用法并用其获取word文档的基本信息。   新建Win…

python统计分析——双样本均值比较

参考资料&#xff1a;python统计分析【托马斯】 1、配对样本t检验 在进行两组数据之间的比较时&#xff0c;有两种情况必须区分开。在第一种情况中&#xff0c;同一对象在不同时候的两个记录值进行相互比较。例如&#xff0c;用学生们进入初中时的身高和他们一年后的身高&…

学习transformer模型-Positional Encoding位置编码的简明介绍

今天介绍transformer模型的positional encoding 位置编码 背景 位置编码用于为序列中的每个标记或单词提供一个相对位置。在阅读句子时&#xff0c;每个单词都依赖于其周围的单词。例如&#xff0c;有些单词在不同的上下文中具有不同的含义&#xff0c;因此模型应该能够理解这…

鸿蒙OS开发实例:【ArkTS 实现MQTT协议】

介绍 MQTT是物联网中的一种协议&#xff0c;在HarmonyOS API9平台&#xff0c;解决方案以C库移植为实现方案。 遥遥领先的平台&#xff0c;使用MQTT怎能不遥遥领先呢&#xff01; 新年快乐&#xff0c;本篇将带领你手把手实现HarmonyOS ArkTS语言的MQTT协议。 准备 阅读…

LLM--提示词Propmt的概念、作用及如何设计提示词

文章目录 1. 什么是提示词&#xff1f;2. 提示词的作用3. 如何设计提示词&#xff1f;3.1. 提供详细的信息3.2. 指定角色3.3. 使用分隔符和特殊符号3.4. 提供示例3.5. 少量示例的思维链&#xff08;COT&#xff09;模型3.6. 思维树&#xff08;TOT&#xff09;模型3.7. 自洽性 …

【4】单链表(有虚拟头节点)

【4】单链表&#xff08;有虚拟头节点&#xff09; 1、虚拟头节点2、构造方法3、node(int index) 返回索引位置的节点4、添加5、删除6、ArrayList 复杂度分析(1) 复杂度分析(2) 数组的随机访问(3) 动态数组 add(E element) 复杂度分析(4) 动态数组的缩容(5) 复杂度震荡 7、单链…

【Linux 10】环境变量

文章目录 &#x1f308; Ⅰ 命令行参数⭐ 1. main 函数的参数⭐ 2. main 函数参数的意义⭐ 3. 查看 argv 数组的内容⭐ 4. 命令行参数结论⭐ 5. 为什么要有命令行参数⭐ 6. 命令行参数传递由谁执行 &#x1f308; Ⅱ 环境变量基本概念⭐ 1. 常见环境变量 &#x1f308; Ⅲ 查看…

LeetCode_876(链表的中间结点)

//双指针//时间复杂度O(n) 空间复杂度O(1)public ListNode middleNode(ListNode head) {ListNode slowhead,fast head;while (fast!null && fast.next!null){slow slow.next;fast fast.next.next;}return slow;} 1->2->3->4->5->null 快指针移动两个…

9款免费云服务器,最长永久免费使用

随着云计算技术的快速发展&#xff0c;越来越多的企业和个人开始选择使用云服务器。云服务器提供了灵活、可扩展且易于管理的资源&#xff0c;使得用户可以根据需求随时调整计算能力。本文将分享9款免费云服务器&#xff0c;其中最长可永久免费使用&#xff0c;为用户提供了更多…