Full Spring与Quartz集成,实现实时通知电子邮件
我目前正在用spring boot开发一个应用程序,它允许用户创建约会。因此,约会基本上有startDateTime和endDateTime字段+电子邮件。创建约会会在MySql数据库的约会表中添加新行 我想做的是在数据库中定义的startDateTime前一小时通过电子邮件通知用户。我在寻找解决办法,但没有找到。我发现jobs(springbatch)可以做到这一点,但是jobs依赖于频率检查(天、周、月),我要找的是实时通知。欢迎为实现该任务的解决方案提供任何帮助或指导Full Spring与Quartz集成,实现实时通知电子邮件,spring,spring-boot,notifications,quartz-scheduler,Spring,Spring Boot,Notifications,Quartz Scheduler,我目前正在用spring boot开发一个应用程序,它允许用户创建约会。因此,约会基本上有startDateTime和endDateTime字段+电子邮件。创建约会会在MySql数据库的约会表中添加新行 我想做的是在数据库中定义的startDateTime前一小时通过电子邮件通知用户。我在寻找解决办法,但没有找到。我发现jobs(springbatch)可以做到这一点,但是jobs依赖于频率检查(天、周、月),我要找的是实时通知。欢迎为实现该任务的解决方案提供任何帮助或指导 问候语您可以使用调度
问候语您可以使用调度库,例如,提供与Spring framework的轻松集成 将约会保存到数据库中后,将在理想的时间(例如,开始日期前一小时)安排“发送电子邮件”作业 “发送电子邮件”作业必须实现
org.quartz.job
,更具体地说是execute
方法,在该方法中,您可以使用您的Autowired
sendmailservice
实现
@Service
public class SchedulingServiceImpl implements SchedulingService {
@Autowired
private Scheduler scheduler;
@Override
public void startScheduler() throws SchedulerException {
if (!scheduler.isStarted()) {
scheduler.start();
}
}
@Override
public void standbyScheduler() throws SchedulerException {
if (!scheduler.isInStandbyMode()) {
scheduler.standby();
}
}
@Override
public void shutdownScheduler() throws SchedulerException {
if (!scheduler.isShutdown()) {
scheduler.shutdown();
}
}
@Override
public void scheduleJob(JobDetail jobDetail, Trigger trigger) throws SchedulerException {
scheduler.scheduleJob(jobDetail, trigger);
}
}
在下面,您可以找到一个(几乎)完整的示例,说明如何在代码中实现这样的需求
更新-计划作业的代码
首先,我们定义一个SchedulingService
接口
public interface SchedulingService {
startScheduler() throws SchedulerException;
void standbyScheduler() throws SchedulerException;
void shutdownScheduler() throws SchedulerException;
void scheduleJob(JobDetail jobDetail, Trigger trigger) throws SchedulerException;
}
以及相关的实施
@Service
public class SchedulingServiceImpl implements SchedulingService {
@Autowired
private Scheduler scheduler;
@Override
public void startScheduler() throws SchedulerException {
if (!scheduler.isStarted()) {
scheduler.start();
}
}
@Override
public void standbyScheduler() throws SchedulerException {
if (!scheduler.isInStandbyMode()) {
scheduler.standby();
}
}
@Override
public void shutdownScheduler() throws SchedulerException {
if (!scheduler.isShutdown()) {
scheduler.shutdown();
}
}
@Override
public void scheduleJob(JobDetail jobDetail, Trigger trigger) throws SchedulerException {
scheduler.scheduleJob(jobDetail, trigger);
}
}
然后在AppointmentServiceImpl
中,我们有一个方法createAppointment()
,它调用scheduleSendEmailJob()
类sendmailjob
是Job
接口的实现,负责使用相关服务发送电子邮件
更新-将参数从调度方法传递到实际作业执行的代码
对于传递参数,将使用jobDataMap。例如:
public class SendEmailJob implements Job {
@Autowired
private AppointmentService appointmentService;
@Autowired
private SendEmailService sendEmailService;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
// Retrieving passed parameters
Long appointmentId = (Long) jobDataMap.get("appointmentId");
Appointment appointment = appointmentService.findById(appointmentId);
// Send email
sendEmailService.sendEmail(appointment);
}
}
注意:约会对象也可以从调度方法传递到实际作业执行,您只需传递:
jobDetail.getJobDataMap().put("appointment", appointment);
并获得:
// Retrieving passed parameters
Appointment appointment = (Appointment) jobDataMap.get("appointment");
更新-配置代码
Beanscheduler
在负责初始化的@Configuration
类中定义
调度配置
类定义为:
@Configuration
public class SchedulingConfiguration {
@Autowired
private ApplicationContext applicationContext;
@Bean
public Scheduler scheduler() throws SchedulerException, IOException {
StdSchedulerFactory factory = new StdSchedulerFactory();
factory.initialize(new ClassPathResource("properties/quartz.properties").getInputStream());
Scheduler scheduler = factory.getScheduler();
scheduler.setJobFactory(springBeanJobFactory());
return scheduler;
}
@Bean
public SpringBeanJobFactory springBeanJobFactory() {
AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
}
我们的quartz.properties
文件位于resources/properties
文件夹中。请注意,作业持久性数据库是一个Oracle实例
# Configure Main Scheduler Properties
org.quartz.scheduler.instanceName = AppScheduler
org.quartz.scheduler.instanceId = AUTO
# Configure ThreadPool
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
# Configure JobStore
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass =
org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.jobStore.tablePrefix = APP.QRTZ_
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource = appDs
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
# Configure Datasources
org.quartz.dataSource.appDs.driver = oracle.jdbc.driver.OracleDriver
org.quartz.dataSource.appDs.URL = jdbc:oracle:thin:@dbsrv:1521:appdb
org.quartz.dataSource.appDs.user = db_user
org.quartz.dataSource.appDs.password = db_pwd
org.quartz.dataSource.appDs.maxConnections = 5
org.quartz.dataSource.appDs.validationQuery = select 0 from dual
最后一步是在应用程序上下文初始化中调用调度程序方法,如下所示(请注意SchedulingService
中添加的方法):
注意:SchedulingContextListener
应在应用程序初始化中的servletContext
中注册,具体取决于Spring配置的定义方式,可以使用Spring引导,也可以使用传统的Spring MVC配置
希望对您有所帮助。您可以使用调度库,例如,提供与Spring framework的轻松集成 将约会保存到数据库中后,将在理想的时间(例如,开始日期前一小时)安排“发送电子邮件”作业 “发送电子邮件”作业必须实现
org.quartz.job
,更具体地说是execute
方法,在该方法中,您可以使用您的Autowired
sendmailservice
实现
@Service
public class SchedulingServiceImpl implements SchedulingService {
@Autowired
private Scheduler scheduler;
@Override
public void startScheduler() throws SchedulerException {
if (!scheduler.isStarted()) {
scheduler.start();
}
}
@Override
public void standbyScheduler() throws SchedulerException {
if (!scheduler.isInStandbyMode()) {
scheduler.standby();
}
}
@Override
public void shutdownScheduler() throws SchedulerException {
if (!scheduler.isShutdown()) {
scheduler.shutdown();
}
}
@Override
public void scheduleJob(JobDetail jobDetail, Trigger trigger) throws SchedulerException {
scheduler.scheduleJob(jobDetail, trigger);
}
}
在下面,您可以找到一个(几乎)完整的示例,说明如何在代码中实现这样的需求
更新-计划作业的代码
首先,我们定义一个SchedulingService
接口
public interface SchedulingService {
startScheduler() throws SchedulerException;
void standbyScheduler() throws SchedulerException;
void shutdownScheduler() throws SchedulerException;
void scheduleJob(JobDetail jobDetail, Trigger trigger) throws SchedulerException;
}
以及相关的实施
@Service
public class SchedulingServiceImpl implements SchedulingService {
@Autowired
private Scheduler scheduler;
@Override
public void startScheduler() throws SchedulerException {
if (!scheduler.isStarted()) {
scheduler.start();
}
}
@Override
public void standbyScheduler() throws SchedulerException {
if (!scheduler.isInStandbyMode()) {
scheduler.standby();
}
}
@Override
public void shutdownScheduler() throws SchedulerException {
if (!scheduler.isShutdown()) {
scheduler.shutdown();
}
}
@Override
public void scheduleJob(JobDetail jobDetail, Trigger trigger) throws SchedulerException {
scheduler.scheduleJob(jobDetail, trigger);
}
}
然后在AppointmentServiceImpl
中,我们有一个方法createAppointment()
,它调用scheduleSendEmailJob()
类sendmailjob
是Job
接口的实现,负责使用相关服务发送电子邮件
更新-将参数从调度方法传递到实际作业执行的代码
对于传递参数,将使用jobDataMap。例如:
public class SendEmailJob implements Job {
@Autowired
private AppointmentService appointmentService;
@Autowired
private SendEmailService sendEmailService;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
// Retrieving passed parameters
Long appointmentId = (Long) jobDataMap.get("appointmentId");
Appointment appointment = appointmentService.findById(appointmentId);
// Send email
sendEmailService.sendEmail(appointment);
}
}
注意:约会对象也可以从调度方法传递到实际作业执行,您只需传递:
jobDetail.getJobDataMap().put("appointment", appointment);
并获得:
// Retrieving passed parameters
Appointment appointment = (Appointment) jobDataMap.get("appointment");
更新-配置代码
Beanscheduler
在负责初始化的@Configuration
类中定义
调度配置
类定义为:
@Configuration
public class SchedulingConfiguration {
@Autowired
private ApplicationContext applicationContext;
@Bean
public Scheduler scheduler() throws SchedulerException, IOException {
StdSchedulerFactory factory = new StdSchedulerFactory();
factory.initialize(new ClassPathResource("properties/quartz.properties").getInputStream());
Scheduler scheduler = factory.getScheduler();
scheduler.setJobFactory(springBeanJobFactory());
return scheduler;
}
@Bean
public SpringBeanJobFactory springBeanJobFactory() {
AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
}
我们的quartz.properties
文件位于resources/properties
文件夹中。请注意,作业持久性数据库是一个Oracle实例
# Configure Main Scheduler Properties
org.quartz.scheduler.instanceName = AppScheduler
org.quartz.scheduler.instanceId = AUTO
# Configure ThreadPool
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
# Configure JobStore
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass =
org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.jobStore.tablePrefix = APP.QRTZ_
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource = appDs
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
# Configure Datasources
org.quartz.dataSource.appDs.driver = oracle.jdbc.driver.OracleDriver
org.quartz.dataSource.appDs.URL = jdbc:oracle:thin:@dbsrv:1521:appdb
org.quartz.dataSource.appDs.user = db_user
org.quartz.dataSource.appDs.password = db_pwd
org.quartz.dataSource.appDs.maxConnections = 5
org.quartz.dataSource.appDs.validationQuery = select 0 from dual
最后一步是在应用程序上下文初始化中调用调度程序方法,如下所示(请注意SchedulingService
中添加的方法):
注意:SchedulingContextListener
应在应用程序初始化中的servletContext
中注册,具体取决于Spring配置的定义方式,可以使用Spring引导,也可以使用传统的Spring MVC配置
希望对您有所帮助。是否有源代码示例,以了解在约会中执行save方法后如何安排作业?用建议的示例实现代码更新我的答案将非常有用。看一看。希望能有帮助。谢谢你的回复。现在更清楚了,但我仍然有一个问题:当使用JobBuilder创建jobdetail时,您只定义类型的类job,但是这个类如何知道我们为哪个约会创建job,从而检索要向其发送电子邮件的合适人员的电子邮件?另外,如果你也能发布conf,那也很好,因为在谷歌,他们经常谈论基于属性文件的配置,这非常令人困惑。谢谢,againI添加了您回复中描述的最后一个类,但仍然不起作用。所以我调试了应用程序,发现listenn