springboot项目接入第三方qq邮箱验证登录
作者:mmseoamin日期:2024-04-01

前言:

本次项目基于springboot 3.x 

jdk为17

Maven版本为:3.8.1 

IDEA版本为:2023.3.x

1、在qq邮箱进行相关的设置

第一步:我们进入qq邮箱的右上角有一个账号与安全设置:我们点进去

springboot项目接入第三方qq邮箱验证登录,第1张

第二步:点进去后来到这个页面:选择安全设置,在最下面有这个服务,我们需要开启这个服务,然后生成一个授权码,生成的授权码记得保存下来,这个很有用处

springboot项目接入第三方qq邮箱验证登录,第2张

2、编写java代码

紧接着在我们的项目工程中就可以编写java代码了

2.1、首先我们先引入相关的maven依赖包

首先在我们的pom.xml文件中引入关于email的依赖包

 
        
            org.springframework.boot
            spring-boot-starter-mail
        

2.2、随后配置yml文件,进行相关的配置

spring:
  mail:
   host: smtp.qq.com # 指定邮件服务器的主机名,这里默认是smtp.qq.com,表示使用的是腾讯的SMTP服务器。
   port: 587 # 456也行
   username: "你的email" # xxxx@qq.com  这里是发送者
   password: "授权码"  # 这里就是我前面提到的授权码了
   properties:   # 其他配置
     mail:
       smtp:
         socketFactoryClass: javax.net.ssl.SSLSocketFactory # 指定SSL Socket工厂类,用于创建加密的邮件连接。
         auto: true # 设置为true表示启用自动连接。
       starttls: # 配置STARTTLS加密连接
         enable: true # 设置为true表示启用STARTTLS。
         required: true # 设置为true表示STARTTLS是必需的,如果不可用,则会抛出异常。
   default-encoding: UTF-8 # 设置邮件内容的默认编码格式为UTF-8 默认就是UTF-8

上面就是配置基本信息了,根据你的需求可以自行更改

2.3、创建Email工具类

我们需要将业务代码整合到一个工具类(EmailSendUtils )中进行编码,我们创建一个专门用于发送email邮箱验证码的类,里面涵盖了发送的步骤,以及随机生成6位字母和数字的验证码。

上代码:

package com.sxy.recordnetwork.Utils;
import com.sxy.recordnetwork.enumeration.Constants;
import org.aspectj.apache.bcel.classfile.Code;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
import javax.swing.*;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
/**
 * 发送邮箱验证码工具类
 * Created by sxy on 2024/3/11.
 */
@Service
public class EmailSendUtils {
    // 注入JavaMailSender接口
    @Autowired
    private JavaMailSender  mailSender;
    // 集成redis进行验证码的缓存
    @Autowired
    private RedisTemplate redisTemplate;
    // 通过value注解得到配置文件中发送者的邮箱
    @Value("${spring.mail.username}")
    private String userName;// 用户发送者
    // 邮箱验证码 定义为StringBuilder对于增删改操作有优势
    private final StringBuilder EMAIL_CODE = new StringBuilder();
    // 创建一个发送邮箱验证的方法
    public void sendVerificationEmail(String to){
        try{
            // 定义email信息格式
            SimpleMailMessage message = new SimpleMailMessage();
            // 调用生成6位数字和字母的方法,生成验证码,该方法在下面定义好了
            generateRandomCode();
            // 设置发件人
            message.setFrom(userName);
            // 接收者邮箱,为调用本方法传入的接收者的邮箱xxx@qq.com
            message.setTo(to);
            // 邮件主题
            message.setSubject(Constants.EMAIL_TITLE.getValue());
            // 邮件内容  设置的邮件内容,这里我使用了常量类字符串,加上验证码,再加上常量类字符串
          message.setText(Constants.EMAIL_MESSAGE.getValue()+EMAIL_CODE+Constants.EMAIL_OUTTIME_TEN.getValue());
            // 开始发送
            mailSender.send(message);
        }catch (Exception e){
            e.printStackTrace();
        }finally{
            // 发送完了之后,将EMAIL_CODE设置为空
            EMAIL_CODE.setLength(0);
        }
    }
    /**
     * 随机生成6位字母加数字组合的验证码
     * @return
     */
    public void generateRandomCode(){
        // 字母和数字组合
        String str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        // 拆分每一个字符放到数组中
        String[] newStr = str.split("");
        // 循环随机生成6为数字和字母组合
        for (int i = 0; i < 6; i++){
            // 通过循环6次,为stringBuilder追加内容,内容为随机数✖62,取整
            EMAIL_CODE.append(newStr[(int)(Math.random() * 62)]);
        }
        //TODO 这里存储的key如果多个用户同时发送的话会覆盖key,就会导致第一个人的验证码被覆盖
        // 存入Redis中并设置时长为2分钟
        redisTemplate.opsForValue().set(Constants.EMAIL_CODE.getValue(), EMAIL_CODE,120, TimeUnit.SECONDS);
    }
}

这里我声明了一个自定义异常类BaseException去继承RuntimeException这个类

package com.sxy.recordnetwork.Exception;
public class BaseException extends RuntimeException{
    public BaseException( String msg) {
        super(msg);
    }
}

然后我们再创建验证码相关的异常类信息去继承这个就可以了

package com.sxy.recordnetwork.Exception.Son;
import com.sxy.recordnetwork.Exception.BaseException;
/**
 *  邮箱验证码异常
 */
public class EmailCodeException extends BaseException {
    public EmailCodeException(String msg) {
        super(msg);
    }
}

注意:这个地方可以看我往期的文章,有写全局异常处理器的使用方法

2.4、在Controller层编写接口调用sendVerificationEmail接口参数为接收者邮箱

package com.sxy.recordnetwork.controller;
import com.sxy.recordnetwork.DTO.USER.UserDtoEmailLogin;
import com.sxy.recordnetwork.DTO.USER.UserDtoPhoneLogin;
import com.sxy.recordnetwork.Exception.Son.EmailCodeException;
import com.sxy.recordnetwork.Utils.EmailSendUtils;
import com.sxy.recordnetwork.enumeration.Constants;
import com.sxy.recordnetwork.common.Result;
import com.sxy.recordnetwork.common.SendCode;
import com.sxy.recordnetwork.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.concurrent.TimeUnit;
/**
 * 第三方短信验证以及其他相关操作
 */
@RequestMapping("/code")
@RestController
@Slf4j
public class CodeController {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserService userService;
    @Autowired
    private EmailSendUtils emailSendUtils;
    /**
     * 邮箱验证码发送
     * @param receiveEmail
     * @return
     */
    @GetMapping("/email/sendEmail")
    public Result sendSimpleMail(@RequestParam(value = "receiveEmail") String receiveEmail) {
        emailSendUtils.sendVerificationEmail(receiveEmail);
        return Result.success(Constants.EMAIL_SEND_SUCCESS.getValue(),null);
    }
    /**
     * qq邮箱验证登录
     * @param emailLogin
     * @return
     */
    @PostMapping("/emailLogin")
    public Result emailLogin(@RequestBody UserDtoEmailLogin emailLogin){
        // 查看是否存在这一个qq邮箱
        if(!userService.getEmail(emailLogin.getEmail())){
            throw new EmailCodeException(Constants.NOT_EXIST_EMAIL.getValue());
        }
        // 从redis数据库中获取email_code验证码用来做判断
        String email_code = (String) redisTemplate.opsForValue().get(Constants.EMAIL_CODE.getValue());
        if(!emailLogin.getCode().equals(email_code)){
            throw new EmailCodeException(Constants.EMAIL_CODE_ERROR.getValue());
        }
        // 登陆成功 清楚本地redis邮箱验证码
        redisTemplate.delete(Constants.EMAIL_CODE.getValue());
        return Result.success(Constants.LOGIN.getValue(),userService.EmailLogin(emailLogin.getEmail()));
    }
}

2.5、声明的常量类:

因为项目中用到了大量的字符串,所以我这里就写了常量类,来代替字符串

package com.sxy.recordnetwork.enumeration;
import lombok.Getter;
/**
 * 枚举类,常量
 */
@Getter
public enum Constants {
    EMAIL_SEND_SUCCESS("皇上,臣妾已为您发送了邮箱哦!"),//邮件发送成功,请查收!
    EMAIL_MESSAGE("您的QQ邮箱验证码为:"),
    EMAIL_OUTTIME_TEN(",请在2分钟内完成验证"),
    EMAIL_TITLE("QQ邮箱验证码"),// 邮箱验证码发送的标题
    EMAIL_CODE("email_code"),// 邮箱验证码redis的key
    EMAIL_CODE_ERROR("皇上,请核实您的QQ邮箱验证码是否正确!"),// qq邮箱验证码错误
    NOT_EXIST_EMAIL("皇上,臣妾没有找到您的QQ邮箱,请确认是否正确!");// 邮箱不存在
    private final String Value;
    Constants(String value){
        this.Value = value;
    }
}

好了,到这里就结束了,这样的话一个qq邮箱验证码就通过发送了