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动态配置定时任务

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/445859.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用java来编写web界面

一、ssm框架整体目录架构 二、编写后端代码 1、编写实体层代码 实体层代码就是你的对象 entity package com.cv.entity;public class Apple {private Integer id;private String name;private Integer quantity;private Integer price;private Integer categoryId;public…

libaom 源码分析系列:noise_model.c 文件

libaom libaom 是 AOMedia(开放媒体联盟)开发的一个开源视频编解码器库,它是 AV1 视频压缩格式的参考实现,并被广泛用于多种生产系统中。libaom 支持多种功能,包括可扩展视频编码(SVC)、实时通信(RTC)优化等,并定期进行更新以提高压缩效率和编码速度 。 libaom 的一些…

2.1 HTML5 - Canvas标签

文章目录 引言Canvas标签概述定义实例&#xff1a;创建画布 理解Canvas坐标系概述实例&#xff1a;获取Canvas坐标 获取Canvas环境上下文概述实例&#xff1a;获取Canvas上下文设置渐变色效果 结语 引言 大家好&#xff0c;今天我们要一起探索HTML5中一个非常有趣且强大的特性…

Redhat的yum源出错——如何将yum源换成阿里云Centos源

文章目录 引言1. 查看和删除已安装的yum包2. 查看系统的版本号3. 镜像文件下载4. 镜像文件安装5. 下载和安装repo文件6. 配置repo文件7. 更新软件包缓存8. 验证9. 问题问题1 参考文献 Linux RedHat更换阿里云yum源 Redhat8.0 yum install问题解决 阿里云镜像 引言 为什么redha…

六西格玛黑带项目:TBX-02无人机飞行稳定性提升——张驰咨询

一、项目背景与问题定义 TBX-02是该公司最新发布的消费级无人机&#xff0c;面向摄影爱好者和户外探险者。产品上市后&#xff0c;通过客户反馈和实际测试数据发现&#xff0c;该无人机在复杂飞行环境中&#xff0c;如强风或快速移动时&#xff0c;存在明显的飞行抖动和稳定性…

【AIGC】OpenAI API在快速开发中的实践与应用:优化ChatGPT提示词Prompt加速工程

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;使用最新型号确保最佳实践利用最新模型进行高效任务处理为什么要选择最新模型&#xff1f;结论 &#x1f4af;指令与上下文的分隔最佳实践分隔指令和上下文的重要性使用符…

一起体验AI动手实验,OceanBase 2024 年度发布会精彩预告

2024年OceanBase年度发布会将于10月23日在北京望京凯悦酒店举行。此次大会围绕“不止于记录”的主题&#xff0c;共同探讨当前数据库领域的前沿话题&#xff0c;包含主论坛、分论坛、AI 动手实训营、开源技术交流会等多个环节&#xff0c;诚邀全国各地的企业和开发者共同参与&a…

[论文期刊|稳定检索]2024年信号处理与光学工程国际会议(SPOE 2024 )

2024年信号处理与光学工程国际会议 2024 International Conference on Signal Processing and Optical Engineering 【1】大会信息 会议名称&#xff1a;2024年信号处理与光学工程国际会议 会议简称&#xff1a;SPOE 2024 大会时间&#xff1a;请查看官网 大会地点&#xf…

51单片机的智能电饭煲【proteus仿真+程序+报告+原理图+演示视频】

1、主要功能 该系统由AT89C51/STC89C52单片机LCD1602显示模块温度传感器继电器按键、LED等模块构成。适用于智能电饭锅等相似项目。 可实现功能: 1、LCD1602实时显示温度、运行模式、煮饭等模式的计时时间 2、首先选择电饭锅的模式&#xff0c;如煮饭、煮粥、蒸、煲汤&#…

Android常用界面控件——ProgressBar

ProgressBar 目录 ProgressBar 在XML中定义ProgressBar ProgressBar风格样式 ProgressBar常用XML属性 在Java代码中控制ProgressBar 实例 什么是ProgressBar&#xff1f; ProgressBar是Android中的一个视图控件&#xff0c;主要用于表示一个任务的进度情况&#xff0c;…

【AI视频】复刻抖音爆款AI数字人作品初体验

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AI视频 | AI数字人 文章目录 &#x1f4af;前言&#x1f4af;抖音上的爆火AI数字人视频&#x1f4af;注册HeyGen账号&#x1f4af;复刻抖音爆款AI数字人&#x1f4af;最终生成效果&#x1f4af;小结 对比原视频效果&#xff1a;…

有了WPF后Winform还有活路吗?

近年来&#xff0c;随着技术的不断发展&#xff0c;Windows Presentation Foundation&#xff08;WPF&#xff09;和Windows Forms&#xff08;WinForms&#xff09;这两种技术在开发桌面应用程序方面一直备受关注。虽然WPF以其强大的功能和灵活性吸引了众多开发者&#xff0c;…

谷歌-BERT-第四步:模型部署

1 需求 需求1&#xff1a;基于gradio实现大模型的WEB UI交互界面 2 接口 3 示例 import gradio as gr from transformers import *classifier pipeline("text-classification", model"./model", tokenizer"./model")gr.Interface.from_pipel…

HarmonyOS NEXT 应用开发实战(三、ArkUI页面底部导航TabBar的实现)

在开发HarmonyOS NEXT应用时&#xff0c;TabBar是用户界面设计中不可或缺的一部分。本文将通过代码示例&#xff0c;带领大家一同实现一个常用的TabBar&#xff0c;涵盖三个主要的内容页&#xff1a;首页、知乎日报和我的页面。以模仿知乎日报的项目为背景驱动&#xff0c;设定…

搭建`mongodb`副本集-开启权限认证 mongo:7.0.5

搭建mongodb副本集-开启权限认证 mongo:7.0.5 1.5.1、创建文件 创建配置文件保存目录和数据保存目录 mkdir -p /data/mongodb/{/conf,/data,/logs}生成和设置权限 这个文件一定要在一个服务里面生成然后复制到其它服务器&#xff0c;所有服务器的这个key一定是相同的。 op…

Python数据分析-Scipy科学计算法

1.认识Scipy SciPy&#xff08;发音为 "Sigh Pie"&#xff09;是一个开源的 Python 算法库和数学工具包。 通常与 NumPy、Matplotlib 和 pandas 等库一起使用&#xff0c;这些库共同构成了 Python 的科学计算基础。 2.使用Scipy基本函数 2.1 引用Scipy函数 impor…

HarmonyOS NEXT应用开发实战(二、封装比UniApp和小程序更简单好用的网络库)

网络访问接口&#xff0c;使用频次最高。之前习惯了uniapp下的网络接口风格&#xff0c;使用起来贼简单方便。转战到鸿蒙上后&#xff0c;原始网络接口写着真累啊&#xff01;目标让鸿蒙上网络接口使用&#xff0c;简单程度比肩uniapp&#xff0c;比Axios更轻量级。源码量也不多…

antd table合并复杂单元格、分组合并行、分组合并列、动态渲染列、嵌套表头

项目里遇到个需求&#xff0c;涉及到比较复杂的单元格合并 、嵌套表头、分组合并行、合并列等&#xff0c;并且数据列还是动态的&#xff0c;效果图如下&#xff1a; 可以分组设置【显示列】例如&#xff1a;当前组为【合同约定】&#xff0c;显示列为【合同节点】和【节点金额…

文件完整性监控:如何提高企业的数据安全性

企业网络庞大而复杂&#xff0c;需要处理大量关键业务数据&#xff0c;这些敏感文件在企业网络中不断传输&#xff0c;并由多个用户和实体存储、共享和访问。FIM 工具或具有 FIM 功能的 SIEM 解决方案使企业能够跟踪未经授权的文件更改、对敏感信息的恶意访问、数据篡改尝试和内…

VSCode 使用 EmmyLua 对lua进行调试

时间&#xff1a;2024年10月 其他&#xff1a;win10&#xff0c;EmmyLua v0.8.20 参考&#xff1a;https://blog.csdn.net/ShenHaoDeHao/article/details/140268354 有几个概念搞清楚就好理解了。一般开发中&#xff0c;我们编写的lua文件由宿主程序的来解析、执行&#xff1…