• SpringBoot定时任务 集成quartz实现定时任务(单实例和分布式两种方式)


    最为常用定时任务框架是Quartz,并且Spring也集成了Quartz的框架,Quartz不仅支持单实例方式还支持分布式方式。本文主要介绍Quartz,基础的Quartz的集成案例本,以及实现基于数据库的分布式任务管理和控制job生命周期。@pdai

    准备知识点

    需要了解常用的Quartz框架。

    什么是Quartz

    来源百度百科, 官网地址:www.quartz-scheduler.org/

    Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标准的Java组件或 EJBs。

    它的特点如下

    • 纯java实现,可以作为独立的应用程序,也可以嵌入在另一个独立式应用程序运行
    • 强大的调度功能,Spring默认的调度框架,灵活可配置;
    • 作业持久化,调度环境持久化机制,可以保存并恢复调度现场。系统关闭数据不会丢失;灵活的应用方式,可以任意定义触发器的调度时间表,支持任务和调度各种组合,组件式监听器、各种插件、线程池等功能,多种存储方式等;
    • 分布式和集群能力,可以被实例化,一个Quartz集群中的每个节点作为一个独立的Quartz使用,通过相同的数据库表来感知到另一个Quartz应用

    Quartz的体系结构

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

    注: 上图来源于www.cnblogs.com/jijm123/p/1…

    什么是Quartz持久化

    • 为什么要持久化

    当程序突然被中断时,如断电,内存超出时,很有可能造成任务的丢失。 可以将调度信息存储到数据库里面,进行持久化,当程序被中断后,再次启动,仍然会保留中断之前的数据,继续执行,而并不是重新开始。

    • Quartz提供了两种持久化方式

    Quartz提供两种基本作业存储类型:

    1. RAMJobStore

    在默认情况下Quartz将任务调度的运行信息保存在内存中,这种方法提供了最佳的性能,因为内存中数据访问最快。不足之处是缺乏数据的持久性,当程序路途停止或系统崩溃时,所有运行的信息都会丢失。

    1. JobStoreTX

    所有的任务信息都会保存到数据库中,可以控制事物,还有就是如果应用服务器关闭或者重启,任务信息都不会丢失,并且可以恢复因服务器关闭或者重启而导致执行失败的任务。

    实现案例 - 单实例方式

    本例将展示quartz实现单实例方式。

    • 引入POM依赖
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-quartz</artifactId>
    </dependency>
    复制代码
    • 定义Job

    只需要继承QuartzJobBean,并重载executeInternal方法即可定义你自己的Job执行逻辑。

    @Slf4j
    public class HelloJob extends QuartzJobBean {
    
        @Override
        protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
            // get parameters
            context.getJobDetail().getJobDataMap().forEach(
                    (k, v) -> log.info("param, key:{}, value:{}", k, v)
            );
            // your logics
            log.info("Hello Job执行时间: " + new Date());
        }
    }
    复制代码
    • 配置Job

    JobDetail, Trigger, Schedule(这里采用CronScheduleBuilder)

    /**
     * @author pdai
     */
    @Configuration
    public class QuartzConfig {
    
        @Bean("helloJob")
        public JobDetail helloJobDetail() {
            return JobBuilder.newJob(HelloJob.class)
                    .withIdentity("DateTimeJob")
                    .usingJobData("msg", "Hello Quartz")
                    .storeDurably()//即使没有Trigger关联时,也不需要删除该JobDetail
                    .build();
        }
    
        @Bean
        public Trigger printTimeJobTrigger() {
            // 每秒执行一次
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/1 * * * * ?");
            return TriggerBuilder.newTrigger()
                    .forJob(helloJobDetail())
                    .withIdentity("quartzTaskService")
                    .withSchedule(cronScheduleBuilder)
                    .build();
        }
    }
    复制代码
    • 执行测试
    2021-10-01 13:09:00.380  INFO 38484 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
    2021-10-01 13:09:00.391  INFO 38484 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
    2021-10-01 13:09:00.392  INFO 38484 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.50]
    2021-10-01 13:09:00.526  INFO 38484 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
    2021-10-01 13:09:00.526  INFO 38484 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1424 ms
    2021-10-01 13:09:00.866  INFO 38484 --- [           main] org.quartz.impl.StdSchedulerFactory      : Using default implementation for ThreadExecutor
    2021-10-01 13:09:00.877  INFO 38484 --- [           main] org.quartz.core.SchedulerSignalerImpl    : Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
    2021-10-01 13:09:00.877  INFO 38484 --- [           main] org.quartz.core.QuartzScheduler          : Quartz Scheduler v.2.3.2 created.
    2021-10-01 13:09:00.878  INFO 38484 --- [           main] org.quartz.simpl.RAMJobStore             : RAMJobStore initialized.
    2021-10-01 13:09:00.878  INFO 38484 --- [           main] org.quartz.core.QuartzScheduler          : Scheduler meta-data: Quartz Scheduler (v2.3.2) 'quartzScheduler' with instanceId 'NON_CLUSTERED'
      Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
      NOT STARTED.
      Currently in standby mode.
      Number of jobs executed: 0
      Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
      Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.
    
    2021-10-01 13:09:00.878  INFO 38484 --- [           main] org.quartz.impl.StdSchedulerFactory      : Quartz scheduler 'quartzScheduler' initialized from an externally provided properties instance.
    2021-10-01 13:09:00.879  INFO 38484 --- [           main] org.quartz.impl.StdSchedulerFactory      : Quartz scheduler version: 2.3.2
    2021-10-01 13:09:00.879  INFO 38484 --- [           main] org.quartz.core.QuartzScheduler          : JobFactory set to: org.springframework.scheduling.quartz.SpringBeanJobFactory@6075b2d3
    2021-10-01 13:09:00.922  INFO 38484 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
    2021-10-01 13:09:00.923  INFO 38484 --- [           main] o.s.s.quartz.SchedulerFactoryBean        : Starting Quartz Scheduler now
    2021-10-01 13:09:00.923  INFO 38484 --- [           main] org.quartz.core.QuartzScheduler          : Scheduler quartzScheduler_$_NON_CLUSTERED started.
    2021-10-01 13:09:00.933  INFO 38484 --- [           main] tech.pdai.springboot.quartz.App          : Started App in 2.64 seconds (JVM running for 3.621)
    2021-10-01 13:09:00.931  INFO 38484 --- [eduler_Worker-1] t.pdai.springboot.quartz.job.HelloJob    : param, key:msg, value:Hello Quartz
    2021-10-01 13:09:00.933  INFO 38484 --- [eduler_Worker-1] t.pdai.springboot.quartz.job.HelloJob    : Hello Job执行时间: Wed Oct 27 13:09:00 CST 2021
    2021-10-01 13:09:01.001  INFO 38484 --- [eduler_Worker-2] t.pdai.springboot.quartz.job.HelloJob    : param, key:msg, value:Hello Quartz
    2021-10-01 13:09:01.001  INFO 38484 --- [eduler_Worker-2] t.pdai.springboot.quartz.job.HelloJob    : Hello Job执行时间: Wed Oct 27 13:09:01 CST 2021
    2021-10-01 13:09:02.000  INFO 38484 --- [eduler_Worker-3] t.pdai.springboot.quartz.job.HelloJob    : param, key:msg, value:Hello Quartz
    2021-10-01 13:09:02.000  INFO 38484 --- [eduler_Worker-3] t.pdai.springboot.quartz.job.HelloJob    : Hello Job执行时间: Wed Oct 27 13:09:02 CST 2021
    2021-10-01 13:09:03.000  INFO 38484 --- [eduler_Worker-4] t.pdai.springboot.quartz.job.HelloJob    : param, key:msg, value:Hello Quartz
    2021-10-01 13:09:03.001  INFO 38484 --- [eduler_Worker-4] t.pdai.springboot.quartz.job.HelloJob    : Hello Job执行时间: Wed Oct 27 13:09:03 CST 2021
    2021-10-01 13:09:04.001  INFO 38484 --- [eduler_Worker-5] t.pdai.springboot.quartz.job.HelloJob    : param, key:msg, value:Hello Quartz
    2021-10-01 13:09:04.001  INFO 38484 --- [eduler_Worker-5] t.pdai.springboot.quartz.job.HelloJob    : Hello Job执行时间: Wed Oct 27 13:09:04 CST 2021
    2021-10-01 13:09:05.002  INFO 38484 --- [eduler_Worker-6] t.pdai.springboot.quartz.job.HelloJob    : param, key:msg, value:Hello Quartz
    2021-10-01 13:09:05.003  INFO 38484 --- [eduler_Worker-6] t.pdai.springboot.quartz.job.HelloJob    : Hello Job执行时间: Wed Oct 27 13:09:05 CST 2021
    2021-10-01 13:09:06.000  INFO 38484 --- [eduler_Worker-7] t.pdai.springboot.quartz.job.HelloJob    : param, key:msg, value:Hello Quartz
    2021-10-01 13:09:06.001  INFO 38484 --- [eduler_Worker-7] t.pdai.springboot.quartz.job.HelloJob    : Hello Job执行时间: Wed Oct 27 13:09:06 CST 2021
    2021-10-01 13:09:07.002  INFO 38484 --- [eduler_Worker-8] t.pdai.springboot.quartz.job.HelloJob    : param, key:msg, value:Hello Quartz
    2021-10-01 13:09:07.002  INFO 38484 --- [eduler_Worker-8] t.pdai.springboot.quartz.job.HelloJob    : Hello Job执行时间: Wed Oct 27 13:09:07 CST 2021
    2021-10-01 13:09:08.002  INFO 38484 --- [eduler_Worker-9] t.pdai.springboot.quartz.job.HelloJob    : param, key:msg, value:Hello Quartz
    2021-10-01 13:09:08.003  INFO 38484 --- [eduler_Worker-9] t.pdai.springboot.quartz.job.HelloJob    : Hello Job执行时间: Wed Oct 27 13:09:08 CST 2021
    2021-10-01 13:09:09.000  INFO 38484 --- [duler_Worker-10] t.pdai.springboot.quartz.job.HelloJob    : param, key:msg, value:Hello Quartz
    2021-10-01 13:09:09.000  INFO 38484 --- [duler_Worker-10] t.pdai.springboot.quartz.job.HelloJob    : Hello Job执行时间: Wed Oct 27 13:09:09 CST 2021
    2021-10-01 13:09:10.001  INFO 38484 --- [eduler_Worker-1] t.pdai.springboot.quartz.job.HelloJob    : param, key:msg, value:Hello Quartz
    2021-10-01 13:09:10.002  INFO 38484 --- [eduler_Worker-1] t.pdai.springboot.quartz.job.HelloJob    : Hello Job执行时间: Wed Oct 27 13:09:10 CST 2021
    2021-10-01 13:09:11.014  INFO 38484 --- [eduler_Worker-2] t.pdai.springboot.quartz.job.HelloJob    : param, key:msg, value:Hello Quartz
    2021-10-01 13:09:11.014  INFO 38484 --- [eduler_Worker-2] t.pdai.springboot.quartz.job.HelloJob    : Hello Job执行时间: Wed Oct 27 13:09:11 CST 2021
    复制代码

    实现案例 - 分布式方式

    本例将展示quartz实现基于数据库的分布式任务管理,和控制job生命周期。

    整体项目结构如下:

    后端实现

    • pom.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.5.3</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
        <modelVersion>4.0.0</modelVersion>
        <groupId>tech.pdai</groupId>
        <artifactId>423-springboot-demo-schedule-quartz-cluster</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-quartz</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.42</version><!--$NO-MVN-MAN-VER$-->
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.20</version>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>com.github.pagehelper</groupId>
                <artifactId>pagehelper</artifactId>
                <version>5.0.0</version>
            </dependency>
        </dependencies>
    
    </project>
    复制代码
    • 创建Schema

    需要提前在MySQL中创建schema: quartz_jobs

    # 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;
    # DROP TABLE IF EXISTS QRTZ_TASK_HISTORY;
    
    CREATE TABLE QRTZ_JOB_DETAILS(
      SCHED_NAME VARCHAR(120) NOT NULL,
      JOB_NAME VARCHAR(200) NOT NULL,
      JOB_GROUP VARCHAR(200) NOT NULL,
      DESCRIPTION VARCHAR(250) NULL,
      JOB_CLASS_NAME VARCHAR(250) NOT NULL,
      IS_DURABLE VARCHAR(1) NOT NULL,
      IS_NONCONCURRENT VARCHAR(1) NOT NULL,
      IS_UPDATE_DATA VARCHAR(1) NOT NULL,
      REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
      JOB_DATA BLOB NULL,
      PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))
      ENGINE=InnoDB;
    
    CREATE TABLE QRTZ_TRIGGERS (
      SCHED_NAME VARCHAR(120) NOT NULL,
      TRIGGER_NAME VARCHAR(200) NOT NULL,
      TRIGGER_GROUP VARCHAR(200) NOT NULL,
      JOB_NAME VARCHAR(200) NOT NULL,
      JOB_GROUP VARCHAR(200) NOT NULL,
      DESCRIPTION VARCHAR(250) NULL,
      NEXT_FIRE_TIME BIGINT(13) NULL,
      PREV_FIRE_TIME BIGINT(13) NULL,
      PRIORITY INTEGER NULL,
      TRIGGER_STATE VARCHAR(16) NOT NULL,
      TRIGGER_TYPE VARCHAR(8) NOT NULL,
      START_TIME BIGINT(13) NOT NULL,
      END_TIME BIGINT(13) NULL,
      CALENDAR_NAME VARCHAR(200) NULL,
      MISFIRE_INSTR SMALLINT(2) NULL,
      JOB_DATA BLOB NULL,
      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))
      ENGINE=InnoDB;
    
    CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
      SCHED_NAME VARCHAR(120) NOT NULL,
      TRIGGER_NAME VARCHAR(200) NOT NULL,
      TRIGGER_GROUP VARCHAR(200) NOT NULL,
      REPEAT_COUNT BIGINT(7) NOT NULL,
      REPEAT_INTERVAL BIGINT(12) NOT NULL,
      TIMES_TRIGGERED BIGINT(10) NOT NULL,
      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))
      ENGINE=InnoDB;
    
    CREATE TABLE QRTZ_CRON_TRIGGERS (
      SCHED_NAME VARCHAR(120) NOT NULL,
      TRIGGER_NAME VARCHAR(200) NOT NULL,
      TRIGGER_GROUP VARCHAR(200) NOT NULL,
      CRON_EXPRESSION VARCHAR(120) NOT NULL,
      TIME_ZONE_ID VARCHAR(80),
      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))
      ENGINE=InnoDB;
    
    CREATE TABLE QRTZ_SIMPROP_TRIGGERS
    (
      SCHED_NAME VARCHAR(120) NOT NULL,
      TRIGGER_NAME VARCHAR(200) NOT NULL,
      TRIGGER_GROUP VARCHAR(200) NOT NULL,
      STR_PROP_1 VARCHAR(512) NULL,
      STR_PROP_2 VARCHAR(512) NULL,
      STR_PROP_3 VARCHAR(512) NULL,
      INT_PROP_1 INT NULL,
      INT_PROP_2 INT NULL,
      LONG_PROP_1 BIGINT NULL,
      LONG_PROP_2 BIGINT NULL,
      DEC_PROP_1 NUMERIC(13,4) NULL,
      DEC_PROP_2 NUMERIC(13,4) NULL,
      BOOL_PROP_1 VARCHAR(1) NULL,
      BOOL_PROP_2 VARCHAR(1) NULL,
      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))
      ENGINE=InnoDB;
    
    CREATE TABLE QRTZ_BLOB_TRIGGERS (
      SCHED_NAME VARCHAR(120) NOT NULL,
      TRIGGER_NAME VARCHAR(200) NOT NULL,
      TRIGGER_GROUP VARCHAR(200) NOT NULL,
      BLOB_DATA BLOB NULL,
      PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
      INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
      FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
      REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
      ENGINE=InnoDB;
    
    CREATE TABLE QRTZ_CALENDARS (
      SCHED_NAME VARCHAR(120) NOT NULL,
      CALENDAR_NAME VARCHAR(200) NOT NULL,
      CALENDAR BLOB NOT NULL,
      PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
      ENGINE=InnoDB;
    
    CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
      SCHED_NAME VARCHAR(120) NOT NULL,
      TRIGGER_GROUP VARCHAR(200) NOT NULL,
      PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
      ENGINE=InnoDB;
    
    CREATE TABLE QRTZ_FIRED_TRIGGERS (
      SCHED_NAME VARCHAR(120) NOT NULL,
      ENTRY_ID VARCHAR(95) NOT NULL,
      TRIGGER_NAME VARCHAR(200) NOT NULL,
      TRIGGER_GROUP VARCHAR(200) NOT NULL,
      INSTANCE_NAME VARCHAR(200) NOT NULL,
      FIRED_TIME BIGINT(13) NOT NULL,
      SCHED_TIME BIGINT(13) NOT NULL,
      PRIORITY INTEGER NOT NULL,
      STATE VARCHAR(16) NOT NULL,
      JOB_NAME VARCHAR(200) NULL,
      JOB_GROUP VARCHAR(200) NULL,
      IS_NONCONCURRENT VARCHAR(1) NULL,
      REQUESTS_RECOVERY VARCHAR(1) NULL,
      PRIMARY KEY (SCHED_NAME,ENTRY_ID))
      ENGINE=InnoDB;
    
    CREATE TABLE QRTZ_SCHEDULER_STATE (
      SCHED_NAME VARCHAR(120) NOT NULL,
      INSTANCE_NAME VARCHAR(200) NOT NULL,
      LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
      CHECKIN_INTERVAL BIGINT(13) NOT NULL,
      PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
      ENGINE=InnoDB;
    
    CREATE TABLE QRTZ_LOCKS (
      SCHED_NAME VARCHAR(120) NOT NULL,
      LOCK_NAME VARCHAR(40) NOT NULL,
      PRIMARY KEY (SCHED_NAME,LOCK_NAME))
      ENGINE=InnoDB;
    
    CREATE TABLE QRTZ_TASK_HISTORY (
      SCHED_NAME VARCHAR(120) NOT NULL,
      INSTANCE_ID VARCHAR(200) NOT NULL,
      FIRE_ID VARCHAR(95) NOT NULL,
      TASK_NAME VARCHAR(200) NULL,
      TASK_GROUP VARCHAR(200) NULL,
      FIRED_TIME BIGINT(13) NULL,
      FIRED_WAY VARCHAR(8) NULL,
      COMPLETE_TIME BIGINT(13) NULL,
      EXPEND_TIME BIGINT(13) NULL,
      REFIRED INT NULL,
      EXEC_STATE VARCHAR(10) NULL,
      LOG TEXT NULL,
      PRIMARY KEY (FIRE_ID)
    )ENGINE=InnoDB;
    
    CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
    CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);
    
    CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
    CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
    CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
    CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
    CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
    CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
    CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
    CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
    CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
    CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
    CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
    CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);
    
    CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
    CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
    CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
    CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
    CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
    CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
    
    CREATE INDEX IDX_QRTZ_TK_S ON QRTZ_TASK_HISTORY(SCHED_NAME);
    
    commit;
    复制代码
    • application.yml
    spring:
      datasource:
        url: jdbc:mysql://localhost:3306/quartz_jobs?useUnicode=true&useSSL=false
        username: root
        password: xxxxxxxx
        driver-class-name: com.mysql.jdbc.Driver
      quartz:
        #相关属性配置
        properties:
          org:
            quartz:
              scheduler:
                instanceName: clusteredScheduler
                instanceId: AUTO
              jobStore:
                class: org.quartz.impl.jdbcjobstore.JobStoreTX
                driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
                tablePrefix: QRTZ_
                isClustered: true
                clusterCheckinInterval: 10000
                useProperties: false
              threadPool:
                class: org.quartz.simpl.SimpleThreadPool
                threadCount: 10
                threadPriority: 5
                threadsInheritContextClassLoaderOfInitializingThread: true
        #数据库方式
        job-store-type: jdbc
    复制代码
    • 定义JobDetails实体
    /** 
     * @author pdai
     *
     */
    @Data
    public class JobDetails{
    	private String cronExpression;	
    	private String jobClassName;	
    	private String triggerGroupName;
    	private String triggerName;
    	private String jobGroupName;
    	private String jobName;
    	private Date nextFireTime;
    	private Date previousFireTime;
    	private Date startTime;
    	private String timeZone;
    	private String status;
    }
    复制代码
    • Job管理类
    package tech.pdai.springboot.quartz.cluster.manager;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import com.github.pagehelper.PageHelper;
    import com.github.pagehelper.PageInfo;
    import org.quartz.CronScheduleBuilder;
    import org.quartz.CronTrigger;
    import org.quartz.DateBuilder;
    import org.quartz.DateBuilder.IntervalUnit;
    import org.quartz.Job;
    import org.quartz.JobBuilder;
    import org.quartz.JobDetail;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobKey;
    import org.quartz.Scheduler;
    import org.quartz.SchedulerException;
    import org.quartz.SimpleScheduleBuilder;
    import org.quartz.Trigger;
    import org.quartz.TriggerBuilder;
    import org.quartz.TriggerKey;
    import org.quartz.impl.matchers.GroupMatcher;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.scheduling.quartz.QuartzJobBean;
    import org.springframework.stereotype.Component;
    import tech.pdai.springboot.quartz.cluster.entity.JobDetails;
    
    /**
     * @author pdai
     */
    @Component
    public class QuartzManager {
    
        @Autowired
        private Scheduler sched;
    
        /**
         * 创建or更新任务,存在则更新不存在创建
         *
         * @param jobClass     任务类
         * @param jobName      任务名称
         * @param jobGroupName 任务组名称
         * @param jobCron      cron表达式
         */
        public void addOrUpdateJob(Class<? extends QuartzJobBean> jobClass, String jobName, String jobGroupName, String jobCron) {
            try {
                TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
                CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
                if (trigger==null) {
                    addJob(jobClass, jobName, jobGroupName, jobCron);
                } else {
                    if (trigger.getCronExpression().equals(jobCron)) {
                        return;
                    }
                    updateJob(jobName, jobGroupName, jobCron);
                }
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 增加一个job
         *
         * @param jobClass     任务实现类
         * @param jobName      任务名称
         * @param jobGroupName 任务组名
         * @param jobCron      cron表达式(如:0/5 * * * * ? )
         */
        public void addJob(Class<? extends QuartzJobBean> jobClass, String jobName, String jobGroupName, String jobCron) {
            try {
                JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();
                Trigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)
                        .startAt(DateBuilder.futureDate(1, IntervalUnit.SECOND))
                        .withSchedule(CronScheduleBuilder.cronSchedule(jobCron)).startNow().build();
    
                sched.scheduleJob(jobDetail, trigger);
                if (!sched.isShutdown()) {
                    sched.start();
                }
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * @param jobClass
         * @param jobName
         * @param jobGroupName
         * @param jobTime
         */
        public void addJob(Class<? extends Job> jobClass, String jobName, String jobGroupName, int jobTime) {
            addJob(jobClass, jobName, jobGroupName, jobTime, -1);
        }
    
        public void addJob(Class<? extends Job> jobClass, String jobName, String jobGroupName, int jobTime, int jobTimes) {
            try {
                JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName)// 任务名称和组构成任务key
                        .build();
                // 使用simpleTrigger规则
                Trigger trigger;
                if (jobTimes < 0) {
                    trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)
                            .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1).withIntervalInSeconds(jobTime))
                            .startNow().build();
                } else {
                    trigger = TriggerBuilder
                            .newTrigger().withIdentity(jobName, jobGroupName).withSchedule(SimpleScheduleBuilder
                                    .repeatSecondlyForever(1).withIntervalInSeconds(jobTime).withRepeatCount(jobTimes))
                            .startNow().build();
                }
                sched.scheduleJob(jobDetail, trigger);
                if (!sched.isShutdown()) {
                    sched.start();
                }
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    
        public void updateJob(String jobName, String jobGroupName, String jobTime) {
            try {
                TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
                CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
                        .withSchedule(CronScheduleBuilder.cronSchedule(jobTime)).build();
                // 重启触发器
                sched.rescheduleJob(triggerKey, trigger);
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 删除任务一个job
         *
         * @param jobName      任务名称
         * @param jobGroupName 任务组名
         */
        public void deleteJob(String jobName, String jobGroupName) {
            try {
                sched.pauseTrigger(TriggerKey.triggerKey(jobName, jobGroupName));
                sched.unscheduleJob(TriggerKey.triggerKey(jobName, jobGroupName));
                sched.deleteJob(new JobKey(jobName, jobGroupName));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 暂停一个job
         *
         * @param jobName
         * @param jobGroupName
         */
        public void pauseJob(String jobName, String jobGroupName) {
            try {
                JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
                sched.pauseJob(jobKey);
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 恢复一个job
         *
         * @param jobName
         * @param jobGroupName
         */
        public void resumeJob(String jobName, String jobGroupName) {
            try {
                JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
                sched.resumeJob(jobKey);
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 立即执行一个job
         *
         * @param jobName
         * @param jobGroupName
         */
        public void runAJobNow(String jobName, String jobGroupName) {
            try {
                JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
                sched.triggerJob(jobKey);
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    
        public PageInfo<JobDetails> queryAllJobBean(int pageNum, int pageSize) {
            PageHelper.startPage(pageNum, pageSize);
            List<JobDetails> jobList = null;
            try {
                GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
                Set<JobKey> jobKeys = sched.getJobKeys(matcher);
                jobList = new ArrayList<>();
                for (JobKey jobKey : jobKeys) {
                    List<? extends Trigger> triggers = sched.getTriggersOfJob(jobKey);
                    for (Trigger trigger : triggers) {
                        JobDetails jobDetails = new JobDetails();
                        if (trigger instanceof CronTrigger) {
                            CronTrigger cronTrigger = (CronTrigger) trigger;
                            jobDetails.setCronExpression(cronTrigger.getCronExpression());
                            jobDetails.setTimeZone(cronTrigger.getTimeZone().getDisplayName());
                        }
                        jobDetails.setTriggerGroupName(trigger.getKey().getName());
                        jobDetails.setTriggerName(trigger.getKey().getGroup());
                        jobDetails.setJobGroupName(jobKey.getGroup());
                        jobDetails.setJobName(jobKey.getName());
                        jobDetails.setStartTime(trigger.getStartTime());
                        jobDetails.setJobClassName(sched.getJobDetail(jobKey).getJobClass().getName());
                        jobDetails.setNextFireTime(trigger.getNextFireTime());
                        jobDetails.setPreviousFireTime(trigger.getPreviousFireTime());
                        jobDetails.setStatus(sched.getTriggerState(trigger.getKey()).name());
                        jobList.add(jobDetails);
                    }
                }
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
            return new PageInfo<>(jobList);
        }
    
        /**
         * 获取所有计划中的任务列表
         *
         * @return
         */
        public List<Map<String, Object>> queryAllJob() {
            List<Map<String, Object>> jobList = null;
            try {
                GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
                Set<JobKey> jobKeys = sched.getJobKeys(matcher);
                jobList = new ArrayList<>();
                for (JobKey jobKey : jobKeys) {
                    List<? extends Trigger> triggers = sched.getTriggersOfJob(jobKey);
                    for (Trigger trigger : triggers) {
                        Map<String, Object> map = new HashMap<>();
                        map.put("jobName", jobKey.getName());
                        map.put("jobGroupName", jobKey.getGroup());
                        map.put("description", "trigger:" + trigger.getKey());
                        Trigger.TriggerState triggerState = sched.getTriggerState(trigger.getKey());
                        map.put("jobStatus", triggerState.name());
                        if (trigger instanceof CronTrigger) {
                            CronTrigger cronTrigger = (CronTrigger) trigger;
                            String cronExpression = cronTrigger.getCronExpression();
                            map.put("jobTime", cronExpression);
                        }
                        jobList.add(map);
                    }
                }
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
            return jobList;
        }
    
        /**
         * 获取所有正在运行的job
         *
         * @return
         */
        public List<Map<String, Object>> queryRunJon() {
            List<Map<String, Object>> jobList = null;
            try {
                List<JobExecutionContext> executingJobs = sched.getCurrentlyExecutingJobs();
                jobList = new ArrayList<>(executingJobs.size());
                for (JobExecutionContext executingJob : executingJobs) {
                    Map<String, Object> map = new HashMap<>();
                    JobDetail jobDetail = executingJob.getJobDetail();
                    JobKey jobKey = jobDetail.getKey();
                    Trigger trigger = executingJob.getTrigger();
                    map.put("jobName", jobKey.getName());
                    map.put("jobGroupName", jobKey.getGroup());
                    map.put("description", "trigger:" + trigger.getKey());
                    Trigger.TriggerState triggerState = sched.getTriggerState(trigger.getKey());
                    map.put("jobStatus", triggerState.name());
                    if (trigger instanceof CronTrigger) {
                        CronTrigger cronTrigger = (CronTrigger) trigger;
                        String cronExpression = cronTrigger.getCronExpression();
                        map.put("jobTime", cronExpression);
                    }
                    jobList.add(map);
                }
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
            return jobList;
        }
    }
    复制代码
    • Job控制器接口
    package tech.pdai.springboot.quartz.cluster.controller;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import com.github.pagehelper.PageInfo;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.scheduling.quartz.QuartzJobBean;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    import tech.pdai.springboot.quartz.cluster.entity.JobDetails;
    import tech.pdai.springboot.quartz.cluster.manager.QuartzManager;
    
    
    /**
     * @author pdai
     */
    @RestController
    @RequestMapping(value = "/job")
    public class JobController {
    
        @Autowired
        private QuartzManager qtzManager;
    
        @SuppressWarnings("unchecked")
        private static Class<? extends QuartzJobBean> getClass(String classname) throws Exception {
            Class<?> class1 = Class.forName(classname);
            return (Class<? extends QuartzJobBean>) class1;
        }
    
        /**
         * @param jobClassName
         * @param jobGroupName
         * @param cronExpression
         * @throws Exception
         */
        @PostMapping(value = "/addjob")
        public void addjob(@RequestParam(value = "jobClassName") String jobClassName,
                           @RequestParam(value = "jobGroupName") String jobGroupName,
                           @RequestParam(value = "cronExpression") String cronExpression) throws Exception {
            qtzManager.addOrUpdateJob(getClass(jobClassName), jobClassName, jobGroupName, cronExpression);
        }
    
        /**
         * @param jobClassName
         * @param jobGroupName
         * @throws Exception
         */
        @PostMapping(value = "/pausejob")
        public void pausejob(@RequestParam(value = "jobClassName") String jobClassName,
                             @RequestParam(value = "jobGroupName") String jobGroupName) throws Exception {
            qtzManager.pauseJob(jobClassName, jobGroupName);
        }
    
        /**
         * @param jobClassName
         * @param jobGroupName
         * @throws Exception
         */
        @PostMapping(value = "/resumejob")
        public void resumejob(@RequestParam(value = "jobClassName") String jobClassName,
                              @RequestParam(value = "jobGroupName") String jobGroupName) throws Exception {
            qtzManager.resumeJob(jobClassName, jobGroupName);
        }
    
        /**
         * @param jobClassName
         * @param jobGroupName
         * @param cronExpression
         * @throws Exception
         */
        @PostMapping(value = "/reschedulejob")
        public void rescheduleJob(@RequestParam(value = "jobClassName") String jobClassName,
                                  @RequestParam(value = "jobGroupName") String jobGroupName,
                                  @RequestParam(value = "cronExpression") String cronExpression) throws Exception {
            qtzManager.addOrUpdateJob(getClass(jobClassName), jobClassName, jobGroupName, cronExpression);
        }
    
        /**
         * @param jobClassName
         * @param jobGroupName
         * @throws Exception
         */
        @PostMapping(value = "/deletejob")
        public void deletejob(@RequestParam(value = "jobClassName") String jobClassName,
                              @RequestParam(value = "jobGroupName") String jobGroupName) throws Exception {
            qtzManager.deleteJob(jobClassName, jobGroupName);
        }
    
        /**
         * @param pageNum
         * @param pageSize
         * @return
         */
        @GetMapping(value = "/queryjob")
        public Map<String, Object> queryjob(@RequestParam(value = "pageNum") Integer pageNum,
                                            @RequestParam(value = "pageSize") Integer pageSize) {
            PageInfo<JobDetails> jobAndTrigger = qtzManager.queryAllJobBean(pageNum, pageSize);
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("JobAndTrigger", jobAndTrigger);
            map.put("number", jobAndTrigger.getTotal());
            return map;
        }
    }
    复制代码
    • 定义具体的Job
    package tech.pdai.springboot.quartz.cluster.job;
    
    import java.util.Date;
    
    import lombok.extern.slf4j.Slf4j;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    import org.springframework.scheduling.quartz.QuartzJobBean;
    
    @Slf4j
    public class HelloJob extends QuartzJobBean {
    
        @Override
        protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
            // get parameters
            context.getJobDetail().getJobDataMap().forEach(
                    (k, v) -> log.info("param, key:{}, value:{}", k, v)
            );
            // your logics
            log.info("Hello Job执行时间: " + new Date());
        }
    }
    复制代码

    前端实现

    简单用VueJS 写个页面测试

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    	<title>QuartzDemo</title>
    	<link rel="stylesheet" href="https://unpkg.com/element-ui@2.0.5/lib/theme-chalk/index.css">
    	<script src="https://unpkg.com/vue/dist/vue.js"></script>
    	<script src="http://cdn.bootcss.com/vue-resource/1.3.4/vue-resource.js"></script>
    	<script src="https://unpkg.com/element-ui@2.0.5/lib/index.js"></script>
    	
    	<style>      
          #top {
    	      background:#20A0FF;
    	      padding:5px;
    	      overflow:hidden
          }
    	</style>
    	
    </head>
    <body>
        <div id="test">		        
    
    		<div id="top">			
    				<el-button type="text" @click="search" style="color:white">查询</el-button>	
    				<el-button type="text" @click="handleadd" style="color:white">添加</el-button>	
    			</span>						
    		</div>	
    				
    		<br/>
    
            <div style="margin-top:15px">	
    
    		  <el-table
    		    ref="testTable"		  
    		    :data="tableData"
    		    style="100%"
    		    border
    		    >
    		    <el-table-column
    		      prop="status"
    		      label="任务状态"
    		      sortable
    		      show-overflow-tooltip>
    		    </el-table-column>
    		    
    		    <el-table-column
    		      prop="jobName"
    		      label="任务名称"
    		      sortable
    		      show-overflow-tooltip>
    		    </el-table-column>
    		    
    		    <el-table-column
    		      prop="jobGroupName"
    		      label="任务所在组"
    		      sortable>
    		    </el-table-column>
    		    
       		    <el-table-column
    		      prop="jobClassName"
    		      label="任务类名"
    		      sortable>
    		    </el-table-column>
    		    
       		    <el-table-column
    		      prop="triggerName"
    		      label="触发器名称"
    		      sortable>
    		    </el-table-column>
    		    
    		    <el-table-column
    		      prop="triggerGroupName"
    		      label="触发器所在组"
    		      sortable>
    		    </el-table-column>
    		    
    		    <el-table-column
    		      prop="cronExpression"
    		      label="表达式"
    		      sortable>
    		    </el-table-column>
    		    
    		    <el-table-column
    		      prop="timeZone"
    		      label="时区"
    		      sortable>
    		    </el-table-column>
    		    
    	        <el-table-column label="操作" width="300">
    		      <template scope="scope">
    		      	<el-button
    		          size="small"
    		          type="warning"
    		          @click="handlePause(scope.$index, scope.row)">暂停</el-button>
    		          
    		        <el-button
    		          size="small"
    		          type="info"
    		          @click="handleResume(scope.$index, scope.row)">恢复</el-button>
    		          
    		        <el-button
    		          size="small"
    		          type="danger"
    		          @click="handleDelete(scope.$index, scope.row)">删除</el-button>
    		          
    		        <el-button
    		          size="small"
    		          type="success"
    		          @click="handleUpdate(scope.$index, scope.row)">修改</el-button>
    		      </template>
    		    </el-table-column>
    		  </el-table>
    		  
    		  <div align="center">
    			  <el-pagination
    			      @size-change="handleSizeChange"
    			      @current-change="handleCurrentChange"
    			      :current-page="currentPage"
    			      :page-sizes="[10, 20, 30, 40]"
    			      :page-size="pagesize"
    			      layout="total, sizes, prev, pager, next, jumper"
    			      :total="totalCount">
    			  </el-pagination>
    		  </div>
    		</div> 
    		
    		<el-dialog title="添加任务" :visible.sync="dialogFormVisible">
    		  <el-form :model="form">
    		    <el-form-item label="任务名称" label-width="120px" style="35%">
    		      <el-input v-model="form.jobName" auto-complete="off"></el-input>
    		    </el-form-item>	    
    		    <el-form-item label="任务分组" label-width="120px" style="35%">
    		      <el-input v-model="form.jobGroup" auto-complete="off"></el-input>
    		    </el-form-item>
    		    <el-form-item label="表达式" label-width="120px" style="35%">
    		      <el-input v-model="form.cronExpression" auto-complete="off"></el-input>
    		    </el-form-item>
    		  </el-form>
    		  <div slot="footer" class="dialog-footer">
    		    <el-button @click="dialogFormVisible = false">取 消</el-button>
    		    <el-button type="primary" @click="add">确 定</el-button>
    		  </div>
    		</el-dialog>
    		
    		<el-dialog title="修改任务" :visible.sync="updateFormVisible">
    		  <el-form :model="updateform">
    		    <el-form-item label="表达式" label-width="120px" style="35%">
    		      <el-input v-model="updateform.cronExpression" auto-complete="off"></el-input>
    		    </el-form-item>
    		  </el-form>
    		  <div slot="footer" class="dialog-footer">
    		    <el-button @click="updateFormVisible = false">取 消</el-button>
    		    <el-button type="primary" @click="update">确 定</el-button>
    		  </div>
    		</el-dialog>
    		
        </div>
    	
        <footer align="center">
            <p>&copy; Quartz 任务管理</p>
        </footer>
    
    	<script>
    	var vue = new Vue({			
    			el:"#test",
    		    data: {		  
    		    	//表格当前页数据
    		    	tableData: [],
    		        
    		        //请求的URL
    		        url:'job/queryjob',
    		        
    		        //默认每页数据量
    		        pagesize: 10,		        
    		        
    		        //当前页码
    		        currentPage: 1,
    		        
    		        //查询的页码
    		        start: 1,
    		        
    		        //默认数据总数
    		        totalCount: 1000,
    		        
    		        //添加对话框默认可见性
    		        dialogFormVisible: false,
    		        
    		        //修改对话框默认可见性
    		        updateFormVisible: false,
    		        
    		        //提交的表单
    		        form: {
    		        	jobName: '',
    		        	jobGroup: '',
    		        	cronExpression: '',
    		          },
    		          
    		        updateform: {
    		        	jobName: '',
    		        	jobGroup: '',
    		        	cronExpression: '',
    		        },
    		    },
    
    		    methods: {
    		    	
    		        //从服务器读取数据
    				loadData: function(pageNum, pageSize){					
    					this.$http.get('job/queryjob?' + 'pageNum=' +  pageNum + '&pageSize=' + pageSize).then(function(res){
    						console.log(res)
                    		this.tableData = res.body.JobAndTrigger.list;
                    		this.totalCount = res.body.number;
                    	},function(){
                      		console.log('failed');
                    	});					
    				},			    		        
    				      
    		        //单行删除
    			    handleDelete: function(index, row) {
    					this.$http.post('job/deletejob',{"jobClassName":row.jobName,"jobGroupName":row.jobGroupName},{emulateJSON: true}).then(function(res){
    						this.loadData( this.currentPage, this.pagesize);
    		            },function(){
    		                console.log('failed');
    		            });
    		        },
    		        
    		        //暂停任务
    		        handlePause: function(index, row){
    		        	this.$http.post('job/pausejob',{"jobClassName":row.jobName,"jobGroupName":row.jobGroupName},{emulateJSON: true}).then(function(res){
    						this.loadData( this.currentPage, this.pagesize);
    		            },function(){
    		                console.log('failed');
    		            });
    		        },
    		        
    		        //恢复任务
    		        handleResume: function(index, row){
    		        	this.$http.post('job/resumejob',{"jobClassName":row.jobName,"jobGroupName":row.jobGroupName},{emulateJSON: true}).then(function(res){
    						this.loadData( this.currentPage, this.pagesize);
    		            },function(){
    		                console.log('failed');
    		            });
    		        },
    		        
    		        //搜索
    		        search: function(){
    		        	this.loadData(this.currentPage, this.pagesize);
    		        },
    		        
    		        //弹出对话框
    		        handleadd: function(){		                
    		            this.dialogFormVisible = true;	              
    		        },
    		        
    		        //添加
    		        add: function(){
    		        	this.$http.post('job/addjob',{"jobClassName":this.form.jobName,"jobGroupName":this.form.jobGroup,"cronExpression":this.form.cronExpression},{emulateJSON: true}).then(function(res){
            				this.loadData(this.currentPage, this.pagesize);
            				this.dialogFormVisible = false;
                        },function(){
                            console.log('failed');
                        });
    		        },
    		        
    		        //更新
    		        handleUpdate: function(index, row){
    		        	console.log(row)
    		        	this.updateFormVisible = true;
    		        	this.updateform.jobName = row.jobClassName;
    		        	this.updateform.jobGroup = row.jobGroupName;
    		        },
    		        
    		        //更新任务
    		        update: function(){
    		        	this.$http.post
    		        	('job/reschedulejob',
    		        			{"jobClassName":this.updateform.jobName,
    		        			 "jobGroupName":this.updateform.jobGroup,
    		        			 "cronExpression":this.updateform.cronExpression
    		        			 },{emulateJSON: true}
    		        	).then(function(res){
    		        		this.loadData(this.currentPage, this.pagesize);
            				this.updateFormVisible = false;
    		        	},function(){
                            console.log('failed');
                        });
    		    
    		        },
    		      
    		        //每页显示数据量变更
    		        handleSizeChange: function(val) {
    		            this.pagesize = val;
    		            this.loadData(this.currentPage, this.pagesize);
    		        },
    		        
    		        //页码变更
    		        handleCurrentChange: function(val) {
    		            this.currentPage = val;
    		            this.loadData(this.currentPage, this.pagesize);
    		        },	      
    		        		        
    		    },	    
    		    
    		    
    		  });
    	
    		  //载入数据
        	  vue.loadData(vue.currentPage, vue.pagesize);
    	</script>  
    	
    </body>
    </html>
    复制代码

    测试效果

    (PS: 这里的任务名称需要改成你自己的完整类名称)

    展示正在运行的Jobs:

    增加新的Job:

    Jobs持久化在数据库:

    示例源码

    github.com/realpdai/te…

    更多内容

    告别碎片化学习,无套路一站式体系化学习后端开发: Java 全栈知识体系 https://pdai.tech

    来源:https://juejin.cn/post/7126687148371083294#
  • 相关阅读:
    在每个类声明之后、每个函数定义结束之后都要加空行。
    不提倡使用全局变量
    头文件中只存放“声明”而不存放“定义”
    用 #include “filename.h” 格式来引用非标准库的头文件
    用 #include <filename.h> 格式来引用标准库的头文件
    为了防止头文件被重复引用
    java Excel导入、自适应版本、将Excel转成List<map>对象
    selenium用java找到表格某一行某一列中含有特定文字的某个元素
    关于java中创建文件,并且写入内容
    java把一个文件的内容复制到另外一个文件
  • 原文地址:https://www.cnblogs.com/konglxblog/p/16725166.html
Copyright © 2020-2023  润新知