SpringBoot集成Quartz数据库配置定时任务

文章参考

https://blog.csdn.net/l18848956739/article/details/86597709

https://blog.csdn.net/xibei19921101/article/details/105012749

https://blog.csdn.net/WLPJLP/article/details/103908448

https://blog.csdn.net/sqlgao22/article/details/100669377

quartz


        如果仅仅只是使用定时任务,可以使用spring的schedule实现,方便,代码量少.易于实现,但是,
当使用分布式进行项目部署的时候,就会出现所有的服务器都在跑同一个定时,出现一个定时任务执行多次的情况,会出现很多问题,使用quartz进行定时任务的调度就可以避免这个问题。

quartz的优点

        1.可以实现多个定时任务进行调度。

        2.可以实现与代码的解耦,通过配置文件的方式进行配置。

        3.功能强大,可以通过cron表达式设置复杂的时间任务调度。

quartz核心:

1.job:(被任务调度的接口),我们需要实现job接口,和继承TimerTask重写run方法一样,重写job中的excute方法,excute方法是任务调度的方法执行位置。

2.JobDetail:必须通过JobDetail来实现Job实例,(基于builder模式实现的)

3.trigger(包括:CronTrigger 和simpleTrigger):指定任务调度的频率时间。何时进行任务调度(基于builder模式实现的)触发器

4.scheduler:结合jobdetail 实例和trigger实例,进行调度的触发的调度器(基于factory模式)。

Quartz 中集群如何工作


一个 Quartz 集群中的每个节点是一个独立的 Quartz 应用,它又管理着其他的节点。意思是你必须对每个节点分别启动或停止。不像许多应用服务器的集群,独立的 Quartz 节点并不与另一其的节点或是管理节点通信。Quartz 应用是通过数据库表来感知到另一应用的。离开了db将无法感知.
 

在这里插入图片描述

项目功能 

1、springboot集成quartz,使用druid连接池 
2、支持http请求任务定时调度,当前支持get、post 请求类型,并记录返回内容
3、通过web界面进行任务管理,包括任务暂停、恢复、修改、历史记录、历史任务查看功能
4、支持调用接口(/quartz/httpJob/add)进行任务添加  
5、根据jobName或jobGroup进行查询

1.导入数据库表

因为Quartz 集群依赖于数据库,所以必须首先创建Quartz数据库表。Quartz 包括了所有被支持的数据库平台的 SQL 脚本。这是是mysql,其他数据库官网下载

注意:创建的表表名都是小写的,在代码中使用的是大写的表名;在liunx中的mysql数据库默认是大小写敏感的,因此使用liunx的数据库会出现找不到表的情况,酌情修改表或是改变数据库配置
表中所有字段详解: quartz中表及其表字段的意义_sqlgao22的博客-CSDN博客

CREATE DATABASE `quartz` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
USE quartz;
-- QUARTZ_TABLE
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;

--  quartz自带表结构

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



-- 定时任务
DROP TABLE IF EXISTS schedule_job;

CREATE TABLE schedule_job(

 ID BIGINT (50) NOT NULL AUTO_INCREMENT COMMENT '任务id',
 JOB_NAME VARCHAR (100) NOT NULL COMMENT '任务名称',
 JOB_GROUP VARCHAR (100) NOT NULL COMMENT '任务分组',
 DESCRIPTION VARCHAR (100) NOT NULL COMMENT '任务描述',
 cron_expression VARCHAR (200) NOT NULL COMMENT 'cron表达式',
 TASK_STATUS VARCHAR (20) NOT NULL COMMENT '任务状态',
 REQUEST_TYPE VARCHAR (50) NOT NULL COMMENT '请求类型{GET或POST请求}',
 HTTP_URL VARCHAR (256) NOT NULL COMMENT '请求url',
 HTTP_PARAMS VARCHAR (20000) COMMENT '请求参数',
 CREATE_TIME datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
 UPDATE_TIME datetime COMMENT '修改时间',
 PRIMARY KEY (ID)

) ENGINE = INNODB DEFAULT CHARSET = utf8 COMMENT = '定时任务';



--  定时任务日志
DROP TABLE IF EXISTS schedule_job_log;

CREATE TABLE schedule_job_log(

ID BIGINT (50) NOT NULL AUTO_INCREMENT COMMENT '日志id',
JOB_ID BIGINT (100) NOT NULL COMMENT '任务id',
JOB_NAME VARCHAR (100) NOT NULL COMMENT '任务名称',
JOB_GROUP VARCHAR (100) NOT NULL COMMENT '任务分组',
DESCRIPTION VARCHAR (100) COMMENT '任务描述',
cron_expression VARCHAR (100) NOT NULL COMMENT 'cron表达式',
TASK_STATUS VARCHAR (20) NOT NULL COMMENT '任务状态 0:成功,1:失败',
REQUEST_TYPE VARCHAR (50) NOT NULL COMMENT '请求类型',
HTTP_URL VARCHAR (256) NOT NULL COMMENT '请求url',
HTTP_PARAMS VARCHAR (20000) COMMENT '请求参数',
times INT (11) COMMENT '耗时(单位:毫秒)',
CREATE_TIME datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
UPDATE_TIME datetime COMMENT '修改时间',
PRIMARY KEY (ID)

) ENGINE = INNODB DEFAULT CHARSET = utf8 COMMENT = '定时任务日志表';

ALTER TABLE schedule_job ADD UNIQUE INDEX `UNIQUEIDX_SCHEDULE_JOB`(`JOB_NAME`, `JOB_GROUP`);
ALTER TABLE schedule_job_log ADD INDEX `IDX_SCHEDULE_JOB_LOG`(`JOB_NAME`, `JOB_GROUP`);

INSERT INTO `httpjob_details` VALUES ('1', 'task_ce', 'web', '测试无参数job', '* * * * * ?' , null,'POST_JSON', 'http://localhost:8080/quartz/test/job', '', '2021-09-22 10:33:00', null);
INSERT INTO `httpjob_details` VALUES ('9', 'task3', 'adce', '测试有参数job' , '* * * * * ?', '0' ,'POST_JSON', 'http://localhost:8080/quartz/test/job', '	\r\n{\r\n  \"jobName\": \"task3\",\r\n  \"jobGroup\": \"adce\"\r\n}', '2021-09-24 16:28:11', null);


commit;

2.引入pom依赖

<dependencies>

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

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

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>

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

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

        <!-- quartz -->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <version>2.2.3</version>
        </dependency>

        <!--httpclient-->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.6</version>
        </dependency>

        <!-- commons-lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8.1</version>
        </dependency>

        <!-- fastJson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.53</version>
        </dependency>

        <!-- druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.9</version>
        </dependency>
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.5</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.4</version>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.7.0</version>
        </dependency>
    </dependencies>

3.application.properties配置

server.port=8080

#UTF-8字符过滤
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true

# mysql
spring.datasource.url=jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf-8&useSSL=false&zeroDateTimeBehavior=convertToNull
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driverClassName=com.mysql.jdbc.Driver

# druid连接池的配置信息
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
spring.datasource.maxWait=60000
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.filters=stat
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000

# mybatis Mapper文件
mybatis.mapper-locations=classpath*:mappings/*.xml
# mybatis别名配置
mybatis.type-aliases-package=com.example.quartz.model

引入quartz.properties配置

注意:使用分布式集群跑定时任务时,需要使用到db持久化,所以需要所有的节点共享一个数据源.
关键配置都有注释

#quartz集群配置
# ===========================================================================
# Configure Main Scheduler Properties 调度器属性
# ===========================================================================
#调度标识名 集群中每一个实例都必须使用相同的名称
org.quartz.scheduler.instanceName: MyQuartzScheduler
#ID设置为自动获取 每一个必须不同
org.quartz.scheduler.instanceId: AUTO
#============================================================================
# Configure ThreadPool
#============================================================================
#线程池的实现类(一般使用SimpleThreadPool即可满足几乎所有用户的需求)
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
#指定线程数,至少为1(无默认值)(一般设置为1-100直接的整数合适)
org.quartz.threadPool.threadCount: 25
#设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5)
org.quartz.threadPool.threadPriority: 5
#============================================================================
# Configure JobStore
#============================================================================
# 信息保存时间 默认值60秒,misfire任务为错过调度触发时间的任务,超过60000ms后被判定为misfire
org.quartz.jobStore.misfireThreshold: 60000
#数据保存方式为数据库持久化
org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
#数据库代理类,一般org.quartz.impl.jdbcjobstore.StdJDBCDelegate可以满足大部分数据库
org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#JobDataMaps是否都为String类型
org.quartz.jobStore.useProperties: false
#数据库别名 随便取
org.quartz.jobStore.dataSource: myDS
#表的前缀,默认QRTZ_
org.quartz.jobStore.tablePrefix: QRTZ_
#是否加入集群
org.quartz.jobStore.isClustered: true
#调度实例失效的检查时间间隔
org.quartz.jobStore.clusterCheckinInterval: 20000
#避免集群环境下job重复执行
org.quartz.jobStore.acquireTriggersWithinLock: true

4.springboot的配置类

(1)druid数据源配置类


import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * druid数据源配置类
 */
@Configuration
public class DataSourceConfig {

    @Value("${spring.datasource.url}")
    private String dbUrl;

    @Value("${spring.datasource.username}")
    private String userName;

    @Value("${spring.datasource.password}")
    private String password;

    @Value("${spring.datasource.driverClassName}")
    private String driverClassName;

    @Value("${spring.datasource.initialSize}")
    private int initialSize;

    @Value("${spring.datasource.minIdle}")
    private int minIdle;

    @Value("${spring.datasource.maxActive}")
    private int maxActive;

    @Value("${spring.datasource.maxWait}")
    private int maxWait;

    @Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
    private int timeBetweenEvictionRunsMillis;

    @Value("${spring.datasource.minEvictableIdleTimeMillis}")
    private int minEvictableIdleTimeMillis;

    @Value("${spring.datasource.validationQuery}")
    private String validationQuery;

    @Value("${spring.datasource.testWhileIdle}")
    private boolean testWhileIdle;

    @Value("${spring.datasource.testOnBorrow}")
    private boolean testOnBorrow;

    @Value("${spring.datasource.testOnReturn}")
    private boolean testOnReturn;

    @Value("${spring.datasource.poolPreparedStatements}")
    private boolean poolPreparedStatements;

    @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
    private int maxPoolPreparedStatementPerConnectionSize;

    @Value("${spring.datasource.filters}")
    private String filters;

    @Value("{spring.datasource.connectionProperties}")
    private String connectionProperties;


    @Primary
    @Bean
    public DataSource dataSource() {
        DruidDataSource datasource = new DruidDataSource();
        datasource.setUrl(this.dbUrl);
        datasource.setUsername(userName);
        datasource.setPassword(password);
        datasource.setDriverClassName(driverClassName);

        //configuration
        datasource.setInitialSize(initialSize);
        datasource.setMinIdle(minIdle);
        datasource.setMaxActive(maxActive);
        datasource.setMaxWait(maxWait);
        datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        datasource.setValidationQuery(validationQuery);
        datasource.setTestWhileIdle(testWhileIdle);
        datasource.setTestOnBorrow(testOnBorrow);
        datasource.setTestOnReturn(testOnReturn);
        datasource.setPoolPreparedStatements(poolPreparedStatements);
        datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);

        WallConfig wallConfig = new WallConfig();
        wallConfig.setMultiStatementAllow(true);
        WallFilter wallFilter= new WallFilter();
        wallFilter.setConfig(wallConfig);
        List<Filter> filterList = new ArrayList<>();
        filterList.add(wallFilter);
        datasource.setProxyFilters(filterList);

        try {
            datasource.setFilters(filters);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        datasource.setConnectionProperties(connectionProperties);

        return datasource;
    }

}  

(2)Quartz配置类

添加 QuartzConfig 类 来声明相关Bean

import com.example.quartz.job.ScheduleJob;
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

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

/**
 * Quartz配置类
 */
@Configuration
public class QuartzConfig {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private JobFactory jobFactory;


    /**
     * 配置quartz配置文件
     */
    @Bean
    public Properties properties() throws IOException {
        Properties properties = new Properties();
        properties.load(new ClassPathResource("/quartz.properties").getInputStream());
        return properties;
    }

    //配置定时任务1
    @Bean
    public JobDetailFactoryBean job1() {
        JobDetailFactoryBean jobDetail = new JobDetailFactoryBean();
        //配置任务的具体实现
        jobDetail.setJobClass(ScheduleJob.class);
        //是否持久化
        jobDetail.setDurability(true);
        //出现异常是否重新执行
        jobDetail.setRequestsRecovery(true);
        //配置定时任务信息
//        jobDetail.setName("");
//        jobDetail.setGroup("");
//        jobDetail.setDescription("");
        return jobDetail;
    }


    /**
     * 配置任务调度工厂,用来生成任务调度器,将一个方法产生为Bean并交给Spring容器管理
     */
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        try {
            // 设置自定义Job Factory,用于Spring管理Job bea
            factory.setJobFactory(jobFactory);
            //配置数据源,这是quartz使用的表的数据库
            factory.setDataSource(dataSource);
            //配置配置文件
            factory.setQuartzProperties(properties());
            //设置自动启动,默认为true
            factory.setAutoStartup(true);
            //开启更新job
            factory.setOverwriteExistingJobs(true);
            factory.setWaitForJobsToCompleteOnShutdown(true);
            // 延迟启动quartz,保证job中的属性的注入
            factory.setStartupDelay(30);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return factory;

    }

    /**
     * 开启当前的任务调度器
     */
    @Bean(name = "scheduler")
    public Scheduler scheduler() {
        return schedulerFactoryBean().getScheduler();
    }

}

(3)任务工厂JobFactory

这里需要注意: 我注入了一个自定义的JobFactory ,解决SpringBoot不能在Quartz中注入Bean的问题

JobFactory具体实现:
 


import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;

/**
 * QuartzJob工厂类 解决SpringBoot不能在Quartz中注入Bean的问题
 * 这里我们需要注意 我注入了一个 自定义的JobFactory ,然后 把其设置为SchedulerFactoryBean 的 JobFactory。其目的是因为我在具体的Job 中 需要Spring 注入一些Service。
 * 所以我们要自定义一个jobfactory, 让其在具体job 类实例化时 使用Spring 的API 来进行依赖注入。
 *
 *
 * 原文链接:https://blog.csdn.net/l18848956739/article/details/86597709
 */
@Component
public class JobFactory extends AdaptableJobFactory {
    /**
     * AutowireCapableBeanFactory接口是BeanFactory的子类,可以连接和填充那些生命周期不被Spring管理的已存在的bean实例
     */

    /**
     * 注入autowire的对象工厂
     */
    @Autowired
    private AutowireCapableBeanFactory beanFactory;

    /**
     * 创建Job实例
     */
    @Override
    protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
        // 调用父类的方法
        final Object job = super.createJobInstance(bundle);
        // 进行注入
        beanFactory.autowireBean(job);
        return job;
    }
}

(4)自定义定时任务类

import com.alibaba.fastjson.JSONObject;
import com.example.quartz.entity.ScheduleJobEntity;
import com.example.quartz.entity.vo.ScheduleJobLogVO;
import com.example.quartz.service.ScheduleJobLogService;
import com.example.quartz.util.HttpClientUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.springframework.beans.BeanUtils;

import javax.annotation.Resource;
import java.util.Date;


/**
 * @Desc 定时任务处理
 */
@Slf4j
@DisallowConcurrentExecution
public class ScheduleJob implements Job {


    @Resource
    private ScheduleJobLogService scheduleJobLogService;


    @Override
    public void execute(JobExecutionContext jobExecutionContext) {

        //JobDetail jobDetail = jobExecutionContext.getJobDetail();
        //Map<String, Object> jobParamsMap = jobDetail.getJobDataMap();

        ScheduleJobEntity scheduleJobEntity = (ScheduleJobEntity) jobExecutionContext.getMergedJobDataMap()
                .get(ScheduleJobEntity.JOB_PARAM_KEY);

        String jobName = scheduleJobEntity.getJobName();
        String jobGroup = scheduleJobEntity.getJobGroup();
        String requestType = scheduleJobEntity.getRequestType();
        String url = scheduleJobEntity.getHttpUrl();
        String jsonParam = scheduleJobEntity.getHttpParams();

        //任务开始时间
        long startTime = System.currentTimeMillis();
        log.info("task start in execute jobName:{}, 开始时间:{}", jobName, new Date());


        //数据库保存执行记录
        ScheduleJobLogVO scheduleJobLogVO = new ScheduleJobLogVO();
        BeanUtils.copyProperties(scheduleJobEntity, scheduleJobLogVO);
        try {
            //执行任务
            String result = chooseRequestType(requestType, url, jsonParam);
            //任务执行时间,单位毫秒
            long times = System.currentTimeMillis() - startTime;
            scheduleJobLogVO.setTimes(String.valueOf(times));
            //任务状态  0:成功 -1:失败
            scheduleJobLogVO.setTaskStatus(getStatusCode(result));
            log.info("Success in execute [{},{},{}]", jobName, jobGroup, "总共耗时:" + times + "毫秒");
        } catch (Exception e) {
            e.printStackTrace();
            log.error("任务执行失败,任务:" + jobName, e);
            scheduleJobLogVO.setTimes(String.valueOf(System.currentTimeMillis() - startTime));
            scheduleJobLogVO.setTaskStatus("-1");
        } finally {
            scheduleJobLogService.insertScheduledTaskLog(scheduleJobLogVO);
        }
    }

    /**
     * resultStatus 返回0 成功,返回-1失败
     */
    private String getStatusCode(String result) {

        JSONObject jsonObject = JSONObject.parseObject(result);
        String resultStatus = jsonObject.getString("status");

        if (StringUtils.equals(resultStatus, "0")) {
            return "0";
        }
        return "-1";
    }

    private String chooseRequestType(String requestType, String url, String jsonParam) {

        String result = "";
        if (StringUtils.equals(requestType, "POST_JSON")) {
            result = HttpClientUtil.sendPostJson(url, jsonParam);
        }

        if (StringUtils.equals(requestType, "GET")) {
            result = HttpClientUtil.sendGetRequestJson(url, jsonParam);
        }
        return result;

    }
}

定时任务业务逻辑接口和实现类

(1)定时业务逻辑接口


import com.example.quartz.entity.ScheduleJobEntity;
import com.example.quartz.entity.vo.ScheduleJobVO;
import com.example.quartz.util.Page;
import org.quartz.SchedulerException;

import java.util.List;

/**
 * 定时任务业务逻辑接口
 */
public interface ScheduleJobService {


    /**
     * 保存定时任务
     *
     * @param JobParam
     */
    void addJob(ScheduleJobEntity scheduleJobEntityParam);


    /**
     * 更新任务cron表达式
     *
     * @param jobName
     * @param jobGroup
     * @param cronExpression
     */
    void updateCronExpression(String jobName, String jobGroup, String cronExpression);


    /**
     * 删除任务
     *
     * @param jobName
     * @param jobGroup
     */
    void deleteJob(String jobName, String jobGroup);

    /**
     * 暂停任务
     *
     * @param jobName
     * @param jobGroup
     */
    void pauseJob(String jobName, String jobGroup);


    /**
     * 恢复任务
     *
     * @param jobName
     * @param jobGroup
     */
    void resumeJob(String jobName, String jobGroup);


    /**
     * 立即执行
     * jobList里面参数如下
     *
     * @param jobName
     * @param jobGroup
     */
    void runJobNow(List<ScheduleJobEntity> jobList);


    /**
     * 获取所有计划中的任务列表
     *
     * @param searchParam
     * @param pageSize    页面大小
     * @param pageNum     页码
     * @return
     */
    Page<ScheduleJobVO> queryScheduleJob(String searchParam, Integer pageSize, Integer pageNum);


    /**
     * 所有正在运行的job
     *
     * @return
     * @throws SchedulerException
     */
    List<ScheduleJobVO> getRunningJob() throws SchedulerException;


    /**
     * 获取所有计划中的任务列表
     *
     * @return
     * @throws SchedulerException
     */
    List<ScheduleJobVO> getAllJob() throws SchedulerException;


}

(2)定时业务逻辑接口实现类

import com.example.quartz.constants.Constant;
import com.example.quartz.entity.ScheduleJobEntity;
import com.example.quartz.entity.vo.ScheduleJobVO;
import com.example.quartz.enu.TriggerStateEnum;
import com.example.quartz.mapper.ScheduleJobMapper;
import com.example.quartz.service.ScheduleJobService;
import com.example.quartz.util.JobUtil;
import com.example.quartz.util.JsonValidUtil;
import com.example.quartz.util.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;


@Slf4j
@Service
public class ScheduleJobServiceImpl implements ScheduleJobService {

    @Resource
    private Scheduler scheduler;


    @Autowired
    private ScheduleJobMapper scheduleJobMapper;


    /**
     * 项目启动时,初始化定时器
     */
    @PostConstruct
    public void init() {
        log.info("实例化List<ScheduleJob>,从数据库读取 :{}", this);
        List<ScheduleJobEntity> scheduleJobEntityList = scheduleJobMapper.getAllTask();
        for (ScheduleJobEntity scheduleJobEntity : scheduleJobEntityList) {
            CronTrigger cronTrigger = JobUtil.getCronTrigger(scheduler, scheduleJobEntity);
            // 如果不存在,则创建
            if (cronTrigger == null) {
                JobUtil.createScheduleJob(scheduler, scheduleJobEntity);
            } else {
                JobUtil.updateScheduleJob(scheduler, scheduleJobEntity);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addJob(ScheduleJobEntity JobParam) {

        String jobName = JobParam.getJobName();
        String jobGroup = JobParam.getJobGroup();
        String jsonParamsStr = JobParam.getHttpParams();
        //任务状态正常
        //通过jobName和jobGroup确保任务的唯一性
        ScheduleJobEntity scheduleJobEntityResult = scheduleJobMapper.getTaskByJobNameAndJobGroup(jobName, jobGroup);
        if (scheduleJobEntityResult != null) {
            throw new RuntimeException("任务名称重复!");
        }

        //对参数进行校验
        if (!JsonValidUtil.isJson(jsonParamsStr)) {
            throw new RuntimeException("请将请求参数转为合法的json字符串!");
        }
        //创建定时任务
        JobUtil.createScheduleJob(scheduler, JobParam);
        //新增job
        scheduleJobMapper.addJob(JobParam);

    }


    @Override
    public void pauseJob(String jobName, String jobGroup) {
        String jobStatus = JobUtil.getJobStatus(scheduler, jobName, jobGroup);
        if (StringUtils.equals(jobStatus, Constant.JOB_STATUS_PAUSED)) {
            throw new RuntimeException("当前任务已是暂停状态!");
        }
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        try {
            scheduler.pauseJob(jobKey);

            //暂停运行和恢复运行需要批量更新任务状态
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void resumeJob(String jobName, String jobGroup) {
        String jobStatus = JobUtil.getJobStatus(scheduler, jobName, jobGroup);
        if (!StringUtils.equals(jobStatus, Constant.JOB_STATUS_PAUSED)) {
            throw new RuntimeException("任务仅在暂停状态时才能恢复!");
        }
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        try {
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
    }


    @Override
    public void deleteJob(String jobName, String jobGroup) {
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        TriggerKey triggerKey = JobUtil.getTriggerKey(jobName, jobGroup);
        try {
            scheduler.pauseTrigger(triggerKey);
            scheduler.unscheduleJob(triggerKey);
            scheduler.deleteJob(jobKey);
            scheduleJobMapper.deletjob(jobName, jobGroup);
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
    }


    @Override
    public void updateCronExpression(String jobName, String jobGroup, String cronExpression) {
        TriggerKey triggerKey = JobUtil.getTriggerKey(jobName, jobGroup);

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

        //按新的cronExpression重新构建trigger
        CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)
                .withSchedule(scheduleBuilder).build();
        try {
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }

    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void runJobNow(List<ScheduleJobEntity> jobList) {
        for (ScheduleJobEntity scheduleJobEntity : jobList) {
            JobUtil.run(scheduler, scheduleJobEntity);
        }
    }

    @Override
    public Page<ScheduleJobVO> queryScheduleJob(String searchParam, Integer pageSize, Integer pageNum) {
        Integer beginIndex = (pageNum - 1) * pageSize;

        Map<String, Object> sqlMap = new HashMap<>();
        sqlMap.put("searchParam", searchParam);
        sqlMap.put("pageSize", pageSize);
        sqlMap.put("beginIndex", beginIndex);

        List<ScheduleJobVO> scheduleJobVOList = scheduleJobMapper.queryScheduleJob(sqlMap);
        for (ScheduleJobVO scheduleJobVO : scheduleJobVOList) {
            //设置jobStatus
            String jobStatus = JobUtil.getJobStatus(scheduler, scheduleJobVO.getJobName(), scheduleJobVO.getJobGroup());
            scheduleJobVO.setTaskStatus(TriggerStateEnum.getTriggerState(jobStatus));
            //任务状态正常,根据cron表达式计算下次运行时间
            if (StringUtils.equals(jobStatus, Constant.JOB_STATUS_NORMAL)) {
                scheduleJobVO.setNextFireTime(JobUtil.getNextFireDate(scheduleJobVO.getCronExpression()));
            }
        }

        Page<ScheduleJobVO> httpJobDetailVOPageVO = new Page<>();
        httpJobDetailVOPageVO.setPageNum(pageNum);
        httpJobDetailVOPageVO.setPageSize(pageSize);
        httpJobDetailVOPageVO.setCount(scheduleJobVOList.size());
        httpJobDetailVOPageVO.setTotalCount(scheduleJobMapper.queryScheduleJobCount(sqlMap));
        httpJobDetailVOPageVO.setResultList(scheduleJobVOList);

        return httpJobDetailVOPageVO;
    }

    /**
     * 所有正在运行的job
     *
     * @return
     * @throws SchedulerException
     */
    @Override
    public List<ScheduleJobVO> getRunningJob() throws SchedulerException {

        List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
        List<ScheduleJobVO> jobList = new ArrayList<ScheduleJobVO>(executingJobs.size());
        for (JobExecutionContext executingJob : executingJobs) {
            ScheduleJobVO job = new ScheduleJobVO();
            JobDetail jobDetail = executingJob.getJobDetail();
            JobKey jobKey = jobDetail.getKey();
            Trigger trigger = executingJob.getTrigger();
            job.setJobName(jobKey.getName());
            job.setJobGroup(jobKey.getGroup());
            job.setDescription("触发器:" + trigger.getKey());
            Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
            job.setTaskStatus(triggerState.name());
            if (trigger instanceof CronTrigger) {
                CronTrigger cronTrigger = (CronTrigger) trigger;
                String cronExpression = cronTrigger.getCronExpression();
                job.setCronExpression(cronExpression);
            }
            jobList.add(job);
        }
        return jobList;
    }


    /**
     * 获取所有计划中的任务列表
     *
     * @return
     * @throws SchedulerException
     */
    @Override
    public List<ScheduleJobVO> getAllJob() throws SchedulerException {
        GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
        Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
        List<ScheduleJobVO> jobList = new ArrayList<ScheduleJobVO>();
        for (JobKey jobKey : jobKeys) {
            List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
            for (Trigger trigger : triggers) {
                ScheduleJobEntity scheduleJobEntity = (ScheduleJobEntity) trigger.getJobDataMap().get(ScheduleJobEntity.JOB_PARAM_KEY);
                ScheduleJobVO scheduleJob=new ScheduleJobVO();
                BeanUtils.copyProperties(scheduleJobEntity, scheduleJob);

                // scheduleJob.setJobName(jobKey.getName());
                // scheduleJob.setJobGroup(jobKey.getGroup());
                // scheduleJob.setDescription("触发器:" + trigger.getKey());
                Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
                scheduleJob.setTaskStatus(triggerState.name());
                if (trigger instanceof CronTrigger) {
                    CronTrigger cronTrigger = (CronTrigger) trigger;
                    String cronExpression = cronTrigger.getCronExpression();
                    //scheduleJob.setCronExpression(cronExpression);
                }

                jobList.add(scheduleJob);
            }
        }
        return jobList;
    }
}

(3)定时任务执行历史记录接口

import com.example.quartz.util.Page;
import com.example.quartz.entity.vo.ScheduleJobLogVO;
import com.example.quartz.entity.vo.ScheduleJobVO;

/**
 * 定时任务执行历史
 */
public interface ScheduleJobLogService {


    /**
     * 定时任务执行日志
     */
    Page<ScheduleJobLogVO> scheduledTaskLogList(String jobName, String jobGroup, String searchParam, Integer pageSize, Integer pageNum);

    /**
     * 查看历史job
     * @param searchParam
     * @param pageSize
     * @param pageNum
     */
    Page<ScheduleJobVO> getHistoryTaskInfoList(String searchParam, Integer pageSize, Integer pageNum);


    int insertScheduledTaskLog(ScheduleJobLogVO scheduleJobLogVO);


}

 (4)定时任务执行历史记录接口实现类

import com.example.quartz.util.Page;
import com.example.quartz.entity.vo.ScheduleJobLogVO;
import com.example.quartz.entity.vo.ScheduleJobVO;
import com.example.quartz.mapper.ScheduleJobLogMapper;
import com.example.quartz.mapper.ScheduleJobMapper;
import com.example.quartz.service.ScheduleJobLogService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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


@Service
public class ScheduleJobLogServiceImpl implements ScheduleJobLogService {

    private static final Logger logger = LogManager.getLogger(ScheduleJobLogServiceImpl.class);


    @Autowired
    private ScheduleJobLogMapper scheduleJobLogMapper;

    @Autowired
    private ScheduleJobMapper scheduleJobMapper;


    @Override
    public Page<ScheduleJobLogVO> scheduledTaskLogList(String jobName, String jobGroup, String searchParam, Integer pageSize, Integer pageNum) {
        Integer beginIndex = (pageNum - 1) * pageSize;

        Map<String, Object> sqlMap = new HashMap<>();
        sqlMap.put("jobName", jobName);
        sqlMap.put("jobGroup", jobGroup);
        sqlMap.put("searchParam", searchParam);
        sqlMap.put("pageSize", pageSize);
        sqlMap.put("beginIndex", beginIndex);

        List<ScheduleJobLogVO> scheduleJobLogVOList = scheduleJobLogMapper.queryscheduledTaskLog(sqlMap);

        Page<ScheduleJobLogVO> httpJobDetailVOPageVO = new Page<>();
        httpJobDetailVOPageVO.setPageNum(pageNum);
        httpJobDetailVOPageVO.setPageSize(pageSize);
        httpJobDetailVOPageVO.setCount(scheduleJobLogVOList.size());
        httpJobDetailVOPageVO.setTotalCount(scheduleJobLogMapper.queryscheduledTaskLogCount(sqlMap));
        httpJobDetailVOPageVO.setResultList(scheduleJobLogVOList);

        return httpJobDetailVOPageVO;
    }

    @Override
    public Page<ScheduleJobVO> getHistoryTaskInfoList(String searchParam, Integer pageSize, Integer pageNum) {
        Integer beginIndex = (pageNum - 1) * pageSize;

        Map<String, Object> sqlMap = new HashMap<>();
        sqlMap.put("searchParam", searchParam);
        sqlMap.put("pageSize", pageSize);
        sqlMap.put("beginIndex", beginIndex);

        List<ScheduleJobVO> scheduleJobVOList = scheduleJobMapper.queryHistoryTaskInfoList(sqlMap);

        Page<ScheduleJobVO> httpJobDetailVOPageVO = new Page<>();
        httpJobDetailVOPageVO.setPageNum(pageNum);
        httpJobDetailVOPageVO.setPageSize(pageSize);
        httpJobDetailVOPageVO.setCount(scheduleJobVOList.size());
        httpJobDetailVOPageVO.setTotalCount(scheduleJobMapper.queryHistoryTaskInfoListCount(sqlMap));
        httpJobDetailVOPageVO.setResultList(scheduleJobVOList);

        return httpJobDetailVOPageVO;
    }

    @Override
    public int insertScheduledTaskLog(ScheduleJobLogVO scheduleJobLogVO) {
        return scheduleJobLogMapper.insertScheduledTaskLog(scheduleJobLogVO);
    }

}

定时业务 mapper接口和mapper.XML

(1)定时任务业务逻辑mapper接口

import com.example.quartz.entity.ScheduleJobEntity;
import com.example.quartz.entity.vo.ScheduleJobVO;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Map;

@Repository
public interface ScheduleJobMapper {


    /**
     * 获取所有任务(用于初始化)
     */
    public List<ScheduleJobEntity> getAllTask();


    /**
     * 查询调度job
     */
    List<ScheduleJobVO> queryScheduleJob(Map<String, Object> map);


    /**
     * 通过 job名字和job分组获取任务
     */
    ScheduleJobEntity getTaskByJobNameAndJobGroup(@Param("jobName") String jobName, @Param("jobGroup") String jobGroup);


    Integer queryScheduleJobCount(Map<String, Object> map);


    /**
     * 新增定时任务
     */
    int addJob(ScheduleJobEntity scheduleJobEntity);


    List<ScheduleJobVO> queryHistoryTaskInfoList(Map<String, Object> map);

    Integer queryHistoryTaskInfoListCount(Map<String, Object> map);




    Integer deletjob(@Param("jobName") String jobName, @Param("jobGroup") String jobGroup);
}

(2)定时任务执行记录mapper接口


@Repository
public interface ScheduleJobLogMapper {

    int insertScheduledTaskLog(ScheduleJobLogVO scheduleJobLogVO);

    List<ScheduleJobLogVO> queryscheduledTaskLog(Map<String, Object> map);

    Integer queryscheduledTaskLogCount(Map<String, Object> map);
}

(3)定时任务业务逻辑mapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.quartz.mapper.ScheduleJobMapper">

    <resultMap id="BaseResultMap" type="com.example.quartz.entity.ScheduleJobEntity">
        <id column="ID" jdbcType="BIGINT" property="jobId"/>
        <result column="JOB_NAME" jdbcType="VARCHAR" property="jobName"/>
        <result column="JOB_GROUP" jdbcType="VARCHAR" property="jobGroup"/>
        <result column="DESCRIPTION" jdbcType="VARCHAR" property="description"/>
        <result column="REQUEST_TYPE" jdbcType="VARCHAR" property="requestType"/>
        <result column="HTTP_URL" jdbcType="VARCHAR" property="httpUrl"/>
        <result column="HTTP_PARAMS" jdbcType="VARCHAR" property="httpParams"/>
        <result column="CRON_EXPRESSION" jdbcType="VARCHAR" property="cronExpression"/>
        <result column="CREATE_TIME" jdbcType="TIMESTAMP" property="createTime"/>
        <result column="UPDATE_TIME" jdbcType="TIMESTAMP" property="updateTime"/>
    </resultMap>

    <sql id="Base_Column_List">
        ID
        ,JOB_NAME,JOB_GROUP,DESCRIPTION,REQUEST_TYPE,HTTP_URL,HTTP_PARAMS,TASK_STATUS, CRON_EXPRESSION, CREATE_TIME,UPDATE_TIME
    </sql>

    <select id="getTaskByJobNameAndJobGroup" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from schedule_job
        where JOB_NAME = #{jobName} and JOB_GROUP = #{jobGroup}
    </select>


    <select id="getAllTask" resultMap="BaseResultMap">
        SELECT t.JOB_NAME,
               t.JOB_GROUP,
               ct.CRON_EXPRESSION,
               hd.ID,
               hd.DESCRIPTION,
               hd.REQUEST_TYPE,
               hd.HTTP_URL,
               hd.HTTP_PARAMS,
               hd.TASK_STATUS,
               hd.CRON_EXPRESSION,
               hd.CREATE_TIME,
               hd.UPDATE_TIME
        FROM QRTZ_TRIGGERS t
                 LEFT JOIN QRTZ_CRON_TRIGGERS ct
                           ON (t.TRIGGER_NAME = ct.TRIGGER_NAME AND t.TRIGGER_GROUP = ct.TRIGGER_GROUP)
                 LEFT JOIN schedule_job hd ON (t.JOB_NAME = hd.JOB_NAME AND t.JOB_GROUP = hd.JOB_GROUP)
        WHERE 1 = 1

    </select>

    <insert id="addJob" parameterType="com.example.quartz.entity.ScheduleJobEntity">
        insert into schedule_job
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="jobId != null">
                ID,
            </if>
            <if test="jobName != null">
                JOB_NAME,
            </if>
            <if test="jobGroup != null">
                JOB_GROUP,
            </if>
            <if test="description != null">
                DESCRIPTION,
            </if>
            <if test="requestType != null">
                REQUEST_TYPE,
            </if>
            <if test="httpUrl != null">
                HTTP_URL,
            </if>
            <if test="httpParams != null">
                HTTP_PARAMS,
            </if>
            <if test="cronExpression != null">
                CRON_EXPRESSION,
            </if>
            <if test="taskStatus != null">
                TASK_STATUS,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="jobId != null">
                #{jobId,jdbcType=BIGINT},
            </if>
            <if test="jobName != null">
                #{jobName,jdbcType=VARCHAR},
            </if>
            <if test="jobGroup != null">
                #{jobGroup,jdbcType=VARCHAR},
            </if>
            <if test="description != null">
                #{description,jdbcType=VARCHAR},
            </if>
            <if test="requestType != null">
                #{requestType,jdbcType=VARCHAR},
            </if>
            <if test="httpUrl != null">
                #{httpUrl,jdbcType=VARCHAR},
            </if>
            <if test="httpParams != null">
                #{httpParams,jdbcType=VARCHAR},
            </if>
            <if test="cronExpression != null">
                #{cronExpression,jdbcType=VARCHAR},
            </if>
            <if test="taskStatus != null">
                #{taskStatus,jdbcType=VARCHAR},
            </if>
        </trim>
    </insert>

    <resultMap id="JobDetailMap" type="com.example.quartz.entity.vo.ScheduleJobVO">
        <id column="ID" jdbcType="BIGINT" property="jobId"/>
        <result column="JOB_NAME" jdbcType="VARCHAR" property="jobName"/>
        <result column="JOB_GROUP" jdbcType="VARCHAR" property="jobGroup"/>
        <result column="DESCRIPTION" jdbcType="VARCHAR" property="description"/>
        <result column="REQUEST_TYPE" jdbcType="VARCHAR" property="requestType"/>
        <result column="HTTP_URL" jdbcType="VARCHAR" property="httpUrl"/>
        <result column="HTTP_PARAMS" jdbcType="VARCHAR" property="httpParams"/>
        <result column="CRON_EXPRESSION" jdbcType="VARCHAR" property="cronExpression"/>
        <result column="TASK_STATUS" jdbcType="VARCHAR" property="taskStatus"/>
        <result column="CREATE_TIME" jdbcType="TIMESTAMP" property="createTime"/>
        <result column="UPDATE_TIME" jdbcType="TIMESTAMP" property="updateTime"/>
    </resultMap>

    <select id="queryScheduleJob" resultMap="JobDetailMap">
        SELECT
        t.JOB_NAME,
        t.JOB_GROUP,
        hd.ID,
        hd.DESCRIPTION,
        hd.REQUEST_TYPE,
        hd.HTTP_URL,
        hd.HTTP_PARAMS,
        hd.TASK_STATUS,
        hd.CREATE_TIME,
        hd.UPDATE_TIME,
        ct.CRON_EXPRESSION
        FROM
        QRTZ_TRIGGERS t
        LEFT JOIN QRTZ_CRON_TRIGGERS ct ON ( t.TRIGGER_NAME = ct.TRIGGER_NAME AND t.TRIGGER_GROUP = ct.TRIGGER_GROUP )
        LEFT JOIN schedule_job hd ON ( t.JOB_NAME = hd.JOB_NAME AND t.JOB_GROUP = hd.JOB_GROUP )
        WHERE
        1=1
        <if test="searchParam != null and searchParam != ''">
            AND ( t.JOB_NAME LIKE concat('%',#{searchParam},'%') OR t.JOB_GROUP LIKE concat('%',#{searchParam},'%') )
        </if>
        ORDER BY hd.ID DESC
        <if test="beginIndex != null and pageSize!=null">
            limit #{beginIndex},#{pageSize}
        </if>
    </select>

    <select id="queryScheduleJobCount" resultType="java.lang.Integer">
        SELECT
        COUNT(1)
        FROM
        QRTZ_TRIGGERS t
        LEFT JOIN QRTZ_CRON_TRIGGERS ct ON ( t.TRIGGER_NAME = ct.TRIGGER_NAME AND t.TRIGGER_GROUP = ct.TRIGGER_GROUP )
        LEFT JOIN schedule_job hd ON ( t.JOB_NAME = hd.JOB_NAME AND t.JOB_GROUP = hd.JOB_GROUP )
        WHERE
        1=1
        <if test="searchParam != null and searchParam != ''">
            AND ( t.JOB_NAME LIKE concat('%',#{searchParam},'%') OR t.JOB_GROUP LIKE concat('%',#{searchParam},'%') )
        </if>
    </select>

    <select id="queryHistoryTaskInfoList" resultMap="JobDetailMap">
        SELECT
        hd.ID,
        hd.JOB_NAME,
        hd.JOB_GROUP,
        hd.DESCRIPTION,
        hd.REQUEST_TYPE,
        hd.HTTP_URL,
        hd.HTTP_PARAMS,
        hd.TASK_STATUS,
        hd.CREATE_TIME,
        hd.UPDATE_TIME
        FROM schedule_job hd
        LEFT JOIN QRTZ_TRIGGERS qt ON ( hd.JOB_NAME = qt.JOB_NAME AND hd.JOB_GROUP = qt.JOB_GROUP )
        WHERE
        (qt.JOB_NAME IS NULL AND qt.JOB_GROUP IS NULL)
        <if test="searchParam != null and searchParam != ''">
            AND ( hd.JOB_NAME LIKE concat('%',#{searchParam},'%') OR hd.JOB_GROUP LIKE concat('%',#{searchParam},'%') )
        </if>
        ORDER BY hd.ID DESC
        <if test="beginIndex != null and pageSize!=null">
            limit #{beginIndex},#{pageSize}
        </if>
    </select>

    <select id="queryHistoryTaskInfoListCount" resultType="java.lang.Integer">
        SELECT
        COUNT(1)
        FROM
        schedule_job hd
        LEFT JOIN QRTZ_TRIGGERS qt ON ( hd.JOB_NAME = qt.JOB_NAME AND hd.JOB_GROUP = qt.JOB_GROUP )
        WHERE
        (qt.JOB_NAME IS NULL AND qt.JOB_GROUP IS NULL)
        <if test="searchParam != null and searchParam != ''">
            AND ( hd.JOB_NAME LIKE concat('%',#{searchParam},'%') OR hd.JOB_GROUP LIKE concat('%',#{searchParam},'%') )
        </if>
    </select>


    <select id="deletjob" resultType="java.lang.Integer">
        delete
        from schedule_job
        where JOB_NAME = #{jobName}
          and JOB_GROUP = #{jobGroup}
    </select>
</mapper>

(4)定时任务执行记录mapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.quartz.mapper.ScheduleJobLogMapper">

    <resultMap id="BaseResultMap" type="com.example.quartz.entity.vo.ScheduleJobLogVO">
        <id column="ID" jdbcType="BIGINT" property="id"/>
        <result column="JOB_ID" jdbcType="BIGINT" property="jobId"/>
        <result column="JOB_NAME" jdbcType="VARCHAR" property="jobName"/>
        <result column="JOB_GROUP" jdbcType="VARCHAR" property="jobGroup"/>
        <result column="DESCRIPTION" jdbcType="VARCHAR" property="description"/>
        <result column="REQUEST_TYPE" jdbcType="VARCHAR" property="requestType"/>
        <result column="HTTP_URL" jdbcType="VARCHAR" property="httpUrl"/>
        <result column="HTTP_PARAMS" jdbcType="VARCHAR" property="httpParams"/>
        <result column="cron_expression" jdbcType="VARCHAR" property="cronExpression"/>
        <result column="TASK_STATUS" jdbcType="VARCHAR" property="taskStatus"/>
        <result column="times" jdbcType="VARCHAR" property="times"/>
        <result column="CREATE_TIME" jdbcType="TIMESTAMP" property="createTime"/>
        <result column="UPDATE_TIME" jdbcType="TIMESTAMP" property="updateTime"/>
    </resultMap>

    <sql id="Base_Column_List">
        ID,JOB_ID,JOB_NAME,JOB_GROUP,DESCRIPTION,REQUEST_TYPE,HTTP_URL,HTTP_PARAMS,cron_expression,TASK_STATUS,times,CREATE_TIME,UPDATE_TIME
    </sql>

    <insert id="insertScheduledTaskLog" parameterType="com.example.quartz.entity.vo.ScheduleJobLogVO">
        insert into schedule_job_log
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="id != null">
                ID,
            </if>
            <if test="jobId != null">
                JOB_ID,
            </if>
            <if test="jobName != null">
                JOB_NAME,
            </if>
            <if test="jobGroup != null">
                JOB_GROUP,
            </if>

            <if test="description != null">
                DESCRIPTION,
            </if>

            <if test="requestType != null">
                REQUEST_TYPE,
            </if>
            <if test="httpUrl != null">
                HTTP_URL,
            </if>
            <if test="httpParams != null">
                HTTP_PARAMS,
            </if>

            <if test="cronExpression != null">
                cron_expression,
            </if>

            <if test="taskStatus != null">
                TASK_STATUS,
            </if>
            <if test="times != null">
                times,
            </if>
            <if test="createTime != null">
                CREATE_TIME,
            </if>

            <if test="updateTime != null">
                UPDATE_TIME,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">

            <if test="id != null">
                #{id,jdbcType=BIGINT},
            </if>
            <if test="jobId != null">
                #{jobId,jdbcType=BIGINT},
            </if>

            <if test="jobName != null">
                #{jobName,jdbcType=VARCHAR},
            </if>
            <if test="jobGroup != null">
                #{jobGroup,jdbcType=VARCHAR},
            </if>

            <if test="description != null">
                #{description,jdbcType=VARCHAR},
            </if>
            <if test="requestType != null">
                #{requestType,jdbcType=VARCHAR},
            </if>
            <if test="httpUrl != null">
                #{httpUrl,jdbcType=VARCHAR},
            </if>
            <if test="httpParams != null">
                #{httpParams,jdbcType=VARCHAR},
            </if>

            <if test="cronExpression != null">
                #{cronExpression,jdbcType=VARCHAR},
            </if>

            <if test="taskStatus != null ">
                #{taskStatus,jdbcType=VARCHAR},
            </if>
            <if test="times != null">
                #{times,jdbcType=VARCHAR},
            </if>
            <if test="createTime != null">
                #{createTime,jdbcType=TIMESTAMP},
            </if>

            <if test="updateTime != null">
                #{updateTime,jdbcType=TIMESTAMP},
            </if>
        </trim>
    </insert>

    <select id="queryscheduledTaskLog" resultMap="BaseResultMap">
        SELECT
        <include refid="Base_Column_List"/>
        FROM
        schedule_job_log t
        WHERE
        1=1
        <if test="jobName != null and jobName != ''">
            AND t.JOB_NAME = #{jobName}
        </if>
        <if test="jobGroup != null and jobGroup != ''">
            AND t.JOB_GROUP = #{jobGroup}
        </if>
        <if test="searchParam != null and searchParam != ''">
            AND ( t.JOB_NAME LIKE concat('%',#{searchParam},'%') OR t.JOB_GROUP LIKE concat('%',#{searchParam},'%') )
        </if>
        ORDER BY t.ID DESC
        <if test="beginIndex != null and pageSize!=null">
            limit #{beginIndex},#{pageSize}
        </if>
    </select>

    <select id="queryscheduledTaskLogCount" resultType="java.lang.Integer">
        SELECT
        COUNT(1)
        FROM
        schedule_job_log t
        WHERE
        1=1
        <if test="jobName != null and jobName != ''">
            AND t.JOB_NAME = #{jobName}
        </if>
        <if test="jobGroup != null and jobGroup != ''">
            AND t.JOB_GROUP = #{jobGroup}
        </if>
        <if test="searchParam != null and searchParam != ''">
            AND ( t.JOB_NAME LIKE concat('%',#{searchParam},'%') OR t.JOB_GROUP LIKE concat('%',#{searchParam},'%') )
        </if>
    </select>

</mapper>

定时任务用到的bean

(1)定时任务entity

import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;

/**
 * 定时任务bean
 */
@Data
public class ScheduleJobEntity implements Serializable {

    private static final long serialVersionUID = -50190044894125802L;

    /**
     * 任务调度参数key
     */
    public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY";


    /**
     * jobId
     */
    private Long jobId;

    /**
     * 任务名称不能为空
     */
    private String jobName;

    /**
     * 任务分组不能为空
     */
    private String jobGroup;

    /**
     * 任务描述
     */
    private String description;

    /**
     * 请求类型{GET POST}
     */
    private String requestType;

    /**
     * 请求URL不能为空
     */
    private String httpUrl;

    /**
     * 请求参数{参数可以为空,必须是json格式}
     */
    private String httpParams;


    /**
     * cron表达式
     */
    private String cronExpression;


    /**
     * 创建时间
     */
    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;

    /**
     * 更新时间
     */
    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    private Date updateTime;


}

(2)定时任务VO


@Data
@Api(value = "定时任务返参")
public class ScheduleJobVO {

    /**
     * jobId
     */
    private Long jobId;

    /**
     * 任务名称
     */
    private String jobName;
    /**
     * 任务分组
     */
    private String jobGroup;
    /**
     * 任务描述
     */
    private String description;


    /**
     * 请求类型{GET POST}
     */
    private String requestType;

    /**
     * 请求URL
     */
    private String httpUrl;

    /**
     * 请求参数{参数可以为空,必须是json格式}
     */
    private String httpParams;

    /**
     * cron表达式
     */
    private String cronExpression;

    /**
     * NONE:不存在, NORMAL:正常, PAUSE:暂停, COMPLETE:完成, ERROR:错误, BLOCKED:阻塞
     */
    private String taskStatus;


    /**
     * 下次执行时间
     */
    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    private Date nextFireTime;

    /**
     * 创建时间
     */
    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;

    /**
     * 更新时间
     */
    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    private Date updateTime;


}

(3)定时任务日志VO


@Data
@Api(value = "定时任务日志返参")
public class ScheduleJobLogVO implements Serializable {

    private static final long serialVersionUID = 2259203435361774854L;

    /**
     * 日志id
     */
    private Long id;

    /**
     * jobId
     */
    private Long jobId;
    /**
     * 任务名称不能为空
     */

    private String jobName;

    /**
     * 任务分组不能为空
     */
    private String jobGroup;

    /**
     * 任务描述
     */
    private String description;

    /**
     * 请求类型{GET POST}
     */
    private String requestType;
    /**
     * 请求URL不能为空
     */

    private String httpUrl;
    /**
     * 请求参数{参数可以为空,必须是json格式}
     */
    private String httpParams;

    /**
     * cron表达式
     */
    private String cronExpression;

    /**
     * 执行状态 0:成功 -1失败
     */
    private String taskStatus;

    /**
     * 执行时间:单位毫秒
     */
    private String times;

    /**
     * 创建时间
     */
    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;

    /**
     * 更新时间
     */
    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    private Date updateTime;

}

(4)添加定时任务入参

import io.swagger.annotations.Api;
import lombok.Data;

import javax.validation.constraints.NotEmpty;

@Data
@Api("添加任务请求参数")
public class AddScheduleJobParam {

    @NotEmpty(message = "任务名称不能为空")
    private String jobName;

    @NotEmpty(message = "任务分组不能为空")
    private String jobGroup;

    /**
     * 描述
     */
    private String description;


    /**
     * 请求类型
     */
    @NotEmpty(message = "请求类型不能为空")
    private String requestType;


    /**
     * 请求URL不能为空
     */
    @NotEmpty(message = "请求URL不能为空")
    private String httpUrl;

    /**
     * 请求参数{参数可以为空,必须是json格式}
     */
    private String httpParams;

    /**
     * cron表达式
     */
    @NotEmpty(message = "cron表达式不能为空")
    private String cronExpression;


}

定时任务用到的工具类

(1)定时任务工具类


import com.example.quartz.constants.Constant;
import com.example.quartz.entity.ScheduleJobEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;

import java.text.ParseException;
import java.util.Date;

/**
 * 定时任务工具类
 */
@Slf4j
public class JobUtil {

    private final static String JOB_NAME = "TASK_";


    /**
     * 获取触发器key
     */
    public static TriggerKey getTriggerKey(Long jobId) {
        return TriggerKey.triggerKey(JOB_NAME + jobId);
    }




    /**
     * 根据jobName和jobGroup生成triggerKey
     */
    public static TriggerKey getTriggerKey(String jobName, String jobGroup) {
        String triggerName = Constant.TRIGGER_PREFIX + jobName;
        String triggerGroup = Constant.TRIGGER_PREFIX + jobGroup;
        return TriggerKey.triggerKey(triggerName, triggerGroup);
    }

    /**
     * 获取jobKey
     */
    public static JobKey getJobKey(Long jobId) {
        return JobKey.jobKey(JOB_NAME + jobId);
    }

    /**
     * 获取jobKey
     */
    public static JobKey getJobKey(String jobName, String jobGroup) {
        return JobKey.jobKey(jobName, jobGroup);
    }

    /**
     * 获取表达式触发器
     */
    public static CronTrigger getCronTrigger(Scheduler scheduler, Long jobId) {
        try {
            return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId));
        } catch (SchedulerException e) {
            throw new RuntimeException("获取定时任务CronTrigger出现异常", e);
        }
    }

    /**
     * 获取表达式触发器
     */
    public static CronTrigger getCronTrigger(Scheduler scheduler, ScheduleJobEntity scheduleJobEntity) {

        TriggerKey triggerKey = getTriggerKey(scheduleJobEntity.getJobName(), scheduleJobEntity.getJobGroup());
        try {
            return (CronTrigger) scheduler.getTrigger(triggerKey);
        } catch (SchedulerException e) {
            throw new RuntimeException("获取定时任务CronTrigger出现异常", e);
        }
    }

    /**
     * 获取job状态
     *
     * @param jobName
     * @param jobGroup
     * @return
     */
    public static String getJobStatus(Scheduler scheduler, String jobName, String jobGroup) {
        String jobStatus = "";
        TriggerKey triggerKey = getTriggerKey(jobName, jobGroup);
        try {
            jobStatus = scheduler.getTriggerState(triggerKey).name();
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
        return jobStatus;
    }

    /**
     * 创建定时任务
     */
    public static void createScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJobEntity) {


        try {
            JobKey JobKey = getJobKey(scheduleJobEntity.getJobName(), scheduleJobEntity.getJobGroup());
            // 通过JobBuilder构建JobDetail实例
            JobDetail jobDetail = JobBuilder.newJob(com.example.quartz.job.ScheduleJob.class).withIdentity(JobKey).build();

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

            TriggerKey triggerKey = getTriggerKey(scheduleJobEntity.getJobName(), scheduleJobEntity.getJobGroup());
            //按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

            //放入参数,运行时的方法可以获取
            jobDetail.getJobDataMap().put(ScheduleJobEntity.JOB_PARAM_KEY, scheduleJobEntity);
            // 开启调度
            scheduler.scheduleJob(jobDetail, trigger);
            //获取job状态
            String jobStatus = JobUtil.getJobStatus(scheduler, scheduleJobEntity.getJobName(), scheduleJobEntity.getJobGroup());
            //暂停任务
            if (StringUtils.equals(jobStatus, Constant.JOB_STATUS_PAUSED)) {
                pauseJob(scheduler, scheduleJobEntity);
            }
            log.info("Success in addJob, [{}]-[{}]", scheduleJobEntity.getJobName(), scheduleJobEntity.getJobGroup());
        } catch (SchedulerException e) {
            throw new RuntimeException("创建定时任务失败", e);
        }
    }

    /**
     * 更新定时任务
     */
    public static void updateScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJobEntity) {
        try {
            TriggerKey triggerKey = getTriggerKey(scheduleJobEntity.getJobName(), scheduleJobEntity.getJobGroup());

            //表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJobEntity.getCronExpression())
                    .withMisfireHandlingInstructionDoNothing();

            CronTrigger trigger = getCronTrigger(scheduler, scheduleJobEntity);

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

            //放入参数
            trigger.getJobDataMap().put(ScheduleJobEntity.JOB_PARAM_KEY, scheduleJobEntity);

            scheduler.rescheduleJob(triggerKey, trigger);
            String jobStatus = JobUtil.getJobStatus(scheduler, scheduleJobEntity.getJobName(), scheduleJobEntity.getJobGroup());
            //暂停任务
            if (StringUtils.equals(jobStatus, Constant.JOB_STATUS_PAUSED)) {
                pauseJob(scheduler, scheduleJobEntity);
            }

        } catch (SchedulerException e) {
            throw new RuntimeException("更新定时任务失败", e);
        }
    }

    /**
     * 立即执行任务
     */
    public static void run(Scheduler scheduler, ScheduleJobEntity scheduleJobEntity) {
        try {
            //参数
            JobDataMap dataMap = new JobDataMap();
            dataMap.put(ScheduleJobEntity.JOB_PARAM_KEY, scheduleJobEntity);
            JobKey JobKey = getJobKey(scheduleJobEntity.getJobName(), scheduleJobEntity.getJobGroup());
            scheduler.triggerJob(JobKey, dataMap);
        } catch (SchedulerException e) {
            throw new RuntimeException("立即执行定时任务失败", e);
        }
    }

    /**
     * 暂停任务
     */
    public static void pauseJob(Scheduler scheduler, Long jobId) {

        try {
            scheduler.pauseJob(getJobKey(jobId));
        } catch (SchedulerException e) {
            throw new RuntimeException("暂停定时任务失败", e);
        }
    }

    /**
     * 暂停任务
     */
    public static void pauseJob(Scheduler scheduler, ScheduleJobEntity scheduleJobEntity) {

        try {
            JobKey JobKey = getJobKey(scheduleJobEntity.getJobName(), scheduleJobEntity.getJobGroup());
            scheduler.pauseJob(JobKey);
        } catch (SchedulerException e) {
            throw new RuntimeException("暂停定时任务失败", e);
        }
    }


    /**
     * 恢复任务
     */
    public static void resumeJob(Scheduler scheduler, ScheduleJobEntity scheduleJobEntity) {
        try {
            String jobStatus = getJobStatus(scheduler, scheduleJobEntity.getJobName(), scheduleJobEntity.getJobGroup());
            JobKey JobKey = getJobKey(scheduleJobEntity.getJobName(), scheduleJobEntity.getJobGroup());
            if (StringUtils.equals(jobStatus, Constant.JOB_STATUS_PAUSED)) {
                scheduler.resumeJob(JobKey);
            }

        } catch (SchedulerException e) {
            throw new RuntimeException("暂停定时任务失败", e);
        }
    }


    /**
     * 批量删除定时任务
     */
    public static void deleteScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJobEntity) {
        try {
            JobKey JobKey = getJobKey(scheduleJobEntity.getJobName(), scheduleJobEntity.getJobGroup());
            scheduler.deleteJob(JobKey);
        } catch (SchedulerException e) {
            throw new RuntimeException("删除定时任务失败", e);
        }
    }

    /**
     * 根据cron表达式获取下次执行时间
     *
     * @param cronExpression
     * @return
     */
    public static Date getNextFireDate(String cronExpression) {
        try {
            CronExpression cron = new CronExpression(cronExpression);
            Date nextFireDate = cron.getNextValidTimeAfter(new Date());
            return nextFireDate;
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
}

(2)Httpclient工具类

import org.apache.commons.codec.Charsets;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * Httpclient请求工具类
 */
public class HttpClientUtil {

    /**
     * 连接主机超时(30s)
     */
    public static final int HTTP_CONNECT_TIMEOUT_30S = 30 * 1000;

    /**
     * 从主机读取数据超时(3min)
     */
    public static final int HTTP_READ_TIMEOUT_3MIN = 180 * 1000;

    /**
     * HTTP成功状态码(200)
     */
    public static final int HTTP_SUCCESS_STATUS_CODE = 200;

    private static final Logger logger = LogManager.getLogger(HttpClientUtil.class);


    private HttpClientUtil() {
    }

    /**
     * get请求 参数为map,格式为json
     */
    public static String sendGetRequestMap(String url, Map<String, Object> formDataParam) {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String result = "";
        // 超时时间设置
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(HTTP_READ_TIMEOUT_3MIN)
                .setConnectTimeout(HTTP_CONNECT_TIMEOUT_30S).build();

        try {
            URIBuilder builder = new URIBuilder(url);
            if (null != formDataParam && formDataParam.size() > 0) {
                // 创建参数队列
                List<NameValuePair> formParams = new ArrayList<>();
                for (Entry<String, Object> entry : formDataParam.entrySet()) {
                    formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
                }
                builder.setParameters(formParams);
            }
            // 设置参数
            HttpGet httpGet = new HttpGet(builder.build());
            httpGet.setConfig(requestConfig);

            // 发送请求
            response = httpclient.execute(httpGet);
            result = EntityUtils.toString(response.getEntity(), Charsets.UTF_8);
            if (response.getStatusLine().getStatusCode() != HTTP_SUCCESS_STATUS_CODE) {
                logger.error("Error in getMap. Request URL is [{}], params [{}]. Result:[{}]", url, formDataParam, result);
            }
        } catch (Exception e) {
            logger.error("Error in getMap", e);
        } finally {
            HttpClientUtils.closeQuietly(httpclient);
            HttpClientUtils.closeQuietly(response);
        }
        return result;
    }

    /**
     * * 发送Get请求,参数json字符串
     */
    public static String sendGetRequestJson(String url, String json) {

        CloseableHttpClient httpclient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String result = "";
        // 超时时间设置
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(HTTP_READ_TIMEOUT_3MIN)
                .setConnectTimeout(HTTP_CONNECT_TIMEOUT_30S).build();

        try {
            URIBuilder builder = new URIBuilder(url);
            if (StringUtils.isNotBlank(json)) {
                // 创建参数队列
                List<NameValuePair> paramsList = new ArrayList<>();
                paramsList.add(new BasicNameValuePair(json, json));
                builder.setParameters(paramsList);
            }
            // 设置参数
            HttpGet httpGet = new HttpGet(builder.build());
            httpGet.setConfig(requestConfig);

            // 发送请求
            response = httpclient.execute(httpGet);
            result = EntityUtils.toString(response.getEntity(), Charsets.UTF_8);
            if (response.getStatusLine().getStatusCode() != HTTP_SUCCESS_STATUS_CODE) {
                logger.error("Error in getMap. Request URL is [{}], params [{}]. Result:[{}]", url, json, result);
            }
        } catch (Exception e) {
            logger.error("Error in getMap", e);
        } finally {
            HttpClientUtils.closeQuietly(httpclient);
            HttpClientUtils.closeQuietly(response);
        }
        return result;
    }

    /**
     * 发送post请求,参数json字符串
     *
     * @param url
     * @param jsonParam json字符串
     * @return 返回为字符串
     */
    public static String sendPostJson(String url, String jsonParam) {

        CloseableHttpClient httpclient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String result = "";
        // 超时时间设置
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(HTTP_READ_TIMEOUT_3MIN)
                .setConnectTimeout(HTTP_CONNECT_TIMEOUT_30S).build();

        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);

        if (StringUtils.isBlank(jsonParam)) {
            jsonParam = "";
        }
        // 设置请求头和请求参数
        StringEntity entity = new StringEntity(jsonParam, "utf-8");
        entity.setContentEncoding("UTF-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);

        try {
            // 发送请求
            response = httpclient.execute(httpPost);
            result = EntityUtils.toString(response.getEntity(), Charsets.UTF_8);
            int statusCode = response.getStatusLine().getStatusCode();

            if (response.getStatusLine().getStatusCode() != HTTP_SUCCESS_STATUS_CODE) {
                logger.error("Error in postJson. Request URL is [{}], params [{}]. Result:[{}]", url, jsonParam, result);
            }
            logger.info("success in execute : result:{}", result);
            System.out.println(" success in execute result: " + result);
        } catch (Exception e) {
            logger.error("Error in postJson", e);
        } finally {
            HttpClientUtils.closeQuietly(httpclient);
            HttpClientUtils.closeQuietly(response);
        }
        return result;
    }

    /**
     * postFormData
     */
    public static String sendPostRequestMap(String url, Map<String, Object> formDataParam) {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String result = "";
        // 超时时间设置
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(HTTP_READ_TIMEOUT_3MIN)
                .setConnectTimeout(HTTP_CONNECT_TIMEOUT_30S).build();

        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        try {
            if (null != formDataParam && formDataParam.size() > 0) {
                // 创建参数队列
                List<NameValuePair> formParams = new ArrayList<>();
                for (Entry<String, Object> entry : formDataParam.entrySet()) {
                    formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
                }
                // 设置参数
                UrlEncodedFormEntity urlEntity = new UrlEncodedFormEntity(formParams, Charsets.UTF_8);
                httpPost.setEntity(urlEntity);
            }

            // 发送请求
            response = httpclient.execute(httpPost);
            result = EntityUtils.toString(response.getEntity(), Charsets.UTF_8);
            if (response.getStatusLine().getStatusCode() != HTTP_SUCCESS_STATUS_CODE) {
                logger.error("Error in postFormData. Request URL is [{}], params [{}]. Result:[{}]", url, formDataParam, result);
            }
        } catch (Exception e) {
            logger.error("Error in postFormData", e);
        } finally {
            HttpClientUtils.closeQuietly(httpclient);
            HttpClientUtils.closeQuietly(response);
        }
        return result;
    }


}

(3)分页工具类


public class Page<T> {

    /**
     * 当前页
     */
    private Integer pageNum;

    /**
     * 每页数量
     */
    private Integer pageSize;

    /**
     * 条数
     */
    private Integer count;

    /**
     * 页数
     */
    private Integer pageCount;

    /**
     * 总条数
     */
    private Integer totalCount;

    /**
     * 分页结果集
     */
    private List<T> resultList;

    public Page() {
    }

    public Integer getPageNum() {
        return pageNum;
    }

    public void setPageNum(Integer pageNum) {
        this.pageNum = pageNum;
    }

    public Integer getPageSize() {
        return pageSize;
    }

    public void setPageSize(Integer pageSize) {
        this.pageSize = pageSize;
    }

    public Integer getCount() {
        return count;
    }

    public void setCount(Integer count) {
        this.count = count;
    }

    public Integer getPageCount() {
        return pageCount;
    }

    public void setPageCount(Integer pageCount) {
        this.pageCount = pageCount;
    }

    public Integer getTotalCount() {
        return totalCount;
    }

    public void setTotalCount(Integer totalCount) {
        this.totalCount = totalCount;

        if (totalCount % pageSize == 0) {
            this.pageCount = totalCount / pageSize;
        } else {
            this.pageCount = totalCount / pageSize + 1;
        }
    }

    public List<T> getResultList() {
        return resultList;
    }

    public void setResultList(List<T> resultList) {
        this.resultList = resultList;
    }
}

(4)返回结果封装工具类


import com.example.quartz.enu.ResultEnum;

import java.io.Serializable;

/**
 * 返回结果封装类
 */

public class Response<T> implements Serializable {

    private static final long serialVersionUID = 676473785338095291L;

    private int status;

    private String message;

    private T data;

    public Response() {
    }

    public Response(int status, String message) {
        this.status = status;
        this.message = message;
    }

    public Response(ResultEnum resultEnum) {
        this.status = resultEnum.getStatus();
        this.message = resultEnum.getMessage();
    }

    public Response(ResultEnum resultEnum, T data) {
        this.status = resultEnum.getStatus();
        this.message = resultEnum.getMessage();
        this.data = data;
    }

    public static Response error() {
        return new Response(ResultEnum.ERROR);
    }

    public static Response error(String errorMessage) {
        return new Response(ResultEnum.ERROR.getStatus(), errorMessage);
    }

    public static Response success() {
        return new Response(ResultEnum.SUCCESS);
    }

    public static <T> Response success(T data) {
        return new Response(ResultEnum.SUCCESS, data);
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

(5)JSON参数格式校验工具类


import com.alibaba.fastjson.JSONObject;

/**
 * JSON校验工具类
 */
public class JsonValidUtil {

    /**
     * 判断字符串是否为json格式
     *
     * @param jsonStr
     * @return
     */
    public static boolean isJson(String jsonStr) {
        try {
            JSONObject.parseObject(jsonStr);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

定时任务常量类和枚举

(1)定时任务常量类


/**
 * 常量类
 */
public class Constant {

    /**
     * trigger名称前缀
     */
    public static final String TRIGGER_PREFIX = "Trigger_";

    public static final String URL = "url";

    public static final String PARAMS = "params";

    public static final String REQUEST_TYPE = "requestType";

    /**
     * RequestType请求类型
     */
    public static final String POST_JSON = "POST_JSON";

    public static final String POST_FORM_DATA = "POST_FORM";

    public static final String GET = "GET";

    /**
     * job状态 NORMAL
     */
    public static final String JOB_STATUS_NORMAL = "NORMAL";

    /**
     * job状态 PAUSED :暂停
     */
    public static final String JOB_STATUS_PAUSED = "PAUSED";

}

(2)定时任务状态枚举

/**
 * 触发器状态枚举
 */
public enum TriggerStateEnum {


    /**
     * 不存在
     */
    NONE("不存在"),

    /**
     * 正常
     */
    NORMAL("正常"),

    /**
     * 暂停
     */
    PAUSED("暂停"),


    /**
     * 完成
     */
    COMPLETE("完成"),

    /**
     * 错误
     */
    ERROR("失败"),

    /**
     * 阻塞
     */
    BLOCKED("阻塞");


    private String desc;


    public String getDesc() {
        return desc;
    }

    TriggerStateEnum(String desc) {
        this.desc = desc;
    }

    public static String getTriggerState(String desc) {
        for (TriggerStateEnum triggerStateEnum : values()) {
            if (triggerStateEnum.name().equals(desc)) {
                return triggerStateEnum.desc;
            }
        }
        return null;
    }


    public static String getState(String str) {
        TriggerStateEnum stateEnum = TriggerStateEnum.valueOf("NONE");
        return stateEnum != null ? stateEnum.desc : null;
    }


    public static void main(String[] args) {
        System.out.println(getState("NONE"));
        System.out.println(getTriggerState("ERROR"));

    }
}

(3)返回状态码及异常信息枚举类

/**
 * 返回状态码及异常信息枚举类
 */
public enum ResultEnum {

    SUCCESS(0, "Success"),
    ERROR(-1, "Error");

    private int status;

    private String message;

    ResultEnum(int status, String message) {
        this.status = status;
        this.message = message;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

定时任务功能Controller


import com.example.quartz.util.Response;
import com.example.quartz.util.Page;
import com.example.quartz.entity.ScheduleJobEntity;
import com.example.quartz.entity.param.AddScheduleJobParam;
import com.example.quartz.entity.vo.ScheduleJobVO;
import com.example.quartz.service.ScheduleJobService;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.quartz.SchedulerException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

/**
 * 定时任务功能Controller
 */
@RestController
@RequestMapping(value = "/quartz/job")
@Slf4j
public class ScheduleJobController {

    @Autowired
    private ScheduleJobService scheduleJobService;


    @ApiOperation(value = "添加job", notes = "添加job")
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public Response addPostJsonJob(@RequestBody @Valid AddScheduleJobParam addJobParam) {
        ScheduleJobEntity scheduleJobEntityParam = new ScheduleJobEntity();
        BeanUtils.copyProperties(addJobParam, scheduleJobEntityParam);
        scheduleJobService.addJob(scheduleJobEntityParam);
        return Response.success();
    }


    @ApiOperation(value = "修改job", notes = "修改job")
    @RequestMapping(value = "/update", method = RequestMethod.POST)
    public Response updateJob(@RequestParam(name = "jobName") String jobName,
                              @RequestParam(name = "jobGroup") String jobGroup,
                              @RequestParam(name = "cronExpression") String cronExpression) {

        scheduleJobService.updateCronExpression(jobName, jobGroup, cronExpression);
        return Response.success();
    }

    /**
     * 删除job
     */
    @ApiOperation(value = "删除job", notes = "删除job")
    @RequestMapping(value = "/delete", method = RequestMethod.POST)
    public Response deleteJob(@RequestParam(name = "jobName") String jobName,
                              @RequestParam(name = "jobGroup") String jobGroup) {

        scheduleJobService.deleteJob(jobName, jobGroup);
        return Response.success();
    }


    /**
     * 暂停job  //暂停运行和恢复运行需要批量更新任务状态
     */
    @ApiOperation(value = "暂停job", notes = "暂停job")
    @RequestMapping(value = "/pause", method = RequestMethod.POST)
    public Response pauseJob(@RequestParam(name = "jobName") String jobName,
                             @RequestParam(name = "jobGroup") String jobGroup) {

        scheduleJobService.pauseJob(jobName, jobGroup);
        return Response.success();
    }


    /**
     * 恢复job
     */
    @ApiOperation(value = "恢复job", notes = "恢复job")
    @RequestMapping(value = "/resume", method = RequestMethod.POST)
    public Response resumeJob(@RequestParam(name = "jobName") String jobName,
                              @RequestParam(name = "jobGroup") String jobGroup) {

        scheduleJobService.resumeJob(jobName, jobGroup);
        return Response.success();
    }

    /**
     * 立即执行job
     */
    @ApiOperation(value = "立即执行任务", notes = "立即执行一次")
    @RequestMapping(value = "/run", method = RequestMethod.POST)
    public Response runJobNow(@RequestBody List<ScheduleJobEntity> jobList) {
        scheduleJobService.runJobNow(jobList);
        return Response.success();
    }

    /**
     * 从数据库:查询所有计划中的任务列表分页
     */
    @RequestMapping(value = "/queryScheduleJob")
    public Response<Page<ScheduleJobVO>> queryScheduleAllJob(@RequestParam(name = "searchParam", required = false) String searchParam,
                                                             @RequestParam(name = "pageSize", required = false, defaultValue = "15") Integer pageSize,
                                                             @RequestParam(name = "pageNum", required = false, defaultValue = "1") Integer pageNum) {
        Page<ScheduleJobVO> result = scheduleJobService.queryScheduleJob(searchParam, pageSize, pageNum);
        return Response.success(result);
    }


    /**
     * 获取所有正在运行的job
     */
    @ApiOperation(value = "获取所有正在运行的job", notes = "获取所有正在运行的job")
    @RequestMapping(value = "/getRunningJob", method = RequestMethod.GET)
    public Response getRunningJob() throws SchedulerException {
        List<ScheduleJobVO> result = scheduleJobService.getRunningJob();
        return Response.success(result);
    }


    /**
     * 获取所有计划中的任务列表
     */
    @ApiOperation(value = "获取所有计划中的任务列表", notes = "获取所有计划中的任务列表")
    @RequestMapping(value = "/getAllJob", method = RequestMethod.GET)
    public Response getAllJob() throws SchedulerException {
        List<ScheduleJobVO> result = scheduleJobService.getAllJob();
        PageInfo<ScheduleJobVO> pageInfo = new PageInfo<>(result);
        return Response.success(pageInfo);
    }

}

(2)定时任务执行记录日志Controller


import com.example.quartz.util.Response;
import com.example.quartz.util.Page;
import com.example.quartz.entity.vo.ScheduleJobLogVO;
import com.example.quartz.entity.vo.ScheduleJobVO;
import com.example.quartz.service.ScheduleJobLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * 定时任务执行记录日志Controller
 */
@RestController
@RequestMapping(value = "/quartz/log")
public class ScheduleJobLogController {

    @Autowired
    private ScheduleJobLogService scheduleJobLogService;


    /**
     * 定时任务执行记录
     */
    @RequestMapping(value = "/jobLogs")
    public Response<Page<ScheduleJobLogVO>> getHistoryScheduleJobLog(@RequestParam(name = "jobName", required = false) String jobName,
                                                                     @RequestParam(name = "jobGroup", required = false) String jobGroup,
                                                                     @RequestParam(name = "searchParam", required = false) String searchParam,
                                                                     @RequestParam(name = "pageSize", required = false, defaultValue = "15") Integer pageSize,
                                                                     @RequestParam(name = "pageNum", required = false, defaultValue = "1") Integer pageNum) {

        Page<ScheduleJobLogVO> result = scheduleJobLogService.scheduledTaskLogList(jobName, jobGroup, searchParam, pageSize, pageNum);
        return Response.success(result);
    }

   
}

(3)定时任务测试Controller


import com.example.quartz.entity.ScheduleJobEntity;
import com.example.quartz.entity.vo.ScheduleJobVO;
import com.example.quartz.mapper.ScheduleJobMapper;
import com.example.quartz.service.ScheduleJobService;
import com.example.quartz.util.Response;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

@Slf4j
@RestController
@RequestMapping(value = "/quartz/test")
public class TestScheduleJobController {


    @Autowired
    private ScheduleJobMapper scheduleJobMapper;


    @Autowired
    private ScheduleJobService scheduleJobService;

    @ApiOperation(value = "测试带参数的job", notes = "测试post请求job,参数不为空")
    @RequestMapping(value = "/job", method = RequestMethod.POST)
    public Response testJob(@RequestBody @Valid ScheduleJobEntity scheduleJobEntity) {

        String jobName = scheduleJobEntity.getJobName();
        String jobGroup = scheduleJobEntity.getJobGroup();
        ScheduleJobEntity scheduleJobEntityResult = scheduleJobMapper.getTaskByJobNameAndJobGroup(jobName, jobGroup);
        return Response.success(scheduleJobEntityResult);
    }

    /**
     * 获取所有计划中的任务列表
     */
    @ApiOperation(value = "测试参数为空的job", notes = "测试post请求job,参数为空")
    @RequestMapping(value = "/getAllJob", method = RequestMethod.POST)
    public Response getAllJob() throws SchedulerException {
        List<ScheduleJobVO> result = scheduleJobService.getAllJob();
        PageInfo<ScheduleJobVO> pageInfo = new PageInfo<>(result);
        return Response.success(pageInfo);
    }
}

定时任务效果

源码下载

https://github.com/helloflygit/springboot-quartz

  • 3
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我了解了您的问题。在Spring Cloud集成Quartz时,需要进行以下数据库配置: 1. 首先,在您的Spring Boot项目中添加Quartz的依赖项。您可以在pom.xml文件中添加以下依赖项: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> ``` 2. 接下来,在application.properties文件中配置Quartz数据库属性,例如: ``` spring.quartz.job-store-type=jdbc spring.quartz.jdbc.initialize-schema=always spring.datasource.url=jdbc:mysql://localhost:3306/quartz spring.datasource.username=root spring.datasource.password=password spring.datasource.driver-class-name=com.mysql.jdbc.Driver ``` 其中,spring.quartz.job-store-type设置为jdbc,表示Quartz将使用数据库存储作业和触发器,spring.quartz.jdbc.initialize-schema设置为always表示每次启动应用程序时都会初始化Quartz数据库,spring.datasource.url、spring.datasource.username、spring.datasource.password和spring.datasource.driver-class-name为您的数据库连接属性。 3. 最后,定义您的定时任务,例如: ``` @Configuration public class QuartzConfiguration { @Bean public JobDetail myJobDetail() { return JobBuilder.newJob(MyJob.class) .withIdentity("myJob") .storeDurably() .build(); } @Bean public Trigger myTrigger() { return TriggerBuilder.newTrigger() .forJob(myJobDetail()) .withIdentity("myTrigger") .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")) .build(); } } @Component public class MyJob implements Job { @Override public void execute(JobExecutionContext context) { // 任务逻辑 } } ``` 其中,定时任务使用Cron表达式配置,该表达式将在每分钟的第0秒开始,每5秒执行一次任务。 以上就是Spring Cloud集成Quartz数据库配置定时任务的方法。希望能够帮助到您!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值