最终效果图
前端页面只需要选择后端的逻辑类,就可以控制定时任务的开启与关闭
下面是整合步骤:
首先从官网中http://www.quartz-scheduler.org/
点击Downloads
下载quartz-2.2.3-distribution.tar
下载后在目录\docs\dbTables下有常用数据库创建quartz表的脚本
table_mysql.sql
table_mysql_innodb.sql
上述两者所有的数据库引擎不一样
MySQL 选择table_mysql.sql 就可以
表的介绍
QRTZ_BLOB_TRIGGERS
作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时候)
QRTZ_CALENDARS
以 Blob 类型存储 Quartz 的 Calendar 信息
QRTZ_CRON_TRIGGERS
存储 Cron Trigger,包括 Cron 表达式和时区信息
QRTZ_FIRED_TRIGGERS
存储与已触发的 Trigger 相关的状态信息,以及相联 Job 的执行信息
QRTZ_JOB_DETAILS
存储每一个已配置的 Job 的详细信息
QRTZ_LOCKS
存储程序的非观锁的信息(假如使用了悲观锁)
QRTZ_PAUSED_TRIGGER_GRPS
存储已暂停的 Trigger 组的信息
QRTZ_SCHEDULER_STATE
存储少量的有关 Scheduler 的状态信息,和别的 Scheduler 实例(假如是用于一个集群中)
QRTZ_SIMPLE_TRIGGERS
存储简单的 Trigger,包括重复次数,间隔,以及已触的次数
QRTZ_SIMPROP_TRIGGERS
简单的出发器详细信息。
QRTZ_TRIGGERS
存储已配置的 Trigger 的信息
准备好定时器表的构建之后,下面项目中整合
在pom.xml 中引入依赖
<!-- 引入quartz框架-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
新增一个properties 文件
org.quartz.scheduler.instanceName = MyScheduler
#开启集群,多个Quartz实例使用同一组数据库表
org.quartz.jobStore.isClustered = false
#分布式节点ID自动生成
org.quartz.scheduler.instanceId = AUTO
#分布式节点有效性检查时间间隔,单位:毫秒
org.quartz.jobStore.clusterCheckinInterval = 10000
#配置线程池线程数量,默认10个
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadPriority = 5
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#使用QRTZ_前缀
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.useProperties=true
org.quartz.jobStore.txIsolationLevelReadCommitted = true
org.quartz.jobStore.tablePrefix = QRTZ_ 如果你更改了表的名称,这里请对应更改
新建一个核心配置类 ScheduleConfiguration
@Configuration
public class ScheduleConfiguration {
@Autowired
private DataSource dataSource;
@Autowired
private MyJobFactory myJobFactory;
@Bean
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
schedulerFactoryBean.setSchedulerName("gbcom");
schedulerFactoryBean.setDataSource(dataSource);
schedulerFactoryBean.setApplicationContextSchedulerContextKey("application");
schedulerFactoryBean.setQuartzProperties(quartzProperties());
schedulerFactoryBean.setTaskExecutor(schedulerThreadPool());
schedulerFactoryBean.setStartupDelay(0);
schedulerFactoryBean.setJobFactory(myJobFactory);
return schedulerFactoryBean;
}
@Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/spring-quartz.properties"));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
@Bean
public Executor schedulerThreadPool(){
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
threadPoolTaskExecutor.setMaxPoolSize(Runtime.getRuntime().availableProcessors());
threadPoolTaskExecutor.setQueueCapacity(Runtime.getRuntime().availableProcessors());
return threadPoolTaskExecutor;
}
@Bean
public Scheduler scheduler() throws IOException {
return schedulerFactoryBean().getScheduler();
}
}
如果job类需要注入spring容器对象还需要添加一个配置类MyJobFactory
@Component
public class MyJobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
// 调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
// 进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
在核心配置类配置
在编写一个QuartzManager 通用类
@Service
public class QuartzManager {
@Autowired
private Scheduler scheduler;
/**
* 功能: 添加一个定时任务
*
* @param jobName
* 任务名
* @param jobGroupName
* 任务组名
* @param triggerName
* 触发器名
* @param triggerGroupName
* 触发器组名
* @param jobClass
* 任务的类类型 eg:TimedMassJob.class
* @param cron
* 时间设置 表达式,参考quartz说明文档
* //@param objects
* 可变参数需要进行传参的值
*/
public void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName,
Class jobClass, String cron, String description,String i) {
try {
// 任务名,任务组,任务执行类
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).withDescription(description).storeDurably().requestRecovery().build();
//System.out.println("jobDetail.getKey:"+jobDetail.getKey());
// 触发器
// if (objects != null) {
// for (int i = 0; i < objects.length; i++) {
// // 该数据可以通过Job中的JobDataMap dataMap =
// // context.getJobDetail().getJobDataMap();来进行参数传递值
// Map<String,Object> mapParams = new HashMap<>();
//
// jobDetail.getJobDataMap().put("name","admin");
// }
// }
jobDetail.getJobDataMap().put("mi",i);
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
triggerBuilder.withDescription(description);
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
CronTrigger trigger = (CronTrigger) triggerBuilder.build();
// 调度容器设置JobDetail和Trigger
scheduler.scheduleJob(jobDetail, trigger);
// 启动
if (!scheduler.isShutdown()) {
scheduler.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void addJobs(QrtzTriggers qrtzTriggers1, QrtzTriggers qrtzTriggers2,Object... objects) {
try {
String jobClassName = qrtzTriggers1.getJobClassName();
ClassLoader loader = ClassLoader.getSystemClassLoader();
Class jobClass = loader.loadClass(jobClassName);
String jobName = qrtzTriggers1.getJobName();
String jobGroupName = qrtzTriggers1.getJobGroup();
// 任务名,任务组,任务执行类
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).storeDurably().requestRecovery().build();
List<QrtzTriggers> qrtzTriggersList = new ArrayList<>();
qrtzTriggersList.add(qrtzTriggers1);
qrtzTriggersList.add(qrtzTriggers2);
List<CronTrigger> cronTriggers = new ArrayList<>();
for (QrtzTriggers qrtzTrigger :
qrtzTriggersList) {
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(qrtzTrigger.getTriggerName(), qrtzTrigger.getTriggerGroup());
triggerBuilder.startNow();
triggerBuilder.withDescription(qrtzTrigger.getDescription());
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(qrtzTrigger.getCron()));
triggerBuilder.forJob(jobDetail);
// 创建Trigger对象
CronTrigger trigger = (CronTrigger) triggerBuilder.build();
cronTriggers.add(trigger);
}
//System.out.println("jobDetail.getKey:"+jobDetail.getKey());
// 触发器
if (objects != null) {
for (int i = 0; i < objects.length; i++) {
// 该数据可以通过Job中的JobDataMap dataMap =
// context.getJobDetail().getJobDataMap();来进行参数传递值
jobDetail.getJobDataMap().put("name","admin");
}
}
// 调度容器设置JobDetail和Trigger
scheduler.addJob(jobDetail,true);
scheduler.scheduleJob(cronTriggers.get(0));
scheduler.scheduleJob(cronTriggers.get(1));
// 启动
if (!scheduler.isShutdown()) {
scheduler.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 功能:修改一个任务的触发时间
*
* @param triggerName
* 触发器名
* @param triggerGroupName
* 触发器组名
* @param cron
* 时间设置,参考quartz说明文档
*/
public void modifyJobTime(String triggerName, String triggerGroupName,
String cron,String description) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(cron)) {
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
triggerBuilder.withDescription(description);
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
trigger = (CronTrigger) triggerBuilder.build();
// 方式一 :修改一个任务的触发时间
scheduler.rescheduleJob(triggerKey, trigger);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 功能: 移除一个任务
*
* @param jobName
* @param jobGroupName
* @param triggerName
* @param triggerGroupName
*/
public void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
// 停止触发器
scheduler.pauseTrigger(triggerKey);
// 移除触发器
scheduler.unscheduleJob(triggerKey);
// 删除任务
scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));
System.out.println("removeJob:"+JobKey.jobKey(jobName));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void pauseJob(String triggerName, String triggerGroupName){
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
scheduler.pauseTrigger(triggerKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
public void startJob(String triggerName, String triggerGroupName){
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
scheduler.resumeTrigger(triggerKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
*
* 功能:启动所有定时任务
*/
public void startJobs() {
try {
scheduler.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 功能:关闭所有定时任务
*/
public void shutdownJobs() {
try {
if (!scheduler.isShutdown()) {
scheduler.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
业务类 写上你需要的业务逻辑
然后去页面配置定时任务即可
后端 定时任务开启,暂停,添加的api接口代码
@RestController
@RequestMapping("/quartz")
public class QuartzTriggersController {
@Autowired
private QrtzTriggersService qrtzTriggersService;
@Autowired
private QrtzCronTriggersService qrtzCronTriggersService;
@Autowired
private QuartzManager quartzManager;
@Autowired
private QrtzJobDetailsService qrtzJobDetailsService;
@GetMapping("/triggers")
public RS getAllTriggers(PagePostVo pagePostVo){
PageHelper.startPage(pagePostVo.getPageNumber(),pagePostVo.getPageSize());
List<QrtzTriggers> triggersList = qrtzTriggersService.getAllTriggers();
List<QrtzCronTriggers> qrtzCronTriggersList = qrtzCronTriggersService.getAllCronTriggers();
List<QrtzJobDetails> qrtzJobDetailsList = qrtzJobDetailsService.getAllJobDetails();
for (QrtzTriggers qrtzTriggers:
triggersList) {
for (QrtzCronTriggers qrtzCronTriggers:
qrtzCronTriggersList) {
if(qrtzCronTriggers.getTriggerGroup().equals(qrtzTriggers.getTriggerGroup())&& qrtzCronTriggers.getTriggerName().equals(qrtzTriggers.getTriggerName())){
qrtzTriggers.setCron(qrtzCronTriggers.getCronExpression());
}
}
for (QrtzJobDetails qrtzJobDetails:
qrtzJobDetailsList) {
if(qrtzJobDetails.getJobGroup().equals(qrtzTriggers.getJobGroup())&& qrtzJobDetails.getJobName().equals(qrtzTriggers.getJobName())){
qrtzTriggers.setJobClassName(qrtzJobDetails.getJobClassName());
}
}
}
PageInfo pageInfo = new PageInfo(triggersList);
long total = pageInfo.getTotal();
return new RS().ok().addResult("data",triggersList).addResult("total",total).addResult("pageNumber",pageInfo.getPageNum())
.addResult("pageSize",pageInfo.getPageSize());
}
@ApiOperation("暂停定时任务")
@PostMapping("/pauseTriggers")
public RS pauseJob(@RequestBody QrtzTriggers qrtzTriggers){
String triggerGroup = qrtzTriggers.getTriggerGroup();
String triggerName = qrtzTriggers.getTriggerName();
String triggerState = qrtzTriggers.getTriggerState();
if(triggerState.equals("PAUSED")){
throw new MyException(1,"请勿重复暂停定时任务");
}
quartzManager.pauseJob(triggerName,triggerGroup);
return new RS().ok();
}
@ApiOperation("开启定时任务")
@PostMapping("/startTriggers")
public RS startJob(@RequestBody QrtzTriggers qrtzTriggers){
String triggerGroup = qrtzTriggers.getTriggerGroup();
String triggerName = qrtzTriggers.getTriggerName();
String triggerState = qrtzTriggers.getTriggerState();
if(triggerState.equals("WAITING")||triggerState.equals("ACQUIRED")){
throw new MyException(1,"请勿重复开启定时任务");
}
quartzManager.startJob(triggerName,triggerGroup);
return new RS().ok();
}
@ApiOperation("移除定时任务")
@DeleteMapping("/triggers/{triggersNames}")
public RS removeJob(@PathVariable String triggersNames){
String[] split = triggersNames.split(",");
for (String triggersName :
split) {
QrtzTriggers qrtzTriggers = qrtzTriggersService.getTriggersByName(triggersName);
String triggerGroup = qrtzTriggers.getTriggerGroup();
String triggerName = qrtzTriggers.getTriggerName();
String jobGroup = qrtzTriggers.getJobGroup();
String jobName = qrtzTriggers.getJobName();
quartzManager.removeJob(jobName,jobGroup,triggerName,triggerGroup);
}
return new RS().ok();
}
@GetMapping("/jobClassName")
public RS getAllJobClassName(){
List<String> jobClassNameList = new ArrayList<>();
try {
PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
CachingMetadataReaderFactory cachingMetadataReaderFactory = new CachingMetadataReaderFactory();
Resource[] resources = new Resource[0];
resources = pathMatchingResourcePatternResolver.getResources("classpath*:com/gbcom/wvp/job/*.class");
for (Resource resource : resources) {
MetadataReader reader = cachingMetadataReaderFactory.getMetadataReader(resource);
String className = reader.getClassMetadata().getClassName();
jobClassNameList.add(className);
}
} catch (IOException e) {
e.printStackTrace();
}
return new RS().ok().addResult("data",jobClassNameList);
}
@ApiOperation("添加定时任务")
@PostMapping("/triggers")
public RS addJob(@RequestBody QrtzTriggers qrtzTriggers) throws ClassNotFoundException {
String cron = qrtzTriggers.getCron();
String description = qrtzTriggers.getDescription();
String jobClassName = qrtzTriggers.getJobClassName();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class jobClass = loader.loadClass(jobClassName);
String jobName = qrtzTriggers.getJobName();
String jobGroup = qrtzTriggers.getJobGroup();
String triggerName = qrtzTriggers.getTriggerName();
String triggerGroup = qrtzTriggers.getTriggerGroup();
//进行一下判断
List<QrtzTriggers> qrtzTriggersList = qrtzTriggersService.getTriggersByNames(triggerName,jobName);
if(qrtzTriggersList!=null && qrtzTriggersList.size()!=0){
throw new MyException(1,"任务名,触发器名不能相同");
}
quartzManager.addJob(jobName,jobGroup,triggerName,triggerGroup,jobClass,cron,description,null);
return new RS().ok();
}
@ApiOperation("修改定时任务")
@PatchMapping("/triggers/{triggersName}")
public RS updateJob(@RequestBody QrtzTriggers qrtzTriggers,@PathVariable String triggersName){
QrtzTriggers triggers = qrtzTriggersService.getTriggersByName(triggersName);
List<QrtzCronTriggers> qrtzCronTriggersList = qrtzCronTriggersService.getAllCronTriggers();
for (QrtzCronTriggers qrtzCronTriggers:
qrtzCronTriggersList) {
if(qrtzCronTriggers.getTriggerGroup().equals(triggers.getTriggerGroup())&& qrtzCronTriggers.getTriggerName().equals(triggers.getTriggerName())){
triggers.setCron(qrtzCronTriggers.getCronExpression());
}
}
String cron = qrtzTriggers.getCron();
String triggerName = qrtzTriggers.getTriggerName();
String triggerGroup = qrtzTriggers.getTriggerGroup();
String description = qrtzTriggers.getDescription();
if(!triggers.getTriggerGroup().equals(triggerGroup)||!triggers.getTriggerName().equals(triggerName)){
//新增一个job
quartzManager.removeJob(triggers.getJobName(),triggers.getJobGroup(),triggers.getTriggerName(),triggers.getTriggerGroup());
quartzManager.addJobs(qrtzTriggers,triggers,null);
}else {
quartzManager.modifyJobTime(triggerName, triggerGroup, cron, description);
}
return new RS().ok();
}
前端页面 写好页面调对应的api接口即可
重启项目时启动定时任务
@Component
public class QueTaskRunner implements ApplicationRunner {
@Autowired
private QrtzTriggersService qrtzTriggersService;
@Autowired
private QuartzManager quartzManager;
@Override
public void run(ApplicationArguments args) throws Exception {
List<QrtzTriggers> triggersList = qrtzTriggersService.getAllTriggers();
for (QrtzTriggers qrtzTriggers:
triggersList) {
String triggerState = qrtzTriggers.getTriggerState();
if(!triggerState.equals("WAITING")||!triggerState.equals("ACQUIRED")){
//项目重启查询出数据库没启动的定时任务
String triggerGroup = qrtzTriggers.getTriggerGroup();
String triggerName = qrtzTriggers.getTriggerName();
quartzManager.startJob(triggerName,triggerGroup);
}
}
}
}
至此,job 已经被我们成功持久化到数据库