Java使用quartz实现任务调度定时任务

1、添加quartz依赖

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-quartz -->
 <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-quartz</artifactId>
       <version>2.5.4</version>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.10</version>
</dependency>

2、实现功能源码

2.1 CronTaskRegistrar  Cron任务注册器

package com.shucha.digitalportalbackstage.biz.task.dispatch;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.config.CronTask;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class CronTaskRegistrar implements DisposableBean {
    private final Map<Runnable, ScheduledTask> scheduledTasks = new ConcurrentHashMap<>(16);
    @Autowired
    private TaskScheduler taskScheduler;

    public TaskScheduler getScheduler() {
        return this.taskScheduler;
    }

    /**
     * 新增定时任务
     *
     * @param task
     * @param cronExpression
     */
    public void addCronTask(Runnable task, String cronExpression) {
        addCronTask(new CronTask(task, cronExpression));
    }

    public void addCronTask(CronTask cronTask) {
        if (cronTask != null) {
            Runnable task = cronTask.getRunnable();
            if (this.scheduledTasks.containsKey(task)) {
                removeCronTask(task);
            }
            this.scheduledTasks.put(task, scheduleCronTask(cronTask));
        }
    }

    /**
     * 移除定时任务
     *
     * @param task
     */
    public void removeCronTask(Runnable task) {
        ScheduledTask scheduledTask = this.scheduledTasks.remove(task);
        if (scheduledTask != null)
            scheduledTask.cancel();
    }

    public ScheduledTask scheduleCronTask(CronTask cronTask) {
        ScheduledTask scheduledTask = new ScheduledTask();
        scheduledTask.future = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());
        return scheduledTask;
    }

    @Override
    public void destroy() throws Exception {
        for (ScheduledTask task : this.scheduledTasks.values()) {
            task.cancel();
        }
        this.scheduledTasks.clear();
    }
}

2.2 ScheduledTask 计划任务

package com.shucha.digitalportalbackstage.biz.task.dispatch;

import java.util.concurrent.ScheduledFuture;

public class ScheduledTask {
    public volatile ScheduledFuture<?> future;
    /**
     * 取消定时任务
     */
    public void cancel() {
        ScheduledFuture<?> future = this.future;
        if (future != null) {
            future.cancel(true);
        }
    }
}

2.3 SchedulingRunnable 调度运行

package com.shucha.digitalportalbackstage.biz.task.dispatch;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.Objects;

public class SchedulingRunnable implements Runnable {
    private static final Logger logger = LoggerFactory.getLogger(SchedulingRunnable.class);
    private String beanName;
    private String methodName;
    private Object[] params;

    public SchedulingRunnable(String beanName, String methodName) {
        this(beanName, methodName, null);
    }

    public SchedulingRunnable(String beanName, String methodName, Object... params) {
        this.beanName = beanName;
        this.methodName = methodName;
        this.params = params;
    }

    @Override
    public void run() {
        logger.info("定时任务开始执行 - bean:{},方法:{},参数:{}", beanName, methodName, params);
        long startTime = System.currentTimeMillis();
        try {
            Object target = SpringContextUtils.getBean(beanName);
            Method method = null;
            if (null != params && params.length > 0) {
                Class<?>[] paramCls = new Class[params.length];
                for (int i = 0; i < params.length; i++) {
                    paramCls[i] = params[i].getClass();
                }
                method = target.getClass().getDeclaredMethod(methodName, paramCls);
            } else {
                method = target.getClass().getDeclaredMethod(methodName);
            }
            ReflectionUtils.makeAccessible(method);
            if (null != params && params.length > 0) {
                method.invoke(target, params);
            } else {
                method.invoke(target);
            }
        } catch (Exception ex) {
            logger.error(String.format("定时任务执行异常 - bean:%s,方法:%s,参数:%s ", beanName, methodName, params), ex);
        }
        long times = System.currentTimeMillis() - startTime;
        logger.info("定时任务执行结束 - bean:{},方法:{},参数:{},耗时:{} 毫秒", beanName, methodName, params, times);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        SchedulingRunnable that = (SchedulingRunnable) o;
        if (params == null) {
            return beanName.equals(that.beanName) &&
                    methodName.equals(that.methodName) &&
                    that.params == null;
        }
        return beanName.equals(that.beanName) &&
                methodName.equals(that.methodName) &&
                params.equals(that.params);
    }

    @Override
    public int hashCode() {
        if (params == null) {
            return Objects.hash(beanName, methodName);
        }
        return Objects.hash(beanName, methodName, params);
    }
}

2.4 SpringContextUtils 

package com.shucha.digitalportalbackstage.biz.task.dispatch;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringContextUtils implements ApplicationContextAware {
    private static ApplicationContext applicationContext = null;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringContextUtils.applicationContext == null) {
            SpringContextUtils.applicationContext = applicationContext;
        }
    }
    //获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
    //通过name获取 Bean.
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }
    //通过class获取Bean.
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }
    //通过name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }
}

2.5  QuartzConfig 配置和项目启动初始化

package com.shucha.digitalportalbackstage.biz.task.quartz.config;

import com.shucha.digitalportalbackstage.biz.model.QuartzJob;
import com.shucha.digitalportalbackstage.biz.service.QuartzJobService;
import com.shucha.digitalportalbackstage.biz.task.quartz.JobFactory;
import com.shucha.digitalportalbackstage.biz.task.quartz.service.QuartzService;
import org.quartz.Scheduler;
import org.quartz.ee.servlet.QuartzInitializerListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
import java.util.UUID;

@Configuration
public class QuartzConfig {
    @Autowired
    private JobFactory jobFactory;
    @Autowired
    private QuartzJobService quartzJobService;
    @Autowired
    private QuartzService quartzService;

    @Bean("schedulerFactory")
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        //设置调度类quartz属性
        schedulerFactoryBean.setQuartzProperties(quartzProperties());
        //设置jobFactory
        schedulerFactoryBean.setJobFactory(jobFactory);
        return schedulerFactoryBean;
    }

    @Bean
    public Properties quartzProperties() throws IOException {
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        //若不做额外配置,会有默认的配置文件加载 在jar org.quartz里面 有一份quartz.properties
        //propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
        propertiesFactoryBean.afterPropertiesSet();
        return propertiesFactoryBean.getObject();
    }

    @Bean
    public QuartzInitializerListener initializerListener() {
        return new QuartzInitializerListener();
    }

    @Bean("scheduler")
    public Scheduler scheduler() throws IOException {
        return schedulerFactoryBean().getScheduler();
    }

    @PostConstruct
    public void init() {
        List<QuartzJob> quartzJobList = quartzJobService.lambdaQuery().list();
        for (QuartzJob q : quartzJobList) {
            quartzService.addJob(q);
        }
    }

    private static String getUuid() {
        return UUID.randomUUID().toString().replace("-", "");
    }
}
QuartzJob实体类
package com.shucha.digitalportalbackstage.biz.model;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.sdy.common.model.BaseModel;
import com.sdy.common.utils.DateUtil;
import com.shucha.digitalportalbackstage.biz.dto.job.SaveJobDTO;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

import java.util.Date;

/**
 * <p>
 *
 * </p>
 *
 * @author tqf
 * @since 2022-03-14
 */
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class QuartzJob extends BaseModel {
    private static final long serialVersionUID = 1L;

    /**
     * UUID
     */
    @ApiModelProperty(value = "UUID")
    @TableId(value = "job_id", type = IdType.INPUT)
    private String jobId;

    /**
     * 定时任务示例的 class路径
     */
    @ApiModelProperty(value = "定时任务示例的 class路径")
    private String className;

    /**
     * cron表达式
     */
    @ApiModelProperty(value = "cron表达式")
    private String cronExpression;

    /**
     * 定时任务名称
     */
    @ApiModelProperty(value = "定时任务名称")
    private String jobName;

    /**
     * 定时任务组
     */
    @ApiModelProperty(value = "定时任务组")
    private String jobGroup;

    /**
     * 触发器名称
     */
    @ApiModelProperty(value = "触发器名称")
    private String triggerName;

    /**
     * 触发器组
     */
    @ApiModelProperty(value = "触发器组")
    private String triggerGroup;

    /**
     * 参数
     */
    @ApiModelProperty(value = "参数")
    private String data;

    /**
     * 备注
     */
    @ApiModelProperty(value = "备注")
    private String description;

    /**
     * 创建时间
     */
    @ApiModelProperty(value = "创建时间")
    @JsonFormat(pattern = DateUtil.DATETIME_FORMAT)
    private Date createTime;

    /**
     * 修改时间
     */
    @ApiModelProperty(value = "修改时间")
    @JsonFormat(pattern = DateUtil.DATETIME_FORMAT)
    private Date updateTime;

    public QuartzJob() {
    }

    public QuartzJob(SaveJobDTO save) {
        this.jobId = save.getJobId();
        this.className = save.getClassName();
        this.cronExpression = save.getCronExpression();
        this.jobName = save.getGroup() + save.getId();
        this.jobGroup = save.getGroup();
        this.triggerName = save.getGroup() + save.getId();
        this.triggerGroup = save.getGroup();
        this.data = JSONObject.toJSONString(save.getData());
        this.description = save.getDescription();
        this.createTime = new Date();
    }
}

2.6 MessageJob 具体的任务调度执行的业务

package com.shucha.digitalportalbackstage.biz.task.quartz.job;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.sdy.common.utils.DateUtil;
import com.shucha.digitalportalbackstage.biz.dto.MaxTimeDTO;
import com.shucha.digitalportalbackstage.biz.mapper.RemindDataMapper;
import com.shucha.digitalportalbackstage.biz.model.*;
import com.shucha.digitalportalbackstage.biz.service.*;
import com.shucha.digitalportalbackstage.biz.utils.SendMsgUtil;
import lombok.SneakyThrows;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
public class MessageJob implements Job {
    @Autowired
    private QuartzJobService quartzJobService;
    @Autowired
    private RemindDataService remindDataService;
    @Autowired
    private ZzdUserAllService zzdUserAllService;
    @Autowired
    private RemindModuleService moduleService;
    @Autowired
    private RemindTemplateService templateService;
    @Autowired
    private RemindMessageService remindMessageService;
    @Autowired
    private RemindDataMapper remindDataMapper;
    @Autowired
    private SendMsgUtil sendMsgUtil;

    private static Pattern pattern = Pattern.compile("(\\$\\{)([\\w]+)(\\})");

    private static Logger log = LoggerFactory.getLogger(MessageJob.class);

    @SneakyThrows
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        Date date = new Date();
        String triggerName = context.getTrigger().getKey().getName();
        log.info("******"+triggerName+"任务开始执行******");
        String jobId = context.getJobDetail().getKey().getName();
        /*jobId = jobId.substring(0, jobId.length() - name.length());
        String databaseId = name.substring(JobGroupConstants.DATABASE.length());*/
        RemindData remindData = JSONObject.toJavaObject(JSONObject.parseObject(JSONObject.toJSONString(context.getMergedJobDataMap().get("myValue"))), RemindData.class);
        if(remindData != null && remindData.getId() != null) {
            // 查询短信模板
            RemindTemplate template = templateService.getOne(Wrappers.<RemindTemplate>lambdaQuery()
                    .orderByDesc(RemindTemplate::getCreateTime),false);
            // 1、根据责任人查询姓名
            String name = "";
            ZzdUserAll zzdUserAll = zzdUserAllService.getById(remindData.getDutyId());
            if(zzdUserAll != null) {
                name = zzdUserAll.getEmployeeName();
            }
            // 2、根据模块ID查询模块名称
            String moduleName = "";
            RemindModule module = moduleService.getById(remindData.getRemindModuleId());
            if(module != null) {
                moduleName = module.getName();
            }
            // 3、不同模块查询对应的最新的创建时间和更新时间
            Integer day = getDay(remindData.getRemindModuleId(), date);

            // 短信发送文本内容
            String messageContent = messageContent(template.getContent(), name, moduleName, day);
            // 执行短信发送
            Boolean b = sendMsgUtil.sendOneMobileMsg(remindData.getPhone(), messageContent);
            if(b) {
                // 更新当前提醒记录的 提醒次数和最新提醒时间
                RemindData data = remindDataService.getById(remindData.getId());
                if(data != null) {
                    data.setRemindTime(date)
                            .setRemindNumber(data.getRemindNumber() + 1)
                            .setRemindTime(date);
                    remindDataService.updateById(data);
                }
                // 生成短信发送记录
                RemindMessage message = new RemindMessage()
                        .setContent(messageContent)
                        .setCreateTime(date)
                        .setRemindDataId(remindData.getId());
                remindMessageService.save(message);
            }
        }
        log.info("******"+triggerName+"任务执行结束******");
    }

    /**
     * 短信模板通配符替换指定的值
     * @param content
     * @param name
     * @param moduleName
     * @param day
     * @return
     */
    public String messageContent(String content, String name, String moduleName, Integer day){
        log.info("替换前:" +content);
        Map<String,Object> params = new HashMap<>();
        params.put("name", name);
        params.put("module", moduleName);
        params.put("day", day);
        //使用的时候建议定义为常量或者字段
        Matcher m = pattern.matcher(content);
        StringBuffer stringBuffer = new StringBuffer();
        while (m.find()) {
            String group = m.group()
                    .replace("$", "")
                    .replace("{", "")
                    .replace("}", "");
            if (params.get(group) == null) {
                continue;
            }
            m.appendReplacement(stringBuffer, (String) params.get(group));
        }
        m.appendTail(stringBuffer);
        Matcher m1 = pattern.matcher(stringBuffer.toString());
        //可以判断出是否替换成功
        if(!m1.find()){
            log.info("替换后:"+stringBuffer.toString());
        }
        return stringBuffer.toString();
    }

    /**
     * 根据不同模块查询 最新创建时间和最新更新时间 然后和当前时间计算相差天数
     * @param id
     * @return
     */
    public int getDay(Long id, Date date){
        int day = 0;
        // id对应的不同模块
        // 1、数智乐清门户-集成入口
        // 2、数智乐清门户-通知公告
        // 3、数智乐清门户-宣传报道
        // 4、数智乐清门户-文明城市创建
        // 5、数智乐清门户-风险气象资讯
        // 6、数智乐清门户-疫苗接种
        // 7、数智乐清门户-重点指标
        // 8、数智乐清门户-新型城镇化
        // 9、数智乐清门户-重点项目
        Date maxTime = null;
        MaxTimeDTO maxTimeDTO = remindDataMapper.getMaxTime(id);
        if(maxTimeDTO != null) {
            Date createTime = maxTimeDTO.getCreateTime();
            Date updateTime = maxTimeDTO.getUpdateTime();
            if( createTime != null && updateTime != null){
                // 计算查看查看那个时间大
                maxTime = createTime.getTime() - updateTime.getTime() >0 ? createTime : updateTime;
            }
            if(updateTime == null) {
                if(createTime != null) {
                    maxTime = createTime;
                }
            }
        }
        day =  (int) ((date.getTime() - maxTime.getTime()) / (1000*3600*24));
        return day;
    }
}

2.7 QuartzService 服务类

package com.shucha.digitalportalbackstage.biz.task.quartz.service;

import com.alibaba.fastjson.JSONObject;
import com.shucha.digitalportalbackstage.biz.model.QuartzJob;

public interface QuartzService {
    /**
     * 创建Job
     *
     * @param job
     */
    Boolean addJob(QuartzJob job);

    /**
     * 执行Job
     *
     * @param job
     */
    Boolean runJob(QuartzJob job);

    /**
     * 修改Job
     *
     * @param job
     */
    Boolean updateJob(QuartzJob job);

    /**
     * 暂停Job
     *
     * @param job
     */
    Boolean pauseJob(QuartzJob job);

    /**
     * 唤醒Job
     *
     * @param job
     */
    Boolean resumeJob(QuartzJob job);

    /**
     * 删除Job
     *
     * @param job
     */
    Boolean deleteJob(QuartzJob job);

    /**
     * 获取Job
     *
     * @param job
     */
    JSONObject queryJob(QuartzJob job);
}

2.8 QuartzServiceImpl 实现类

package com.shucha.digitalportalbackstage.biz.task.quartz.service;

import com.alibaba.fastjson.JSONObject;
import com.shucha.digitalportalbackstage.biz.model.QuartzJob;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class QuartzServiceImpl implements QuartzService{
    private static Logger log = LoggerFactory.getLogger(QuartzServiceImpl.class);
    @Autowired
    @Qualifier("scheduler")
    private Scheduler scheduler;


    @Override
    public Boolean addJob(QuartzJob job) {
        try {
//            JSONObject data = job.getData();
            JSONObject data =JSONObject.parseObject(job.getData());
            log.info("当前任务携带的业务参数={}", data.toJSONString());
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put("myValue", data);
            String jobId = job.getJobId();
            String jobName = job.getJobName();
            String jobUnique = jobId + jobName;
            JobDetail jobDetail = JobBuilder
                    .newJob((Class<? extends Job>) Class.forName(job.getClassName()))
                    // 指定执行类
                    .withIdentity(jobUnique, job.getJobGroup())
                    // 指定name和group
                    .requestRecovery().withDescription(job.getDescription())
                    .setJobData(jobDataMap)
                    .build();
            // 创建表达式调度构建器
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder
                    .cronSchedule(job.getCronExpression());
            // 创建触发器
            CronTrigger cronTrigger = TriggerBuilder.newTrigger()
                    .withIdentity(job.getTriggerName(), job.getTriggerGroup())
                    .withDescription(job.getDescription())

                    .withSchedule(cronScheduleBuilder).build();
            scheduler.scheduleJob(jobDetail, cronTrigger);
            scheduler.start();
            log.info("定时任务[{}]创建成功,开始执行", jobId + jobName);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public Boolean runJob(QuartzJob job) {
        try {
            String jobId = job.getJobId();
            String jobName = job.getJobName();
            String jobUnique = jobId + jobName;
            scheduler.triggerJob(JobKey.jobKey(jobUnique,
                    job.getJobGroup()));
            log.info("定时任务[{}]执行成功", jobUnique);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public Boolean updateJob(QuartzJob job) {
        try {
            String jobId = job.getJobId();
            String jobName = job.getJobName();
            String jobUnique = jobId + jobName;
            TriggerKey triggerKey = new TriggerKey(job.getTriggerName(),
                    job.getTriggerGroup());
            CronTrigger cronTrigger = (CronTrigger) scheduler
                    .getTrigger(triggerKey);
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder
                    .cronSchedule(job.getCronExpression());
            // 重新构件表达式
            CronTrigger trigger = cronTrigger.getTriggerBuilder()
                    .withIdentity(triggerKey).withSchedule(cronScheduleBuilder)
                    .withDescription(job.getDescription())
                    .build();
            scheduler.rescheduleJob(triggerKey, trigger);
            log.info("定时任务[{}]更新成功", jobUnique);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public Boolean pauseJob(QuartzJob job) {

        try {
            String jobId = job.getJobId();
            String jobName = job.getJobName();
            String jobUnique = jobId + jobName;
            scheduler.pauseJob(JobKey.jobKey(jobUnique,
                    job.getJobGroup()));
            log.info("定时任务[{}]暂停成功", jobUnique);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public Boolean resumeJob(QuartzJob job) {
        try {
            String jobId = job.getJobId();
            String jobName = job.getJobName();
            String jobUnique = jobId + jobName;
            scheduler.resumeJob(JobKey.jobKey(jobUnique,
                    job.getJobGroup()));
            log.info("定时任务[{}]唤醒成功", jobUnique);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public Boolean deleteJob(QuartzJob job) {

        try {
            String jobId = job.getJobId();
            String jobName = job.getJobName();
            String jobUnique = jobId + jobName;
            scheduler.deleteJob(JobKey.jobKey(jobUnique, job.getJobGroup()));
            log.info("定时任务[{}]删除成功", jobUnique);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public JSONObject queryJob(QuartzJob job) {
        TriggerKey triggerKey = new TriggerKey(job.getTriggerName(),
                job.getTriggerGroup());
        try {
            CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if (null == cronTrigger) {
                return null;
            }
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("expression", cronTrigger.getCronExpression());
            jsonObject.put("state", scheduler.getTriggerState(triggerKey));
            jsonObject.put("description", cronTrigger.getDescription());
            return jsonObject;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

2.9 JobFactory

package com.shucha.digitalportalbackstage.biz.task.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 JobFactory extends AdaptableJobFactory {
    @Autowired
    private AutowireCapableBeanFactory beanFactory;

    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        Object jobInstance = super.createJobInstance(bundle);
        beanFactory.autowireBean(jobInstance);
        return jobInstance;
    }
}

2.10 JobGroupConstants

package com.shucha.digitalportalbackstage.biz.task.quartz;

import java.util.HashMap;
import java.util.Map;

public class JobGroupConstants {
    private static final Map<String, String> groupClass = new HashMap<>();
    public static final String MESSAGE = "message";

    public static final String MESSAGE_CLASS = "com.shucha.digitalportalbackstage.biz.task.quartz.job.MessageJob";

    static {
        groupClass.put(MESSAGE, MESSAGE_CLASS);
    }

    public static String getGroupClass(String group) {
        return groupClass.get(group);
    }
}

2.11 SaveJobDTO 实体类

package com.shucha.digitalportalbackstage.biz.dto.job;

import lombok.Data;

import java.util.Map;

@Data
public class SaveJobDTO {

    private String jobId;
    /**
     * 组
     */
    private String group;


    private String className;

    /**
     * 组对应的表的 主键ID
     */
    private Long id;
    /**
     * cron 表达式
     */
    private String cronExpression;
    /**
     * 参数
     */
    private Map<String, Object> data;

    /**
     * 备注
     */
    private String description;

    public SaveJobDTO(String group, Long id, String cronExpression, Map<String, Object> data) {
        this.group = group;
        this.id = id;
        this.cronExpression = cronExpression;
        this.data = data;
    }

    public SaveJobDTO() {
    }
}

2.12 任务调度表结构

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for quartz_job
-- ----------------------------
DROP TABLE IF EXISTS `quartz_job`;
CREATE TABLE `quartz_job`  (
  `job_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'UUID',
  `class_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '定时任务示例的 class路径',
  `cron_expression` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'cron表达式',
  `job_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '定时任务名称',
  `job_group` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '定时任务组',
  `trigger_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '触发器名称',
  `trigger_group` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '触发器组',
  `data` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '参数',
  `description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `update_time` datetime(0) NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '修改时间',
  PRIMARY KEY (`job_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '定时任务表' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of quartz_job
-- ----------------------------
INSERT INTO `quartz_job` VALUES ('032925693ba04290a133fda816476a1c', 'com.shucha.digitalportalbackstage.biz.task.quartz.job.MessageJob', '0 25 12 15 * ?', 'message5', 'message', 'message5', 'message', '{\"cycleType\":0,\"monthWeek\":\"15\",\"createTime\":1647250687831,\"phone\":\"17816857416\",\"remindNumber\":0,\"createId\":214,\"remindModuleId\":1,\"dutyId\":465,\"id\":5,\"time\":\"12:25\"}', NULL, '2022-03-14 17:38:08', NULL);

SET FOREIGN_KEY_CHECKS = 1;

2.13 项目结构

dispath文件夹下的文件可以删除掉,这里没有使用

2.14 源码demo下载

demo源码下载https://download.csdn.net/download/tanqingfu1/84932500

2.15 QuartzJobService 

package com.shucha.digitalportalbackstage.biz.service;

import com.sdy.common.model.BizException;
import com.sdy.mvc.service.BaseService;
import com.shucha.digitalportalbackstage.biz.dto.job.SaveJobDTO;
import com.shucha.digitalportalbackstage.biz.model.QuartzJob;

/**
 * <p>
 * 服务类
 * </p>
 *
 * @author
 * @since 2022-03-14
 */
public interface QuartzJobService extends BaseService<QuartzJob> {
    Boolean saveJob(SaveJobDTO save) throws BizException;

    Boolean deleteJob(Long id, String group);

    Boolean updateJob(SaveJobDTO save) throws BizException;

//    QuartzJob getJobByGroupAndId(String group, Long id);
}

 2.16 QuartzJobServiceImpl

package com.shucha.digitalportalbackstage.biz.service.impl;

import com.sdy.common.model.BizException;
import com.sdy.common.utils.Assert;
import com.sdy.mvc.service.impl.BaseServiceImpl;
import com.shucha.digitalportalbackstage.biz.dto.job.SaveJobDTO;
import com.shucha.digitalportalbackstage.biz.mapper.QuartzJobMapper;
import com.shucha.digitalportalbackstage.biz.model.QuartzJob;
import com.shucha.digitalportalbackstage.biz.service.QuartzJobService;
import com.shucha.digitalportalbackstage.biz.task.quartz.JobGroupConstants;
import com.shucha.digitalportalbackstage.biz.task.quartz.service.QuartzService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.UUID;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author tqf
 * @since 2022-03-14
 */
@Slf4j
@Service
public class QuartzJobServiceImpl extends BaseServiceImpl<QuartzJob> implements QuartzJobService {
    @Autowired
    private QuartzJobMapper quartzJobMapper;
    @Autowired
    private QuartzService quartzService;

    /**
     * 新增 定时任务
     *
     * @param saveJob
     * @return
     * @throws BizException
     */
    @Override
    public Boolean saveJob(SaveJobDTO saveJob) throws BizException {
        String groupClass = JobGroupConstants.getGroupClass(saveJob.getGroup());
        Assert.isNull(groupClass, "请添加定时任务的Class!");
        saveJob.setClassName(groupClass);
        saveJob.setJobId(getUuid());
        QuartzJob quartzJob = new QuartzJob(saveJob);
        boolean save = save(quartzJob);
        Assert.notTrue(save, "新增失败!");
        return quartzService.addJob(quartzJob);
    }

    /**
     * 删除定时任务
     *
     * @param id
     * @param group
     * @return
     */
    @Override
    public Boolean deleteJob(Long id, String group) {
        Boolean b;
        QuartzJob quartzJob = lambdaQuery().eq(QuartzJob::getJobGroup, group)
                .eq(QuartzJob::getJobName, group + id).one();
        // 需要判断是否存在定时任务
        if(quartzJob != null) {
            removeById(quartzJob.getJobId());
            b = quartzService.deleteJob(quartzJob);
        } else {
            b = true;
        }
        return b;
    }

    /**
     * 修改定时任务
     *
     * @param update
     * @return
     * @throws BizException
     */
    @Override
    public Boolean updateJob(SaveJobDTO update) throws BizException {
        QuartzJob quartzJob = getById(update.getJobId());
        Assert.isNull(quartzJob, "定时任务不存在!");
        lambdaUpdate().eq(QuartzJob::getJobId, update.getJobId())
                .set(QuartzJob::getCronExpression, update.getCronExpression())
                .update();
        quartzJob.setCronExpression(update.getCronExpression());
        return quartzService.updateJob(quartzJob);
    }

    private static String getUuid() {
        return UUID.randomUUID().toString().replace("-", "");
    }
}

2.17 定时任务调用

2.17.1 新建定时任务 

// 新建定时任务
JSON jsons = (JSON) JSON.toJSON(remindData);
Map<String, Object> paramMap = JSONObject.parseObject(jsons.toString());
quartzJobService.saveJob(new SaveJobDTO(JobGroupConstants.MESSAGE, remindData.getId(), cronExp, paramMap));

cronExp 字段是cron表达式,参照下面文章获取
// https://blog.csdn.net/tanqingfu1/article/details/123474993?spm=1001.2014.3001.5502

// 下面方法校验cron表达式是否正确
CronExpression.isValidExpression("0 0 29 ? *")
            

2.17.2 更新定时任务

// 更新定时任务
String jobName = JobGroupConstants.MESSAGE + remindData.getId();
QuartzJob quartzJob = quartzJobService.lambdaQuery().eq(QuartzJob::getJobName, jobName).one();
SaveJobDTO dto = new SaveJobDTO();
dto.setJobId(quartzJob.getJobId());
dto.setCronExpression(cronExp);
quartzJobService.updateJob(dto);

cronExp 字段是cron表达式,参照下面文章获取
// https://blog.csdn.net/tanqingfu1/article/details/123474993?spm=1001.2014.3001.5502

2.17.3 删除定时任务

// 删除定时任务
quartzJobService.deleteJob(id, JobGroupConstants.MESSAGE);
  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码奴生来只知道前进~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值