单体应用,任务持久化到数据库,省略了数据库交互的代码
package com.yang.springbootquartz.rest;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* @author: Yang
* @date: 2018/8/9 22:54
* @description: 前台的调度任务持久化到数据库
* 每个任务需要有唯一key,避免重复任务
*/
@Slf4j
@RestController
@RequestMapping("/my")
public class MyQuartzController {
@Resource
private Scheduler scheduler;
/**
* 添加调度任务
*/
@PostMapping("/add")
private void add(@RequestBody Task task) throws Exception {
//1.查询数据库,避免重复复
//2.任务入库
//3.删除任务,防止重复
this.deleteFromQuartz(task.getJobClassName());
//4.将任务托管给quartz
this.addToQuartz(task.getJobClassName(), task.getCronExpression(), task.getParam());
//5.将数据库中对应记录的状态修改为已托管
}
/**
* 将任务托管到Quartz框架
*
* @param className
* @param cronExpression
* @param param
*/
void addToQuartz(String className, String cronExpression, String param) throws Exception {
//0.利用Quartz内置方法,校验cron表达式的合法性,前端可用此正则【/^[a-zA-Z]+(.([a-zA-Z])+)+$/】进行校验
if (!CronExpression.isValidExpression(cronExpression)) {
log.error("cron表达式不合法");
return;
}
// 1.构建job信息
JobDetail jobDetail = JobBuilder
.newJob(getClass(className).getClass())
.withIdentity(className)
.usingJobData("param", param)
.build();
// 2.表达式调度构建器(即任务执行的时间)
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
// 3.按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(className).withSchedule(scheduleBuilder).build();
// 4.装载job和trigger
this.scheduler.scheduleJob(jobDetail, trigger);
// 5.启动调度器
this.scheduler.start();
}
/**
* 删除调度任务
*
* @param task
* @throws SchedulerException
*/
@PostMapping("/delete")
public void delete(@RequestBody Task task) throws SchedulerException {
//1.删除已托管到quartz中的任务
this.deleteFromQuartz(task.getJobClassName());
//2.删除数据库记录
}
/**
* @param className
*/
void deleteFromQuartz(String className) throws SchedulerException {
//1.暂停任务的trigger
this.scheduler.pauseTrigger(TriggerKey.triggerKey(className));
//2.取消任务的调度
this.scheduler.unscheduleJob(TriggerKey.triggerKey(className));
//3.删除任务
this.scheduler.deleteJob(JobKey.jobKey(className));
}
private static Job getClass(String className) throws Exception {
Class<?> class1 = Class.forName(className);
return (Job) class1.newInstance();
}
}
@Data
class Task {
//任务唯一标识,可以根据业务,考虑替换目前以className为标记的实现
private String taskKey;
//任务类名,类名应该以下拉的方式呈现,供前端选择
private String jobClassName;
//cron表达式,需要校验
private String cronExpression;
//任务参数
private String param;
}
/**
* 项目重启时,需要将已经持久化的任务全部重新托管给Quartz,所以需要在项目启动后,对Quartz进行初始化
*/
@Order(100)
@Component
class QuartzTaskInitializer implements CommandLineRunner {
@Resource
private MyQuartzController myQuartzController;
@Override
public void run(String... args) throws Exception {
//1.从数据库查询出所有未删除,且状态为已托管的任务记录列表
List<Task> taskList = new ArrayList<>();
//2.便利重新托管
taskList.forEach(it -> {
try {
this.myQuartzController.deleteFromQuartz(it.getJobClassName());
this.myQuartzController.addToQuartz(it.getJobClassName(), it.getCronExpression(), it.getParam());
} catch (Exception e) {
e.printStackTrace();
}
});
}
}