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>
<!--<!– druid数据库连接池 –>-->
<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