You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 08:06:23