本次项目基于springboot 3.x
jdk为17
Maven版本为:3.8.1
IDEA版本为:2023.3.x
第一步:我们进入qq邮箱的右上角有一个账号与安全设置:我们点进去
第二步:点进去后来到这个页面:选择安全设置,在最下面有这个服务,我们需要开启这个服务,然后生成一个授权码,生成的授权码记得保存下来,这个很有用处
紧接着在我们的项目工程中就可以编写java代码了
首先在我们的pom.xml文件中引入关于email的依赖包
org.springframework.boot spring-boot-starter-mail
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
上面就是配置基本信息了,根据你的需求可以自行更改
我们需要将业务代码整合到一个工具类(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); } }
注意:这个地方可以看我往期的文章,有写全局异常处理器的使用方法
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())); } }
因为项目中用到了大量的字符串,所以我这里就写了常量类,来代替字符串
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邮箱验证码就通过发送了