Springboot 整合 quartz
·
1.下载quartz的sql文件
直接download,后解压找到 table_mysql.sql 数据库使用的是mysql数据库

2.将sql文件导入到需要链接的数据库,得到以下文件

3. 引入quartz的maven依赖
lombok我在代码中有用到,一起加上了
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<!-- quartz -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
4.配置 application.properties
spring.datasource.url= jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
# Quartz
spring.quartz.job-store-type=jdbc
spring.quartz.jdbc.initialize-schema=never
spring.quartz.properties.scheduler.instanceName=clusteredScheduler
spring.quartz.properties.scheduler.instanceId=AUTO
spring.quartz.properties.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
spring.quartz.properties.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
spring.quartz.properties.jobStore.tablePrefix=qrtz_
spring.quartz.properties.jobStore.isClustered=true
spring.quartz.properties.jobStore.clusterCheckinInterval=10000
spring.quartz.properties.jobStore.useProperties=false
spring.quartz.properties.threadPool.class=org.quartz.simpl.SimpleThreadPool
spring.quartz.properties.threadPool.threadCount=10
spring.quartz.properties.threadPool.threadPriority=5
spring.quartz.properties.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
5.controller层
@RestController
@RequestMapping("/quartz")
public class QuartzController {
private final IJobService jobService;
@Autowired
public QuartzController(IJobService jobService) {
this.jobService = jobService;
}
@GetMapping("/all")
public JsonResult queryAllJobs() {
List<ScheduleJobDTO> list = jobService.listAllJob();
return JsonResult.ok(list);
}
@GetMapping("/running")
public JsonResult queryRunningJobs() {
List<ScheduleJobDTO> list = jobService.listRunningJob();
return JsonResult.ok(list);
}
@PostMapping("")
public JsonResult addJob(@RequestBody ScheduleJobParam param) {
boolean flag = jobService.addJob(param);
return flag ? JsonResult.ok() : JsonResult.error("添加失败");
}
@PutMapping("/pause")
public JsonResult<String> pauseJob(@RequestBody ScheduleJobParam param) {
boolean flag = jobService.pauseJob(param.getJobName(), param.getJobGroup());
return flag ? JsonResult.ok() : JsonResult.error("停止失败");
}
@PutMapping("/resume")
public JsonResult<String> resumeJob(@RequestBody ScheduleJobParam param) {
boolean flag = jobService.resumeJob(param.getJobName(), param.getJobGroup());
return flag ? JsonResult.ok() : JsonResult.error("停止失败");
}
@DeleteMapping("")
public JsonResult<String> deleteJob(@RequestBody ScheduleJobParam param) {
boolean flag = jobService.deleteJob(param.getJobName(), param.getJobGroup());
return flag ? JsonResult.ok() : JsonResult.error("删除失败");
}
}
6.service接口
public interface IJobService {
/**
* 查询所有任务列表
* @return
*/
List<ScheduleJobDTO> listAllJob();
/**
* 获取正在运行的任务列表
* @return
*/
List<ScheduleJobDTO> listRunningJob();
/**
* 新增任务
* @param job job
* @return
*/
boolean addJob(ScheduleJobParam job);
/**
* 执行 job
* @param jobName jobName
* @param jobGroupName jobGroupName
* @return
*/
boolean triggerJob(String jobName, String jobGroupName);
/**
* 启动所有定时任务
* @return
*/
boolean startJobs();
/**
* 删除任务
* @param jobName jobName
* @param jobGroupName jobGroupName
* @return
*/
boolean deleteJob(String jobName, String jobGroupName);
/**
* 暂停任务
* @param jobName jobName
* @param jobGroupName jobGroupName
* @return
*/
boolean pauseJob(String jobName, String jobGroupName);
/**
* 恢复任务
* @param jobName jobName
* @param jobGroupName jobGroupName
* @return
*/
boolean resumeJob(String jobName, String jobGroupName);
}
7.service实现
@Service("jobService")
@Slf4j
public class JobServiceImpl implements IJobService {
public static final String TRIGGER_IDENTITY_PREFIX = "trigger_";
/**
* 调度器
*/
private final Scheduler scheduler;
@Autowired
public JobServiceImpl(Scheduler scheduler) {
this.scheduler = scheduler;
}
@Override
public List<ScheduleJobDTO> listAllJob(){
List<ScheduleJobDTO> result = new ArrayList<>();
try {
GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
for (JobKey jobKey : jobKeys) {
List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
for (Trigger trigger : triggers) {
ScheduleJobDTO scheduleJob = new ScheduleJobDTO();
scheduleJob.setJobName(jobKey.getName())
.setJobGroup(jobKey.getGroup())
.setJobDescription(trigger.getDescription())
.setTriggerStatus(scheduler.getTriggerState(trigger.getKey()).ordinal())
.setTriggerStatusName(scheduler.getTriggerState(trigger.getKey()).name());
result.add(scheduleJob);
}
}
} catch (SchedulerException e) {
log.error("获取所有任务列表失败,错误:{}", e.getMessage());
}
return result;
}
@Override
public List<ScheduleJobDTO> listRunningJob() {
List<ScheduleJobDTO> result = new ArrayList<>();
try {
// 获取列表
List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
result = getJobListData(executingJobs);
} catch (SchedulerException e) {
log.error("获取运行任务列表失败,错误:{}", e.getMessage());
}
return result;
}
@Override
public boolean addJob(ScheduleJobParam jobParam) {
try {
// 加载执行类
Class<? extends Job> clazz = (Class<? extends Job>) Class.forName(jobParam.getJobClass());
clazz.newInstance();
// 1. 创建 job
JobDetail job = JobBuilder.newJob(clazz)
.withIdentity(jobParam.getJobName(), jobParam.getJobGroup())
.withDescription(jobParam.getJobDescription())
.build();
JobDataMap jobDataMap = job.getJobDataMap();
List<Map<String, Object>> data = jobParam.getJobMapData();
if (data != null && data.size() > 0) {
data.forEach(jobDataItem -> {
jobDataItem.keySet().forEach((key) -> {
jobDataMap.put(key, jobDataItem.get(key));
});
});
}
// 配置cron运行规则,即执行时间
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(jobParam.getCronExpression());
// 2. 创建 Trigger
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(TRIGGER_IDENTITY_PREFIX + jobParam.getJobName(), jobParam.getJobGroup())
.startNow()
.withSchedule(cronScheduleBuilder)
.build();
// 3. 注册任务和定时器
scheduler.scheduleJob(job, trigger);
scheduler.start();
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException | SchedulerException e) {
log.error("添加任务 {} 失败,错误: {}", jobParam.getJobName(), e.getMessage());
return false;
}
return true;
}
@Override
public boolean triggerJob(String jobName, String jobGroupName) {
JobKey key = new JobKey(jobName, jobGroupName);
try {
scheduler.triggerJob(key);
} catch (SchedulerException e) {
log.error("任务 {} 触发失败", jobName);
return false;
}
return true;
}
@Override
public boolean startJobs() {
try {
scheduler.start();
} catch (SchedulerException e) {
log.error("启动所有任务失败:", e);
return false;
}
return true;
}
@Override
public boolean deleteJob(String jobName, String jobGroupName) {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
try {
// 停止触发器
scheduler.pauseTrigger(triggerKey);
// 删除触发器
scheduler.unscheduleJob(triggerKey);
// 删除任务
scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));
} catch (SchedulerException e) {
log.error("删除任务 {} 失败,错误:{}", jobName, e.getMessage());
return false;
}
return true;
}
@Override
public boolean pauseJob(String jobName, String jobGroupName) {
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
try {
scheduler.pauseJob(jobKey);
} catch (SchedulerException e) {
log.error("停止任务 {} 失败,错误:{}", jobName, e.getMessage());
return false;
}
return true;
}
@Override
public boolean resumeJob(String jobName, String jobGroupName) {
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
try {
scheduler.resumeJob(jobKey);
} catch (SchedulerException e) {
log.error("恢复任务 {} 失败,错误:{}", jobName, e.getMessage());
return false;
}
return true;
}
private List<ScheduleJobDTO> getJobListData(List<JobExecutionContext> executingJobs) {
List<ScheduleJobDTO> result = new ArrayList<>();
try {
for (JobExecutionContext jobItem : executingJobs) {
ScheduleJobDTO scheduleJobItem = getJobDataByJobExecutionContext(jobItem);
result.add(scheduleJobItem);
}
} catch (SchedulerException e) {
log.error("获取任务状态失败,错误:{}", e.getMessage());
}
return result;
}
/**
* 从 JobExecutionContext 中解析获取数据
* @param jobContext JobExecutionContext
* @return
* @throws SchedulerException
*/
private ScheduleJobDTO getJobDataByJobExecutionContext(JobExecutionContext jobContext) throws SchedulerException {
JobDetail jobDetail = jobContext.getJobDetail();
JobKey jobKey = jobDetail.getKey();
Trigger trigger = jobContext.getTrigger();
// 封装 ScheduleJobDTO 返回,想要获取更多的数据(如 JobDataMap)可自行添加
ScheduleJobDTO scheduleJob = new ScheduleJobDTO();
scheduleJob.setJobName(jobKey.getName())
.setJobGroup(jobKey.getGroup())
.setJobDescription(trigger.getDescription())
.setTriggerStatus(scheduler.getTriggerState(trigger.getKey()).ordinal())
.setTriggerStatusName(scheduler.getTriggerState(trigger.getKey()).name());
return scheduleJob;
}
}
8.实体类,与数据库和前端页面交互使用
@Data
@Accessors(chain = true)
public class ScheduleJobDTO {
private String jobName;
private String jobGroup;
private String jobDescription;
private Integer triggerStatus;
private String triggerStatusName;
}
@Data
@Accessors(chain = true)
public class ScheduleJobParam {
private String jobName;
private String jobGroup;
private String jobClass;
private String cronExpression;
private String jobDescription;
/**
* 额外的数据
*/
private List<Map<String, Object>> jobMapData;
}
/**
* 返回结果对象工具类
*/
public class JsonResult<T> extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
private JsonResult() {
}
/**
* 返回成功
*/
public static JsonResult ok() {
return ok("操作成功");
}
/**
* 返回成功
*/
public static JsonResult ok(Object message) {
return ok(200, message);
}
/**
* 返回成功
*/
public static JsonResult ok(int code, Object message) {
JsonResult jsonResult = new JsonResult();
jsonResult.put("code", code);
jsonResult.put("msg", message);
return jsonResult;
}
public static JsonResult<String> error(String message) {
JsonResult jsonResult = new JsonResult();
jsonResult.put("code", 500);
jsonResult.put("msg", message);
return jsonResult;
}
}
9.两个测试任务类
public class EatJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) {
System.out.println(DateUtil.now() + " 这是 吃吃吃 的逻辑执行部分。。。。。。");
}
}
public class RunJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) {
System.out.println(DateUtil.now() + " 这是跑跑跑的逻辑执行部分。。。。。。");
}
}
10.测试
添加 http://127.0.0.1:8900/quartz

查询 http://127.0.0.1:8900/quartz/all

停止 http://127.0.0.1:8900/quartz/pause

恢复/启动 http://127.0.0.1:8900/quartz/resume

请求报文:
注意 jobclass 配置为EatJob的全路径
{
"jobName": "eat",
"jobGroup": "dosomething",
"jobDescription": "吃吃吃",
"jobClass": "com.seage.demo.quartz.job.EatJob",
"cronExpression": "0/10 * * * * ? *"
}
后台可以看到打印台打印的日志

在添加、停止、重启时都看一下控制台打印,如果不打印或者重新打印说明成功了。
11.遇到的问题
控制台打印找不到类路径,说明 jobClass没找到任务类
查看数据库表 qrtz_job_details 的JOB_CLASS_NAME配置错误
org.quartz.JobPersistenceException: Couldn't retrieve job because a required class was not found: com.seage.demo.quartz.job1.EatJob

更多推荐


所有评论(0)