Spring Boot整合Quartz实现定时任务

源码已上传至 GitHub:spring-boot-quartz

添加依赖

编辑文件 pom.xml:

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

添加配置

编辑配置文件 application.yml,添加以下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
spring:
quartz:
# 采用数据库存储方式
job-store-type: jdbc
jdbc:
# 不重新创建数据表
initialize-schema: never
properties:
org:
quartz:
scheduler:
instanceId: AUTO
jobStore:
class: org.quartz.impl.jdbcjobstore.JobStoreTX
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# 数据表前缀
tablePrefix: qrtz_
# 连接池
threadPool:
class: org.quartz.simpl.SimpleThreadPool
threadCount: 10
threadPriority: 5
threadsInheritContextClassLoaderOfInitializingThread: true

创建数据表供 Quartz 使用

sql 语句可在 jdbcjobstore 找到,Quartz 提供了 tables_mysql_innodb.sql

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#
# 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);

执行完 sql 语句可以在数据库中看到以下11个表:

Quartz表

使用

创建 ScheduleJobDTO

新建类 ScheduleJobDTO,用于封装任务信息返回到前端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Data
@Accessors(chain = true)
public class ScheduleJobDTO {

private String jobName;
private String jobGroup;
private String jobDescription;
private Integer triggerStatus;
private String triggerStatusName;

/**
* 额外的数据
*/
private List<Map<String, Object>> jobMapData;
}

创建 ScheduleJobParam

新建类 ScheduleJobParam,封装请求参数,用于接收前端传递过来的参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Getter
@Setter
@ToString
@Accessors(chain = true)
public class ScheduleJobParam {

@NotBlank(message = "任务名称不能为空")
private String jobName;

@NotBlank(message = "任务分组不能为空")
private String jobGroup;

@NotBlank(message = "执行类名不能为空")
private String jobClass;

@NotBlank(message = "cron表达式不能为空")
private String cronExpression;

private String jobDescription;

/**
* 额外的数据
*/
private List<Map<String, Object>> jobMapData;
}

创建 IJobService

新建类 IJobService ,用于定义任务的获取、新增、停止、恢复、删除等接口。

IJobService.java 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public interface IJobService {

/**
* 查询所有任务列表
* @return
*/
List<ScheduleJobDTO> listAllJob();

/**
* 获取正在运行的任务列表
* @return
*/
List<ScheduleJobDTO> listRunningJob();

/**
* 新增任务
* @param job job
* @return
*/
boolean addJob(ScheduleJobParam job);

/**
* 执行 job
* @param jobName jobName
* @param jobGroupName jobGroupName
* @return
*/
boolean triggerJob(String jobName, String jobGroupName);

/**
* 启动所有定时任务
* @return
*/
boolean startJobs();

/**
* 删除任务
* @param jobName jobName
* @param jobGroupName jobGroupName
* @return
*/
boolean deleteJob(String jobName, String jobGroupName);

/**
* 暂停任务
* @param jobName jobName
* @param jobGroupName jobGroupName
* @return
*/
boolean pauseJob(String jobName, String jobGroupName);

/**
* 恢复任务
* @param jobName jobName
* @param jobGroupName jobGroupName
* @return
*/
boolean resumeJob(String jobName, String jobGroupName);
}

创建 JobServiceImpl

新建类 JobServiceImpl,用于实现 IJobService接口,实现任务的获取、新增、停止、恢复、删除等功能。

JobServiceImpl.java 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
@Service("jobService")
@Slf4j
public class JobServiceImpl implements IJobService {

public static final String TRIGGER_IDENTITY_PREFIX = "trigger_";

/**
* 调度器
*/
private final Scheduler scheduler;

@Autowired
public JobServiceImpl(Scheduler scheduler) {
this.scheduler = scheduler;
}

@Override
public List<ScheduleJobDTO> listAllJob() {
List<ScheduleJobDTO> result = new ArrayList<>();
try {
GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
for (JobKey jobKey : jobKeys) {
List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
for (Trigger trigger : triggers) {
ScheduleJobDTO scheduleJob = new ScheduleJobDTO();
scheduleJob.setJobName(jobKey.getName())
.setJobGroup(jobKey.getGroup())
.setJobDescription(trigger.getDescription())
.setTriggerStatus(scheduler.getTriggerState(trigger.getKey()).ordinal())
.setTriggerStatusName(scheduler.getTriggerState(trigger.getKey()).name());

result.add(scheduleJob);
}
}
} catch (SchedulerException e) {
log.error("获取所有任务列表失败,错误:{}", e.getMessage());
}
return result;
}

@Override
public List<ScheduleJobDTO> listRunningJob() {
List<ScheduleJobDTO> result = new ArrayList<>();
try {
// 获取列表
List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();

result = getJobListData(executingJobs);

} catch (SchedulerException e) {
log.error("获取运行任务列表失败,错误:{}", e.getMessage());
}
return result;
}

@Override
public boolean addJob(ScheduleJobParam jobParam) {
try {
// 加载执行类
Class<? extends Job> clazz = (Class<? extends Job>) Class.forName(jobParam.getJobClass());
clazz.newInstance();

// 1. 创建 job
JobDetail job = JobBuilder.newJob(clazz)
.withIdentity(jobParam.getJobName(), jobParam.getJobGroup())
.withDescription(jobParam.getJobDescription())
.build();

JobDataMap jobDataMap = job.getJobDataMap();

List<Map<String, Object>> data = jobParam.getJobMapData();
if (data != null && data.size() > 0) {
data.forEach(jobDataItem -> {
jobDataItem.keySet().forEach((key) -> {
jobDataMap.put(key, jobDataItem.get(key));
});
});
}

// 配置cron运行规则,即执行时间
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(jobParam.getCronExpression());

// 2. 创建 Trigger
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(TRIGGER_IDENTITY_PREFIX + jobParam.getJobName(), jobParam.getJobGroup())
.startNow()
.withSchedule(cronScheduleBuilder)
.build();

// 3. 注册任务和定时器
scheduler.scheduleJob(job, trigger);
scheduler.start();
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException | SchedulerException e) {
log.error("添加任务 {} 失败,错误: {}", jobParam.getJobName(), e.getMessage());
return false;
}
return true;
}

@Override
public boolean triggerJob(String jobName, String jobGroupName) {
JobKey key = new JobKey(jobName, jobGroupName);
try {
scheduler.triggerJob(key);
} catch (SchedulerException e) {
log.error("任务 {} 触发失败", jobName);
return false;
}
return true;
}

@Override
public boolean startJobs() {
try {
scheduler.start();
} catch (SchedulerException e) {
log.error("启动所有任务失败:", e);
return false;
}
return true;
}

@Override
public boolean deleteJob(String jobName, String jobGroupName) {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
try {
// 停止触发器
scheduler.pauseTrigger(triggerKey);
// 删除触发器
scheduler.unscheduleJob(triggerKey);
// 删除任务
scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));
} catch (SchedulerException e) {
log.error("删除任务 {} 失败,错误:{}", jobName, e.getMessage());
return false;
}
return true;
}

@Override
public boolean pauseJob(String jobName, String jobGroupName) {
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
try {
scheduler.pauseJob(jobKey);
} catch (SchedulerException e) {
log.error("停止任务 {} 失败,错误:{}", jobName, e.getMessage());
return false;
}
return true;
}

@Override
public boolean resumeJob(String jobName, String jobGroupName) {
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
try {
scheduler.resumeJob(jobKey);
} catch (SchedulerException e) {
log.error("恢复任务 {} 失败,错误:{}", jobName, e.getMessage());
return false;
}
return true;
}

private List<ScheduleJobDTO> getJobListData(List<JobExecutionContext> executingJobs) {
List<ScheduleJobDTO> result = new ArrayList<>();
try {
for (JobExecutionContext jobItem : executingJobs) {
ScheduleJobDTO scheduleJobItem = getJobDataByJobExecutionContext(jobItem);
result.add(scheduleJobItem);
}
} catch (SchedulerException e) {
log.error("获取任务状态失败,错误:{}", e.getMessage());
}
return result;
}

/**
* 从 JobExecutionContext 中解析获取数据
* @param jobContext JobExecutionContext
* @return
* @throws SchedulerException
*/
private ScheduleJobDTO getJobDataByJobExecutionContext(JobExecutionContext jobContext) throws SchedulerException {
JobDetail jobDetail = jobContext.getJobDetail();
JobKey jobKey = jobDetail.getKey();
Trigger trigger = jobContext.getTrigger();
// 封装 ScheduleJobDTO 返回,想要获取更多的数据(如 JobDataMap)可自行添加
ScheduleJobDTO scheduleJob = new ScheduleJobDTO();
scheduleJob.setJobName(jobKey.getName())
.setJobGroup(jobKey.getGroup())
.setJobDescription(trigger.getDescription())
.setTriggerStatus(scheduler.getTriggerState(trigger.getKey()).ordinal())
.setTriggerStatusName(scheduler.getTriggerState(trigger.getKey()).name());
return scheduleJob;
}
}

创建任务类

新建两个任务类(实现 org.quartz.Job 接口),用于定时任务执行,我这建了 EatJobDrinkJob

EatJob 内容如下:

1
2
3
4
5
6
7
8
9
public class EatJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) {
// 通过 jobExecutionContext 可获取到任务的相关信息
// JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(new Date()) + " 正在吃饭......");
}
}

DrinkJob 内容如下:

1
2
3
4
5
6
7
8
public class DrinkJob implements Job {

@Override
public void execute(JobExecutionContext jobExecutionContext) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(new Date()) + " 正在喝东西......");
}
}

创建 controller

新建 controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@RestController
@RequestMapping("/jobs")
public class MainController {

private final IJobService jobService;

@Autowired
public MainController(IJobService jobService) {
this.jobService = jobService;
}

@GetMapping("/all")
public JsonResult<List<ScheduleJobDTO>> queryAllJobs() {
List<ScheduleJobDTO> list = jobService.listAllJob();
return JsonResult.ok(list);
}

@GetMapping("/running")
public JsonResult<List<ScheduleJobDTO>> queryRunningJobs() {
List<ScheduleJobDTO> list = jobService.listRunningJob();
return JsonResult.ok(list);
}

@PostMapping("")
public JsonResult<String> addJob(@RequestBody @Valid ScheduleJobParam param) {
boolean flag = jobService.addJob(param);
return flag ? JsonResult.ok() : JsonResult.error("添加任务失败");
}

@PutMapping("/pause")
public JsonResult<String> pauseJob(@RequestBody @Valid ScheduleJobParam param) {
boolean flag = jobService.pauseJob(param.getJobName(), param.getJobGroup());
return flag ? JsonResult.ok() : JsonResult.error("停止任务失败");
}

@PutMapping("/resume")
public JsonResult<String> resumeJob(@RequestBody @Valid ScheduleJobParam param) {
boolean flag = jobService.resumeJob(param.getJobName(), param.getJobGroup());
return flag ? JsonResult.ok() : JsonResult.error("停止任务失败");
}

@DeleteMapping("")
public JsonResult<String> deleteJob(@RequestBody @Valid ScheduleJobParam param) {
boolean flag = jobService.deleteJob(param.getJobName(), param.getJobGroup());
return flag ? JsonResult.ok() : JsonResult.error("删除任务失败");
}
}

测试

启动项目,使用 Postman 发送请求测试:

  1. 获取所有任务列表,请求 http://127.0.0.1:8077/jobs/all,由于没有任务,所以返回为空;

获取列表结果

  1. 新增任务,使用 POST 请求 http://127.0.0.1:8077/jobs,请求参数如下;其中 cron 表达式可使用 https://cron.qqe2.com/ 这个工具生成;

添加任务

此时,再去请求获取任务列表,成功返回列表:

获取到任务列表

  1. 停止任务,使用 PUT 请求 http://127.0.0.1:8077/jobs/pause,参数参考添加参数,发现控制台已不输出信息;

  2. 恢复任务,使用 PUT 请求 http://127.0.0.1:8077/jobs/resume,参数参考添加参数,发现控制台又重新输出信息,说明任务已成功恢复执行;

  3. 删除任务,使用 DELETE 请求 http://127.0.0.1:8077/jobs,参数参考添加参数,操作完成后控制台不再输出信息,再次请求获取任务列表,发现返回空列表了,说明删除任务成功。

删除任务

至此,Spring Boot 整合 Quartz 完成。

GitHub:spring-boot-quartz