Java实现邮箱修改密码
前置设置
- 存储邮箱以及验证码需要提前配置好redis
maven中加入redis配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
application.yml中加入redis的配置
spring:
data:
redis:
host: localhost # Redis 服务器地址
port: 6379 # Redis 端口号
password: '' # Redis 密码(如果未设置密码,可留空)
lettuce:
pool:
max-active: 8 # 最大连接数
max-idle: 8 # 最大空闲连接数
min-idle: 0 # 最小空闲连接数
RedisCache
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
/**
* @Title: RedisCache
* @Author David
* @Package com.work.spring.springbootwork.config
* @Date 2024/9/11 下午1:34
*/
@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component
public class RedisCache
{
@Autowired
public RedisTemplate redisTemplate;
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 时间
* @param timeUnit 时间颗粒度
*/
public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit)
{
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}
/**
* 判断 key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public Boolean hasKey(String key)
{
return redisTemplate.hasKey(key);
}
/**
* 获得缓存的基本对象。
*
* @param key 缓存键值
* @return 缓存键值对应的数据
*/
public <T> T getCacheObject(final String key)
{
ValueOperations<String, T> operation = redisTemplate.opsForValue();
return operation.get(key);
}
/**
* 删除单个对象
*
* @param key
*/
public boolean deleteObject(final String key)
{
return redisTemplate.delete(key);
}
}
SpringBoot内置包解决
application.yml中加入mail的配置
spring:
mail:
host: smtp.163.com # 你邮箱的smtp地址
username: xxxxxxxx@163.com # 申请了smtp的邮箱
password: xxxxxxxxxxx # SMTP服务的秘钥
properties:
mail:
smtp:
auth: true
starttls:
enable: true
maven中加入mail配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
创建测试服务类MailServiceImp
概述:
generateSixDigitCode
用于生成验证码。checkEmail
检查邮箱是否存在。sendMail
用于向用户发送包含验证码的邮件。resetPassword
处理用户重置密码的逻辑。updateEmailList
是一个定时任务,用于每小时更新 Redis 中的学生邮箱数据。
1. generateSixDigitCode
方法
- 功能:生成一个六位的随机数字验证码。
- 说明:该方法使用随机数生成器,生成一个包含六位数字的验证码。这个验证码通常用于身份验证,如重置密码时发送给用户。
2. checkEmail
方法
- 功能:检查给定的邮箱是否存在于 Redis 缓存中。
- 说明:该方法从 Redis 中获取存储的学生邮箱列表,并遍历它以检查给定邮箱是否在列表中。如果找到了对应的邮箱,则返回
true
,否则返回false
。这确保了只有系统中存在的邮箱才可以发送验证码。
3. sendMail
方法
- 功能:向指定邮箱发送验证码邮件。
- 说明:首先,调用
checkEmail
验证邮箱是否存在。如果邮箱存在,生成验证码并通过邮件发送给用户。邮件内容包含验证码及其有效期(通常为 15 分钟)。邮件发送后,验证码会存入 Redis,并设置过期时间为 15 分钟。这确保了验证码的时效性。
4. resetPassword
方法
- 功能:根据用户输入的验证码和邮箱重置密码。
- 说明:该方法首先检查验证码是否已过期(通过检查 Redis 中是否有与该邮箱关联的验证码)。如果验证码有效,且与用户输入的验证码匹配,则认为用户身份验证成功,可以进行密码重置操作。操作成功后,系统会删除 Redis 中的验证码记录,以确保每个验证码只能使用一次。
5. updateEmailList
方法
- 功能:定时从数据库中获取学生邮箱列表并将其缓存到 Redis 中。
- 说明:这是一个定时任务,每隔一小时从数据库中获取学生邮箱列表,并将其存储到 Redis 中。这样,系统可以确保每次发送验证码时都能使用最新的邮箱数据。同时,Redis 中的邮箱列表过期时间被设置为两小时,以保证数据的及时性并避免可能的缓存过期问题。
import com.work.spring.springbootwork.config.RedisCache;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* @Title: MailServiceImp
* @Author David
* @Package com.work.spring.springbootwork.service
* @Date 2024/9/11 下午4:40
*/
@Service
public class MailServiceImp {
@Resource
private JavaMailSender mailSender;
@Value("${spring.mail.username}")
private String from;
@Resource
private RedisCache redisCache;
// 生成六位数字验证码
public String generateSixDigitCode() {
String digits = "0123456789";
StringBuilder code = new StringBuilder();
Random random = new Random();
for (int i = 0; i < 6; i++) {
code.append(digits.charAt(random.nextInt(digits.length())));
}
return code.toString();
}
// 检查邮箱是否在 Redis 中
public boolean checkEmail(String email) {
String[] studentEmailSet = redisCache.getCacheObject("Student_Email");
for (Object str : studentEmailSet) {
if (str.equals(email)) {
return true;
}
}
return false;
}
// 发送验证码邮件
public String sendMail(String email) {
if (!checkEmail(email)) {
return "邮箱不存在";
}
SimpleMailMessage message = new SimpleMailMessage();
message.setSubject("【验证码】");
String code = generateSixDigitCode();
// 邮件内容
message.setText("您好,\n\n您正在尝试重置密码,您的验证码是:" + code +
"。\n验证码有效期为15分钟,请及时使用。\n\n如果非本人操作,请忽略此邮件,感谢您的理解!");
message.setTo(email);
message.setFrom(from);
// 发送邮件
mailSender.send(message);
// 将验证码存入Redis,设置15分钟过期
redisCache.setCacheObject(email, code, 15, TimeUnit.MINUTES);
return "邮件发送成功";
}
// 重置密码逻辑
public String resetPassword(String email, String code, String password) {
// 检查验证码是否过期
if (!redisCache.hasKey(email)) {
return "验证码已过期,请重新获取";
}
// 获取Redis中的验证码
String cachedCode = redisCache.getCacheObject(email);
// 验证码匹配
if (cachedCode != null && cachedCode.equals(code)) {
// 重置密码逻辑(此处可以加入实际的重置密码功能)
redisCache.deleteObject(email); // 删除缓存中的验证码
return "密码重置成功,新密码为:" + password;
}
return "验证码错误或已过期,请重新尝试";
}
// 定时任务:每小时更新学生邮箱数据
@Scheduled(fixedDelay = 3600000L) // 1小时执行一次(单位:毫秒, 1小时 = 60 * 60 * 1000)
public void updateEmailList() {
// 模拟从数据库中获取邮箱
List<String> emailList = new ArrayList<>();
emailList.add("xxxxxx@163.com");
HashSet<Object> studentEmailSet = new HashSet<>(emailList);
String[] emailArray = studentEmailSet.toArray(new String[studentEmailSet.size()]);
// 将邮箱存入Redis,设置2小时过期,防止定时任务运行慢了
redisCache.setCacheObject("Student_Email", emailArray, 2, TimeUnit.HOURS);
}
}
创建测试控制类SpringMailController
import com.work.spring.springbootwork.service.MailServiceImp;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @Title: SpringMailController
* @Author David
* @Package com.work.spring.springbootwork.controller
* @Date 2024/9/11 下午1:05
*/
@RestController
public class SpringMailController {
@Resource
private MailServiceImp mailService;
// 发送邮件请求
@GetMapping("/sendMail")
public String sendMail(@RequestParam("email") String email) {
return mailService.sendMail(email);
}
// 重置密码请求
@GetMapping("/resetpassword")
public String resetPassword(@RequestParam("email") String email,
@RequestParam("code") String code,
@RequestParam("password") String password) {
return mailService.resetPassword(email, code, password);
}
}
JavaEE自带包解决
逻辑与SpringBoot的相同,下面只给出服务层代码基础业务的实现
MailServiceImp
import jakarta.mail.Message;
import jakarta.mail.Session;
import jakarta.mail.Transport;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import org.eclipse.angus.mail.util.MailSSLSocketFactory;
import org.springframework.stereotype.Service;
import java.util.Properties;
import java.util.Random;
/**
* @Title: MailServiceImp
* @Author David
* @Package com.work.spring.springbootwork.service
* @Date 2024/9/10 下午9:38
* @description: 模拟发送邮件的服务类
*/
@Service
public class MailServiceImp {
// 邮箱服务器的配置
private static final String MAIL_HOST = "smtp.163.com";
private static final String MAIL_USERNAME = "xxxxxx@163.com"; // 发件人邮箱
private static final String MAIL_PASSWORD = "xxxxxxxxxxxxxxxx"; // 授权码(非登录密码)
/**
* 发送邮件
* @param recipientEmail 收件人邮箱
* @param verificationCode 验证码
* @return 发送状态
*/
public String sendMail(String recipientEmail, String verificationCode) throws Exception {
Properties prop = new Properties();
// 开启debug调试,以便在控制台查看
prop.setProperty("mail.debug", "true");
// 设置邮件服务器主机名
prop.setProperty("mail.host", MAIL_HOST);
// 发送服务器需要身份验证
prop.setProperty("mail.smtp.auth", "true");
// 发送邮件协议名称
prop.setProperty("mail.transport.protocol", "smtp");
// 开启SSL加密
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable", "true");
prop.put("mail.smtp.ssl.socketFactory", sf);
// 创建邮件会话
Session session = Session.getInstance(prop);
Transport transport = session.getTransport();
// 连接邮件服务器,使用发件人邮箱及授权码
transport.connect(MAIL_HOST, MAIL_USERNAME, MAIL_PASSWORD);
// 创建邮件
Message message = createSimpleMail(session, recipientEmail, verificationCode);
// 发送邮件
transport.sendMessage(message, message.getAllRecipients());
transport.close();
return "邮件发送成功";
}
/**
* 创建一个包含验证码的邮件
* @param session 邮件会话
* @param recipientEmail 收件人邮箱
* @param verificationCode 验证码
* @return 邮件对象
* @throws Exception 创建邮件异常
*/
private MimeMessage createSimpleMail(Session session, String recipientEmail, String verificationCode) throws Exception {
// 创建邮件对象
MimeMessage message = new MimeMessage(session);
// 设置发件人
message.setFrom(new InternetAddress(MAIL_USERNAME));
// 设置收件人
message.setRecipient(Message.RecipientType.TO, new InternetAddress(recipientEmail));
// 设置邮件标题
message.setSubject("您的验证码");
// 设置邮件内容
message.setContent("您好,\n\n您的验证码是:" + verificationCode + "。\n请在1分钟内使用。", "text/html;charset=UTF-8");
return message;
}
/**
* 生成六位验证码
* @return 验证码
*/
public String generateSixDigitCode() {
String[] characters = {
"q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "a", "s", "d", "f", "g", "h", "j", "k", "l", "z", "x", "c", "v", "b", "n", "m",
"A", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "A", "S", "D", "F", "G", "H", "J", "K", "L", "Z", "X", "C", "V", "B", "N", "M",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
};
StringBuilder code = new StringBuilder();
Random random = new Random();
for (int i = 0; i < 6; i++) {
code.append(characters[random.nextInt(characters.length)]);
}
return code.toString();
}
}
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 David
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果