springboot使用TemplateEngine发送HTML邮箱验证码
和别的博主没什么不一样,但是别的博主都没有贴出来TemplateEngine使用是html模板的路径设置这里贴出
并附上完整教程
pom.xml依赖
<!-- 邮箱maven -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- TemplateEngine maven -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
application.yml设置
此处使用QQ邮箱,其他邮箱自行百度
mail:
host: smtp.qq.com #邮箱服务器地址 此处为QQ邮箱的
username: xxx@qq.com #邮箱账号
password: xxxxxx #邮箱密码,此处为QQ邮箱授权码,下图有介绍
default-encoding: utf-8 #默认编码
from: xxx@qq.com #邮件发件人
properties.mail.smtp.starttls.enable: true
properties.mail.smtp.starttls.required: true
properties.mail.smtp.ssl.enable: true
thymeleaf:
prefix: classpath:/mail/ #prefix:指定模板所在的目录
check-template-location: true #check-tempate-location: 检查模板路径是否存在
cache: false #cache: 是否缓存,开发模式下设置为false,避免改了模板还要重启服务器,线上设置为true,可以提高性能。
suffix: .html
mode: HTML5
存放模板地址以及格式
开启QQ邮箱授权码:
模板格式
想要美观一点可以自己重新写一个
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
h1{
color: red;
}
</style>
</head>
<body>
尊敬的用户,您好:<br><br>
本次请求的邮件验证码为:<br>
<h1>[[${message}]]</h1>
本验证码5分钟内有效,请及时输入。(请勿泄露此验证码)<br>
如非本人操作,请忽略该邮件。<br>
(这是一封自动发送的邮件,请不要直接回复)<br>
</body>
</html>
工具类
此处使用了SecureRandom是由于Random创建的是伪随机数,可被破解,具体可看一下下面文章
Random和SecureRandom详解
Java 随机数生成器 Random & SecureRandom 原理分析
package com.example.springbootservicepractice.util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.security.SecureRandom;
/**
* @author 凌殇
* @date 2022年03月08日 15:40
*/
public class ValidateCodeUtil {
//Random 不是密码学安全的,加密相关的推荐使用 SecureRandom
private static Random RANDOM = new SecureRandom();
private static final String randomString = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWSYZ";
private final static String token = "MAILTOKEN";
/**
* 生成6位随机数字
* @return 返回6位数字验证码
*/
public String generateVerCode(HttpServletRequest request, HttpServletResponse response) {
HttpSession session = request.getSession();
char[] nonceChars = new char[6];
for (int index = 0; index < nonceChars.length; ++index) {
nonceChars[index] = randomString.charAt(RANDOM.nextInt(randomString.length()));
}
//移除之前的session中的验证码信息
session.removeAttribute(token);
//将验证码放入session
session.setAttribute(token,new String(nonceChars));//设置token,参数token是要设置的具体值
return new String(nonceChars);
}
}
创建service接口以及实现类
附带邮箱验证码、邮箱发送html验证码、邮箱发送html以及附件
package com.example.springbootservicepractice.service;
import org.springframework.stereotype.Service;
@Service("iMailService")
public interface IMailService {
/**
* 发送邮件
* @param receiver 邮件收件人
* @param subject 邮件主题
* @param verCode 邮件验证码
*/
void sendEmailVerCode(String receiver, String subject, String verCode);
/**
* 发送HTML邮件
*
* @param to 收件人
* @param subject 主题
* @param content 内容
*/
void sendHtmlMail(String to, String subject, String content);
/**
* 发送带附件的邮件
*
* @param to 收件人
* @param subject 主题
* @param content 内容
* @param filePath 附件
*/
void sendAttachmentsMail(String to, String subject, String content, String filePath);
}
package com.example.springbootservicepractice.service.impl;
import com.example.springbootservicepractice.service.IMailService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.MailSendException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import javax.mail.internet.MimeMessage;
import java.io.File;
/**
* @author 凌殇
* @date 2022年03月08日 16:33
*/
@Slf4j
@Service
public class MailServiceImpl implements IMailService {
@Autowired
JavaMailSenderImpl mailSender;
@Autowired
TemplateEngine templateEngine;
/**
* 从配置文件中获取发件人
*/
@Value("${spring.mail.username}")
private String sender;
/**
* 邮件发送
* @param receiver 收件人
* @param subject 主题
* @param verCode 验证码
* @throws MailSendException 邮件发送错误
*/
@Async
public void sendEmailVerCode(String receiver, String subject, String verCode) throws MailSendException {
SimpleMailMessage message = new SimpleMailMessage();
message.setSubject("验证码"); //设置邮件标题
message.setText("尊敬的用户,您好:\n"
+ "\n本次请求的邮件验证码为:\n<span>" + verCode + "</span>,本验证码5分钟内有效,请及时输入。(请勿泄露此验证码)\n"
+ "\n如非本人操作,请忽略该邮件。\n(这是一封自动发送的邮件,请不要直接回复)"); //设置邮件正文
message.setTo(receiver); //设置收件人
message.setFrom(sender); //设置发件人
mailSender.send(message); //发送邮件
}
/**
* html邮件
*
* @param to 收件人
* @param subject 主题
* @param content 内容
*/
@Override
public void sendHtmlMail(String to, String subject, String content) {
//获取MimeMessage对象
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper messageHelper;
try {
messageHelper = new MimeMessageHelper(message, true);
//邮件发送人
messageHelper.setFrom(sender);
//邮件接收人
messageHelper.setTo(to);
//邮件主题
message.setSubject(subject);
Context context = new Context();
//设置传入模板的页面的参数 参数名为:id 参数随便写一个就行
context.setVariable("message", content);
//emailTemplate是你要发送的模板我这里用的是Thymeleaf
String process = templateEngine.process("emailTemplate", context);
//邮件内容,html格式
messageHelper.setText(process, true);
//发送
mailSender.send(message);
//日志信息
log.info("邮件已经发送。");
} catch (Exception e) {
log.error("发送邮件时发生异常!", e);
}
}
/**
* 带附件的邮件
*
* @param to 收件人
* @param subject 主题
* @param content 内容
* @param filePath 附件
*/
@Override
public void sendAttachmentsMail(String to, String subject, String content, String filePath) {
MimeMessage message = mailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(sender);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, true);
FileSystemResource file = new FileSystemResource(new File(filePath));
String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
helper.addAttachment(fileName, file);
mailSender.send(message);
//日志信息
log.info("邮件已经发送。");
} catch (Exception e) {
log.error("发送邮件时发生异常!", e);
}
}
}
controller类
package com.example.springbootservicepractice.controller;
import com.example.springbootservicepractice.service.IMailService;
import com.example.springbootservicepractice.util.ValidateCodeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* @author 凌殇
* @date 2022年03月08日 16:50
*/
@RestController
public class EmailController {
@Autowired
IMailService iMailService;
@PostMapping("/email")
public void sendEmail(@RequestParam("emailAddress") String emailAddress,HttpServletRequest request, HttpServletResponse response, HttpSession session) {
try {
ValidateCodeUtil validateCode = new ValidateCodeUtil();
iMailService.sendHtmlMail(emailAddress,"验证码", validateCode.generateVerCode(request,response));
//获取存放在session域中的验证码
String sessionCode= String.valueOf(session.getAttribute("MAILTOKEN")).toLowerCase();
System.out.println("session里的验证码:"+sessionCode);
} catch (Exception e) {
e.printStackTrace();
}
}
@PostMapping("/emailCaptcha")
public boolean getCheckCaptcha(@RequestParam("code") String code, HttpSession session) {
try {
// 获取存放在session域中的验证码 toLowerCase() 不区分大小写进行验证码校验
String sessionCode= String.valueOf(session.getAttribute("MAILTOKEN")).toLowerCase();
System.out.println("session里的验证码:"+sessionCode);
String receivedCode=code.toLowerCase();
System.out.println("用户的验证码:"+receivedCode);
return !sessionCode.equals("") && !receivedCode.equals("") && sessionCode.equals(receivedCode);
} catch (Exception e) {
return false;
}
}
}
进行效验
postman发送请求
控制台输出结果
发送验证码效验请求
第一次错误尝试
第二次正确尝试
控制台输出结果
完成