springboot-动态定时任务

需求:日历小程序项目中,日程提醒可以由用户自己来指定时间,如某天某时某分执行提醒,还可以随时修改这个设置。

(定时器是项目启动时就定义好的任务,而这里需要让用户动态设置定时任务)

 

  1. 添加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>

 

  1. 添加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;
    }

}

  1. 添加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();
    }

}

 

 

  1. 添加一个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());
        }
    }
}

 

  1. 添加一个实体类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;
    }
}

 

 

  1. 添加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;
    }
}

 

  1. 封装一个业务类

因为一个日程有多个提醒,添加修改删除提醒都是以日程为单位的,因此进行封装。

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);
        }
    }
}

 

  1. 日期和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;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41665356/article/details/89182976