SpringBoot教程(二十四) | SpringBoot实现分布式定时任务之Quartz(动态新增、修改等操作)
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 {@Overrideprotected 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 {@Resourceprivate Scheduler scheduler;/*** 保存一个 Quartz 作业到调度器中。** @param quartzBean 包含作业和触发器配置信息的 QuartzBean 对象。* @throws SchedulerException 如果在调度作业或触发器时发生错误。* @throws ClassNotFoundException 如果找不到指定的作业类。*/@Override@SneakyThrowspublic 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);}}/*** 移除定时任务--根据任务名称移除*/@Overridepublic void delete(String jobName) {delete(jobName, Scheduler.DEFAULT_GROUP);}/*** 移除定时任务*/@Override@SneakyThrowspublic 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@SneakyThrowspublic void update(QuartzBean quartzBean) {delete(quartzBean.getJobName());save(quartzBean);}/*** 查询单个定时任务*/@Overridepublic QuartzBean selectByName(String jobName) {return selectByName(jobName, Scheduler.DEFAULT_GROUP);}/*** 查询单个定时任务*/@Override@SneakyThrowspublic 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@SneakyThrowspublic 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;}/*** 暂停定时任务*/@Overridepublic void pause(String jobName) {pause(jobName, Scheduler.DEFAULT_GROUP);}/*** 暂停定时任务*/@Override@SneakyThrowspublic 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);}/*** 恢复定时任务*/@Overridepublic void resume(String jobName) {resume(jobName, Scheduler.DEFAULT_GROUP);}/*** 恢复定时任务*/@Override@SneakyThrowspublic 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);}/*** 执行定时任务*/@Overridepublic void executeJob(String jobName) {executeJob(jobName, Scheduler.DEFAULT_GROUP);}/*** 执行定时任务*/@Override@SneakyThrowspublic 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 {@Autowiredprivate 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动态配置定时任务
相关文章:
SpringBoot教程(二十四) | SpringBoot实现分布式定时任务之Quartz(动态新增、修改等操作)
SpringBoot教程(二十四) | SpringBoot实现分布式定时任务之Quartz(动态新增、修改等操作) 前言数据库脚本创建需要被调度的方法创建相关实体类创建业务层接口创建业务层实现类控制层类测试结果 前言 我这边的SpringBoot的版本为2…...
Matlab详细学习教程 MATLAB使用教程与知识点总结
Matlab语言教程 章节目录 一、Matlab简介与基础操作 二、变量与数据类型 三、矩阵与数组操作 四、基本数学运算与函数 五、图形绘制与数据可视化 六、控制流与逻辑运算 七、脚本与函数编写 八、数据导入与导出 九、Matlab应用实例分析 一、Matlab简介与基础操作 重点内容知识…...
【ELKB】Kibana使用
搭建好ELKB后访问地址:http://localhost:5601 输入账号密码登录以后 左侧导航有home、Analysis、Enterprise search 、Observability、Security、Management home:首页Analysis:工具来分析及可视化数据Enterprise search:企业级搜…...
ChatGPT免费使用:人工智能在现代社会中的作用
随着人工智能技术的不断发展,越来越多的应用程序和工具开始使用GPT作为其语言模型。但是,这些应用程序和工具是否收费?如果是免费的,那么他们是如何盈利的?在本文中,我们将探讨ChatGPT免费使用的背后原理&a…...
腾讯音乐:从 Elasticsearch 到 Apache Doris 内容库升级,统一搜索分析引擎,成本直降 80%
导读: 为满足更严苛数据分析的需求,腾讯音乐借助 Apache Doris 替代了 Elasticsearch 集群,统一了内容库数据平台的内容搜索和分析引擎。并基于 Doris 倒排索引和全文检索的能力,支持了复杂的自定义标签计算,实现秒级查…...
CubeMX的FreeRTOS学习
一、FreeRTOS的介绍 什么是FreeRTOS? Free即免费的,RTOS的全称是Real Time Operating system,中文就是实时操作系统。 注意:RTOS不是指某一个确定的系统,而是指一类的操作系统。比如:us/OS,FreeRTOS&…...
C语言初始:数据类型和变量
、 一.数据类型介绍 人有黄人白人黑人,那么数据呢? 我们大家可以看出谁是黄种人,谁是白种人,谁是黑种人,这是因为他们是类似的。 数据也是有类型的,就譬如整数类型,字符类型,浮点…...
Linux shellcheck工具
安装工具 通过linux yum源下载,可能因为yum源的问题找不到软件包,或者下载的软件包版本太旧。 ShellCheck的源代码托管在GitHub上(推荐下载方式): GitHub - koalaman/shellcheck: ShellCheck, a static analysis tool for shell scripts 对下…...
FLINK SQL时间属性
Flink三种时间属性简介 在Flink SQL中,时间属性是一个核心概念,它主要用于处理与时间相关的数据流。Flink支持三种时间属性:事件时间(event time)、处理时间(processing time)和摄入时间&#…...
android——Groovy gralde 脚本迁移到DSL
1、implementation的转换 implementation com.github.CymChad:BaseRecyclerViewAdapterHelper:*** 转换为 implementation ("com.github.CymChad:BaseRecyclerViewAdapterHelper:***") 2、plugin的转换 apply plugin: kotlin-android-extensions 转换为&#x…...
工程项目管理中的最常见概念!蓝燕云总结!
01 怎么理解工程项目管理? 建设工程项目管理指的是专业性的管理,并非行政事务管理。建设工程项目管理是对工程项目全生命周期的管理,确保项目能够按计划的进度、成本和质量完成。 建设工程项目不同阶段管理的主要内容不同,通常…...
PostgreSQL AUTO INCREMENT
PostgreSQL AUTO INCREMENT 在数据库管理系统中,自动递增(AUTO INCREMENT)是一种常见特性,用于在插入新记录时自动生成唯一的标识符。PostgreSQL,作为一个功能强大的开源关系数据库管理系统,也提供了类似的…...
24-10-13-读书笔记(二十五)-《一只特立独行的猪》([中] 王小波)用一生来学习艺术
文章目录 《一只特立独行的猪》([中] 王小波)目录阅读笔记记录总结 《一只特立独行的猪》([中] 王小波) 十月第五篇,放慢脚步,秋季快要过去了,要步入冬季了,心中也是有些跌宕起伏&am…...
Java—继承性与多态性
目录 一、this关键字 1. 理解this 2. this练习 二、继承性 2.1 继承性的理解 2.1.1 多层继承 2.2 继承性的使用练习 2.2.1 练习1 2.2.2 练习2 2.3 方法的重写 2.4 super关键字 2.4.1 子类对象实例化 三、多态性 3.1 多态性的理解 3.2 向下转型与多态练习 四、Ob…...
打通华为认证实验考试“痛点”:备考指南全解析
华为认证体系中的实验考试环节,尤其是针对高端的HCIE认证,是评估考生实践技能的关键部分。这一环节的核心目标是检验考生对华为设备和解决方案的操作熟练度、技术实施技能以及面对现实工作挑战时的问题解决能力。通过在真实环境中进行的实践操作…...
【软考】子系统划分
目录 1. 子系统划分的原则1.1 子系统要具有相对独立性1.2 子系统之间数据的依赖性尽量小1.3 子系统划分的结果应使数据几余较小1.4 子系统的设置应考虑今后管理发展的需要1.5 子系统的划分应便于系统分阶段实现1.6 子系统的划分应考虑到各类资源的充分利用 2. 子系统结构设计3.…...
【Python】selenium获取鼠标在网页上的位置,并定位到网页位置模拟点击的方法
在使用Selenium写自动化爬虫时,遇到验证码是常事了。我在写爬取测试的时候,遇到了点击型的验证码,例如下图这种: 这种看似很简单,但是它居然卡爬虫?用简单的点触验证码的方法来做也没法实现 平常的点触的方…...
【C++ 真题】B2078 含 k 个 3 的数
含 k 个 3 的数 题目描述 输入两个正整数 m m m 和 k k k,其中 1 < m ≤ 1 0 15 1 \lt m \leq 10^{15} 1<m≤1015, 1 < k ≤ 15 1 \lt k \leq 15 1<k≤15 ,判断 m m m 是否恰好含有 k k k 个 3 3 3,如果满足条…...
蓝桥杯省赛真题——冶炼金属
问题描述 小蓝有一个神奇的炉子用于将普通金属 O 冶炼成为一种特殊金属 X。这个炉子有一个称作转换率的属性 V,V 是一个正整数,这意味着消耗 V 个普通金属 O 恰好可以冶炼出一个特殊金属 X,当普通金属 O 的数目不足 V 时,无法继续…...
【Mac苹果电脑安装】DBeaverEE for Mac 数据库管理工具软件教程【保姆级教程】
Mac分享吧 文章目录 DBeaverEE 数据库管理工具 软件安装完成,打开效果图片Mac电脑 DBeaverEE 数据库管理工具 软件安装——v24.21️⃣:下载软件2️⃣:安装JDK,根据下图操作步骤提示完成安装3️⃣:安装DBeaverEE&#…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
