需求:日历小程序项目中,日程提醒可以由用户自己来指定时间,如某天某时某分执行提醒,还可以随时修改这个设置。
(定时器是项目启动时就定义好的任务,而这里需要让用户动态设置定时任务)
- 添加maven
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
- 添加MyJobFactory
package com.quartz;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;
@Component
public class MyJobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
// 调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
// 进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
- 添加Scheduler的bean类
package com.quartz;
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
@Configuration
public class QuartzConfig {
@Autowired
private MyJobFactory myJobFactory;
@Bean
public SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
schedulerFactoryBean.setJobFactory(myJobFactory);
System.out.println("myJobFactory:"+myJobFactory);
return schedulerFactoryBean;
}
@Bean
public Scheduler scheduler() {
return schedulerFactoryBean().getScheduler();
}
}
- 添加一个job类
package com.quartz;
import org.quartz.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
public class NotifyJob implements Job {
private SimpleDateFormat dateFormat() {
return new SimpleDateFormat("HH:mm:ss");
}
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
Scheduler scheduler = context.getScheduler();
Trigger trigger = context.getTrigger();
JobDetail jobDetail = context.getJobDetail();
Job job = context.getJobInstance();
String jobstring = job.toString();
System.out.println(dateFormat().format(new Date()) + " ------------ " + jobDetail.getKey() + " " + trigger.getKey());
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
Notify notify = (Notify) dataMap.get("data");
Iterator iter = dataMap.entrySet().iterator();
if (notify != null) {
System.out.println(notify.toString());
}
}
}
- 添加一个实体类Notify
用于参数传递
package com.quartz;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.validation.Constraint;
import java.util.List;
@Getter
@Setter
@ToString
public class Notify {
Long eventId;// 日程id
Long toUserId;// 目标用户id
String content;// 消息内容
List<String> cronList;// 提醒时间列表
public Notify(Long eventId, Long toUserId, String content, List<String> cronList){
this.eventId = eventId;
this.toUserId = toUserId;
this.content = content;
this.cronList = cronList;
}
}
- 添加ScheduleManager类
package com.quartz;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Service
/**
* 任务调度类
*/
public class ScheduleManager {
@Autowired
private Scheduler scheduler;
/**
* 功能: 添加一个定时任务
* @param jobName 任务名
* @param jobGroupName 任务组名
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param jobClass 任务的类类型 eg:TimedMassJob.class
* @param cron 时间设置 表达式,参考quartz说明文档
* @param notify 任务参数
*/
public void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName,
Class jobClass, String cron, Notify notify) {
try {
// 任务名,任务组,任务执行类
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();
if (notify != null) {
jobDetail.getJobDataMap().put("data", notify);
}
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
CronTrigger trigger = (CronTrigger) triggerBuilder.build();
// 调度容器设置JobDetail和Trigger
scheduler.scheduleJob(jobDetail, trigger);
// 启动
if (!scheduler.isShutdown()) {
scheduler.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 功能:修改一个任务的触发时间
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param cron 时间设置,参考quartz说明文档
*/
public void modifyJobTime( String triggerName, String triggerGroupName, String cron) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(cron)) {
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
trigger = (CronTrigger) triggerBuilder.build();
// 方式一 :修改一个任务的触发时间
scheduler.rescheduleJob(triggerKey, trigger);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 功能: 移除一个任务
*
* @param jobName
* @param jobGroupName
* @param triggerName
* @param triggerGroupName
*/
public void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
// 停止触发器
scheduler.pauseTrigger(triggerKey);
// 移除触发器
scheduler.unscheduleJob(triggerKey);
// 删除任务
scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 功能:启动所有定时任务
*/
public void startJobs() {
try {
scheduler.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 功能:关闭所有定时任务
*/
public void shutdownJobs() {
try {
if (!scheduler.isShutdown()) {
scheduler.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void get(){
// 希望查一下都有哪些任务在列表中等待,但是没成功
try {
List<String> list = scheduler.getTriggerGroupNames();
System.out.println(list.toString());
String [] sch = scheduler.getContext().getKeys();
Map<String,Object> map = scheduler.getContext().getWrappedMap();
List<String> list2 = scheduler.getCalendarNames();
List<String> list3 = scheduler.getJobGroupNames();
ListenerManager listenerManager = scheduler.getListenerManager();
for (int i = 0; i < list.size(); ++i){
String groupName = list.get(i);
Set<JobKey> jobKey = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName));
for (JobKey jk: jobKey) {
String jobName = jk.getName();
String jobGroup = jk.getGroup();
List<Trigger> triggers = (List<Trigger>) scheduler.getTriggersOfJob(jk);
System.out.println("[jobName] : " + jobName + " [groupName] : " + jobGroup );
}
}
System.out.println("...");
} catch (SchedulerException e) {
e.printStackTrace();
}
}
public boolean isExist(String triggerName, String triggerGroupName){
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if (trigger != null) {
return true;
}
} catch (SchedulerException e) {
e.printStackTrace();
}
return false;
}
}
- 封装一个业务类
因为一个日程有多个提醒,添加修改删除提醒都是以日程为单位的,因此进行封装。
package com.quartz;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class EventRemmindService {
@Resource
private ScheduleManager scheduleManager;
public void addOrUpdate(Notify notify){
String triggerName = "trigger_" + notify.getEventId() + "_" + 0;
String triggerGroupName = "event_TriggerGroup";
if (scheduleManager.isExist(triggerName, triggerGroupName)){
delete(notify);
}
add(notify);
}
public void delete(Notify notify){
Long eventId = notify.getEventId();
// 同一日程在一小时类的提醒不会超过5个
for (int i = 0; i < 5; ++i){
String jobName = "job_" + eventId + "_" + i;
String jobGroupName = "event_jobGroup" ;
String triggerName = "trigger_" + eventId + "_" + i;
String triggerGroupName = "event_TriggerGroup";
if (!scheduleManager.isExist(triggerName, triggerGroupName)){
break;
}
scheduleManager.removeJob(jobName,jobGroupName,triggerName,triggerGroupName);
}
}
public void add(Notify notify){
Long eventId = notify.getEventId();
for (int i = 0; i < notify.cronList.size(); ++i){
String jobName = "job_" + eventId + "_" + i;
String jobGroupName = "event_jobGroup" ;
String triggerName = "trigger_" + eventId + "_" + i;
String triggerGroupName = "event_TriggerGroup";
String cron = notify.getCronList().get(i);//"6/10 * * * * ?";
scheduleManager.addJob(jobName,jobGroupName,triggerName,triggerGroupName, NotifyJob.class, cron, notify);
}
}
}
- 日期和cron转换类
package com.quartz;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 该类提供Quartz的cron表达式与Date之间的转换
* Created by zhanglei
*/
public class CronDateUtil {
private static final String CRON_DATE_FORMAT = "ss mm HH dd MM ? yyyy";
/***
*
* @param date 时间
* @return cron类型的日期
*/
public static String getCron(final Date date){
SimpleDateFormat sdf = new SimpleDateFormat(CRON_DATE_FORMAT);
String formatTimeStr = "";
if (date != null) {
formatTimeStr = sdf.format(date);
}
return formatTimeStr;
}
/***
*
* @param cron Quartz cron的类型的日期
* @return Date日期
*/
public static Date getDate(final String cron) {
if(cron == null) {
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat(CRON_DATE_FORMAT);
Date date = null;
try {
date = sdf.parse(cron);
} catch (ParseException e) {
return null;// 此处缺少异常处理,自己根据需要添加
}
return date;
}
}