Java Spring项目实现用户邮件重发1分钟冷却间隔的方案问询
1分钟邮件发送间隔限制实现方案
实现思路
核心是记录每个用户上次发送同类邮件的时间,每次收到发信请求时先校验时间差,只有间隔≥60秒才执行发信逻辑,同时更新最后发信时间。
具体实现步骤
步骤1:扩展User实体,新增最后发信时间字段
在你的User类中增加lastVerificationEmailSendTime字段,用于记录最近一次发送验证邮件的时间:
import java.time.LocalDateTime; public class User { // 原有字段省略 private LocalDateTime lastVerificationEmailSendTime; // 新增getter、setter public LocalDateTime getLastVerificationEmailSendTime() { return lastVerificationEmailSendTime; } public void setLastVerificationEmailSendTime(LocalDateTime lastVerificationEmailSendTime) { this.lastVerificationEmailSendTime = lastVerificationEmailSendTime; } }
记得同步更新数据库User表,增加对应的datetime类型字段。
步骤2:修改发信业务逻辑,增加间隔校验
修改userService.sendVerificationEmail方法,加入时间差校验逻辑,仅符合条件时才执行发信:
import java.time.Duration; import java.time.LocalDateTime; import org.springframework.mail.MailException; import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; // 其他依赖省略 public void sendVerificationEmail(User user, String to) throws RuntimeException { LocalDateTime now = LocalDateTime.now(); // 校验发信间隔 LocalDateTime lastSendTime = user.getLastVerificationEmailSendTime(); if (lastSendTime != null) { long secondsBetween = Duration.between(lastSendTime, now).getSeconds(); if (secondsBetween < 60) { // 间隔不足60秒,抛出异常给上层处理 throw new RuntimeException("操作过于频繁,请" + (60 - secondsBetween) + "秒后再试"); } } // 原有发信逻辑 SimpleMailMessage simpleMailMessage = new SimpleMailMessage(); simpleMailMessage.setFrom(from); simpleMailMessage.setTo(to); simpleMailMessage.setSubject(subject); simpleMailMessage.setText(content + "http://localhost:8080/confirm-email?id=" + user.getId()); try { mailSender.send(simpleMailMessage); // 发信成功后更新最后发信时间,同步到数据库 user.setLastVerificationEmailSendTime(now); userRepository.save(user); } catch (MailException mailException) { // 发信失败的异常处理,可根据业务需求打日志、抛异常 throw new RuntimeException("邮件发送失败,请稍后重试"); } }
步骤3:修改Controller层,增加异常处理
调整Controller代码,捕获业务层抛出的异常,返回对应提示:
@RequestMapping( value = "/resendMail", method = RequestMethod.POST) public ApiException sendMail(@Valid @RequestBody EmailRequest emailRequest) { ApiException response = null; User user = userRepository.findByEmail(emailRequest.getEmail()); if(user != null) { try { userService.sendVerificationEmail(user, user.getEmail()); response = new ApiException("链接已发送到该邮箱", null, HttpStatus.OK); } catch (RuntimeException e) { // 捕获业务层抛出的间隔不足、发信失败异常 response = new ApiException(e.getMessage(), null, HttpStatus.BAD_REQUEST); } } else { response = new ApiException("用户不存在", null, HttpStatus.NOT_FOUND); } return response; }
扩展优化建议
- 如果是分布式部署场景,可使用Redis存储用户最后发信时间,避免多节点数据库同步延迟问题,同时可设置key自动过期(过期时间60秒),无需持久化存储该字段
- 高并发场景下可增加分布式锁,避免同一用户短时间内多次请求穿透校验
- 如果不需要长期存储发信时间,也可使用Guava Cache等本地缓存实现(仅适用于单机部署)
内容的提问来源于stack exchange,提问作者Aleyna
相关产品推荐
相关产品推荐

