当前位置: 首页 > news >正文

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_triggersblog类型存储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教程&#xff08;二十四&#xff09; | SpringBoot实现分布式定时任务之Quartz&#xff08;动态新增、修改等操作&#xff09; 前言数据库脚本创建需要被调度的方法创建相关实体类创建业务层接口创建业务层实现类控制层类测试结果 前言 我这边的SpringBoot的版本为2…...

Matlab详细学习教程 MATLAB使用教程与知识点总结

Matlab语言教程 章节目录 一、Matlab简介与基础操作 二、变量与数据类型 三、矩阵与数组操作 四、基本数学运算与函数 五、图形绘制与数据可视化 六、控制流与逻辑运算 七、脚本与函数编写 八、数据导入与导出 九、Matlab应用实例分析 一、Matlab简介与基础操作 重点内容知识…...

【ELKB】Kibana使用

搭建好ELKB后访问地址&#xff1a;http://localhost:5601 输入账号密码登录以后 左侧导航有home、Analysis、Enterprise search 、Observability、Security、Management home&#xff1a;首页Analysis&#xff1a;工具来分析及可视化数据Enterprise search&#xff1a;企业级搜…...

ChatGPT免费使用:人工智能在现代社会中的作用

随着人工智能技术的不断发展&#xff0c;越来越多的应用程序和工具开始使用GPT作为其语言模型。但是&#xff0c;这些应用程序和工具是否收费&#xff1f;如果是免费的&#xff0c;那么他们是如何盈利的&#xff1f;在本文中&#xff0c;我们将探讨ChatGPT免费使用的背后原理&a…...

腾讯音乐:从 Elasticsearch 到 Apache Doris 内容库升级,统一搜索分析引擎,成本直降 80%

导读&#xff1a; 为满足更严苛数据分析的需求&#xff0c;腾讯音乐借助 Apache Doris 替代了 Elasticsearch 集群&#xff0c;统一了内容库数据平台的内容搜索和分析引擎。并基于 Doris 倒排索引和全文检索的能力&#xff0c;支持了复杂的自定义标签计算&#xff0c;实现秒级查…...

CubeMX的FreeRTOS学习

一、FreeRTOS的介绍 什么是FreeRTOS&#xff1f; Free即免费的&#xff0c;RTOS的全称是Real Time Operating system,中文就是实时操作系统。 注意&#xff1a;RTOS不是指某一个确定的系统&#xff0c;而是指一类的操作系统。比如&#xff1a;us/OS&#xff0c;FreeRTOS&…...

C语言初始:数据类型和变量

、 一.数据类型介绍 人有黄人白人黑人&#xff0c;那么数据呢&#xff1f; 我们大家可以看出谁是黄种人&#xff0c;谁是白种人&#xff0c;谁是黑种人&#xff0c;这是因为他们是类似的。 数据也是有类型的&#xff0c;就譬如整数类型&#xff0c;字符类型&#xff0c;浮点…...

Linux shellcheck工具

安装工具 通过linux yum源下载&#xff0c;可能因为yum源的问题找不到软件包&#xff0c;或者下载的软件包版本太旧。 ShellCheck的源代码托管在GitHub上(推荐下载方式)&#xff1a; GitHub - koalaman/shellcheck: ShellCheck, a static analysis tool for shell scripts 对下…...

FLINK SQL时间属性

Flink三种时间属性简介 在Flink SQL中&#xff0c;时间属性是一个核心概念&#xff0c;它主要用于处理与时间相关的数据流。Flink支持三种时间属性&#xff1a;事件时间&#xff08;event time&#xff09;、处理时间&#xff08;processing time&#xff09;和摄入时间&#…...

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 怎么理解工程项目管理&#xff1f; 建设工程项目管理指的是专业性的管理&#xff0c;并非行政事务管理。建设工程项目管理是对工程项目全生命周期的管理&#xff0c;确保项目能够按计划的进度、成本和质量完成。 建设工程项目不同阶段管理的主要内容不同&#xff0c;通常…...

PostgreSQL AUTO INCREMENT

PostgreSQL AUTO INCREMENT 在数据库管理系统中&#xff0c;自动递增&#xff08;AUTO INCREMENT&#xff09;是一种常见特性&#xff0c;用于在插入新记录时自动生成唯一的标识符。PostgreSQL&#xff0c;作为一个功能强大的开源关系数据库管理系统&#xff0c;也提供了类似的…...

24-10-13-读书笔记(二十五)-《一只特立独行的猪》([中] 王小波)用一生来学习艺术

文章目录 《一只特立独行的猪》&#xff08;[中] 王小波&#xff09;目录阅读笔记记录总结 《一只特立独行的猪》&#xff08;[中] 王小波&#xff09; 十月第五篇&#xff0c;放慢脚步&#xff0c;秋季快要过去了&#xff0c;要步入冬季了&#xff0c;心中也是有些跌宕起伏&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…...

打通华为认证实验考试“痛点”:备考指南全解析

华为认证体系中的实验考试环节&#xff0c;尤其是针对高端的HCIE认证&#xff0c;是评估考生实践技能的关键部分。这一环节的核心目标是检验考生对华为设备和解决方案的操作熟练度、技术实施技能以及面对现实工作挑战时的问题解决能力。通过在真实环境中进行的实践操作&#xf…...

【软考】子系统划分

目录 1. 子系统划分的原则1.1 子系统要具有相对独立性1.2 子系统之间数据的依赖性尽量小1.3 子系统划分的结果应使数据几余较小1.4 子系统的设置应考虑今后管理发展的需要1.5 子系统的划分应便于系统分阶段实现1.6 子系统的划分应考虑到各类资源的充分利用 2. 子系统结构设计3.…...

【Python】selenium获取鼠标在网页上的位置,并定位到网页位置模拟点击的方法

在使用Selenium写自动化爬虫时&#xff0c;遇到验证码是常事了。我在写爬取测试的时候&#xff0c;遇到了点击型的验证码&#xff0c;例如下图这种&#xff1a; 这种看似很简单&#xff0c;但是它居然卡爬虫&#xff1f;用简单的点触验证码的方法来做也没法实现 平常的点触的方…...

【C++ 真题】B2078 含 k 个 3 的数

含 k 个 3 的数 题目描述 输入两个正整数 m m m 和 k k k&#xff0c;其中 1 < m ≤ 1 0 15 1 \lt m \leq 10^{15} 1<m≤1015&#xff0c; 1 < k ≤ 15 1 \lt k \leq 15 1<k≤15 &#xff0c;判断 m m m 是否恰好含有 k k k 个 3 3 3&#xff0c;如果满足条…...

蓝桥杯省赛真题——冶炼金属

问题描述 小蓝有一个神奇的炉子用于将普通金属 O 冶炼成为一种特殊金属 X。这个炉子有一个称作转换率的属性 V&#xff0c;V 是一个正整数&#xff0c;这意味着消耗 V 个普通金属 O 恰好可以冶炼出一个特殊金属 X&#xff0c;当普通金属 O 的数目不足 V 时&#xff0c;无法继续…...

【Mac苹果电脑安装】DBeaverEE for Mac 数据库管理工具软件教程【保姆级教程】

Mac分享吧 文章目录 DBeaverEE 数据库管理工具 软件安装完成&#xff0c;打开效果图片Mac电脑 DBeaverEE 数据库管理工具 软件安装——v24.21️⃣&#xff1a;下载软件2️⃣&#xff1a;安装JDK&#xff0c;根据下图操作步骤提示完成安装3️⃣&#xff1a;安装DBeaverEE&#…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

JVM 内存结构 详解

内存结构 运行时数据区&#xff1a; Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器&#xff1a; ​ 线程私有&#xff0c;程序控制流的指示器&#xff0c;分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...