SpringBoot教程(二十四) | SpringBoot实现分布式定时任务之Quartz(动态新增、修改等操作)
- 前言
- 数据库脚本
- 创建需要被调度的方法
- 创建相关实体类
- 创建业务层接口
- 创建业务层实现类
- 控制层类
- 测试结果
前言
我这边的SpringBoot的版本为2.6.13,其中Quartz是使用的以下方式引入
<!--quartz定时任务-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
数据库脚本
首先确定maven拉取了 spring-boot-starter-quartz 的依赖,再接着到私仓下面找到
"你的私仓地址\org\quartz-scheduler\quartz\2.3.2"把这个下面的quartz-2.3.2.jar 给解压
然后到这个文件的 “quartz-2.3.2\org\quartz\impl\jdbcjobstore” 下面就可以可以看到
我这边选择的是“tables_mysql_innodb.sql”脚本
内容如下,执行以后会出现11张表
#
# In your Quartz properties file, you'll need to set
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#
#
# By: Ron Cordell - roncordell
# I didn't see this anywhere, so I thought I'd post it here. This is the script from Quartz to create the tables in a MySQL database, modified to use INNODB instead of MYISAM.
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;
CREATE TABLE QRTZ_JOB_DETAILS(
SCHED_NAME VARCHAR(120) NOT NULL,
JOB_NAME VARCHAR(190) NOT NULL,
JOB_GROUP VARCHAR(190) NOT NULL,
DESCRIPTION VARCHAR(250) 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 NULL,
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
JOB_NAME VARCHAR(190) NOT NULL,
JOB_GROUP VARCHAR(190) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
NEXT_FIRE_TIME BIGINT(13) NULL,
PREV_FIRE_TIME BIGINT(13) NULL,
PRIORITY INTEGER NULL,
TRIGGER_STATE VARCHAR(16) NOT NULL,
TRIGGER_TYPE VARCHAR(8) NOT NULL,
START_TIME BIGINT(13) NOT NULL,
END_TIME BIGINT(13) NULL,
CALENDAR_NAME VARCHAR(190) NULL,
MISFIRE_INSTR SMALLINT(2) NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) 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),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_CRON_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
CRON_EXPRESSION VARCHAR(120) NOT NULL,
TIME_ZONE_ID VARCHAR(80),
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
STR_PROP_1 VARCHAR(512) NULL,
STR_PROP_2 VARCHAR(512) NULL,
STR_PROP_3 VARCHAR(512) NULL,
INT_PROP_1 INT NULL,
INT_PROP_2 INT NULL,
LONG_PROP_1 BIGINT NULL,
LONG_PROP_2 BIGINT NULL,
DEC_PROP_1 NUMERIC(13,4) NULL,
DEC_PROP_2 NUMERIC(13,4) NULL,
BOOL_PROP_1 VARCHAR(1) NULL,
BOOL_PROP_2 VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_BLOB_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_CALENDARS (
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(190) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
ENGINE=InnoDB;
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_FIRED_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
INSTANCE_NAME VARCHAR(190) NOT NULL,
FIRED_TIME BIGINT(13) NOT NULL,
SCHED_TIME BIGINT(13) NOT NULL,
PRIORITY INTEGER NOT NULL,
STATE VARCHAR(16) NOT NULL,
JOB_NAME VARCHAR(190) NULL,
JOB_GROUP VARCHAR(190) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID))
ENGINE=InnoDB;
CREATE TABLE QRTZ_SCHEDULER_STATE (
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(190) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
ENGINE=InnoDB;
CREATE TABLE QRTZ_LOCKS (
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME))
ENGINE=InnoDB;
CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
commit;
表的说明
表名称 | 说明 |
---|---|
qrtz_blob_triggers | blog类型存储triggers |
qrtz_calendars | 以blog类型存储Calendar信息 |
qrtz_cron_triggers | 存储cron trigger信息 |
qrtz_fired_triggers | 存储已触发的trigger相关信息 |
qrtz_job_details | 存储每一个已配置的job details |
qrtz_locks | 存储悲观锁的信息 |
qrtz_paused_trigger_grps | 存储已暂停的trigger组信息 |
qrtz_scheduler_state | 存储Scheduler状态信息 |
qrtz_simple_triggers | 存储simple trigger信息 |
qrtz_simprop_triggers | 存储其他几种trigger信息 |
qrtz_triggers | 存储已配置的trigger信息 |
创建需要被调度的方法
package com.example.springbootfull.quartztest;
import lombok.extern.slf4j.Slf4j;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* @DisallowConcurrentExecution : 此标记用在实现Job的类上面,意思是不允许并发执行.
* 因为Quartz的是并发操作的,要非常注意线程不安全,最好加上这个注解,以防止导致业务数据错乱
*/
@Slf4j
@DisallowConcurrentExecution
public class BookTask extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
JobDetail jobDetail = context.getJobDetail();
log.info("book定时任务-开始执行,"
+ "任务名:" + jobDetail.getKey().getName()
+ ",组名:" + jobDetail.getKey().getGroup()
+ " "
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()));
// try {
// Thread.sleep(3000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
log.info("book定时任务-执行结束,"
+ "任务名:" + jobDetail.getKey().getName()
+ ",组名:" + jobDetail.getKey().getGroup()
+ " "
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()));
}
}
创建相关实体类
package com.example.springbootfull.quartztest.bean;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
// 使用@Data注解自动为该类生成getter、setter、equals、hashCode和toString方法
@Data
public class QuartzBean {
// 任务名称
private String jobName;
// 任务组的名称
private String jobGroupName;
// 任务的状态(例如:运行中、已停止等)
private String state;
// 执行任务的类名(通常是一个实现了Job接口的类的全限定名)
private String jobClass;
// 间隔单位(例如:秒、分钟、小时等)
private String intervalUnit;
// 间隔单位的可读名称(例如:Seconds、Minutes、Hours等)
private String intervalUnitName;
// 时间间隔的数量(例如:如果intervalUnit是Minutes,这个值可能是5,表示每5分钟执行一次)
private Integer timeInterval;
// Cron表达式,用于更复杂的任务调度(例如:每天凌晨1点执行)
private String cronExpression;
// 任务开始时间,使用@DateTimeFormat和@JsonFormat注解来指定日期格式和时区
// @DateTimeFormat用于Spring MVC绑定表单数据时解析日期
// @JsonFormat用于JSON序列化/反序列化时处理日期
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date startTime;
// 任务结束时间,格式同上
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date endTime;
// 任务的描述信息
private String description;
}
创建业务层接口
package com.example.springbootfull.quartztest.service;
import com.example.springbootfull.quartztest.bean.QuartzBean;
import com.example.springbootfull.quartztest.zdyresult.ResponseResult;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.stereotype.Service;
import java.util.List;
public interface IQuartzService {
/**
* 添加定时任务信息
*
* @param quartzBean 定时任务信息
*/
void save(QuartzBean quartzBean);
/**
* 移除定时任务--根据任务名称移除
*
* @param jobName 任务名
*/
void delete(String jobName);
/**
* 移除定时任务
*
* @param groupName 组名
* @param jobName 任务名
*/
void delete(String jobName, String groupName);
/**
* 修改定时任务
*
* @param quartzBean 任务信息
*/
void update(QuartzBean quartzBean);
/**
* 添加任务
*
* @param jobName 任务名
* @return 任务信息
*/
QuartzBean selectByName(String jobName);
/**
* 查询单个定时任务信息
*
* @param groupName 组名称
* @param jobName 任务名称
* @return 查询结果
*/
QuartzBean selectByName(String jobName, String groupName);
/**
* 查询定时任务列表
*
* @param quartzBean 查询条件
* @return 查询结果
*/
List<QuartzBean> selectList(QuartzBean quartzBean);
/**
* 暂停定时任务
*
* @param jobName 任务名
*/
void pause(String jobName);
/**
* 暂停定时任务
*
* @param jobName 任务名
* @param groupName 组名
*/
void pause(String jobName, String groupName);
/**
* 恢复定时任务
*
* @param jobName 任务名
*/
void resume(String jobName);
/**
* 恢复定时任务
*
* @param jobName 任务名
* @param groupName 组名
*/
void resume(String jobName, String groupName);
/**
* 执行定时任务
*
* @param jobName 任务名
*/
void executeJob(String jobName);
/**
* 执行定时任务
*
* @param jobName 任务名
* @param groupName 组名
*/
void executeJob(String jobName, String groupName);
}
创建业务层实现类
package com.example.springbootfull.quartztest.serviceImpl;
import com.example.springbootfull.quartztest.bean.QuartzBean;
import com.example.springbootfull.quartztest.service.IQuartzService;
import lombok.SneakyThrows;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.*;
@Service
public class QuartzServiceImpl implements IQuartzService {
@Resource
private Scheduler scheduler;
/**
* 保存一个 Quartz 作业到调度器中。
*
* @param quartzBean 包含作业和触发器配置信息的 QuartzBean 对象。
* @throws SchedulerException 如果在调度作业或触发器时发生错误。
* @throws ClassNotFoundException 如果找不到指定的作业类。
*/
@Override
@SneakyThrows
public void save(QuartzBean quartzBean) {
// 通过反射获取作业类的 Class 对象
Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(quartzBean.getJobClass());
// 获取作业名称
String jobName = quartzBean.getJobName();
// 获取作业组名称,如果没有指定则使用默认组
String jobGroupName = !StringUtils.hasText(quartzBean.getJobGroupName()) ? Scheduler.DEFAULT_GROUP : quartzBean.getJobGroupName();
// 获取触发器组名称,通常与作业组名称相同
String triggerGroupName = !StringUtils.hasText(quartzBean.getJobGroupName()) ? Scheduler.DEFAULT_GROUP : quartzBean.getJobGroupName();
// 获取作业开始时间,如果没有指定则使用当前时间
Date startTime = quartzBean.getStartTime() == null ? new Date() : quartzBean.getStartTime();
// 获取作业结束时间
Date endTime = quartzBean.getEndTime();
// 获取作业描述,如果没有指定则使用空字符串
String description = !StringUtils.hasText(quartzBean.getDescription()) ? "" : quartzBean.getDescription();
// 构建作业详情对象
JobDetail jobDetail = JobBuilder.newJob(jobClass)
.withIdentity(jobName, jobGroupName) // 设置作业名称和组名称
.withDescription(description) // 设置作业描述
.build();
// 检查是否指定了 Cron 表达式
if (quartzBean.getCronExpression() != null && quartzBean.getCronExpression().length() > 0) {
// 如果指定了 Cron 表达式,则构建基于 Cron 的触发器
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(jobName, triggerGroupName) // 设置触发器名称和组名称
.startAt(startTime) // 设置触发器开始时间
.endAt(endTime) // 设置触发器结束时间(可选)
.withSchedule(CronScheduleBuilder.cronSchedule(quartzBean.getCronExpression())
.withMisfireHandlingInstructionDoNothing()) // 设置 Cron 计划和误触发处理策略
.build();
// 将作业和触发器添加到调度器中
scheduler.scheduleJob(jobDetail, trigger);
} else {
// 如果没有指定 Cron 表达式,则构建基于日历间隔的触发器
DateBuilder.IntervalUnit cycleUnit = DateBuilder.IntervalUnit.valueOf(quartzBean.getIntervalUnit());
Integer timeInterval = quartzBean.getTimeInterval();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(jobName, triggerGroupName) // 设置触发器名称和组名称
.startAt(startTime) // 设置触发器开始时间
.endAt(endTime) // 设置触发器结束时间(可选)
.withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule()
.withInterval(timeInterval, cycleUnit) // 设置间隔计划和单位
.withMisfireHandlingInstructionDoNothing()) // 设置误触发处理策略
.build();
// 将作业和触发器添加到调度器中
scheduler.scheduleJob(jobDetail, trigger);
}
}
/**
* 移除定时任务--根据任务名称移除
*/
@Override
public void delete(String jobName) {
delete(jobName, Scheduler.DEFAULT_GROUP);
}
/**
* 移除定时任务
*/
@Override
@SneakyThrows
public void delete(String jobName, String groupName) {
groupName = !StringUtils.hasText(groupName) ? Scheduler.DEFAULT_GROUP : groupName;
// 指定作业(Job)
JobKey jobKey = new JobKey(jobName, groupName);
// 指定触发器
TriggerKey triggerKey = new TriggerKey(jobName, groupName);
// 使用scheduler对象暂停与指定TriggerKey相关联的触发器
scheduler.pauseTrigger(triggerKey);
// 使用scheduler对象暂停与指定JobKey相关联的作业。
scheduler.pauseJob(jobKey);
// 移除触发器
scheduler.unscheduleJob(triggerKey);
// 删除任务
scheduler.deleteJob(jobKey);
}
/**
* 修改定时任务
*/
@Override
@SneakyThrows
public void update(QuartzBean quartzBean) {
delete(quartzBean.getJobName());
save(quartzBean);
}
/**
* 查询单个定时任务
*/
@Override
public QuartzBean selectByName(String jobName) {
return selectByName(jobName, Scheduler.DEFAULT_GROUP);
}
/**
* 查询单个定时任务
*/
@Override
@SneakyThrows
public QuartzBean selectByName(String jobName, String groupName) {
groupName = !StringUtils.hasText(groupName) ? Scheduler.DEFAULT_GROUP : groupName;
QuartzBean quartzBean = new QuartzBean();
JobKey jobKey = new JobKey(jobName, groupName);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
quartzBean.setJobName(jobName);
quartzBean.setJobGroupName(groupName);
setJob(jobKey, quartzBean, jobDetail);
return quartzBean;
}
/**
* 查询定时任务列表
*/
@Override
@SneakyThrows
public List<QuartzBean> selectList(QuartzBean quartzBean) {
List<QuartzBean> quartzBeans = new ArrayList<>();
GroupMatcher<JobKey> mathcher = GroupMatcher.anyJobGroup();
String keyWord = quartzBean.getJobName();
Set<JobKey> jobKeys = scheduler.getJobKeys(mathcher);
if (jobKeys==null) {
return new ArrayList<>();
}
for (JobKey jobKey : jobKeys) {
if (StringUtils.hasText(keyWord) && !jobKey.getName().contains(keyWord)) {
continue;
}
QuartzBean quartzBean2 = new QuartzBean();
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
quartzBean2.setJobName(jobKey.getName());
quartzBean2.setJobGroupName(jobKey.getGroup());
List<? extends Trigger> triggers = setJob(jobKey, quartzBean2, jobDetail);
quartzBean2.setState(scheduler.getTriggerState(triggers.get(0).getKey()).name());
quartzBeans.add(quartzBean2);
}
return quartzBeans;
}
/**
* 暂停定时任务
*/
@Override
public void pause(String jobName) {
pause(jobName, Scheduler.DEFAULT_GROUP);
}
/**
* 暂停定时任务
*/
@Override
@SneakyThrows
public void pause(String jobName, String groupName) {
groupName = !StringUtils.hasText(groupName) ? Scheduler.DEFAULT_GROUP : groupName;
TriggerKey triggerKey = new TriggerKey(jobName, groupName);
scheduler.pauseTrigger(triggerKey);
JobKey jobKey = new JobKey(jobName);
scheduler.pauseJob(jobKey);
}
/**
* 恢复定时任务
*/
@Override
public void resume(String jobName) {
resume(jobName, Scheduler.DEFAULT_GROUP);
}
/**
* 恢复定时任务
*/
@Override
@SneakyThrows
public void resume(String jobName, String groupName) {
//检查groupName是否有有效的文本内容,没有有效的则用默认的组名
groupName = !StringUtils.hasText(groupName) ? Scheduler.DEFAULT_GROUP : groupName;
TriggerKey triggerKey = new TriggerKey(jobName, groupName);
scheduler.resumeTrigger(triggerKey);
JobKey jobKey = new JobKey(jobName);
scheduler.resumeJob(jobKey);
}
/**
* 执行定时任务
*/
@Override
public void executeJob(String jobName) {
executeJob(jobName, Scheduler.DEFAULT_GROUP);
}
/**
* 执行定时任务
*/
@Override
@SneakyThrows
public void executeJob(String jobName, String groupName) {
//检查groupName是否有有效的文本内容,没有有效的则用默认的组名
groupName = !StringUtils.hasText(groupName) ? Scheduler.DEFAULT_GROUP : groupName;
JobKey jobKey = new JobKey(jobName, groupName);
scheduler.triggerJob(jobKey);
}
/**
* 根据提供的JobKey和JobDetail信息,设置QuartzBean的属性,并返回与该作业关联的触发器列表。
*
* @param jobKey 作业的唯一标识,包括作业名称和作业组名。
* @param quartzBean 用于封装Quartz作业相关属性的对象。
* @param jobDetail 包含作业详细信息的JobDetail对象。
* @return 与指定作业关联的触发器列表,列表中的触发器类型可能是CronTrigger或CalendarIntervalTrigger等。
* @throws SchedulerException 如果在获取触发器列表时发生错误。
*/
private List<? extends Trigger> setJob(JobKey jobKey, QuartzBean quartzBean, JobDetail jobDetail) throws SchedulerException {
// 设置作业类名和描述
quartzBean.setJobClass(jobDetail.getJobClass().getName());
quartzBean.setDescription(jobDetail.getDescription());
// 尝试获取与指定作业关联的触发器列表
List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
// 检查触发器列表是否为空或没有元素
if (triggers == null || triggers.isEmpty()) {
// 根据业务需求,可以选择抛出异常、返回空列表或进行其他处理
// 这里为了简化,直接返回空列表(注意:这可能会隐藏潜在的问题)
return Collections.emptyList();
}
// 获取第一个触发器(注意:这里假设至少有一个触发器)
Trigger trigger = triggers.get(0);
// 设置触发器的开始时间和结束时间
quartzBean.setStartTime(trigger.getStartTime());
quartzBean.setEndTime(trigger.getEndTime());
// 根据触发器的具体类型设置相应的属性
if (trigger instanceof CronTrigger) {
// 如果是CronTrigger类型,则获取Cron表达式
CronTrigger cronTrigger = (CronTrigger) trigger; // 使用instanceof后可以直接强制转换,无需再次检查类型
quartzBean.setCronExpression(cronTrigger.getCronExpression());
} else if (trigger instanceof CalendarIntervalTrigger) {
// 如果是CalendarIntervalTrigger类型,则获取重复间隔单位和重复间隔时间
CalendarIntervalTrigger calendarIntervalTrigger = (CalendarIntervalTrigger) trigger;
quartzBean.setIntervalUnit(calendarIntervalTrigger.getRepeatIntervalUnit().toString());
quartzBean.setTimeInterval(calendarIntervalTrigger.getRepeatInterval());
}
// 注意:这里只处理了两种类型的触发器,如果有其他类型的触发器,需要添加相应的处理逻辑
// 返回与指定作业关联的触发器列表
return triggers;
}
}
控制层类
package com.example.springbootfull.quartztest.controller;
import com.example.springbootfull.quartztest.bean.QuartzBean;
import com.example.springbootfull.quartztest.service.IQuartzService;
import com.example.springbootfull.quartztest.zdyresult.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("taskScheduler")
public class QuartzController {
@Autowired
private IQuartzService quartzService;
/**
* 添加定时任务信息
*
* @param quartzBean 定时任务信息
* @return ReturnModel 添加定时任务
*/
@PostMapping(value = "save")
public ResponseResult<String> save(@RequestBody QuartzBean quartzBean) {
// {
// "jobName": "bookTask",
// "description": "书籍定时任务",
// // "startTime": "2024-01-12 15:20:00",
// // "endTime": "2024-01-13 00:00:00",
// "jobClass": "com.example.springbootfull.quartztest.BookTask",
// "cronExpression": "*/10 * * * * ?"
// }
quartzService.save(quartzBean);
return ResponseResult.success(quartzBean.getJobName());
}
/**
* 移除定时任务
*
* @param quartzBean 定时任务信息
* @return ReturnModel 移除定时任务
*/
@PostMapping(value = "/delete")
public ResponseResult<String> delete(@RequestBody QuartzBean quartzBean) {
// {
// "jobName": "bookTask"
// }
quartzService.delete(quartzBean.getJobName());
return ResponseResult.success(quartzBean.getJobName());
}
/**
* 修改定时任务
*
* @param quartzBean 定时任务信息
* @return ReturnModel 修改定时任务
*/
@PostMapping(value = "update")
public ResponseResult<String> update(@RequestBody QuartzBean quartzBean) {
// {
// "jobName":"bookTask",
// "description":"1",
// "jobTypeRadio":"expression",
// "startTime":"2024-01-13 14:00:00",
// "endTime":"",
// "jobClass":"com.example.demo.system.controller.BookTask",
// "cronExpression":"*/30 * * * * ?"
// }
quartzService.update(quartzBean);
return ResponseResult.success(quartzBean.getJobName());
}
/**
* 暂停定时任务
*
* @param quartzBean 定时任务名称
* @return ReturnModel 暂停定时任务
*/
@PostMapping(value = "pause")
public ResponseResult<String> pause(@RequestBody QuartzBean quartzBean) {
// {
// "jobName": "bookTask2"
// }
quartzService.pause(quartzBean.getJobName());
return ResponseResult.success(quartzBean.getJobName());
}
/**
* 恢复定时任务
*
* @param quartzBean 定时任务名称
* @return ReturnModel 恢复定时任务
*/
@PostMapping(value = "resume")
public ResponseResult<String> resume(@RequestBody QuartzBean quartzBean) {
// {
// "jobName": "bookTask2"
// }
quartzService.resume(quartzBean.getJobName());
return ResponseResult.success(quartzBean.getJobName());
}
/**
* 执行定时任务
*
* @param quartzBean 定时任务名称
* @return ReturnModel 执行定时任务
*/
@PostMapping(value = "executeJob")
public ResponseResult<String> executeJob(@RequestBody QuartzBean quartzBean) {
// {
// "jobName": "bookTask2"
// }
quartzService.executeJob(quartzBean.getJobName());
return ResponseResult.success(quartzBean.getJobName());
}
/**
* 查询单个定时任务信息
*
* @param jobName 任务名称
* @return ReturnModel 查询单个定时任务信息
*/
@GetMapping(value = "selectByName")
public ResponseResult<QuartzBean> selectByName(@RequestParam("jobName") String jobName) {
QuartzBean quartzBean = quartzService.selectByName(jobName);
return ResponseResult.success(quartzBean);
}
/**
* 查询定时任务列表
*
* @param quartzBean 查询条件
* @return ReturnModel 查询定时任务列表
*/
@PostMapping(value = "selectList")
public ResponseResult<List<QuartzBean>> selectList(@RequestBody QuartzBean quartzBean) {
// {
// "jobName": ""
// }
List<QuartzBean> quartzBeans = quartzService.selectList(quartzBean);
return ResponseResult.success(quartzBeans);
}
}
测试结果
我这边只测试一下查看
参考文章
【1】【QUARTZ】springboot+quartz动态配置定时任务