springboot整合quartz实现定时任务动态增删改查

springboot整合quartz

  • quartz介绍
    • Quartz 核心概念
  • 使用
    • 依赖
    • 配置文件
    • 启动类
    • quartz工具类
    • job业务
    • 用到的对象类
    • 接口
    • service
    • 实现类
    • 测试

quartz介绍

Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标准的Java组件或 EJBs。Quartz的最新版本为Quartz 2.3.2。
中文官方文档:https://www.w3cschool.cn/quartz_doc/

Quartz 核心概念

1.Job 表示一个工作,要执行的具体内容。
2.JobDetail 表示一个具体的可执行的调度程序,Job 是这个可执行程调度程序所要执行的内容,另外 JobDetail 还包含了这个任务调度的方案和策略。
3.Trigger 代表一个调度参数的配置,什么时候去调。
4.Scheduler 代表一个调度容器,一个调度容器中可以注册多个 JobDetail 和 Trigger。当 Trigger 与 JobDetail 组合,就可以被 Scheduler 容器调度了。

使用

依赖

springboot整合quartz依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>

pom文件

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.5.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3</version>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
            <version>3.0.0</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

配置文件

quartz必须配置,如果在application.yml文件配置了quartz属性,则不需要quartz.properties文件。
application.yml文件

server:
  port: 8802
spring:
  application:
    name: quartz-curd
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/quartz_curd?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root
    password: root
  quartz:
    #quartz定时任务,采用数据库方式
    job-store-type: jdbc
    initialize-schema: never
    #定时任务启动开关,true-false-关
    auto-startup: true
    #延迟1秒启动定时任务
    startup-delay: 1s
    #启动时更新己存在的Job
    overwrite-existing-jobs: true
    properties:
      org:
        quartz:
          scheduler:
            instanceName: MyScheduler
            #ID设置为自动获取 每一个必须不同 (所有调度器实例中是唯一的)
            instanceId: AUTO
          jobStore:
            class: org.springframework.scheduling.quartz.LocalDataSourceJobStore
            #StdJDBCDelegate说明支持集群
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
            #quartz内部表的前缀
            tablePrefix: QRTZ_
            #是否加入集群
            isClustered: false
            #容许的最大作业延长时间
            misfireThreshold: 12000
            #分布式节点有效性检查时间间隔,单位:毫秒
            clusterCheckinInterval: 15000
            #配置是否使用
            useProperties: false
          threadPool:
            #ThreadPool实现的类名
            class: org.quartz.simpl.SimpleThreadPool
            #线程数量
            threadCount: 20
            #线程优先级
            threadPriority: 5
            #配置是否启动自动加载数据库内的定时任务,默认true
            threadsInheritContextClassLoaderOfInitializingThread: true

注意:initialize-schema: never,这个属性,第一次生成quartz内置表时设置为always,生成后改为never,不然每次启动系统都会重新生成表。

启动类

@SpringBootApplication
@EnableOpenApi
public class QuartzService {
    public static void main(String[] args) {
        SpringApplication.run(QuartzService.class,args);
    }
}

添加启动类后可以运行项目,生成quartz内置表,
生成11张表
springboot整合quartz实现定时任务动态增删改查_第1张图片

quartz工具类

包含定时任务添加,修改,运行,暂停,恢复,删除和查询。

package com.test.quartz.utils;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.test.quartz.pojo.JobInfo;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.spi.MutableTrigger;

import java.util.*;

import static org.quartz.Trigger.TriggerState.*;

/**
 * @author清梦
 * @site www.xiaomage.com
 * @company xxx公司
 * @create 2023-06-08 14:41
 */
@Slf4j
public class QuartzUtil {

    private static Map<Trigger.TriggerState, String> TRIGGER_STATE;

    public static final String END_JOB_SUFFIX = ":endTask";

    static {
        TRIGGER_STATE = new HashMap<>();
        TRIGGER_STATE.put(NONE, "空");
        TRIGGER_STATE.put(NORMAL, "正常");
        TRIGGER_STATE.put(PAUSED, "暂停");
        TRIGGER_STATE.put(COMPLETE, "完成");
        TRIGGER_STATE.put(ERROR, "错误");
        TRIGGER_STATE.put(BLOCKED, "阻塞");
    }

    /**
     * 创建定时任务,创建定时任务后默认为启动状态
     * @param scheduler 调度器
     * @param jobInfo 定时任务信息类
     * 原文链接:https://blog.csdn.net/yyyy11119/article/details/121139580
     */
    public static void createScheduleJob(Scheduler scheduler, JobInfo jobInfo)throws Exception{
        //获取定时任务的执行类,必须是类的绝对路径
        //定时任务类需要是job类的具体实现 QuartzJobBean是job的抽象类。
        Class<? extends Job> jobClass = (Class<? extends Job>)Class.forName(jobInfo.getJobClassName());
        //构建定时任务信息
        JobKey jobKey = JobKey.jobKey(jobInfo.getJobName(),jobInfo.getJobGroup());
        TriggerKey triggerKey = TriggerKey.triggerKey(jobInfo.getJobName(),jobInfo.getJobGroup());
        JobDetail jobDetail = JobBuilder.newJob(jobClass)
                .withIdentity(jobKey).build();
        //设置定时任务的执行方式
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(jobInfo.getCronExpression());
        //构建触发器trigger
        CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)
                .withDescription(jobInfo.getDescription())
                .usingJobData("jobClassName",jobInfo.getJobClassName())
                .withSchedule(scheduleBuilder)
                .startAt(jobInfo.getStartTime())
                //如果设置了结束时间,到期任务自动删除,我们不想任务过期就删除,所以zhudiao
                //.endAt(jobInfo.getEndTime())
                .build();
        // 修改 misfire 策略,如果开始时间在添加任务之前,不修改策略会导致新增时任务会立即运行一次
        chgMisFire(trigger);
        //如果参数不为空,写入参数
        ObjectMapper mapper = new ObjectMapper();
        if (!StringUtils.isBlank(jobInfo.getParameter())) {
            Map param = mapper.readValue(jobInfo.getParameter(), Map.class);
            jobDetail.getJobDataMap().putAll(param);
        }
        scheduler.scheduleJob(jobDetail,trigger);
        //如果设置了结束时间,添加一个终止任务
        if (null != jobInfo.getEndTime()){
            addEndJob(scheduler,jobInfo);
        }
    }

    /**
     * 添加停止任务
     * @param scheduler 调度器
     * @param jobInfo 定时任务信息类
     */
    public static void addEndJob(Scheduler scheduler,JobInfo jobInfo)throws SchedulerException,JsonProcessingException,ClassNotFoundException{
        String jobName = jobInfo.getJobName();
        String group = jobName + END_JOB_SUFFIX;
        JobKey jobKey = JobKey.jobKey(jobName,group);
        String endJobName = "jobName-" + System.currentTimeMillis();
        TriggerKey triggerKey = TriggerKey.triggerKey(endJobName,group);
        if (scheduler.checkExists(triggerKey) && scheduler.checkExists(jobKey)) {
            log.info("{}----开始添加终止任务",jobName);
            SimpleTrigger trigger = (SimpleTrigger) scheduler.getTrigger(triggerKey);
            trigger = trigger.getTriggerBuilder().withDescription(jobInfo.getDescription() + "-[结束任务]")
                    .withIdentity(triggerKey)
                    .startAt(jobInfo.getEndTime()).build();
            // 修改 misfire 策略
            chgMisFire(trigger);
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            ObjectMapper mapper = new ObjectMapper();
            if (!StringUtils.isBlank(jobInfo.getParameter())) {
                Map param = mapper.readValue(jobInfo.getParameter(), Map.class);
                jobDetail.getJobDataMap().putAll(param);
            }
            scheduler.deleteJob(jobKey);
            scheduler.scheduleJob(jobDetail, trigger);
            return;
        }
        Class<? extends Job> jobClass = (Class<? extends Job>)Class.forName(jobInfo.getJobClassName());
        //构建定时任务信息
        JobDetail jobDetail = JobBuilder.newJob(jobClass)
                .withIdentity(jobKey).build();
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
                .withDescription(jobKey.getGroup() + "-[结束任务]")
                .startAt(jobInfo.getEndTime())
                .build();
        // 修改 misfire 策略
        chgMisFire(trigger);

        ObjectMapper mapper = new ObjectMapper();
        if (!StringUtils.isBlank(jobInfo.getParameter())) {
            log.info("parameter:{}",jobInfo.getParameter());
            Map param = mapper.readValue(jobInfo.getParameter(), Map.class);
            jobDetail.getJobDataMap().putAll(param);
        }
        scheduler.scheduleJob(jobDetail, trigger);
    }

    /**
     * 根据任务明细暂停定时任务
     * @param scheduler 调度器
     * @param jobName 定时任务名称
     */
    public static void pauseScheduleJob(Scheduler scheduler,String jobName,String jobGroup)throws SchedulerException{
        JobKey jobKey = JobKey.jobKey(jobName,jobGroup);
        scheduler.pauseJob(jobKey);
    }

    /**
     * 根据任务名称恢复定时任务
     * @param scheduler 调度器
     * @param jobName 任务名称
     */
    public static void resumeScheduleJob(Scheduler scheduler,String jobName,String jobGroup)throws SchedulerException{
        JobKey jobKey = JobKey.jobKey(jobName,jobGroup);
        scheduler.resumeJob(jobKey);
    }

    /**
     * 根据任务名称运行一次定时任务
     * @param scheduler 调度器
     * @param jobName 任务名称
     */
    public static void runOnce(Scheduler scheduler,String jobName,String jobGroup)throws SchedulerException{
        JobKey jobKey = JobKey.jobKey(jobName,jobGroup);
        scheduler.triggerJob(jobKey);
    }

    /**
     * 更新定时任务
     * @param scheduler 调度器
     * @param jobInfo 定时任务类
     */
    public static void updateScheduleJob(Scheduler scheduler,JobInfo jobInfo)throws SchedulerException,JsonProcessingException,ClassNotFoundException{
        //获取对应任务的触发器
        TriggerKey triggerKey = TriggerKey.triggerKey(jobInfo.getJobName(),jobInfo.getJobGroup());
        //设置定时任务执行方式
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(jobInfo.getCronExpression());
        //重新构建定时任务的触发器
        CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        cronTrigger = cronTrigger.getTriggerBuilder()
                .withIdentity(triggerKey)
                .withSchedule(scheduleBuilder)
                .withDescription(jobInfo.getDescription())
                .usingJobData("jobClassName",jobInfo.getJobClassName())
                .startAt(jobInfo.getStartTime())
                .endAt(jobInfo.getEndTime()).build();
        // 修改 misfire 策略,测试时注掉,方便观察
        //chgMisFire(trigger);
        //重置对应的定时任务
        //如果参数不为空,写入参数
        JobKey jobKey = JobKey.jobKey(jobInfo.getJobName(),jobInfo.getJobGroup());
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        ObjectMapper mapper = new ObjectMapper();
        if (!StringUtils.isBlank(jobInfo.getParameter())) {
            Map param = mapper.readValue(jobInfo.getParameter(), Map.class);
            jobDetail.getJobDataMap().clear();
            jobDetail.getJobDataMap().putAll(param);
        }
        scheduler.rescheduleJob(triggerKey,cronTrigger);
        //如果设置了结束时间,添加一个终止任务
        if (null != jobInfo.getEndTime()){
            addEndJob(scheduler,jobInfo);
        }
    }

    /**
     * 删除定时任务
     * @param scheduler 调度器
     * @param jobName 任务名称
     */
    public static void deleteScheduleJob(Scheduler scheduler,String jobName,String jobGroup)throws SchedulerException{
        JobKey jobKey = JobKey.jobKey(jobName,jobGroup);
        scheduler.deleteJob(jobKey);
    }

    /**
     * 查询所有定时任务
     * @param scheduler 调度器
     */
    public static List<JobInfo> findAll(Scheduler scheduler,String jobGroup)throws SchedulerException{
        GroupMatcher<JobKey> matcher;
        if (StringUtils.isBlank(jobGroup)){
            matcher = GroupMatcher.anyGroup();
        }else {
            matcher = GroupMatcher.groupEquals(jobGroup);
        }

        List<JobInfo> list = new ArrayList<>();
        Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
        for (JobKey jobKey:jobKeys){
            JobInfo jobInfo = new JobInfo();
            jobInfo.setJobName(jobKey.getName());
            jobInfo.setJobGroup(jobKey.getGroup());
            TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(),jobKey.getGroup());
            CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            //终止任务没有设置业务实现类
            if (!jobKey.getGroup().contains(END_JOB_SUFFIX)){
                jobInfo.setJobClassName(cronTrigger.getJobDataMap().getString("jobClassName"));
                System.out.println("className:" + scheduler.getJobDetail(jobKey).getJobDataMap().getString("jobClassName"));
                jobInfo.setDescription(cronTrigger.getDescription());
                jobInfo.setCronExpression(cronTrigger.getCronExpression());
                jobInfo.setStartTime(cronTrigger.getStartTime());
            }

            jobInfo.setJobStatus(getJobStatus(scheduler,triggerKey));
            JobDataMap map = scheduler.getJobDetail(jobKey).getJobDataMap();
            jobInfo.setParameter(JSONObject.toJSONString(map));

            //直接在cronTrigger设置结束时间,到期后会自动删除,我们用结束时间设置了一个定时任务,到期停止
            //jobInfo.setEndTime(cronTrigger.getEndTime());
            TriggerKey endJobTriggerKey = TriggerKey.triggerKey(jobKey.getName(),jobKey.getName() + END_JOB_SUFFIX);
            SimpleTrigger endJobTrigger = (SimpleTrigger) scheduler.getTrigger(endJobTriggerKey);
            if (null != endJobTrigger){
                jobInfo.setEndTime(endJobTrigger.getStartTime());
            }
            list.add(jobInfo);
        }
        return list;
    }

    /**
     * 获取定时任务状态
     * @param scheduler 调度器
     * @param triggerKey 触发器
     * @return
     * @throws SchedulerException
     */
    public static String getJobStatus(Scheduler scheduler,TriggerKey triggerKey) throws SchedulerException{
        Trigger.TriggerState triggerState = scheduler.getTriggerState(triggerKey);
        return TRIGGER_STATE.get(triggerState);
    }

    /**
     * 错过触发策略:即错过了定时任务的开始时间可以做什么,此处设置什么也不做,即过了开始时间也不执行
     * 如果不设置,默认为立即触发一次,例如设置定时任务开始时间为10点,没有设置结束时间,在10点后重启系统,
     * 如果不设置为CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING,那么开始时间在重启前的定时任务会全部重新触发一次
     * @param trigger
     */
    private static void chgMisFire(Trigger trigger) {
        // 修改 misfire 策略
        if (trigger instanceof MutableTrigger) {
            MutableTrigger mutableTrigger = (MutableTrigger) trigger;
            mutableTrigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);
        }
    }
}

注意在添加和修改定时任务时,结束时间的设置一定要注意,直接设置结束时间,到期后任务会自动删除
springboot整合quartz实现定时任务动态增删改查_第2张图片

job业务

具体让job执行什么操作,都可以在这里实现,个人只是打印了任务名称和参数

package com.test.quartz.job;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.test.quartz.mapper.TriggersMapper;
import com.test.quartz.pojo.Triggers;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import static com.test.quartz.utils.QuartzUtil.END_JOB_SUFFIX;

/**
 * @author清梦
 * @site www.xiaomage.com
 * @company xxx公司
 * @create 2023-06-08 16:07
 */
@Slf4j
public class MyJob extends QuartzJobBean {

    @Autowired
    private TriggersMapper triggersMapper;

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        String now = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        //获取参数信息
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        String name = jobDetail.getKey().getName();
        String jobGroup = jobDetail.getKey().getGroup();
        Iterator<Map.Entry<String, Object>> iterator = jobDataMap.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<String, Object> entry = iterator.next();
            log.info("定时任务-{}:{}-启动,参数为:key:{} ,value:{}",name,jobGroup,entry.getKey(),entry.getValue());
        }

        Trigger cronTrigger = jobExecutionContext.getTrigger();
        String group = cronTrigger.getKey().getGroup();
        //有终止任务标记的修改状态为pause
        if (group.contains(END_JOB_SUFFIX)){
            String jobName = group.split(END_JOB_SUFFIX)[0];
            log.info("jobName:{}",jobName);
            QueryWrapper<Triggers> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("job_name",jobName);
            List<Triggers> triggers = triggersMapper.selectList(queryWrapper);
            for (Triggers trigger:triggers){
                triggersMapper.updateTriggerState("PAUSED",trigger.getJobName(),trigger.getJobGroup());
            }
            return;
        }
    }
}

用到的对象类

package com.test.quartz.pojo;

import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;

import java.util.Date;

/**
 * @author清梦
 * @site www.xiaomage.com
 * @company xxx公司
 * @create 2023-06-08 14:29
 */
@Data
@TableName("tb_job_info")
public class JobInfo{

    //任务类名
    private String jobClassName;

    //cron表达式
    private String cronExpression;

    //参数
    private String parameter;

    //任务名称
    private String jobName;

    //任务分组
    private String jobGroup;

    //描述
    private String description;

    //任务状态
    private String jobStatus;

    //任务开始时间
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date startTime;

    //任务结束时间
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date endTime;

}

job_info表根据自己需求建立,本项目中只用于对象传输。建表sql如下。
注意:我建表使用utf8mb4编码,数据库也得是utf8mb4才行,如果数据库是utf8,建表编码也改成utf8。

CREATE TABLE `tb_job_info` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `create_by` varchar(32) DEFAULT NULL COMMENT '创建人',
  `create_at` datetime DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(32) DEFAULT NULL COMMENT '修改人',
  `update_at` datetime DEFAULT NULL COMMENT '修改时间',
  `del_flag` int(11) DEFAULT '0' COMMENT '删除状态:0-未删除,1-已删除',
  `job_class_name` varchar(255) DEFAULT NULL COMMENT '任务类名',
  `cron_expression` varchar(255) DEFAULT NULL COMMENT 'cron表达式',
  `parameter` varchar(255) DEFAULT NULL COMMENT '参数',
  `job_name` varchar(20) DEFAULT NULL COMMENT '任务类名',
  `job_group` varchar(20) DEFAULT NULL COMMENT '任务分组',
  `description` varchar(255) DEFAULT NULL COMMENT '描述',
  `job_status` int(11) DEFAULT NULL COMMENT '任务状态',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='任务信息表'

vo对象

@Data
public class OperateVo {
    private String jobName;

    private String jobGroup;

    private Integer operateType;
}

用到的枚举

package com.test.quartz.enums;

/**
 * @author清梦
 * @site www.xiaomage.com
 * @company xxx公司
 * @create 2023-06-09 15:16
 */
public enum OperateEnum {
    ADD(1,"添加"),
    UPDATE(2,"修改"),
    RUN_ONCE(3,"运行一次"),
    PAUSE(4,"暂停"),
    RESUME(5,"恢复"),
    DELETE(6,"删除");

    private Integer code;

    private String msg;

    OperateEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

接口

编写接口测试

package com.test.quartz.controller;

import com.test.quartz.pojo.JobInfo;
import com.test.quartz.service.JobService;
import com.test.quartz.vo.OperateVo;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

/**
 * @author清梦
 * @site www.xiaomage.com
 * @company xxx公司
 * @create 2023-06-08 18:20
 */
@RestController
@RequestMapping("job")
@Api(tags = "定时任务操作")
public class JobController {

    @Autowired
    private JobService jobService;

    @GetMapping("findAll")
    public ResponseEntity findAll(String jobGroup){
        return jobService.findAll(jobGroup);
    }

    @PostMapping("save")
    public ResponseEntity save(@RequestBody JobInfo jobInfo,Integer operateType){
        return jobService.save(jobInfo,operateType);
    }

    @PostMapping("operate")
    public ResponseEntity operate(@RequestBody OperateVo vo){
        return jobService.operate(vo);
    }
}


service

public interface JobService {
    ResponseEntity findAll(String jobGroup);

    ResponseEntity save(JobInfo jobInfo,Integer operateType);

    ResponseEntity operate(OperateVo vo);
}

实现类

package com.test.quartz.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.test.quartz.enums.OperateEnum;
import com.test.quartz.job.MyJob;
import com.test.quartz.pojo.JobInfo;
import com.test.quartz.service.JobService;
import com.test.quartz.utils.QuartzUtil;
import com.test.quartz.vo.OperateVo;
import jdk.nashorn.internal.runtime.logging.Logger;
import lombok.extern.slf4j.Slf4j;
import org.quartz.CronExpression;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @author清梦
 * @site www.xiaomage.com
 * @company xxx公司
 * @create 2023-06-08 18:24
 */
@Service
@Slf4j
public class JobServiceImpl implements JobService {

    @Autowired
    private Scheduler scheduler;

    @Override
    public ResponseEntity findAll(String jobGroup) {
        List<JobInfo> list = new ArrayList<>();
        try {
            list = QuartzUtil.findAll(scheduler,jobGroup);
        }catch (SchedulerException e){
            log.error("查询定时任务列表失败:{}",e);
            return ResponseEntity.ok("查询失败");
        }catch (Exception e){
            log.error("查询定时任务列表失败:{}",e);
            return ResponseEntity.ok("查询失败");
        }
        return ResponseEntity.ok(list);
    }

    @Override
    public ResponseEntity save(JobInfo jobInfo,Integer operateType){
        String msg = "";
        try {
            //校验cron是否有效
            if (!CronExpression.isValidExpression(jobInfo.getCronExpression())){
                return ResponseEntity.ok("cron表达式错误");
            }

            if (OperateEnum.ADD.getCode() == operateType){
                msg = OperateEnum.ADD.getMsg();
                QuartzUtil.createScheduleJob(scheduler,jobInfo);
            }else if (OperateEnum.UPDATE.getCode() == operateType){
                msg = OperateEnum.UPDATE.getMsg();
                QuartzUtil.updateScheduleJob(scheduler,jobInfo);
            }

        }catch (Exception e){
            log.error("定时任务-{}-失败,jobName:{},错误信息:{}",msg ,jobInfo.getJobName(),e);
            return ResponseEntity.ok("定时任务" + msg + "失败");
        }
        return ResponseEntity.ok("定时任务" + msg + "成功");
    }

    @Override
    public ResponseEntity operate(OperateVo vo) {
        String jobName = vo.getJobName();
        String jobGroup = vo.getJobGroup();
        Integer type = vo.getOperateType();
        String msg = "";
        try {
            if (OperateEnum.RUN_ONCE.getCode() == type){
                msg = OperateEnum.RUN_ONCE.getMsg();
                QuartzUtil.runOnce(scheduler,jobName,jobGroup);
            }else if (OperateEnum.PAUSE.getCode() == type){
                msg = OperateEnum.PAUSE.getMsg();
                QuartzUtil.pauseScheduleJob(scheduler,jobName,jobGroup);
            }else if (OperateEnum.RESUME.getCode() == type){
                msg = OperateEnum.RESUME.getMsg();
                QuartzUtil.resumeScheduleJob(scheduler,jobName,jobGroup);
            }else if (OperateEnum.DELETE.getCode() == type){
                msg = OperateEnum.DELETE.getMsg();
                QuartzUtil.deleteScheduleJob(scheduler,jobName,jobGroup);
            }
        }catch (Exception e){
            log.error("定时任务:{}-{}失败:{}",msg,e);
            return ResponseEntity.ok("定时任务:" + jobName + msg + "-失败");
        }
        return ResponseEntity.ok("定时任务:" + jobName + msg + "-成功");
    }
}


测试

因为没有前端页面,我们引入了swagger,运行项目后在浏览器输入
http://localhost:8802/swagger-ui/,出现页面如下
springboot整合quartz实现定时任务动态增删改查_第3张图片
进入定时任务操作接口,先测试添加和修改
springboot整合quartz实现定时任务动态增删改查_第4张图片

输入参数,点击执行
springboot整合quartz实现定时任务动态增删改查_第5张图片

添加成功后可以在查询接口查看,不输入任务分组时可以看到设置的定时终止任务
springboot整合quartz实现定时任务动态增删改查_第6张图片
参考博客:
https://blog.csdn.net/yyyy11119/article/details/121139580
本博客源码地址:
https://gitee.com/qfp17393120407/springboot_quartz.git

你可能感兴趣的:(spring,boot,java,mybatis,quartz)