quartz介绍
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标准的Java组件或 EJBs。Quartz的最新版本为Quartz 2.3.2。
中文官方文档:https://www.w3cschool.cn/quartz_doc/
Quartz 核心概念
1.Job 表示一个工作,要执行的具体内容。
2.JobDetail 表示一个具体的可执行的调度程序,Job 是这个可执行程调度程序所要执行的内容,另外 JobDetail 还包含了这个任务调度的方案和策略。
3.Trigger 代表一个调度参数的配置,什么时候去调。
4.Scheduler 代表一个调度容器,一个调度容器中可以注册多个 JobDetail 和 Trigger。当 Trigger 与 JobDetail 组合,就可以被 Scheduler 容器调度了。
使用
依赖
springboot整合quartz依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
pom文件
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
配置文件
quartz必须配置,如果在application.yml文件配置了quartz属性,则不需要quartz.properties文件。
application.yml文件
server:
port: 8802
spring:
application:
name: quartz-curd
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/quartz_curd?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: root
quartz:
#quartz定时任务,采用数据库方式
job-store-type: jdbc
initialize-schema: never
#定时任务启动开关,true-开 false-关
auto-startup: true
#延迟1秒启动定时任务
startup-delay: 1s
#启动时更新己存在的Job
overwrite-existing-jobs: true
properties:
org:
quartz:
scheduler:
instanceName: MyScheduler
#ID设置为自动获取 每一个必须不同 (所有调度器实例中是唯一的)
instanceId: AUTO
jobStore:
class: org.springframework.scheduling.quartz.LocalDataSourceJobStore
#StdJDBCDelegate说明支持集群
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#quartz内部表的前缀
tablePrefix: QRTZ_
#是否加入集群
isClustered: false
#容许的最大作业延长时间
misfireThreshold: 12000
#分布式节点有效性检查时间间隔,单位:毫秒
clusterCheckinInterval: 15000
#配置是否使用
useProperties: false
threadPool:
#ThreadPool实现的类名
class: org.quartz.simpl.SimpleThreadPool
#线程数量
threadCount: 20
#线程优先级
threadPriority: 5
#配置是否启动自动加载数据库内的定时任务,默认true
threadsInheritContextClassLoaderOfInitializingThread: true
注意:initialize-schema: never,这个属性,第一次生成quartz内置表时设置为always,生成后改为never,不然每次启动系统都会重新生成表。
启动类
@SpringBootApplication
@EnableOpenApi
public class QuartzService {
public static void main(String[] args) {
SpringApplication.run(QuartzService.class,args);
}
}
添加启动类后可以运行项目,生成quartz内置表,
生成11张表
quartz工具类
包含定时任务添加,修改,运行,暂停,恢复,删除和查询。
package com.test.quartz.utils;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.test.quartz.pojo.JobInfo;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.spi.MutableTrigger;
import java.util.*;
import static org.quartz.Trigger.TriggerState.*;
/**
* @author清梦
* @site www.xiaomage.com
* @company xxx公司
* @create 2023-06-08 14:41
*/
@Slf4j
public class QuartzUtil {
private static Map<Trigger.TriggerState, String> TRIGGER_STATE;
public static final String END_JOB_SUFFIX = ":endTask";
static {
TRIGGER_STATE = new HashMap<>();
TRIGGER_STATE.put(NONE, "空");
TRIGGER_STATE.put(NORMAL, "正常");
TRIGGER_STATE.put(PAUSED, "暂停");
TRIGGER_STATE.put(COMPLETE, "完成");
TRIGGER_STATE.put(ERROR, "错误");
TRIGGER_STATE.put(BLOCKED, "阻塞");
}
/**
* 创建定时任务,创建定时任务后默认为启动状态
* @param scheduler 调度器
* @param jobInfo 定时任务信息类
* 原文链接:https://blog.csdn.net/yyyy11119/article/details/121139580
*/
public static void createScheduleJob(Scheduler scheduler, JobInfo jobInfo)throws Exception{
//获取定时任务的执行类,必须是类的绝对路径
//定时任务类需要是job类的具体实现 QuartzJobBean是job的抽象类。
Class<? extends Job> jobClass = (Class<? extends Job>)Class.forName(jobInfo.getJobClassName());
//构建定时任务信息
JobKey jobKey = JobKey.jobKey(jobInfo.getJobName(),jobInfo.getJobGroup());
TriggerKey triggerKey = TriggerKey.triggerKey(jobInfo.getJobName(),jobInfo.getJobGroup());
JobDetail jobDetail = JobBuilder.newJob(jobClass)
.withIdentity(jobKey).build();
//设置定时任务的执行方式
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(jobInfo.getCronExpression());
//构建触发器trigger
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(triggerKey)
.withDescription(jobInfo.getDescription())
.usingJobData("jobClassName",jobInfo.getJobClassName())
.withSchedule(scheduleBuilder)
.startAt(jobInfo.getStartTime())
//如果设置了结束时间,到期任务自动删除,我们不想任务过期就删除,所以zhudiao
//.endAt(jobInfo.getEndTime())
.build();
// 修改 misfire 策略,如果开始时间在添加任务之前,不修改策略会导致新增时任务会立即运行一次
chgMisFire(trigger);
//如果参数不为空,写入参数
ObjectMapper mapper = new ObjectMapper();
if (!StringUtils.isBlank(jobInfo.getParameter())) {
Map param = mapper.readValue(jobInfo.getParameter(), Map.class);
jobDetail.getJobDataMap().putAll(param);
}
scheduler.scheduleJob(jobDetail,trigger);
//如果设置了结束时间,添加一个终止任务
if (null != jobInfo.getEndTime()){
addEndJob(scheduler,jobInfo);
}
}
/**
* 添加停止任务
* @param scheduler 调度器
* @param jobInfo 定时任务信息类
*/
public static void addEndJob(Scheduler scheduler,JobInfo jobInfo)throws SchedulerException,JsonProcessingException,ClassNotFoundException{
String jobName = jobInfo.getJobName();
String group = jobName + END_JOB_SUFFIX;
JobKey jobKey = JobKey.jobKey(jobName,group);
String endJobName = "jobName-" + System.currentTimeMillis();
TriggerKey triggerKey = TriggerKey.triggerKey(endJobName,group);
if (scheduler.checkExists(triggerKey) && scheduler.checkExists(jobKey)) {
log.info("{}----开始添加终止任务",jobName);
SimpleTrigger trigger = (SimpleTrigger) scheduler.getTrigger(triggerKey);
trigger = trigger.getTriggerBuilder().withDescription(jobInfo.getDescription() + "-[结束任务]")
.withIdentity(triggerKey)
.startAt(jobInfo.getEndTime()).build();
// 修改 misfire 策略
chgMisFire(trigger);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
ObjectMapper mapper = new ObjectMapper();
if (!StringUtils.isBlank(jobInfo.getParameter())) {
Map param = mapper.readValue(jobInfo.getParameter(), Map.class);
jobDetail.getJobDataMap().putAll(param);
}
scheduler.deleteJob(jobKey);
scheduler.scheduleJob(jobDetail, trigger);
return;
}
Class<? extends Job> jobClass = (Class<? extends Job>)Class.forName(jobInfo.getJobClassName());
//构建定时任务信息
JobDetail jobDetail = JobBuilder.newJob(jobClass)
.withIdentity(jobKey).build();
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
.withDescription(jobKey.getGroup() + "-[结束任务]")
.startAt(jobInfo.getEndTime())
.build();
// 修改 misfire 策略
chgMisFire(trigger);
ObjectMapper mapper = new ObjectMapper();
if (!StringUtils.isBlank(jobInfo.getParameter())) {
log.info("parameter:{}",jobInfo.getParameter());
Map param = mapper.readValue(jobInfo.getParameter(), Map.class);
jobDetail.getJobDataMap().putAll(param);
}
scheduler.scheduleJob(jobDetail, trigger);
}
/**
* 根据任务明细暂停定时任务
* @param scheduler 调度器
* @param jobName 定时任务名称
*/
public static void pauseScheduleJob(Scheduler scheduler,String jobName,String jobGroup)throws SchedulerException{
JobKey jobKey = JobKey.jobKey(jobName,jobGroup);
scheduler.pauseJob(jobKey);
}
/**
* 根据任务名称恢复定时任务
* @param scheduler 调度器
* @param jobName 任务名称
*/
public static void resumeScheduleJob(Scheduler scheduler,String jobName,String jobGroup)throws SchedulerException{
JobKey jobKey = JobKey.jobKey(jobName,jobGroup);
scheduler.resumeJob(jobKey);
}
/**
* 根据任务名称运行一次定时任务
* @param scheduler 调度器
* @param jobName 任务名称
*/
public static void runOnce(Scheduler scheduler,String jobName,String jobGroup)throws SchedulerException{
JobKey jobKey = JobKey.jobKey(jobName,jobGroup);
scheduler.triggerJob(jobKey);
}
/**
* 更新定时任务
* @param scheduler 调度器
* @param jobInfo 定时任务类
*/
public static void updateScheduleJob(Scheduler scheduler,JobInfo jobInfo)throws SchedulerException,JsonProcessingException,ClassNotFoundException{
//获取对应任务的触发器
TriggerKey triggerKey = TriggerKey.triggerKey(jobInfo.getJobName(),jobInfo.getJobGroup());
//设置定时任务执行方式
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(jobInfo.getCronExpression());
//重新构建定时任务的触发器
CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
cronTrigger = cronTrigger.getTriggerBuilder()
.withIdentity(triggerKey)
.withSchedule(scheduleBuilder)
.withDescription(jobInfo.getDescription())
.usingJobData("jobClassName",jobInfo.getJobClassName())
.startAt(jobInfo.getStartTime())
.endAt(jobInfo.getEndTime()).build();
// 修改 misfire 策略,测试时注掉,方便观察
//chgMisFire(trigger);
//重置对应的定时任务
//如果参数不为空,写入参数
JobKey jobKey = JobKey.jobKey(jobInfo.getJobName(),jobInfo.getJobGroup());
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
ObjectMapper mapper = new ObjectMapper();
if (!StringUtils.isBlank(jobInfo.getParameter())) {
Map param = mapper.readValue(jobInfo.getParameter(), Map.class);
jobDetail.getJobDataMap().clear();
jobDetail.getJobDataMap().putAll(param);
}
scheduler.rescheduleJob(triggerKey,cronTrigger);
//如果设置了结束时间,添加一个终止任务
if (null != jobInfo.getEndTime()){
addEndJob(scheduler,jobInfo);
}
}
/**
* 删除定时任务
* @param scheduler 调度器
* @param jobName 任务名称
*/
public static void deleteScheduleJob(Scheduler scheduler,String jobName,String jobGroup)throws SchedulerException{
JobKey jobKey = JobKey.jobKey(jobName,jobGroup);
scheduler.deleteJob(jobKey);
}
/**
* 查询所有定时任务
* @param scheduler 调度器
*/
public static List<JobInfo> findAll(Scheduler scheduler,String jobGroup)throws SchedulerException{
GroupMatcher<JobKey> matcher;
if (StringUtils.isBlank(jobGroup)){
matcher = GroupMatcher.anyGroup();
}else {
matcher = GroupMatcher.groupEquals(jobGroup);
}
List<JobInfo> list = new ArrayList<>();
Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
for (JobKey jobKey:jobKeys){
JobInfo jobInfo = new JobInfo();
jobInfo.setJobName(jobKey.getName());
jobInfo.setJobGroup(jobKey.getGroup());
TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(),jobKey.getGroup());
CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
//终止任务没有设置业务实现类
if (!jobKey.getGroup().contains(END_JOB_SUFFIX)){
jobInfo.setJobClassName(cronTrigger.getJobDataMap().getString("jobClassName"));
System.out.println("className:" + scheduler.getJobDetail(jobKey).getJobDataMap().getString("jobClassName"));
jobInfo.setDescription(cronTrigger.getDescription());
jobInfo.setCronExpression(cronTrigger.getCronExpression());
jobInfo.setStartTime(cronTrigger.getStartTime());
}
jobInfo.setJobStatus(getJobStatus(scheduler,triggerKey));
JobDataMap map = scheduler.getJobDetail(jobKey).getJobDataMap();
jobInfo.setParameter(JSONObject.toJSONString(map));
//直接在cronTrigger设置结束时间,到期后会自动删除,我们用结束时间设置了一个定时任务,到期停止
//jobInfo.setEndTime(cronTrigger.getEndTime());
TriggerKey endJobTriggerKey = TriggerKey.triggerKey(jobKey.getName(),jobKey.getName() + END_JOB_SUFFIX);
SimpleTrigger endJobTrigger = (SimpleTrigger) scheduler.getTrigger(endJobTriggerKey);
if (null != endJobTrigger){
jobInfo.setEndTime(endJobTrigger.getStartTime());
}
list.add(jobInfo);
}
return list;
}
/**
* 获取定时任务状态
* @param scheduler 调度器
* @param triggerKey 触发器
* @return
* @throws SchedulerException
*/
public static String getJobStatus(Scheduler scheduler,TriggerKey triggerKey) throws SchedulerException{
Trigger.TriggerState triggerState = scheduler.getTriggerState(triggerKey);
return TRIGGER_STATE.get(triggerState);
}
/**
* 错过触发策略:即错过了定时任务的开始时间可以做什么,此处设置什么也不做,即过了开始时间也不执行
* 如果不设置,默认为立即触发一次,例如设置定时任务开始时间为10点,没有设置结束时间,在10点后重启系统,
* 如果不设置为CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING,那么开始时间在重启前的定时任务会全部重新触发一次
* @param trigger
*/
private static void chgMisFire(Trigger trigger) {
// 修改 misfire 策略
if (trigger instanceof MutableTrigger) {
MutableTrigger mutableTrigger = (MutableTrigger) trigger;
mutableTrigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);
}
}
}
注意:在添加和修改定时任务时,结束时间的设置一定要注意,直接设置结束时间,到期后任务会自动删除
job业务
具体让job执行什么操作,都可以在这里实现,个人只是打印了任务名称和参数
package com.test.quartz.job;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.test.quartz.mapper.TriggersMapper;
import com.test.quartz.pojo.Triggers;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import static com.test.quartz.utils.QuartzUtil.END_JOB_SUFFIX;
/**
* @author清梦
* @site www.xiaomage.com
* @company xxx公司
* @create 2023-06-08 16:07
*/
@Slf4j
public class MyJob extends QuartzJobBean {
@Autowired
private TriggersMapper triggersMapper;
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
JobDetail jobDetail = jobExecutionContext.getJobDetail();
String now = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
//获取参数信息
JobDataMap jobDataMap = jobDetail.getJobDataMap();
String name = jobDetail.getKey().getName();
String jobGroup = jobDetail.getKey().getGroup();
Iterator<Map.Entry<String, Object>> iterator = jobDataMap.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<String, Object> entry = iterator.next();
log.info("定时任务-{}:{}-启动,参数为:key:{} ,value:{}",name,jobGroup,entry.getKey(),entry.getValue());
}
Trigger cronTrigger = jobExecutionContext.getTrigger();
String group = cronTrigger.getKey().getGroup();
//有终止任务标记的修改状态为pause
if (group.contains(END_JOB_SUFFIX)){
String jobName = group.split(END_JOB_SUFFIX)[0];
log.info("jobName:{}",jobName);
QueryWrapper<Triggers> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("job_name",jobName);
List<Triggers> triggers = triggersMapper.selectList(queryWrapper);
for (Triggers trigger:triggers){
triggersMapper.updateTriggerState("PAUSED",trigger.getJobName(),trigger.getJobGroup());
}
return;
}
}
}
用到的对象类
package com.test.quartz.pojo;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
/**
* @author清梦
* @site www.xiaomage.com
* @company xxx公司
* @create 2023-06-08 14:29
*/
@Data
@TableName("tb_job_info")
public class JobInfo{
//任务类名
private String jobClassName;
//cron表达式
private String cronExpression;
//参数
private String parameter;
//任务名称
private String jobName;
//任务分组
private String jobGroup;
//描述
private String description;
//任务状态
private String jobStatus;
//任务开始时间
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date startTime;
//任务结束时间
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date endTime;
}
job_info表根据自己需求建立,本项目中只用于对象传输。建表sql如下。
注意:我建表使用utf8mb4编码,数据库也得是utf8mb4才行,如果数据库是utf8,建表编码也改成utf8。
CREATE TABLE `tb_job_info` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`create_by` varchar(32) DEFAULT NULL COMMENT '创建人',
`create_at` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(32) DEFAULT NULL COMMENT '修改人',
`update_at` datetime DEFAULT NULL COMMENT '修改时间',
`del_flag` int(11) DEFAULT '0' COMMENT '删除状态:0-未删除,1-已删除',
`job_class_name` varchar(255) DEFAULT NULL COMMENT '任务类名',
`cron_expression` varchar(255) DEFAULT NULL COMMENT 'cron表达式',
`parameter` varchar(255) DEFAULT NULL COMMENT '参数',
`job_name` varchar(20) DEFAULT NULL COMMENT '任务类名',
`job_group` varchar(20) DEFAULT NULL COMMENT '任务分组',
`description` varchar(255) DEFAULT NULL COMMENT '描述',
`job_status` int(11) DEFAULT NULL COMMENT '任务状态',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='任务信息表'
vo对象
@Data
public class OperateVo {
private String jobName;
private String jobGroup;
private Integer operateType;
}
用到的枚举
package com.test.quartz.enums;
/**
* @author清梦
* @site www.xiaomage.com
* @company xxx公司
* @create 2023-06-09 15:16
*/
public enum OperateEnum {
ADD(1,"添加"),
UPDATE(2,"修改"),
RUN_ONCE(3,"运行一次"),
PAUSE(4,"暂停"),
RESUME(5,"恢复"),
DELETE(6,"删除");
private Integer code;
private String msg;
OperateEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
接口
编写接口测试
package com.test.quartz.controller;
import com.test.quartz.pojo.JobInfo;
import com.test.quartz.service.JobService;
import com.test.quartz.vo.OperateVo;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
/**
* @author清梦
* @site www.xiaomage.com
* @company xxx公司
* @create 2023-06-08 18:20
*/
@RestController
@RequestMapping("job")
@Api(tags = "定时任务操作")
public class JobController {
@Autowired
private JobService jobService;
@GetMapping("findAll")
public ResponseEntity findAll(String jobGroup){
return jobService.findAll(jobGroup);
}
@PostMapping("save")
public ResponseEntity save(@RequestBody JobInfo jobInfo,Integer operateType){
return jobService.save(jobInfo,operateType);
}
@PostMapping("operate")
public ResponseEntity operate(@RequestBody OperateVo vo){
return jobService.operate(vo);
}
}
service
public interface JobService {
ResponseEntity findAll(String jobGroup);
ResponseEntity save(JobInfo jobInfo,Integer operateType);
ResponseEntity operate(OperateVo vo);
}
实现类
package com.test.quartz.service.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.test.quartz.enums.OperateEnum;
import com.test.quartz.job.MyJob;
import com.test.quartz.pojo.JobInfo;
import com.test.quartz.service.JobService;
import com.test.quartz.utils.QuartzUtil;
import com.test.quartz.vo.OperateVo;
import jdk.nashorn.internal.runtime.logging.Logger;
import lombok.extern.slf4j.Slf4j;
import org.quartz.CronExpression;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* @author清梦
* @site www.xiaomage.com
* @company xxx公司
* @create 2023-06-08 18:24
*/
@Service
@Slf4j
public class JobServiceImpl implements JobService {
@Autowired
private Scheduler scheduler;
@Override
public ResponseEntity findAll(String jobGroup) {
List<JobInfo> list = new ArrayList<>();
try {
list = QuartzUtil.findAll(scheduler,jobGroup);
}catch (SchedulerException e){
log.error("查询定时任务列表失败:{}",e);
return ResponseEntity.ok("查询失败");
}catch (Exception e){
log.error("查询定时任务列表失败:{}",e);
return ResponseEntity.ok("查询失败");
}
return ResponseEntity.ok(list);
}
@Override
public ResponseEntity save(JobInfo jobInfo,Integer operateType){
String msg = "";
try {
//校验cron是否有效
if (!CronExpression.isValidExpression(jobInfo.getCronExpression())){
return ResponseEntity.ok("cron表达式错误");
}
if (OperateEnum.ADD.getCode() == operateType){
msg = OperateEnum.ADD.getMsg();
QuartzUtil.createScheduleJob(scheduler,jobInfo);
}else if (OperateEnum.UPDATE.getCode() == operateType){
msg = OperateEnum.UPDATE.getMsg();
QuartzUtil.updateScheduleJob(scheduler,jobInfo);
}
}catch (Exception e){
log.error("定时任务-{}-失败,jobName:{},错误信息:{}",msg ,jobInfo.getJobName(),e);
return ResponseEntity.ok("定时任务" + msg + "失败");
}
return ResponseEntity.ok("定时任务" + msg + "成功");
}
@Override
public ResponseEntity operate(OperateVo vo) {
String jobName = vo.getJobName();
String jobGroup = vo.getJobGroup();
Integer type = vo.getOperateType();
String msg = "";
try {
if (OperateEnum.RUN_ONCE.getCode() == type){
msg = OperateEnum.RUN_ONCE.getMsg();
QuartzUtil.runOnce(scheduler,jobName,jobGroup);
}else if (OperateEnum.PAUSE.getCode() == type){
msg = OperateEnum.PAUSE.getMsg();
QuartzUtil.pauseScheduleJob(scheduler,jobName,jobGroup);
}else if (OperateEnum.RESUME.getCode() == type){
msg = OperateEnum.RESUME.getMsg();
QuartzUtil.resumeScheduleJob(scheduler,jobName,jobGroup);
}else if (OperateEnum.DELETE.getCode() == type){
msg = OperateEnum.DELETE.getMsg();
QuartzUtil.deleteScheduleJob(scheduler,jobName,jobGroup);
}
}catch (Exception e){
log.error("定时任务:{}-{}失败:{}",msg,e);
return ResponseEntity.ok("定时任务:" + jobName + msg + "-失败");
}
return ResponseEntity.ok("定时任务:" + jobName + msg + "-成功");
}
}
测试
因为没有前端页面,我们引入了swagger,运行项目后在浏览器输入
http://localhost:8802/swagger-ui/,出现页面如下
进入定时任务操作接口,先测试添加和修改
输入参数,点击执行
添加成功后可以在查询接口查看,不输入任务分组时可以看到设置的定时终止任务
参考博客:
https://blog.csdn.net/yyyy11119/article/details/121139580
本博客源码地址:
https://gitee.com/qfp17393120407/springboot_quartz.git