基于Spring Boot实现许可证到期前定时发送提醒邮件API
实现许可证到期提前提醒的Spring Boot方案
1. 核心依赖配置
在pom.xml中引入必要依赖,覆盖邮件发送、定时调度、数据持久化需求:
<dependencies> <!-- Spring Mail 邮件发送 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <!-- Spring Scheduling 定时任务 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-scheduling</artifactId> </dependency> <!-- Spring Data JPA 数据持久化 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- MySQL驱动(按需替换为其他数据库驱动) --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> </dependencies>
2. 许可证实体设计
创建License实体存储核心信息,包含到期日期、提前提醒月数、通知邮箱等字段:
import jakarta.persistence.*; import java.time.LocalDate; @Entity @Table(name = "licenses") public class License { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String userId; private LocalDate expiryDate; private Integer reminderMonths; // 提前提醒的月数 private String notifyEmail; private boolean reminderSent; // 标记是否已发送提醒,避免重复触发 // Getters & Setters }
3. 邮件发送服务
实现基础邮件发送逻辑,封装为可复用的Service:
import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.stereotype.Service; @Service public class EmailService { private final JavaMailSender mailSender; public EmailService(JavaMailSender mailSender) { this.mailSender = mailSender; } public void sendExpiryReminder(String toEmail, LocalDate expiryDate) { SimpleMailMessage message = new SimpleMailMessage(); message.setTo(toEmail); message.setSubject("[重要提醒] 您的许可证即将到期"); message.setText(String.format("您好,您的许可证将于%s到期,请及时办理续期或相关手续。", expiryDate)); mailSender.send(message); } }
4. 定时任务实现
使用@Scheduled注解实现每日检查,筛选出需要发送提醒的许可证:
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.time.LocalDate; import java.util.List; @Component public class LicenseReminderTask { private final LicenseRepository licenseRepo; private final EmailService emailService; public LicenseReminderTask(LicenseRepository licenseRepo, EmailService emailService) { this.licenseRepo = licenseRepo; this.emailService = emailService; } // 每天凌晨1点执行检查 @Scheduled(cron = "0 0 1 * * ?") public void checkAndSendReminders() { LocalDate today = LocalDate.now(); // 查询未发送提醒且当前日期等于(到期日-提前月数)的许可证 List<License> targetLicenses = licenseRepo.findNeedRemindLicenses(today); for (License license : targetLicenses) { try { emailService.sendExpiryReminder(license.getNotifyEmail(), license.getExpiryDate()); license.setReminderSent(true); licenseRepo.save(license); } catch (Exception e) { // 捕获邮件发送异常,避免中断后续任务 e.printStackTrace(); } } } }
同时在启动类添加@EnableScheduling注解开启定时任务功能。
5. 数据库查询方法
在LicenseRepository中定义自定义查询,匹配需要触发提醒的许可证:
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import java.time.LocalDate; import java.util.List; public interface LicenseRepository extends JpaRepository<License, Long> { // MySQL适配的日期计算查询 @Query("SELECT l FROM License l WHERE l.reminderSent = false " + "AND l.expiryDate.minusMonths(l.reminderMonths) = :today") List<License> findNeedRemindLicenses(@Param("today") LocalDate today); }
注:不同数据库的日期函数语法不同,H2可替换为DATEADD('MONTH', -l.reminderMonths, l.expiryDate),需根据实际使用的数据库调整。
6. API接口实现
提供创建许可证的接口,接收用户设置的到期日期、提前提醒月数等参数:
import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/licenses") public class LicenseController { private final LicenseRepository licenseRepo; public LicenseController(LicenseRepository licenseRepo) { this.licenseRepo = licenseRepo; } @PostMapping public ResponseEntity<License> createLicense(@RequestBody License license) { license.setReminderSent(false); // 默认标记未发送提醒 License savedLicense = licenseRepo.save(license); return ResponseEntity.ok(savedLicense); } }
7. 邮件服务器配置
在application.properties中配置邮件发送服务器信息(以QQ邮箱为例):
spring.mail.host=smtp.qq.com spring.mail.port=587 spring.mail.username=your-email@qq.com spring.mail.password=your-authorization-code spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true
关键注意事项
- 重复发送防护:通过
reminderSent字段标记已发送状态,避免同一许可证多次触发提醒。 - 时区一致性:确保服务器时区与业务时区一致,避免日期计算偏差。
- 异常容错:在邮件发送逻辑中添加异常捕获,防止单个邮件发送失败导致整个定时任务中断。
- 扩展性优化:若需支持多种提醒周期(如提前1天、1周),可将
reminderMonths扩展为reminderType(月/周/天)+reminderValue的组合字段。
内容的提问来源于stack exchange,提问作者Cpt_Levi
相关产品推荐
相关产品推荐

