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

SpringBoot实现定时任务,使用自带的定时任务以及调度框架quartz的配置使用

SpringBoot实现定时任务,使用自带的定时任务以及调度框架quartz的配置使用

文章目录

  • SpringBoot实现定时任务,使用自带的定时任务以及调度框架quartz的配置使用
    • 一. 使用SpringBoot自带的定时任务(适用于小型应用)
    • 二. 使用调度框架quartz(适用于中大型应用)
    • 三、数据库模式quartz的使用
        • 1. 创建数据库表
        • 2. 制定一个定时任务
        • 3. 写配置文件
        • 4. 创建接收和相应实体类
        • 5. 增删改查的controller层接口
        • 6. 编写接口测试代码

一. 使用SpringBoot自带的定时任务(适用于小型应用)

创建SpringBoot项目,创建SpringBootTestJob 类,作为定时任务类

 @Component@EnableSchedulingpublic class SpringBootTestJob {@Scheduled(cron = "0/5 * * * * ?") // 每五秒执行一次private void test() {System.out.println("SpringBootTestJob TEST");}}
  • 适用性: 适合单体应用,不适合集群,没法实时更改定时任务状态和策略

启动后,可以看到,每五秒打印内容:
在这里插入图片描述

二. 使用调度框架quartz(适用于中大型应用)

  1. 增加依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
  1. 创建定时任务类
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;/*** @author SaoE* @date 2025/1/19 20:06*/
public class TestJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {System.out.println("TestJob TEST");}
}
  1. 增加quartz配置类QuartzConfig
 @Configurationpublic class QuartzConfig {/*** 声明一个任务* @return*/@Beanpublic JobDetail jobDetail() {return JobBuilder.newJob(TestJob.class).withIdentity("TestJob", "test").storeDurably().build();}/*** 声明一个触发器,什么时候触发这个任务* @return*/@Beanpublic Trigger trigger() {return TriggerBuilder.newTrigger().forJob(jobDetail()).withIdentity("trigger", "trigger").startNow().withSchedule(CronScheduleBuilder.cronSchedule("*/2 * * * * ?")).build();}}
  1. 启动主类
    可以看到控制台每两秒打印信息:
    在这里插入图片描述
  2. 禁止任务并发执行
    任务类增加注解@DisallowConcurrentExecution,修改如下:
@DisallowConcurrentExecution
public class TestJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {System.out.println("TestJob TEST开始");try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("TestJob TEST结束");}
}

此时打印输出为上一个任务结束后,下一个任务立即开始。如果没有这个注解,则会并发执行。

三、数据库模式quartz的使用

1. 创建数据库表
-- #
-- # Quartz seems to work best with the driver mm.mysql-2.0.7-bin.jar
-- #
-- # PLEASE consider using mysql with innodb tables to avoid locking issues
-- #
-- # In your Quartz properties file, you'll need to set
-- # org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
-- #
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  comment '定时任务名称',JOB_NAME  VARCHAR(200) NOT NULL  comment 'job名称',JOB_GROUP VARCHAR(200) NOT NULL  comment 'job组',DESCRIPTION VARCHAR(250) NULL  comment '描述',JOB_CLASS_NAME   VARCHAR(250) NOT NULL  comment 'job类名',IS_DURABLE VARCHAR(1) NOT NULL  comment '是否持久化',IS_NONCONCURRENT VARCHAR(1) NOT NULL  comment '是否非同步',IS_UPDATE_DATA VARCHAR(1) NOT NULL  comment '是否更新数据',REQUESTS_RECOVERY VARCHAR(1) NOT NULL  comment '请求是否覆盖',JOB_DATA BLOB NULL  comment 'job数据',PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);
CREATE TABLE QRTZ_TRIGGERS
(SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',TRIGGER_NAME VARCHAR(200) NOT NULL comment '触发器名称',TRIGGER_GROUP VARCHAR(200) NOT NULL  comment '触发器组',JOB_NAME  VARCHAR(200) NOT NULL  comment 'job名称',JOB_GROUP VARCHAR(200) NOT NULL  comment 'job组',DESCRIPTION VARCHAR(250) NULL  comment '描述',NEXT_FIRE_TIME BIGINT(13) NULL  comment '下一次触发时间',PREV_FIRE_TIME BIGINT(13) NULL  comment '前一次触发时间',PRIORITY INTEGER NULL  comment '等级',TRIGGER_STATE VARCHAR(16) NOT NULL  comment '触发状态',TRIGGER_TYPE VARCHAR(8) NOT NULL  comment '触发类型',START_TIME BIGINT(13) NOT NULL  comment '开始时间',END_TIME BIGINT(13) NULL  comment '结束时间',CALENDAR_NAME VARCHAR(200) NULL  comment '日程名称',MISFIRE_INSTR SMALLINT(2) NULL  comment '未触发实例',JOB_DATA BLOB NULL  comment 'job数据',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)
);
CREATE TABLE QRTZ_SIMPLE_TRIGGERS
(SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',TRIGGER_NAME VARCHAR(200) NOT NULL  comment '触发器名称',TRIGGER_GROUP VARCHAR(200) NOT NULL  comment '触发器组',REPEAT_COUNT BIGINT(7) NOT NULL  comment '重复执行次数',REPEAT_INTERVAL BIGINT(12) NOT NULL  comment '重复执行间隔',TIMES_TRIGGERED BIGINT(10) NOT NULL  comment '已经触发次数',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)
);
CREATE TABLE QRTZ_CRON_TRIGGERS
(SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',TRIGGER_NAME VARCHAR(200) NOT NULL  comment '触发器名称',TRIGGER_GROUP VARCHAR(200) NOT NULL  comment '触发器组',CRON_EXPRESSION VARCHAR(200) NOT NULL  comment 'cron表达式',TIME_ZONE_ID VARCHAR(80)  comment '时区',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)
);
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
(SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',TRIGGER_NAME VARCHAR(200) NOT NULL  comment '触发器名称',TRIGGER_GROUP VARCHAR(200) NOT NULL  comment '触发器组',STR_PROP_1 VARCHAR(512) NULL  comment '开始配置1',STR_PROP_2 VARCHAR(512) NULL  comment '开始配置2',STR_PROP_3 VARCHAR(512) NULL  comment '开始配置3',INT_PROP_1 INT NULL  comment 'int配置1',INT_PROP_2 INT NULL  comment 'int配置2',LONG_PROP_1 BIGINT NULL  comment 'long配置1',LONG_PROP_2 BIGINT NULL  comment 'long配置2',DEC_PROP_1 NUMERIC(13,4) NULL  comment '配置描述1',DEC_PROP_2 NUMERIC(13,4) NULL  comment '配置描述2',BOOL_PROP_1 VARCHAR(1) NULL  comment 'bool配置1',BOOL_PROP_2 VARCHAR(1) NULL  comment 'bool配置2',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)
);
CREATE TABLE QRTZ_BLOB_TRIGGERS
(SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',TRIGGER_NAME VARCHAR(200) NOT NULL  comment '触发器名称',TRIGGER_GROUP VARCHAR(200) NOT NULL  comment '触发器组',BLOB_DATA BLOB NULL  comment '数据',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)
);
CREATE TABLE QRTZ_CALENDARS
(SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',CALENDAR_NAME  VARCHAR(200) NOT NULL comment '日程名称',CALENDAR BLOB NOT NULL  comment '日程数据',PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
(SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',TRIGGER_GROUP  VARCHAR(200) NOT NULL  comment '触发器组',PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_FIRED_TRIGGERS
(SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',ENTRY_ID VARCHAR(95) NOT NULL  comment 'entryId',TRIGGER_NAME VARCHAR(200) NOT NULL  comment '触发器名称',TRIGGER_GROUP VARCHAR(200) NOT NULL  comment '触发器组',INSTANCE_NAME VARCHAR(200) NOT NULL  comment '实例名称',FIRED_TIME BIGINT(13) NOT NULL  comment '执行时间',SCHED_TIME BIGINT(13) NOT NULL  comment '定时任务时间',PRIORITY INTEGER NOT NULL  comment '等级',STATE VARCHAR(16) NOT NULL  comment '状态',JOB_NAME VARCHAR(200) NULL  comment 'job名称',JOB_GROUP VARCHAR(200) NULL  comment 'job组',IS_NONCONCURRENT VARCHAR(1) NULL  comment '是否异步',REQUESTS_RECOVERY VARCHAR(1) NULL  comment '是否请求覆盖',PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);
CREATE TABLE QRTZ_SCHEDULER_STATE
(SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',INSTANCE_NAME VARCHAR(200) NOT NULL  comment '实例名称',LAST_CHECKIN_TIME BIGINT(13) NOT NULL  comment '最近检入时间',CHECKIN_INTERVAL BIGINT(13) NOT NULL  comment '检入间隔',PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);
CREATE TABLE QRTZ_LOCKS
(SCHED_NAME VARCHAR(120) NOT NULL  comment '定时任务名称',LOCK_NAME  VARCHAR(40) NOT NULL  comment 'lock名称',PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);
2. 制定一个定时任务

和上面一样的TestJob

@DisallowConcurrentExecution
public class TestJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {System.out.println("TestJob TEST开始");try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("TestJob TEST结束");}
}
3. 写配置文件

MyJobFactory.java:

@Component
public class MyJobFactory extends SpringBeanJobFactory {@Resourceprivate AutowireCapableBeanFactory beanFactory;/*** 这里覆盖了super的createJobInstance方法,对其创建出来的类再进行autowire。*/@Overrideprotected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {Object jobInstance = super.createJobInstance(bundle);beanFactory.autowireBean(jobInstance);return jobInstance;}
}

SchedulerConfig.java:

@Configuration
public class SchedulerConfig {@Resourceprivate MyJobFactory myJobFactory;@Beanpublic SchedulerFactoryBean schedulerFactoryBean(@Qualifier("dataSource") DataSource dataSource) throws IOException {SchedulerFactoryBean factory = new SchedulerFactoryBean();factory.setDataSource(dataSource);factory.setJobFactory(myJobFactory);factory.setStartupDelay(2);return factory;}
}
4. 创建接收和相应实体类

接收实体类CronJobReq.java:

public class CronJobReq {private String group;private String name;private String description;private String cronExpression;@Overridepublic String toString() {final StringBuffer sb = new StringBuffer("CronJobDto{");sb.append("cronExpression='").append(cronExpression).append('\'');sb.append(", group='").append(group).append('\'');sb.append(", name='").append(name).append('\'');sb.append(", description='").append(description).append('\'');sb.append('}');return sb.toString();}public String getGroup() {return group;}public void setGroup(String group) {this.group = group;}public String getCronExpression() {return cronExpression;}public void setCronExpression(String cronExpression) {this.cronExpression = cronExpression;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

响应实体类CronJobResp.java:

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class CronJobResp {private String group;private String name;private String description;private String state;private String cronExpression;@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")private Date nextFireTime;@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")private Date preFireTime;@Overridepublic String toString() {final StringBuffer sb = new StringBuffer("CronJobDto{");sb.append("cronExpression='").append(cronExpression).append('\'');sb.append(", group='").append(group).append('\'');sb.append(", name='").append(name).append('\'');sb.append(", description='").append(description).append('\'');sb.append(", state='").append(state).append('\'');sb.append(", nextFireTime=").append(nextFireTime);sb.append(", preFireTime=").append(preFireTime);sb.append('}');return sb.toString();}public String getGroup() {return group;}public void setGroup(String group) {this.group = group;}public String getCronExpression() {return cronExpression;}public void setCronExpression(String cronExpression) {this.cronExpression = cronExpression;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Date getNextFireTime() {return nextFireTime;}public void setNextFireTime(Date nextFireTime) {this.nextFireTime = nextFireTime;}public Date getPreFireTime() {return preFireTime;}public void setPreFireTime(Date preFireTime) {this.preFireTime = preFireTime;}public String getState() {return state;}public void setState(String state) {this.state = state;}
}
5. 增删改查的controller层接口

任务和quartz通过接口来关联。CronJobReq类的name属性会告诉quartz操作哪个定时任务。

JobController.java:

@RestController
@RequestMapping(value = "/admin/job")
public class JobController {private static Logger LOG = LoggerFactory.getLogger(JobController.class);@Autowiredprivate SchedulerFactoryBean schedulerFactoryBean;@RequestMapping(value = "/run")public CommonResp<Object> run(@RequestBody CronJobReq cronJobReq) throws SchedulerException {String jobClassName = cronJobReq.getName();String jobGroupName = cronJobReq.getGroup();LOG.info("手动执行任务开始:{}, {}", jobClassName, jobGroupName);schedulerFactoryBean.getScheduler().triggerJob(JobKey.jobKey(jobClassName, jobGroupName));return new CommonResp<>();}@RequestMapping(value = "/add")public CommonResp add(@RequestBody CronJobReq cronJobReq) {String jobClassName = cronJobReq.getName();String jobGroupName = cronJobReq.getGroup();String cronExpression = cronJobReq.getCronExpression();String description = cronJobReq.getDescription();LOG.info("创建定时任务开始:{},{},{},{}", jobClassName, jobGroupName, cronExpression, description);CommonResp commonResp = new CommonResp();try {// 通过SchedulerFactory获取一个调度器实例Scheduler sched = schedulerFactoryBean.getScheduler();// 启动调度器sched.start();//构建job信息JobDetail jobDetail = JobBuilder.newJob((Class<? extends Job>) Class.forName(jobClassName)).withIdentity(jobClassName, jobGroupName).build();//表达式调度构建器(即任务执行的时间)CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);//按新的cronExpression表达式构建一个新的triggerCronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobClassName, jobGroupName).withDescription(description).withSchedule(scheduleBuilder).build();sched.scheduleJob(jobDetail, trigger);} catch (SchedulerException e) {LOG.error("创建定时任务失败:" + e);commonResp.setSuccess(false);commonResp.setMessage("创建定时任务失败:调度异常");} catch (ClassNotFoundException e) {LOG.error("创建定时任务失败:" + e);commonResp.setSuccess(false);commonResp.setMessage("创建定时任务失败:任务类不存在");}LOG.info("创建定时任务结束:{}", commonResp);return commonResp;}@RequestMapping(value = "/pause")public CommonResp pause(@RequestBody CronJobReq cronJobReq) {String jobClassName = cronJobReq.getName();String jobGroupName = cronJobReq.getGroup();LOG.info("暂停定时任务开始:{},{}", jobClassName, jobGroupName);CommonResp commonResp = new CommonResp();try {Scheduler sched = schedulerFactoryBean.getScheduler();sched.pauseJob(JobKey.jobKey(jobClassName, jobGroupName));} catch (SchedulerException e) {LOG.error("暂停定时任务失败:" + e);commonResp.setSuccess(false);commonResp.setMessage("暂停定时任务失败:调度异常");}LOG.info("暂停定时任务结束:{}", commonResp);return commonResp;}@RequestMapping(value = "/resume")public CommonResp resume(@RequestBody CronJobReq cronJobReq) {String jobClassName = cronJobReq.getName();String jobGroupName = cronJobReq.getGroup();LOG.info("重启定时任务开始:{},{}", jobClassName, jobGroupName);CommonResp commonResp = new CommonResp();try {Scheduler sched = schedulerFactoryBean.getScheduler();sched.resumeJob(JobKey.jobKey(jobClassName, jobGroupName));} catch (SchedulerException e) {LOG.error("重启定时任务失败:" + e);commonResp.setSuccess(false);commonResp.setMessage("重启定时任务失败:调度异常");}LOG.info("重启定时任务结束:{}", commonResp);return commonResp;}@RequestMapping(value = "/reschedule")public CommonResp reschedule(@RequestBody CronJobReq cronJobReq) {String jobClassName = cronJobReq.getName();String jobGroupName = cronJobReq.getGroup();String cronExpression = cronJobReq.getCronExpression();String description = cronJobReq.getDescription();LOG.info("更新定时任务开始:{},{},{},{}", jobClassName, jobGroupName, cronExpression, description);CommonResp commonResp = new CommonResp();try {Scheduler scheduler = schedulerFactoryBean.getScheduler();TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobGroupName);// 表达式调度构建器CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);CronTriggerImpl trigger1 = (CronTriggerImpl) scheduler.getTrigger(triggerKey);trigger1.setStartTime(new Date()); // 重新设置开始时间CronTrigger trigger = trigger1;// 按新的cronExpression表达式重新构建triggertrigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withDescription(description).withSchedule(scheduleBuilder).build();// 按新的trigger重新设置job执行scheduler.rescheduleJob(triggerKey, trigger);} catch (Exception e) {LOG.error("更新定时任务失败:" + e);commonResp.setSuccess(false);commonResp.setMessage("更新定时任务失败:调度异常");}LOG.info("更新定时任务结束:{}", commonResp);return commonResp;}@RequestMapping(value = "/delete")public CommonResp delete(@RequestBody CronJobReq cronJobReq) {String jobClassName = cronJobReq.getName();String jobGroupName = cronJobReq.getGroup();LOG.info("删除定时任务开始:{},{}", jobClassName, jobGroupName);CommonResp commonResp = new CommonResp();try {Scheduler scheduler = schedulerFactoryBean.getScheduler();scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName, jobGroupName));scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName, jobGroupName));scheduler.deleteJob(JobKey.jobKey(jobClassName, jobGroupName));} catch (SchedulerException e) {LOG.error("删除定时任务失败:" + e);commonResp.setSuccess(false);commonResp.setMessage("删除定时任务失败:调度异常");}LOG.info("删除定时任务结束:{}", commonResp);return commonResp;}@RequestMapping(value="/query")public CommonResp query() {LOG.info("查看所有定时任务开始");CommonResp commonResp = new CommonResp();List<CronJobResp> cronJobDtoList = new ArrayList();try {Scheduler scheduler = schedulerFactoryBean.getScheduler();for (String groupName : scheduler.getJobGroupNames()) {for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {CronJobResp cronJobResp = new CronJobResp();cronJobResp.setName(jobKey.getName());cronJobResp.setGroup(jobKey.getGroup());//get job's triggerList<Trigger> triggers = (List<Trigger>) scheduler.getTriggersOfJob(jobKey);CronTrigger cronTrigger = (CronTrigger) triggers.get(0);cronJobResp.setNextFireTime(cronTrigger.getNextFireTime());cronJobResp.setPreFireTime(cronTrigger.getPreviousFireTime());cronJobResp.setCronExpression(cronTrigger.getCronExpression());cronJobResp.setDescription(cronTrigger.getDescription());Trigger.TriggerState triggerState = scheduler.getTriggerState(cronTrigger.getKey());cronJobResp.setState(triggerState.name());cronJobDtoList.add(cronJobResp);}}} catch (SchedulerException e) {LOG.error("查看定时任务失败:" + e);commonResp.setSuccess(false);commonResp.setMessage("查看定时任务失败:调度异常");}commonResp.setContent(cronJobDtoList);LOG.info("查看定时任务结束:{}", commonResp);return commonResp;}}
6. 编写接口测试代码

test.http:

POST http://localhost:8000/batch/admin/job/add
Content-Type: application/json{"name": "com.mystudy.train.batch.job.TestJob","jobGroupName": "default","cronExpression": "*/2 * * * * ?","desc": "test job"
}###GET http://localhost:8000/batch/admin/job/query###POST http://localhost:8000/batch/admin/job/pause
Content-Type: application/json{"name": "com.mystudy.train.batch.job.TestJob","jobGroupName": "default"
}###POST http://localhost:8000/batch/admin/job/resume
Content-Type: application/json{"name": "com.mystudy.train.batch.job.TestJob","jobGroupName": "default"
}###POST http://localhost:8000/batch/admin/job/reschedule
Content-Type: application/json{
"name": "com.mystudy.train.batch.job.TestJob",
"jobGroupName": "default",
"cronExpression": "*/5 * * * * ?",
"desc": "test job"
}###POST http://localhost:8000/batch/admin/job/delete
Content-Type: application/json{
"name": "com.mystudy.train.batch.job.TestJob",
"jobGroupName": "default"
}###

相关文章:

SpringBoot实现定时任务,使用自带的定时任务以及调度框架quartz的配置使用

SpringBoot实现定时任务&#xff0c;使用自带的定时任务以及调度框架quartz的配置使用 文章目录 SpringBoot实现定时任务&#xff0c;使用自带的定时任务以及调度框架quartz的配置使用一. 使用SpringBoot自带的定时任务&#xff08;适用于小型应用&#xff09;二. 使用调度框架…...

java上传图片功能实现

1 MinIO核心概念 下面介绍MinIO中的几个核心概念&#xff0c;这些概念在所有的对象存储服务中也都是通用的。 对象&#xff08;Object&#xff09; 对象是实际的数据单元&#xff0c;例如我们上传的一个图片。 存储桶&#xff08;Bucket&#xff09; 存储桶是用于组织对象的命…...

73,【5】BUUCTF WEB [网鼎杯 2020 玄武组]SSRFMe(未解出)

进入靶场 又是代码又是代码又是代码又是代码又是代码又是代码又是代码又是代码又是代码又是代码又是代码又是代码又是代码又是代码 <?php // 检查 URL 是否为内部 IP 地址 function check_inner_ip($url) {// 使用正则表达式检查 URL 格式是否以 http、https、gopher 或 d…...

【FreeRTOS 教程 一】任务结构体及其基础创建使用

目录 一、任务与协程的区别&#xff1a; &#xff08;1&#xff09;任务的特点&#xff1a; &#xff08;2&#xff09;协程的特点&#xff1a; &#xff08;3&#xff09;总结&#xff1a; 二、任务概述 &#xff1a; &#xff08;1&#xff09;任务状态&#xff1a; &…...

深入剖析 JVM 内存模型

前言&#xff1a; 下面分别介绍了新生代和老年代的不同收集器及其相关子类型&#xff0c;并附有示例代码和说明&#xff0c;感兴趣的朋友可以参考一下。 简介&#xff1a; 在 Java 虚拟机&#xff08;JVM&#xff09;的世界里&#xff0c;内存模型是其核心架构之一&#xff0…...

解决DeepSeek-R1模型在Cursor中使用报错的问题

在使用Cursor时&#xff0c;如果你尝试调用DeepSeek-R1模型&#xff0c;可能会遇到以下报错信息&#xff1a; {"error": {"message": "deepseek-reasoner does not support successive user or assistant messages (messages[1] and messages[2] in …...

ASP.NET Core 6.0 如何处理丢失的 Startup.cs 文件

介绍 .NET 6.0 已经发布&#xff0c;ASP.NET Core 6.0 也已发布。其中有不少变化让很多人感到困惑。例如&#xff0c;“谁动了我的奶酪”&#xff0c;它在哪里Startup.cs&#xff1f;在这篇文章中&#xff0c;我将深入研究这个问题&#xff0c;看看它移动到了哪里以及其他变化。…...

Java如何向http/https接口发出请求

用Java发送web请求所用到的包都在java.net下&#xff0c;在具体使用时可以用如下代码&#xff0c;你可以把它封装成一个工具类 import javax.net.ssl.*; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Outpu…...

数据分析 变异系数

目录 变异系数的应用场景包括&#xff1a; 特点&#xff1a; 注意事项&#xff1a; np.nanvar——方差&#xff0c;np.sanstd标准差 简单来讲就是平均值/标准差 变异系数&#xff08;Coefficient of Variation, CV&#xff09;是一种相对量的变异指标&#xff0c;常用于衡…...

利用免费GIS工具箱实现高斯泼溅切片,将 PLY 格式转换为 3dtiles

在地理信息系统&#xff08;GIS&#xff09;和三维数据处理领域&#xff0c;不同数据格式有其独特应用场景与优势。PLY&#xff08;Polygon File Format&#xff09;格式常用于存储多边形网格数据&#xff0c;而 3DTiles 格式在 Web 端三维场景展示等方面表现出色。将 PLY 格式…...

面试-二维数组

应用 快递业务有N个站点&#xff0c;1<N<10000&#xff1b;站点0、站点1可达&#xff0c;记作0-1&#xff1b;如果0-1、1-2&#xff0c;则站点0、站点2可达&#xff0c;记作0-2&#xff1b;s[i][j]1表示i-j可达&#xff0c;反之s[i][j]0表示i-j不可达&#xff1b;s[i][j…...

如何使用 findIndex() 方法查找数组中的第一个匹配元素的索引?

使用 findIndex() 方法查找数组中第一个匹配元素的索引 目录 简介findIndex() 方法概述如何使用 findIndex() 查找第一个匹配元素的索引 基本用法使用箭头函数和回调函数 实际项目中的代码示例 示例 1&#xff1a;查找第一个符合条件的用户索引示例 2&#xff1a;查找第一个符…...

5. 马科维茨资产组合模型+政策意图AI金融智能体(Qwen-Max)增强方案(理论+Python实战)

目录 0. 承前1. AI金融智能体1.1 What is AI金融智能体1.2 Why is AI金融智能体1.3 How to AI金融智能体 2. 数据要素&计算流程2.1 参数集设置2.2 数据获取&预处理2.3 收益率计算2.4 因子构建与预期收益率计算2.5 协方差矩阵计算2.6 投资组合优化2.7 持仓筛选2.8 AI金融…...

Centos类型服务器等保测评整/etc/pam.d/system-auth

修改服务器配置文件/etc/pam.d/system-auth&#xff0c;但是&#xff0c;把一下配置放在password的配置第一行才会生效 执行命令&#xff1a;配置口令要求&#xff1a;大小写字母、数字、特殊字符组合、至少8位&#xff0c;包括强制设置root口令&#xff01; sed -i 14a pas…...

从工厂到桌面:3D打印制造潮玩手办

传统潮玩手办的制造过程复杂且成本高昂。从设计到成品&#xff0c;需要经过多道工序&#xff0c;包括手工建模、模具制作、注塑成型等。这一过程不仅耗时耗力&#xff0c;而且难以满足消费者日益增长的个性化需求。此外&#xff0c;传统制造方式对于小批量生产或定制化产品的经…...

Java高频面试之SE-16

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本牛马baby今天又来了&#xff01;哈哈哈哈哈嗝&#x1f436; Java中异常的处理方式有哪些&#xff1f; 在 Java 中&#xff0c;异常的处理方式主要有以下几种&#xff1a; 1. 使用 try-catch 语句 …...

三分钟简单了解一些HTML的标签和语法_01

1.图片建议建立一个文件夹如下图所示 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"keywords"><title>魔神羽落</title><style>.testone{background-color: #ff53e…...

缓存-Redis-数据结构-redis哪些数据结构是跳表实现的?

在 Redis 中&#xff0c;跳表&#xff08;Skip List&#xff09; 被用于实现 有序集合&#xff08;Sorted Set&#xff09; 数据结构。以下是对此实现的详细解释&#xff1a; Redis中的有序集合&#xff08;Sorted Set&#xff09; 有序集合&#xff08;Sorted Set&#xff0…...

Linux 系统错误处理简介

Linux 系统错误处理简介 1. errno&#xff1a;错误代码的载体2. strerror()&#xff1a;错误信息的翻译官3. perror()&#xff1a;便捷的错误信息输出4. 系统调用与库函数的区别5. 错误处理的最佳实践 在 C/C 程序开发中&#xff0c;我们经常需要处理各种错误情况 Linux 系统提…...

逐笔成交逐笔委托Level2高频数据下载和分析:20250122

逐笔委托逐笔成交下载 链接: https://pan.baidu.com/s/1WP6eGLip3gAbt7yFKg4XqA?pwd7qtx 提取码: 7qtx Level2逐笔成交逐笔委托数据分享下载 通过Level2逐笔成交和逐笔委托这种每一笔的毫秒级别的数据可以分析出很多有用的点&#xff0c;包括主力意图&#xff0c;虚假动作&…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)

引言 在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已成为技术领域的焦点。从智能写作到代码生成&#xff0c;LLM 的应用场景不断扩展&#xff0c;深刻改变了我们的工作和生活方式。然而&#xff0c;理解这些模型的内部…...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...

通过MicroSip配置自己的freeswitch服务器进行调试记录

之前用docker安装的freeswitch的&#xff0c;启动是正常的&#xff0c; 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...

数据结构第5章:树和二叉树完全指南(自整理详细图文笔记)

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 原创笔记&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 上一篇&#xff1a;《数据结构第4章 数组和广义表》…...