SpringBoot集成Quartz并持久化

MySql sql语句

/*
MySQL Data Transfer
Source Host: 101.132.168.240
Source Database: quartz
Target Host: 101.132.168.240
Target Database: quartz
Date: 2019/7/2 15:13:56
*/

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for QRTZ_BLOB_TRIGGERS
-- ----------------------------
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,
  PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
  KEY `SCHED_NAME` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
  CONSTRAINT `QRTZ_BLOB_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for QRTZ_CALENDARS
-- ----------------------------
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 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for QRTZ_CRON_TRIGGERS
-- ----------------------------
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) DEFAULT NULL,
  PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
  CONSTRAINT `QRTZ_CRON_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for QRTZ_FIRED_TRIGGERS
-- ----------------------------
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` int(11) NOT NULL,
  `STATE` varchar(16) NOT NULL,
  `JOB_NAME` varchar(200) DEFAULT NULL,
  `JOB_GROUP` varchar(200) DEFAULT NULL,
  `IS_NONCONCURRENT` varchar(1) DEFAULT NULL,
  `REQUESTS_RECOVERY` varchar(1) DEFAULT NULL,
  PRIMARY KEY (`SCHED_NAME`,`ENTRY_ID`),
  KEY `IDX_QRTZ_FT_TRIG_INST_NAME` (`SCHED_NAME`,`INSTANCE_NAME`),
  KEY `IDX_QRTZ_FT_INST_JOB_REQ_RCVRY` (`SCHED_NAME`,`INSTANCE_NAME`,`REQUESTS_RECOVERY`),
  KEY `IDX_QRTZ_FT_J_G` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
  KEY `IDX_QRTZ_FT_JG` (`SCHED_NAME`,`JOB_GROUP`),
  KEY `IDX_QRTZ_FT_T_G` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
  KEY `IDX_QRTZ_FT_TG` (`SCHED_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for QRTZ_JOB_DETAILS
-- ----------------------------
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) DEFAULT 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,
  PRIMARY KEY (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
  KEY `IDX_QRTZ_J_REQ_RECOVERY` (`SCHED_NAME`,`REQUESTS_RECOVERY`),
  KEY `IDX_QRTZ_J_GRP` (`SCHED_NAME`,`JOB_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for QRTZ_LOCKS
-- ----------------------------
CREATE TABLE `QRTZ_LOCKS` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `LOCK_NAME` varchar(40) NOT NULL,
  PRIMARY KEY (`SCHED_NAME`,`LOCK_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for QRTZ_PAUSED_TRIGGER_GRPS
-- ----------------------------
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 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for QRTZ_SCHEDULER_STATE
-- ----------------------------
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 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for QRTZ_SIMPLE_TRIGGERS
-- ----------------------------
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`),
  CONSTRAINT `QRTZ_SIMPLE_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for QRTZ_SIMPROP_TRIGGERS
-- ----------------------------
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) DEFAULT NULL,
  `STR_PROP_2` varchar(512) DEFAULT NULL,
  `STR_PROP_3` varchar(512) DEFAULT NULL,
  `INT_PROP_1` int(11) DEFAULT NULL,
  `INT_PROP_2` int(11) DEFAULT NULL,
  `LONG_PROP_1` bigint(20) DEFAULT NULL,
  `LONG_PROP_2` bigint(20) DEFAULT NULL,
  `DEC_PROP_1` decimal(13,4) DEFAULT NULL,
  `DEC_PROP_2` decimal(13,4) DEFAULT NULL,
  `BOOL_PROP_1` varchar(1) DEFAULT NULL,
  `BOOL_PROP_2` varchar(1) DEFAULT NULL,
  PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
  CONSTRAINT `QRTZ_SIMPROP_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for QRTZ_TRIGGERS
-- ----------------------------
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) DEFAULT NULL,
  `NEXT_FIRE_TIME` bigint(13) DEFAULT NULL,
  `PREV_FIRE_TIME` bigint(13) DEFAULT NULL,
  `PRIORITY` int(11) DEFAULT NULL,
  `TRIGGER_STATE` varchar(16) NOT NULL,
  `TRIGGER_TYPE` varchar(8) NOT NULL,
  `START_TIME` bigint(13) NOT NULL,
  `END_TIME` bigint(13) DEFAULT NULL,
  `CALENDAR_NAME` varchar(200) DEFAULT NULL,
  `MISFIRE_INSTR` smallint(2) DEFAULT NULL,
  `JOB_DATA` blob,
  PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
  KEY `IDX_QRTZ_T_J` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
  KEY `IDX_QRTZ_T_JG` (`SCHED_NAME`,`JOB_GROUP`),
  KEY `IDX_QRTZ_T_C` (`SCHED_NAME`,`CALENDAR_NAME`),
  KEY `IDX_QRTZ_T_G` (`SCHED_NAME`,`TRIGGER_GROUP`),
  KEY `IDX_QRTZ_T_STATE` (`SCHED_NAME`,`TRIGGER_STATE`),
  KEY `IDX_QRTZ_T_N_STATE` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
  KEY `IDX_QRTZ_T_N_G_STATE` (`SCHED_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
  KEY `IDX_QRTZ_T_NEXT_FIRE_TIME` (`SCHED_NAME`,`NEXT_FIRE_TIME`),
  KEY `IDX_QRTZ_T_NFT_ST` (`SCHED_NAME`,`TRIGGER_STATE`,`NEXT_FIRE_TIME`),
  KEY `IDX_QRTZ_T_NFT_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`),
  KEY `IDX_QRTZ_T_NFT_ST_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_STATE`),
  KEY `IDX_QRTZ_T_NFT_ST_MISFIRE_GRP` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
  CONSTRAINT `QRTZ_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for task_entity
-- ----------------------------
CREATE TABLE `task_entity` (
  `job_id` varchar(255) NOT NULL,
  `create_time` datetime DEFAULT NULL,
  `cron_expression` varchar(255) DEFAULT NULL,
  `description` varchar(255) DEFAULT NULL,
  `is_concurrent` varchar(255) DEFAULT NULL,
  `job_group` varchar(255) DEFAULT NULL,
  `job_name` varchar(255) DEFAULT NULL,
  `job_status` varchar(255) DEFAULT NULL,
  `run_job_class_name` varchar(255) DEFAULT NULL,
  `run_job_method_name` varchar(255) DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`job_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

项目准备

POM 文件内容

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.demo</groupId>
    <artifactId>springboot-jdbc-quartz</artifactId>
    <version>1.0-SNAPSHOT</version>

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

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--quartz -->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <!-- <version>2.3.0</version> -->
        </dependency>
        <!--定时任务需要依赖context模块-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--<dependency>-->
        <!--<groupId>org.springframework.boot</groupId>-->
        <!--<artifactId>spring-boot-starter-quartz</artifactId>-->
        <!--</dependency>-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>
        <!--&lt;!&ndash; druid数据库连接池 &ndash;&gt;-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>-->

        <dependency><!--页面模板依赖-->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!--开发切面类所用的支持-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
    </dependencies>

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

application.yml 内容

spring:
  jpa:
    hibernate:
      ddl-auto: update
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    show-sql: true
    jackson:
      default-property-inclusion: non_null
  # 模板引擎
  thymeleaf:
    mode: HTML
    encoding: utf-8
    # 禁用缓存
    cache: false
    #调整页面路径
    prefix: classpath:/templates/
  datasource:
    url: jdbc:mysql://101.132.168.240:3306/quartz?serverTimezone=GMT&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
    username: root
    password: HUANGfu0110..
    #driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      initialSize: 2
      minIdle: 2
      maxActive: 30

项目结构

|-Springboot-jdbc-quartz

​ |----src

​ |----java

​ |----com

​ |----demo.xxxxx

​ |----resources

​ |-----static

​ |-----templates

代码编写

resources里面创建quartz.properties文件

#使用自己的配置文件
org.quartz.jobStore.useProperties:false

#默认或是自己改名字都行
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
#如果使用集群,instanceId必须唯一,设置成AUTO
org.quartz.scheduler.instanceId = AUTO


org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true


#存储方式使用JobStoreTX,也就是数据库
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#是否使用集群(如果项目只部署到 一台服务器,就不用了)
org.quartz.jobStore.isClustered = false
org.quartz.jobStore.clusterCheckinInterval=20000
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.dataSource = myDS

#配置数据源
#数据库中quartz表的表名前缀
org.quartz.dataSource.myDS.driver = com.mysql.cj.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc:mysql://101.132.168.240:3306/quartz?serverTimezone=GMT&characterEncoding=utf-8
org.quartz.dataSource.myDS.user = root
org.quartz.dataSource.myDS.password = HUANGfu0110..
org.quartz.dataSource.myDS.maxConnections = 5

创建SpringBoot核心启动类

package com.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author 皇甫
 */
@SpringBootApplication
public class QuartzDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(QuartzDemoApplication.class, args);
    }
}

创建一个实体 用于映射任务 对应表Task_Entity 直接运行 jpa自动创建

注意 映射类必须实现Serializable接口,任务的持久化需要序列化

package com.demo.dataobject;

import lombok.Data;
import org.hibernate.annotations.DynamicUpdate;

import javax.persistence.Entity;
import javax.persistence.Id;
import java.io.Serializable;
import java.util.Date;

/**
 * 任务实体映射
 * @author 皇甫
 */
@Entity
@Data
@DynamicUpdate
public class TaskEntity implements Serializable {
    /**
     * 运行中
     */
    public static final String STATUS_RUNNING = "0";
    /**
     * 停止
     */
    public static final String STATUS_NOT_RUNNING = "1";
    @Id
    private String jobId;
    private Date createTime;
    private Date updateTime;
    /**
     * 任务名称
     */
    private String jobName;
    /**
     * 任务分组
     */
    private String jobGroup;
    /**
     * 任务启动状态
     */
    private String jobStatus;
    /**
     * cron表达式
     */
    private String cronExpression;
    /**
     * 任务描述
     */
    private String description;
    /**
     * 具体类名  全限定名
     */
    private String runJobClassName;
    /**
     * 任务状态
     */
    private String isConcurrent;
    /**
     * 任务方法名
     */
    private String runJobMethodName;

    public void preCreate(){
        this.createTime = new Date();
    }
    public void preUpdate(){
        this.updateTime = new Date();
    }

    public TaskEntity() {
    }

    public TaskEntity(Date createTime, Date updateTime, String jobName, String jobGroup, String jobStatus, String cronExpression, String description, String runJobClassName, String isConcurrent, String runJobMethodName) {
        this.createTime = createTime;
        this.updateTime = updateTime;
        this.jobName = jobName;
        this.jobGroup = jobGroup;
        this.jobStatus = jobStatus;
        this.cronExpression = cronExpression;
        this.description = description;
        this.runJobClassName = runJobClassName;
        this.isConcurrent = isConcurrent;
        this.runJobMethodName = runJobMethodName;
    }
}

创建Dao接口 这里使用SpringBoot-jpa

package com.demo.dao;

import com.demo.dataobject.TaskEntity;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * @author 皇甫
 */
public interface TaskDao extends JpaRepository<TaskEntity,String> {}

创建quartz和SpringBoot的配置类

package com.demo.conf;

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;

/**
 * @author 皇甫 
 * 
 */
@Component
public class JobFactory extends AdaptableJobFactory {
    @Autowired
    private AutowireCapableBeanFactory autowireCapableBeanFactory;

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

package com.demo.conf;

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.SchedulerFactoryBean;

/**
 * @author 皇甫
 */
@Configuration
public class QuartzConfig {
    @Autowired
    private JobFactory jobFactory;

    /**
     * 指定持久化配置文件
     * @return
     */
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(){
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        schedulerFactoryBean.setJobFactory(jobFactory);
        // 用于quartz集群,QuartzScheduler 启动时更新己存在的Job
        schedulerFactoryBean.setOverwriteExistingJobs(true);
        schedulerFactoryBean.setStartupDelay(1);
        schedulerFactoryBean.setConfigLocation(new ClassPathResource("/quartz.properties"));
        return schedulerFactoryBean;
    }

    /**
     * 创建getScheduler
     * @return
     */
    @Bean
    public Scheduler scheduler(){
        return schedulerFactoryBean().getScheduler();
    }
}

package com.demo.conf;

import com.demo.dataobject.TaskEntity;
import com.demo.util.QuartzUtil;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

/**
 * 任务对象  我们需要通过此方法来反射执行任务类
 * @author 皇甫
 */
@DisallowConcurrentExecution
public class TaskObject implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        TaskEntity job = (TaskEntity)context.getJobDetail().getJobDataMap().get("job");
        QuartzUtil.invokeMethod(job);
    }
}

SpringBoot静态资源配置

package com.demo.conf;

import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author 皇甫
 */
public class WebConfig implements WebMvcConfigurer {
    /**
     * 配置静态资源拦截
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }
}
重点 :创建任务的业务接口
package com.demo.service;

import com.demo.dataobject.TaskEntity;
import org.quartz.SchedulerException;

import java.util.List;

/**
 * @author 皇甫
 */
public interface QuartzService {
    /**
     * 查询所有任务列表
     * @return
     */
    List<TaskEntity> findAll();

    /**
     * 添加一个任务
     * @param taskEntity
     */
    void addJob(TaskEntity taskEntity);

    /**
     * 根据Id查询一个对象
     * @param id
     * @return
     */
    TaskEntity findOneById(String id);

    /**
     * 更改任务的状态   开始  停止
     * @param jobId
     * @param cmd
     */
    void changeJobStatus(String jobId, String cmd) throws SchedulerException;

    /**
     * 更改任务 cron表达式 数据库
     * @param id
     * @param cron
     */
    void updateJobCron(String id,String cron) throws SchedulerException;

    /**
     * 增加一个任务
     * @param id
     */
    void addTask(String id) throws SchedulerException;

    /**
     * 暂停一个任务
     * @param id
     */
    void pauseJob(String id) throws SchedulerException;

    /**
     * 恢复暂停的任务
     * @param id
     */
    void resumeJob(String id) throws SchedulerException;

    /**
     * 立即开始执行
     * @param id
     */
    void runAJobNow(String id) throws SchedulerException;
}

创建一个工具类用于反射执行作业方法

package com.demo.util;

import com.demo.dataobject.TaskEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author 皇甫
 */
public class QuartzUtil {
    private static final Logger logger = LoggerFactory.getLogger(QuartzUtil.class);
    public static void invokeMethod(TaskEntity entity){
        logger.info("-------------------------【创建任务对象】开始创建任务对象----------------------" );
        String className = entity.getRunJobClassName();
        String methodName = entity.getRunJobMethodName();
        Object object = null;
        Class clazz = null;
        try{
            clazz = Class.forName(className);
            object = clazz.newInstance();

            Method declaredMethod = clazz.getDeclaredMethod(methodName);
            declaredMethod.invoke(object);
            logger.info("-------------------------【创建任务对象】创建任务对象成功,任务名:{}----------------------",entity.getJobName());
        }catch (ClassNotFoundException notFoundException){
            logger.error("------------------【创建任务对象】执行任务错误,找不到对应类{}-----------------",notFoundException.getMessage() );
        }catch (NoSuchMethodException noSuchMethodException){
            logger.error("------------------【创建任务对象】执行任务错误,找不到对应方法{}-----------------",noSuchMethodException.getMessage() );
        }catch (InstantiationException instantiationException){
            logger.error("------------------【创建任务对象】执行任务错误,无法实例化对象,建议:查看是否存在无参构造{}-----------------",instantiationException.getMessage() );
        }catch (IllegalAccessException illegalAccessException){
            logger.error("------------------【创建任务对象】执行任务错误,无法实例化对象,建议:查看类全限定名是否正确{}-----------------",illegalAccessException.getMessage() );
        }catch (InvocationTargetException invocationTargetException){
            logger.error("------------------【创建任务对象】执行任务错误,运行方法失败{}-----------------",invocationTargetException.getMessage() );
        }catch (Exception e){
            logger.error("------------------【创建任务对象】执行任务错误,未知错误{}-----------------",e.getMessage() );
        }

    }
}

创建任务接口的实现类
package com.demo.service.impl;

import com.demo.conf.TaskObject;
import com.demo.dao.TaskDao;
import com.demo.dataobject.TaskEntity;
import com.demo.service.QuartzService;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;

/**
 * @author 皇甫
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class QuartzServiceImpl implements QuartzService {
    @Autowired
    private TaskDao taskDao;
    @Autowired
    private Scheduler scheduler;
    private final String STOP = "STOP";
    private final String START = "START";

    /**
     * 查询所有
     * @return
     */
    @Override
    public List<TaskEntity> findAll() {
        return taskDao.findAll();
    }

    /**
     * 数据库添加一个任务
     * @param taskEntity
     */
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    @Override
    public void addJob(TaskEntity taskEntity) {
        taskEntity.setJobId(UUID.randomUUID().toString());
        taskEntity.preCreate();
        taskEntity.setJobStatus(TaskEntity.STATUS_NOT_RUNNING);
        taskDao.save(taskEntity);
    }

    /**
     * 数据库根据Id查询一个任务详情
     * @param id
     * @return
     */
    @Override
    public TaskEntity findOneById(String id) {
        return taskDao.findById(id).get();
    }

    /**
     * 停止开始运行任务
     * @param jobId
     * @param cmd 操作类型  stop停止  start开始
     */
    @Override
    public void changeJobStatus(String jobId, String cmd) throws SchedulerException {
        TaskEntity oneById = findOneById(jobId);
        if(oneById == null){
            return;
        }
        //停止
        if(STOP.equals(cmd)){
            //定位任务
            JobKey jobKey = JobKey.jobKey(oneById.getJobName(), oneById.getJobGroup());
            //停止任务
            oneById.setJobStatus(TaskEntity.STATUS_NOT_RUNNING);
            scheduler.deleteJob(jobKey);
        }else if(START.equals(cmd)){
            //开始一个任务
            oneById.setJobStatus(TaskEntity.STATUS_RUNNING);
            //重新开始  添加一个任务
            addJob(oneById);

        }else{
            return;
        }
        //将修改信息保存再数据库
        taskDao.save(oneById);
    }

    /**
     * 修改任务运行信息 cron
     * @param id
     * @param cron
     */
    @Override
    public void updateJobCron(String id, String cron) throws SchedulerException {
        TaskEntity job = findOneById(id);
        if(job == null){
            return;
        }
        //开始修改运行周期
        job.setCronExpression(cron);

        //判断任务是否再运行中 如果是运行中就执行job修改 如果没有运行则只执行修改数据库即可
        if(TaskEntity.STATUS_RUNNING.equals(job.getJobStatus())){
            //精确任务
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
            //获取这个任务的触发器
            CronTrigger trigger = (CronTrigger)scheduler.getTrigger(triggerKey);
            //设置新的定时器
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
            //给触发器绑定新的定时任务
            trigger = trigger.getTriggerBuilder()
                    .withSchedule(cronScheduleBuilder)
                    .withIdentity(triggerKey)
                    .build();
            //绑定定时器和触发器
            scheduler.rescheduleJob(triggerKey, trigger);

        }
    }

    @Override
    public void addTask(String id) throws SchedulerException {
        TaskEntity job = findOneById(id);
        if(job == null || TaskEntity.STATUS_RUNNING.equals(job.getJobStatus())){
            return;
        }
        //创建任务信息
        TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
        //创建一个触发器
        CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        //查看此触发器是否存在  有可能存在  因为启动任务也调用了这个方法
        if(null == cronTrigger){
            //如果不存在  开始创建一个定时任务
            JobDetail jobDetail = JobBuilder.newJob(TaskObject.class)
                    .withIdentity(job.getJobName(), job.getJobGroup())
                    .build();
            //将任务对对象产地给任务工厂 生产任务
            jobDetail.getJobDataMap().put("job",job);
            //创建一个定时器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
            //创建新的触发器
            cronTrigger = TriggerBuilder.newTrigger()
                    .withSchedule(scheduleBuilder)
                    .withIdentity(job.getJobName(), job.getJobGroup())
                    .build();
            //绑定触发器和任务详情
            scheduler.scheduleJob(jobDetail,cronTrigger);
        }else{
            // Trigger已存在,那么更新相应的定时设置
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
            //修改触发器
            cronTrigger = cronTrigger.getTriggerBuilder()
                    .withIdentity(triggerKey)
                    .withSchedule(scheduleBuilder)
                    .build();
            //按照新的运行
            scheduler.rescheduleJob(triggerKey,cronTrigger);
        }
        job.setJobStatus(TaskEntity.STATUS_RUNNING);
        taskDao.save(job);
    }

    /**
     * 暂停一个任务
     * @param id
     */
    @Override
    public void pauseJob(String id) throws SchedulerException {
        TaskEntity job = findOneById(id);
        //获取任务详细  key
        JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
        //暂停
        scheduler.pauseJob(jobKey);
    }

    /**
     * 开始任务  恢复暂停
     */
    @Override
    public void resumeJob(String id) throws SchedulerException {
        TaskEntity job = findOneById(id);
        //获取任务详细  key
        JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
        scheduler.resumeJob(jobKey);
    }

    /**
     * 不等待  立即执行该任务
     * @param id
     */
    @Override
    public void runAJobNow(String id) throws SchedulerException {
        TaskEntity job = findOneById(id);
        //获取任务详细  key
        JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
        scheduler.triggerJob(jobKey);
    }
}

创建和前端交互的接口

package com.demo.controller;

import com.demo.dataobject.TaskEntity;
import com.demo.service.QuartzService;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import java.util.*;

/**
 * @author 皇甫
 */
@Controller
public class JobController {
    @Autowired
    private QuartzService quartzService;

    @RequestMapping("findAll.html")
    public ModelAndView findAll(ModelAndView modelAndView){
        List<TaskEntity> all = quartzService.findAll();
        modelAndView.addObject("all", all);
        modelAndView.setViewName("/quartzs");
        return modelAndView;
    }
    @RequestMapping("/addJob.html")
    public ModelAndView addView(ModelAndView modelAndView){
        modelAndView.setViewName("/addJob");
        return modelAndView;
    }

    /**
     * 添加一个任务
     * @param job
     */
    @RequestMapping("addDbJob.do")
    @ResponseBody
    public Object addDbJob(TaskEntity job){
        quartzService.addJob(job);
        Map<String,Object> hashMap = new HashMap<String,Object>();
        hashMap.put("code","000");
        hashMap.put("msg","成功");
        return hashMap;
    }

    /**
     * 改变任务状态
     * @param id
     * @param cmd
     */
    @RequestMapping("changeJobStatus.do")
    @ResponseBody
    public Object changeJobStatus(@RequestParam("id") String id,@RequestParam("cmd") String cmd){
        Map<String,Object> hashMap = new HashMap<String,Object>();
        try {
            quartzService.changeJobStatus(id, cmd);
            hashMap.put("code","000");
            hashMap.put("msg","成功");
        } catch (SchedulerException e) {
            e.printStackTrace();
            hashMap.put("code","1000");
            hashMap.put("msg","失败");
        }
        return hashMap;
    }

    /**
     * 更改任务运行周期
     * @param id
     * @param cron
     */
    @RequestMapping("updateJobCron.do")
    @ResponseBody
    public Object updateJobCron(@RequestParam("id") String id,@RequestParam("cron") String cron){
        Map<String,Object> hashMap = new HashMap<String,Object>();
        try {
            quartzService.updateJobCron(id, cron);
            hashMap.put("code","000");
            hashMap.put("msg","成功");
        } catch (SchedulerException e) {
            e.printStackTrace();
            hashMap.put("code","1000");
            hashMap.put("msg","失败");
        }
        return hashMap;
    }

    /**
     * 增加一个任务
     * @param id
     * @return
     */
    @RequestMapping("addTask.do")
    @ResponseBody
    public Object addTask(String id){
        Map<String,Object> hashMap = new HashMap<String,Object>();
        try {
            quartzService.addTask(id);
            hashMap.put("code","000");
            hashMap.put("msg","成功");
        } catch (SchedulerException e) {
            e.printStackTrace();
            hashMap.put("code","1000");
            hashMap.put("msg","失败");
        }
        return hashMap;
    }
    @ResponseBody
    @RequestMapping("pauseJob.do")
    public Object pauseJob(String id){
        Map<String,Object> hashMap = new HashMap<String,Object>();
        try {
            quartzService.pauseJob(id);
            hashMap.put("code","000");
            hashMap.put("msg","成功");
        } catch (SchedulerException e) {
            e.printStackTrace();
            hashMap.put("code","1000");
            hashMap.put("msg","失败");
        }
        return hashMap;
    }

    /**
     * 恢复任务
     * @param id
     */
    @ResponseBody
    @RequestMapping("resumeJob.do")
    public Object resumeJob(String id){
        Map<String,Object> hashMap = new HashMap<String,Object>();
        try {
            quartzService.resumeJob(id);
            hashMap.put("code","000");
            hashMap.put("msg","成功");
        } catch (SchedulerException e) {
            e.printStackTrace();
            hashMap.put("code","1000");
            hashMap.put("msg","失败");
        }
        return hashMap;
    }
    @RequestMapping("runAJobNow.do")
    @ResponseBody
    public Object runAJobNow(String id){
        Map<String,Object> hashMap = new HashMap<String,Object>();
        try {
            quartzService.runAJobNow(id);
            hashMap.put("code","000");
            hashMap.put("msg","成功");
        } catch (SchedulerException e) {
            e.printStackTrace();
            hashMap.put("code","1000");
            hashMap.put("msg","失败");
        }
        return hashMap;
    }

}

为了测试用 我们编写一个任务类

package com.demo.job;

/**
 * 打印任务
 * @author huangfu
 */
public class PrintHelloWordJob {
    public void print(){
        System.out.println("Hello World"+System.nanoTime());
    }
}

编写前端页面

在templates目录下创建quartzs.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>全部任务</title>
    <style type="text/css">
        table {
            border: 1px solid black;
            text-align: center;
            border-collapse: collapse;
        }
        table thead th {
            border: 1px solid black;
        }
        table tbody td {
            border: 1px solid black;
        }
    </style>
    <script type="text/javascript" src="../static/jquery/jquery-3.3.1.js" th:src="@{/jquery/jquery-3.3.1.js}"></script>
    <script type="text/javascript" src="../static/index.js" th:src="@{/index.js}"></script>
</head>
<body>
    <div style="align-content: center">
        <table cellpadding="0" cellspacing="0">
            <thead>
                <th>任务编号</th>
                <th>任务名称</th>
                <th>任务分组</th>
                <th>任务状态</th>
                <th>启动状态</th>
                <th>任务类名</th>
                <th>任务方法名</th>
                <th>cron表达式</th>
                <th>创建时间</th>
                <th>修改时间</th>
                <th>操作</th>
            </thead>

            <tbody>
                <tr th:each="job:${all}">
                    <td th:text="${job.jobId}"></td>
                    <td th:text="${job.jobName}"></td>
                    <td th:text="${job.jobGroup}"></td>
                    <td th:text="${job.jobStatus}"></td>
                    <td th:text="${job.isConcurrent}"></td>
                    <td th:text="${job.runJobClassName}"></td>
                    <td th:text="${job.runJobMethodName}"></td>
                    <td th:text="${job.cronExpression}"></td>
                    <td th:text="${job.createTime}"></td>
                    <td th:text="${job.updateTime}"></td>
                    <td>
                        <a id="add">新增</a>
                        <a onclick="start(this);" id="start" href="#">开始</a>
                        <a onclick="stop(this);" id="stop" href="#">停止</a>
                        <a onclick="pause(this);" id="pause" href="#">暂停</a>
                        <a onclick="ref(this)" id="ref" href="#">恢复</a>
                    </td>

                </tr>
            </tbody>
        </table>
    </div>
</body>
</html>

创建一个addJob.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>添加任务</title>
    <script type="text/javascript" src="../static/jquery/jquery-3.3.1.js" th:src="@{/jquery/jquery-3.3.1.js}"></script>
    <script type="text/javascript" src="../static/index.js" th:src="@{/index.js}"></script>
</head>
<body>
    <form id="form" method="post">
        任务名称:<input id="jobName" name="jobName" type="text"/><br/>
        任务分组:<input id="jobGroup" name="jobGroup" type="text"/><br/>
        cron周期:<input id="cronExpression" name="cronExpression" type="text"/><br/>
        全限定名:<input id="runJobClassName" name="runJobClassName" type="text"/><br/>
        方法名:<input id="runJobMethodName" name="runJobMethodName" type="text"/><br/>
        任务详细描述:<input id="description" name="description" type="text"/><br/>

        <button id="addJob">添加</button>
    </form>
</body>
</html>

在static目录下创建一个index.js 并把jquery复制进去

function start(obj){
    var x = $(obj).parent().parent().find("td");
    var id = x.eq(0).text()

    $.ajax({
        url:"/addTask.do",
        data:{
            id : id
        },
        type:"post",
        dataType:"json",
        success:function(data){
            if(data.code=='000'){
                alert(data.msg)
                window.location = "/findAll.html";
            }
        }
    })


}

function stop(obj){
    var x = $(obj).parent().parent().find("td");
    var id = x.eq(0).text()

    $.ajax({
        url:"/changeJobStatus.do",
        data:{
            id : id,
            cmd : "STOP"
        },
        type:"post",
        dataType:"json",
        success:function(data){
            if(data.code=='000'){
                alert(data.msg)
                window.location = "/findAll.html";
            }
        }
    })
}

function pause(obj){
    var x = $(obj).parent().parent().find("td");
    var id = x.eq(0).text()

    $.ajax({
        url:"/pauseJob.do",
        data:{
            id : id
        },
        type:"post",
        dataType:"json",
        success:function(data){
            if(data.code=='000'){
                alert(data.msg)
                window.location = "/findAll.html";
            }
        }
    })
}

function ref(obj){
    var x = $(obj).parent().parent().find("td");
    var id = x.eq(0).text()

    $.ajax({
        url:"/resumeJob.do",
        data:{
            id : id
        },
        type:"post",
        dataType:"json",
        success:function(data){
            if(data.code=='000'){
                alert(data.msg)
                window.location = "/findAll.html";
            }
        }
    })
}

$(function () {
    var win = {};
    $("#add").on("click",function () {
        win = window.open("/addJob.html",
            "_blank",
            "height=300,width=600",
            false
        );
    });


    $("#addJob").on("click",function () {
        $.ajax({
            //几个参数需要注意一下
            type: "POST",//方法类型
            dataType: "json",//预期服务器返回的数据类型
            url: "addDbJob.do" ,//url
            data: $('#form').serialize(),
            success: function (data) {
                alert(data)
                var dataObj = JSON.parse(data);
                console.log(dataObj)
                if(dataObj.code=='000'){
                    alert(dataObj.msg)

                    win.close();
                }
            }

        });
    });
})

运行实例

访问地址:http://localhost:8080/addJob.html
在这里插入图片描述

填写数据

在这里插入图片描述

作者前端极度垃圾 所以能看就行 点击添加后 在其访问连接 http://localhost:8080/findAll.html

在这里插入图片描述

点击开始

提示成功后观看后台打印

在这里插入图片描述

查看数据库 QRTZ_JOB_DETAILS 持久化成功

在这里插入图片描述
Github地址:https://github.com/huangfusuper/springboot-jdbc-quartz.git

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值