(企业 / 公司项目)如何使用分布式任务调度框架Quartz集成 和 SpringBoot自带的定时任务集成?

news2024/10/1 7:37:57

SpringBoot自带的定时任务

首先在你的微服务项目中创建一个新的模块,定时调度模块

 pom.xml里面关联公共模块common的依赖其他不需要改变

 然后启动类别删,启动项目是否报错,写一个简单的测试类访问路径是否成功

package com.jiawa.train.batch.controller;

import com.jiawa.train.batch.feign.BusinessFeign;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {


    @Resource
    BusinessFeign businessFeign;

    @GetMapping("/hello")
    public String hello() {
        return "Hello World! Batch!";
    }
}

创建一个包job 创建类 SpringBootTestJob.java

 package com.jiawa.train.batch.job;

 import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;

 /**
  * 适合单体应用,不适合集群
  * 没法实时更改定时任务状态和策略
  */
 @Component
 @EnableScheduling // 开启定时任务
 public class SpringBootTestJob {

     @Scheduled(cron = "0/5 * * * * ?")//   每5秒执行一次 每5秒执行一次 cron 从左到右空格隔开:秒 分钟 小时 日期 月份 星期
     private void test() {
         // 增加分布式锁,解决集群问题
         System.out.println("SpringBootTestJob TEST");
     }
 }

多个定时任务就写多个@Scheduled, 定时任务的三要素也要知道:1. 执行的内容:功能逻辑 2. 执行的策略: cron表达式  3. 开关: 开启定时任务

SpringBoot自带的定时任务缺点:  无法实时更改任务状态,就是当我想把定时任务暂停一下今天的数据有问题,但是这个就无法进行暂停所以用专业的任务调度的框架。

SpringBoot自带的定时任务优点:  开发速度快适合小型的项目,两个注解就好了

分布式任务调度框架Quartz集成

首先导入依赖pom.xml。 这里没有版本是因为我的这个是子模块 版本由父模块控制

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

跟着思路来导入了依赖之后我们就开始声明我们的任务了, 创建一个配置类 quartzConfig   触发器就是调用前面声明的任务方法来定时

 package com.jiawa.train.batch.config;

 import com.jiawa.train.batch.job.TestJob;
 import org.quartz.*;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;

 @Configuration
 public class QuartzConfig {

     /**
      * 声明一个任务
      * @return
      */
     @Bean
     public JobDetail jobDetail() {
         return JobBuilder.newJob(TestJob.class)
                 .withIdentity("TestJob", "test")//  任务名称和组构成任务key
                 .storeDurably()
                 .build();
     }

     /**
      * 声明一个触发器,什么时候触发这个任务
      * @return
      */
     @Bean
     public Trigger trigger() {
         return TriggerBuilder.newTrigger()// 创建一个新的触发器
                 .forJob(jobDetail()) // 将任务detail作为触发器要触发的任务
                 .withIdentity("trigger", "trigger")    // 为触发器设置一个唯一标识,例如 "trigger" 和 "trigger"
                 .startNow()  // 立即触发任务,从当前时间开始
                 .withSchedule(CronScheduleBuilder.cronSchedule("*/2 * * * * ?"))  // 设置触发器的调度规则,使用 cron 格式的字符串,表示每隔 2 分钟触发一次任务
                 .build();
     }
 }

上面代码写了注释的,任务名称TestJob这里就创建一个任务来对应,实现的是Job是框架quartz里面的接口

@DisallowConcurrentExecution //  禁止并发执行

package com.jiawa.train.batch.job;

import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

@DisallowConcurrentExecution //  禁止并发执行
public class TestJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("TestJob TEST开始");
        // try {
        //     Thread.sleep(3000);
        // } catch (InterruptedException e) {
        //     e.printStackTrace();
        // }
        System.out.println("TestJob TEST结束");
    }
}

 这就集成了框架的使用,springboot自带的定时任务也在使用。前面是简单的使用

在项目中集成框架

数据库配置quartz框架调度任务,官方提供的数据库MySQL,创建这几张表记得分库

#
# Quartz seems to work best with the driver mm.mysql-2.0.7-bin.jar
#
# PLEASE consider using mysql with innodb tables to avoid locking issues
#
# In your Quartz properties file, you'll need to set
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;
CREATE TABLE QRTZ_JOB_DETAILS
(
  SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',
  JOB_NAME  VARCHAR(200) NOT NULL  comment 'job名称',
  JOB_GROUP VARCHAR(200) NOT NULL  comment 'job组',
  DESCRIPTION VARCHAR(250) NULL  comment '描述',
  JOB_CLASS_NAME   VARCHAR(250) NOT NULL  comment 'job类名',
  IS_DURABLE VARCHAR(1) NOT NULL  comment '是否持久化',
  IS_NONCONCURRENT VARCHAR(1) NOT NULL  comment '是否非同步',
  IS_UPDATE_DATA VARCHAR(1) NOT NULL  comment '是否更新数据',
  REQUESTS_RECOVERY VARCHAR(1) NOT NULL  comment '请求是否覆盖',
  JOB_DATA BLOB NULL  comment 'job数据',
  PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);
CREATE TABLE QRTZ_TRIGGERS
(
  SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',
  TRIGGER_NAME VARCHAR(200) NOT NULL comment '触发器名称',
  TRIGGER_GROUP VARCHAR(200) NOT NULL  comment '触发器组',
  JOB_NAME  VARCHAR(200) NOT NULL  comment 'job名称',
  JOB_GROUP VARCHAR(200) NOT NULL  comment 'job组',
  DESCRIPTION VARCHAR(250) NULL  comment '描述',
  NEXT_FIRE_TIME BIGINT(13) NULL  comment '下一次触发时间',
  PREV_FIRE_TIME BIGINT(13) NULL  comment '前一次触发时间',
  PRIORITY INTEGER NULL  comment '等级',
  TRIGGER_STATE VARCHAR(16) NOT NULL  comment '触发状态',
  TRIGGER_TYPE VARCHAR(8) NOT NULL  comment '触发类型',
  START_TIME BIGINT(13) NOT NULL  comment '开始时间',
  END_TIME BIGINT(13) NULL  comment '结束时间',
  CALENDAR_NAME VARCHAR(200) NULL  comment '日程名称',
  MISFIRE_INSTR SMALLINT(2) NULL  comment '未触发实例',
  JOB_DATA BLOB NULL  comment 'job数据',
  PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
  REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
);
CREATE TABLE QRTZ_SIMPLE_TRIGGERS
(
  SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',
  TRIGGER_NAME VARCHAR(200) NOT NULL  comment '触发器名称',
  TRIGGER_GROUP VARCHAR(200) NOT NULL  comment '触发器组',
  REPEAT_COUNT BIGINT(7) NOT NULL  comment '重复执行次数',
  REPEAT_INTERVAL BIGINT(12) NOT NULL  comment '重复执行间隔',
  TIMES_TRIGGERED BIGINT(10) NOT NULL  comment '已经触发次数',
  PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
  REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_CRON_TRIGGERS
(
  SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',
  TRIGGER_NAME VARCHAR(200) NOT NULL  comment '触发器名称',
  TRIGGER_GROUP VARCHAR(200) NOT NULL  comment '触发器组',
  CRON_EXPRESSION VARCHAR(200) NOT NULL  comment 'cron表达式',
  TIME_ZONE_ID VARCHAR(80)  comment '时区',
  PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
  REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
(
  SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',
  TRIGGER_NAME VARCHAR(200) NOT NULL  comment '触发器名称',
  TRIGGER_GROUP VARCHAR(200) NOT NULL  comment '触发器组',
  STR_PROP_1 VARCHAR(512) NULL  comment '开始配置1',
  STR_PROP_2 VARCHAR(512) NULL  comment '开始配置2',
  STR_PROP_3 VARCHAR(512) NULL  comment '开始配置3',
  INT_PROP_1 INT NULL  comment 'int配置1',
  INT_PROP_2 INT NULL  comment 'int配置2',
  LONG_PROP_1 BIGINT NULL  comment 'long配置1',
  LONG_PROP_2 BIGINT NULL  comment 'long配置2',
  DEC_PROP_1 NUMERIC(13,4) NULL  comment '配置描述1',
  DEC_PROP_2 NUMERIC(13,4) NULL  comment '配置描述2',
  BOOL_PROP_1 VARCHAR(1) NULL  comment 'bool配置1',
  BOOL_PROP_2 VARCHAR(1) NULL  comment 'bool配置2',
  PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
  REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_BLOB_TRIGGERS
(
  SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',
  TRIGGER_NAME VARCHAR(200) NOT NULL  comment '触发器名称',
  TRIGGER_GROUP VARCHAR(200) NOT NULL  comment '触发器组',
  BLOB_DATA BLOB NULL  comment '数据',
  PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
  REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_CALENDARS
(
  SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',
  CALENDAR_NAME  VARCHAR(200) NOT NULL comment '日程名称',
  CALENDAR BLOB NOT NULL  comment '日程数据',
  PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
(
  SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',
  TRIGGER_GROUP  VARCHAR(200) NOT NULL  comment '触发器组',
  PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_FIRED_TRIGGERS
(
  SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',
  ENTRY_ID VARCHAR(95) NOT NULL  comment 'entryId',
  TRIGGER_NAME VARCHAR(200) NOT NULL  comment '触发器名称',
  TRIGGER_GROUP VARCHAR(200) NOT NULL  comment '触发器组',
  INSTANCE_NAME VARCHAR(200) NOT NULL  comment '实例名称',
  FIRED_TIME BIGINT(13) NOT NULL  comment '执行时间',
  SCHED_TIME BIGINT(13) NOT NULL  comment '定时任务时间',
  PRIORITY INTEGER NOT NULL  comment '等级',
  STATE VARCHAR(16) NOT NULL  comment '状态',
  JOB_NAME VARCHAR(200) NULL  comment 'job名称',
  JOB_GROUP VARCHAR(200) NULL  comment 'job组',
  IS_NONCONCURRENT VARCHAR(1) NULL  comment '是否异步',
  REQUESTS_RECOVERY VARCHAR(1) NULL  comment '是否请求覆盖',
  PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);
CREATE TABLE QRTZ_SCHEDULER_STATE
(
  SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',
  INSTANCE_NAME VARCHAR(200) NOT NULL  comment '实例名称',
  LAST_CHECKIN_TIME BIGINT(13) NOT NULL  comment '最近检入时间',
  CHECKIN_INTERVAL BIGINT(13) NOT NULL  comment '检入间隔',
  PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);
CREATE TABLE QRTZ_LOCKS
(
  SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',
  LOCK_NAME  VARCHAR(40) NOT NULL  comment 'lock名称',
  PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);

创建两个固定的配置类,这两个类在任何项目中可以使用都是差不多的固定写法

MyJobFactory.java

package com.jiawa.train.batch.config;

import jakarta.annotation.Resource;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
import org.springframework.stereotype.Component;

@Component
public class MyJobFactory extends SpringBeanJobFactory {

    @Resource
    private AutowireCapableBeanFactory beanFactory;

    /**
     * 这里覆盖了super的createJobInstance方法,对其创建出来的类再进行autowire。
     */
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        Object jobInstance = super.createJobInstance(bundle);
        beanFactory.autowireBean(jobInstance);
        return jobInstance;
    }
}

创建一个config工具类,根据数据库进行调度任务 连接数据库指定定时时间。调度器

package com.jiawa.train.batch.config;

import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import javax.sql.DataSource;
import java.io.IOException;

@Configuration
public class SchedulerConfig {

    @Resource
    private MyJobFactory myJobFactory;

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(@Qualifier("dataSource") DataSource dataSource) throws IOException {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setDataSource(dataSource);// 连接数据库
        factory.setJobFactory(myJobFactory);// 指定前面创建的配置类
        factory.setStartupDelay(2); //  延迟2秒启动
        return factory;
    }
}

 接下来开始完成定时任务的接口,使得定时任务让接口来控制,首先创建请求数据request

package com.jiawa.train.batch.req;

public class CronJobReq {
    private String group; // 分组

    private String name;//   任务名称

    private String description;//  描述

    private String cronExpression;//  执行时间表达式

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("CronJobDto{");
        sb.append("cronExpression='").append(cronExpression).append('\'');
        sb.append(", group='").append(group).append('\'');
        sb.append(", name='").append(name).append('\'');
        sb.append(", description='").append(description).append('\'');
        sb.append('}');
        return sb.toString();
    }

    public String getGroup() {
        return group;
    }

    public void setGroup(String group) {
        this.group = group;
    }

    public String getCronExpression() {
        return cronExpression;
    }

    public void setCronExpression(String cronExpression) {
        this.cronExpression = cronExpression;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

设置响应数据类response,进行set和get

package com.jiawa.train.batch.resp;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;

import java.util.Date;

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class CronJobResp {
    private String group;// 分组

    private String name; // 任务名称

    private String description; // 描述

    private String state;// 状态

    private String cronExpression;// 定时任务表达式

    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date nextFireTime;// 

    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date preFireTime;// 

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("CronJobDto{");
        sb.append("cronExpression='").append(cronExpression).append('\'');
        sb.append(", group='").append(group).append('\'');
        sb.append(", name='").append(name).append('\'');
        sb.append(", description='").append(description).append('\'');
        sb.append(", state='").append(state).append('\'');
        sb.append(", nextFireTime=").append(nextFireTime);
        sb.append(", preFireTime=").append(preFireTime);
        sb.append('}');
        return sb.toString();
    }

    public String getGroup() {
        return group;
    }

    public void setGroup(String group) {
        this.group = group;
    }

    public String getCronExpression() {
        return cronExpression;
    }

    public void setCronExpression(String cronExpression) {
        this.cronExpression = cronExpression;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getNextFireTime() {
        return nextFireTime;
    }

    public void setNextFireTime(Date nextFireTime) {
        this.nextFireTime = nextFireTime;
    }

    public Date getPreFireTime() {
        return preFireTime;
    }

    public void setPreFireTime(Date preFireTime) {
        this.preFireTime = preFireTime;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
}

 创建controller类接口,实现对定时任务的控制返回状态 添加定时任务。 当然如果项目中有一个控台端这就是控台的接口

创建定时任务,暂停,重置,启动定时任务,删除以及查看总共有多少个定时任务打开

package com.jiawa.train.batch.controller;

import com.jiawa.train.batch.req.CronJobReq;
import com.jiawa.train.batch.resp.CronJobResp;
import com.jiawa.train.common.resp.CommonResp;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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


@RestController
@RequestMapping(value = "/admin/job")
public class JobController {

    private static Logger LOG = LoggerFactory.getLogger(JobController.class);

    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;

    @RequestMapping(value = "/run")
    public CommonResp<Object> run(@RequestBody CronJobReq cronJobReq) throws SchedulerException {
        String jobClassName = cronJobReq.getName();
        String jobGroupName = cronJobReq.getGroup();
        LOG.info("手动执行任务开始:{}, {}", jobClassName, jobGroupName);
        schedulerFactoryBean.getScheduler().triggerJob(JobKey.jobKey(jobClassName, jobGroupName));
        return new CommonResp<>();
    }

    @RequestMapping(value = "/add")
    public CommonResp add(@RequestBody CronJobReq cronJobReq) {
        String jobClassName = cronJobReq.getName();
        String jobGroupName = cronJobReq.getGroup();
        String cronExpression = cronJobReq.getCronExpression();
        String description = cronJobReq.getDescription();
        LOG.info("创建定时任务开始:{},{},{},{}", jobClassName, jobGroupName, cronExpression, description);
        CommonResp commonResp = new CommonResp();

        try {
            // 通过SchedulerFactory获取一个调度器实例
            Scheduler sched = schedulerFactoryBean.getScheduler();

            // 启动调度器
            sched.start();

            //构建job信息
            JobDetail jobDetail = JobBuilder.newJob((Class<? extends Job>) Class.forName(jobClassName)).withIdentity(jobClassName, jobGroupName).build();

            //表达式调度构建器(即任务执行的时间)
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);

            //按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobClassName, jobGroupName).withDescription(description).withSchedule(scheduleBuilder).build();

            sched.scheduleJob(jobDetail, trigger);

        } catch (SchedulerException e) {
            LOG.error("创建定时任务失败:" + e);
            commonResp.setSuccess(false);
            commonResp.setMessage("创建定时任务失败:调度异常");
        } catch (ClassNotFoundException e) {
            LOG.error("创建定时任务失败:" + e);
            commonResp.setSuccess(false);
            commonResp.setMessage("创建定时任务失败:任务类不存在");
        }
        LOG.info("创建定时任务结束:{}", commonResp);
        return commonResp;
    }

    @RequestMapping(value = "/pause")
    public CommonResp pause(@RequestBody CronJobReq cronJobReq) {
        String jobClassName = cronJobReq.getName();
        String jobGroupName = cronJobReq.getGroup();
        LOG.info("暂停定时任务开始:{},{}", jobClassName, jobGroupName);
        CommonResp commonResp = new CommonResp();
        try {
            Scheduler sched = schedulerFactoryBean.getScheduler();
            sched.pauseJob(JobKey.jobKey(jobClassName, jobGroupName));
        } catch (SchedulerException e) {
            LOG.error("暂停定时任务失败:" + e);
            commonResp.setSuccess(false);
            commonResp.setMessage("暂停定时任务失败:调度异常");
        }
        LOG.info("暂停定时任务结束:{}", commonResp);
        return commonResp;
    }

    @RequestMapping(value = "/resume")
    public CommonResp resume(@RequestBody CronJobReq cronJobReq) {
        String jobClassName = cronJobReq.getName();
        String jobGroupName = cronJobReq.getGroup();
        LOG.info("重启定时任务开始:{},{}", jobClassName, jobGroupName);
        CommonResp commonResp = new CommonResp();
        try {
            Scheduler sched = schedulerFactoryBean.getScheduler();
            sched.resumeJob(JobKey.jobKey(jobClassName, jobGroupName));
        } catch (SchedulerException e) {
            LOG.error("重启定时任务失败:" + e);
            commonResp.setSuccess(false);
            commonResp.setMessage("重启定时任务失败:调度异常");
        }
        LOG.info("重启定时任务结束:{}", commonResp);
        return commonResp;
    }

    @RequestMapping(value = "/reschedule")
    public CommonResp reschedule(@RequestBody CronJobReq cronJobReq) {
        String jobClassName = cronJobReq.getName();
        String jobGroupName = cronJobReq.getGroup();
        String cronExpression = cronJobReq.getCronExpression();
        String description = cronJobReq.getDescription();
        LOG.info("更新定时任务开始:{},{},{},{}", jobClassName, jobGroupName, cronExpression, description);
        CommonResp commonResp = new CommonResp();
        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobGroupName);
            // 表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
            CronTriggerImpl trigger1 = (CronTriggerImpl) scheduler.getTrigger(triggerKey);
            trigger1.setStartTime(new Date()); // 重新设置开始时间
            CronTrigger trigger = trigger1;

            // 按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withDescription(description).withSchedule(scheduleBuilder).build();

            // 按新的trigger重新设置job执行
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (Exception e) {
            LOG.error("更新定时任务失败:" + e);
            commonResp.setSuccess(false);
            commonResp.setMessage("更新定时任务失败:调度异常");
        }
        LOG.info("更新定时任务结束:{}", commonResp);
        return commonResp;
    }

    @RequestMapping(value = "/delete")
    public CommonResp delete(@RequestBody CronJobReq cronJobReq) {
        String jobClassName = cronJobReq.getName();
        String jobGroupName = cronJobReq.getGroup();
        LOG.info("删除定时任务开始:{},{}", jobClassName, jobGroupName);
        CommonResp commonResp = new CommonResp();
        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName, jobGroupName));
            scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName, jobGroupName));
            scheduler.deleteJob(JobKey.jobKey(jobClassName, jobGroupName));
        } catch (SchedulerException e) {
            LOG.error("删除定时任务失败:" + e);
            commonResp.setSuccess(false);
            commonResp.setMessage("删除定时任务失败:调度异常");
        }
        LOG.info("删除定时任务结束:{}", commonResp);
        return commonResp;
    }

    @RequestMapping(value="/query")
    public CommonResp query() {
        LOG.info("查看所有定时任务开始");
        CommonResp commonResp = new CommonResp();
        List<CronJobResp> cronJobDtoList = new ArrayList();
        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            for (String groupName : scheduler.getJobGroupNames()) {
                for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
                    CronJobResp cronJobResp = new CronJobResp();
                    cronJobResp.setName(jobKey.getName());
                    cronJobResp.setGroup(jobKey.getGroup());

                    //get job's trigger
                    List<Trigger> triggers = (List<Trigger>) scheduler.getTriggersOfJob(jobKey);
                    CronTrigger cronTrigger = (CronTrigger) triggers.get(0);
                    cronJobResp.setNextFireTime(cronTrigger.getNextFireTime());
                    cronJobResp.setPreFireTime(cronTrigger.getPreviousFireTime());
                    cronJobResp.setCronExpression(cronTrigger.getCronExpression());
                    cronJobResp.setDescription(cronTrigger.getDescription());
                    Trigger.TriggerState triggerState = scheduler.getTriggerState(cronTrigger.getKey());
                    cronJobResp.setState(triggerState.name());

                    cronJobDtoList.add(cronJobResp);
                }

            }
        } catch (SchedulerException e) {
            LOG.error("查看定时任务失败:" + e);
            commonResp.setSuccess(false);
            commonResp.setMessage("查看定时任务失败:调度异常");
        }
        commonResp.setContent(cronJobDtoList);
        LOG.info("查看定时任务结束:{}", commonResp);
        return commonResp;
    }

}

开始测试接口是否成功 

POST http://localhost:8000/batch/admin/job/add
Content-Type: application/json

{
  "name": "com.jiawa.train.batch.job.TestJob",
  "jobGroupName": "default",
  "cronExpression": "*/2 * * * * ?",
  "desc": "test job"
}

###

GET http://localhost:8000/batch/admin/job/query

###

POST http://localhost:8000/batch/admin/job/pause
Content-Type: application/json

{
  "name": "com.jiawa.train.batch.job.TestJob",
  "jobGroupName": "default"
}

###

POST http://localhost:8000/batch/admin/job/resume
Content-Type: application/json

{
  "name": "com.jiawa.train.batch.job.TestJob",
  "jobGroupName": "default"
}

###

POST http://localhost:8000/batch/admin/job/reschedule
Content-Type: application/json

{
"name": "com.jiawa.train.batch.job.TestJob",
"jobGroupName": "default",
"cronExpression": "*/5 * * * * ?",
"desc": "test job"
}

###

POST http://localhost:8000/batch/admin/job/delete
Content-Type: application/json

{
"name": "com.jiawa.train.batch.job.TestJob",
"jobGroupName": "default"
}

###

POST http://localhost:8000/batch/admin/job/run
Content-Type: application/json

{
"name": "com.jiawa.train.batch.job.DailyTrainJob",
"jobGroupName": "default"
}

 以上就是接口控制定时任务的开始结束添加删除的功能。

下一篇就是多节点场景中如何调度任务quartz

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1332938.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

力扣日记12.24-【二叉树篇】236. 二叉树的最近公共祖先

力扣日记&#xff1a;【二叉树篇】236. 二叉树的最近公共祖先 日期&#xff1a;2023.12.24 参考&#xff1a;代码随想录、力扣 ps&#xff1a;提前祝 平安夜快乐&#xff01; 236. 二叉树的最近公共祖先 题目描述 难度&#xff1a;中等 给定一个二叉树, 找到该树中两个指定节点…

nodejs+vue+ElementUi摄影作品图片分享工作室管理系统

第1周 2.21&#xff5e;2.27 查阅资料&#xff0c;学习vscode开发平台和vue框架技术 第2周 2.28&#xff5e;3.6 对软件功能需求进行分析, 软件功能模块划分及软件界面设计 第3周 3.7&#xff5e;3.13 撰写并提交毕业设计开题报告、英文资料翻译 第4周 3.14&#xff5…

[Linux] MySQL数据库之索引

一、索引的相关知识 1.1 索引的简介 索引是一个排序列表&#xff0c;包含索引值和包含该值的数据行的物理地址&#xff08;类似于 c 语言链表&#xff0c;通过指针指向数据记录的内存地址&#xff09;。 使用索引后可以不用扫描全表来定位某行的数据&#xff0c;而是先通过索…

Linux环境变量剖析

一、什么是环境变量 概念&#xff1a;环境变量&#xff08;environment variables&#xff09;一般是指在操作系统中用来指定操作系统运行环境的一些参数&#xff0c;是在操作系统中一个具有特定名字的对象&#xff0c;它包含了一个或多个应用程序所将使用到的信息&#xff0c…

excel统计分析——S-W正态性检验

参考资料&#xff1a; [1]马兴华,张晋昕.数值变量正态性检验常用方法的对比[J].循证医学,2014,14(02):123-128. 统计推断——正态性检验&#xff08;图形方法、偏度和峰度、统计&#xff08;拟合优度&#xff09;检验&#xff09;_sm.distributions.ecdf-CSDN博客 【统计学】…

Linux操作系统基础 – 修改文件权限

Linux操作系统基础 – 修改文件权限 Linux Operating System Essentials - Modify File Rights By JacksonML 文件是Linux操作系统存储信息的基本结构。文件是一组信息的集合。 在Linux操作系统和Windows操作系统相比较的最大不同&#xff0c;是Linux文件没有扩展名&#xff…

2023年全球前端大技术大会(GMTC北京站2023)-核心PPT资料下载

一、峰会简介 大会以“业务至上&#xff0c;效率为王”为主题&#xff0c;策划了 1 个主会场&#xff0c;10 个技术专场。会议议题包含前端 DevOps 实践、低代码、大前端监控、跨端技术选型、团队可持续发展、IoT 动态应用开发、移动端性能与效率优化、TypeScript、大前端技术…

等腰三角形两底角相等

等腰三角形定义: 是指至少有两边相等的三角形。相等的两个边称为这个三角形的腰 二.证明 有等腰△ABC,AB和AC是腰,p是BC的中点 证明等腰三角形两底角相等 即 ∠ A B P ∠ P C A ∠ABP∠PCA ∠ABP∠PCA ∴ ∴ ∴ 三角形内角和为180 ∵ { ∠ A B P ∠ A P B ∠ B A P 180 …

形态学处理

形态学处理的相关内容 &#xff08;1&#xff09;基于图像形态进行处理的一般方法 &#xff08;2&#xff09;这些处理方法基本是对二进制图像进行处理 &#xff08;3&#xff09;卷积核决定着图像处理后的结果 形态学图像处理 &#xff08;1&#xff09;腐蚀&#xff08;…

如何打包鸿蒙应用并发布到应用市场

知识点&#xff1a; HarmonyOS 应用打包后的文件为.app 格式&#xff0c; android 打包后的文件为.apk&#xff0c;IOS 打包后的文件为.apa HarmonyOS通过数字证书&#xff08;.cer文件&#xff09;和Profile文件&#xff08;.p7b文件&#xff09;等签名信息来保证应用的完整性…

最常见的SQL报错注入函数(floor、updatexml、extractvalue)及payload总结

SQL报错注入是一种常见的SQL注入攻击方式&#xff0c;攻击者通过注入恶意代码&#xff0c;触发数据库的错误响应&#xff0c;并从错误信息中获取有用的信息。 下面介绍最常见的三个报错注入函数用法及payload总结&#xff1a; 1、floor() 使用floor报错注入&#xff0c;需要…

VS2020使用MFC开发一个贪吃蛇游戏

背景&#xff1a; 贪吃蛇游戏 按照如下步骤实现:。初始化地图 。通过键盘控制蛇运动方向&#xff0c;注意重新设置运动方向操作。 。制造食物。 。让蛇移动&#xff0c;如果吃掉食物就重新生成一个食物&#xff0c;如果会死亡就break。用蛇的坐标将地图中的空格替换为 #和”将…

[动态规划]完全背包问题及其优化

题目描述 有N种物品和一个容量为 V 的背包&#xff0c;每种物品都有无限件可用。 第 i 种物品的体积是Ci&#xff0c;价值是Wi。求解在不超过背包容量的情况下&#xff0c;能够获得的最大价值。 输入 第一行为两个整数N、V(1≤N,V≤10000)&#xff0c;分别代表题目描述中的物…

java 怎么读取文件创建时间?

Java读取文件创建时间的实现方法 在工作时候&#xff0c;我们有时候需要获取到文件的最后更新时间&#xff0c;根据最近更新时间&#xff0c;来处理其他业务。那么&#xff0c;在Java中&#xff0c;怎么获取到文件最后更新时间呢&#xff1f;接下来凯哥(个人号&#xff1a;凯哥…

教你应对Github最新的2FA二次验证! 无地区限制, 你的Github账户可能被封禁!

文章目录 2FA 定义2FA验证方法1 硬件令牌2.推送通知3.SMS 验证4 基于语音的身份验证 解决方案安装身份验证器的谷歌浏览器插件打开 github 的二维码&#xff0c;直接扫描 2FA 定义 双因素身份验证 (2FA) 是一种身份和访管理安全方法&#xff0c;需要经过两种形式的身份验证才能…

大数据----MapReduce实现统计单词

目录 一、简介二、实现单词统计数据准备编程MapReduceJob 三、运行四、结果 一、简介 Hadoop MapReduce 是一个编程框架&#xff0c;它可以轻松地编写应用程序&#xff0c;以可靠的、容错的方式处理大量的数据(数千个节点)。 正如其名&#xff0c;MapReduce 的工作模式主要分…

每日一题——Leetcode908

方法一 数学思想&#xff1a; 其实就是看数组中最大值和最小值一个加上k一个减去k是否能刚好凑到0&#xff0c;如果不能就是两者之差 var smallestRangeI function(nums, k) {var min9999,max-1for(var i0;i<nums.length;i){min Math.min(min,nums[i])max Math.max(max…

Python数据分析 Matplotlib篇 基本方法初识 (第1讲)

Python数据分析 Matplotlib篇(第1讲)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹…

leetcode 1576. 替换所有的问号(easy)(优质解法)

链接&#xff1a;1576. 替换所有的问号 代码&#xff1a; class Solution {public String modifyString(String s) {char[] charSs.toCharArray();int lengthcharS.length;//遍历找到 &#xff1f;for(int i0;i<length;i){if(charS[i]?){//遍历 a ~ z 选择一个合适的字符来…

Linux怎么解压zip格式文件?

Linux解压命令zip是一种常见的文件压缩格式&#xff0c;用于把文件打包成一个zip文件&#xff0c;当我们需要共享或是发送时&#xff0c;能够更快速的发送&#xff0c;储存起来能够减少储存空间。那我们在Linux上怎么使用解压命令zip来解压zip格式文件呢&#xff1f;我们一起来…