springboot实现xxl-job简单调用
需要提前配置 xxl-job 的数据库 在 \xxl-job-3.1.0\xxl-job-admin\src\main\resources\application.properties
#spring.datasource.url=jdbc:mysql://127.0.0.1:6003/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
#spring.datasource.username=root
#spring.datasource.password=JAmz5wFC
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
springboot
<!-- Job 相关 -->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
spring:
application:
name: xxl-job-combat-project
xxl:
job:
# 调度中心配置
admin:
addresses: http://127.0.0.1:58080/xxl-job-admin # 调度中心地址
# 执行器配置
executor:
appname: ${spring.application.name} # 执行器名称,必须全局唯一,在调度中心配置时使用
logpath: ./xxl-job/log # 任务日志存放路径
logretentiondays: 30 # 日志保留天数
# 通信令牌
accessToken: QMLnVWvRCkswUQ6CrT1xmJ86i # 必须与调度中心配置的 accessToken 一致
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@Slf4j
public class XxlJobConfig {
@Value("${xxl.job.admin.addresses:http://127.0.0.1:8080/xxl-job-admin}")
private String adminAddresses;
@Value("${xxl.job.accessToken}")
private String accessToken;
@Value("${xxl.job.executor.appname}")
private String appname;
@Value("${xxl.job.executor.logpath}")
private String logPath;
@Value("${xxl.job.executor.logretentiondays}")
private int logRetentionDays;
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
log.info(">>>>>>>>>>> xxl-job config init.");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(appname);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
}
简单的 bean 模式
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.stereotype.Component;
@Component
public class AlarmClockHandler {
@XxlJob("wakeUpTheAlarmClock")
public void wakeUpTheAlarmClock() throws Exception {
XxlJobHelper.log("要起床了哦"); // 在调度中心可以看到这个日志
}
}
2025-06-17 11:14:03 [com.xxl.job.core.thread.JobThread#run]-[133]-[xxl-job, JobThread-5-1750130043336]
----------- xxl-job job execute start -----------
----------- Param:
2025-06-17 11:14:03 [com.runbrick.job.handler.AlarmClockHandler#wakeUpTheAlarmClock]-[14]-[xxl-job, JobThread-5-1750130043336] 要起床了哦
2025-06-17 11:14:03 [com.xxl.job.core.thread.JobThread#run]-[179]-[xxl-job, JobThread-5-1750130043336]
----------- xxl-job job execute end(finish) -----------
----------- Result: handleCode=200, handleMsg = null
2025-06-17 11:14:03 [com.xxl.job.core.thread.TriggerCallbackThread#callbackLog]-[197]-[xxl-job, executor TriggerCallbackThread]
----------- xxl-job job callback finish.
[Load Log Finish]
简单的 bean 传参模式
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class AlarmClockHandler {
@XxlJob("wakeUpTheAlarmClockParam")
public void wakeUpTheAlarmClockParam() throws Exception {
String param = XxlJobHelper.getJobParam();
// 提取 param 中的 name
Map<String, Object> paramMap = objectMapper.readValue(param, new TypeReference<Map<String, Object>>() {});
XxlJobHelper.log("{}该起床了哦", paramMap.get("name")); // 在调度中心可以看到这个日志
}
}
{"name":"张三"}
2025-06-17 11:34:01 [com.xxl.job.core.thread.JobThread#run]-[133]-[xxl-job, JobThread-6-1750131241860]
----------- xxl-job job execute start -----------
----------- Param:{"name":"张三"}
2025-06-17 11:34:01 [com.runbrick.job.handler.AlarmClockHandler#wakeUpTheAlarmClockParam]-[30]-[xxl-job, JobThread-6-1750131241860] 张三该起床了哦
2025-06-17 11:34:01 [com.xxl.job.core.thread.JobThread#run]-[179]-[xxl-job, JobThread-6-1750131241860]
----------- xxl-job job execute end(finish) -----------
----------- Result: handleCode=200, handleMsg = null
2025-06-17 11:34:01 [com.xxl.job.core.thread.TriggerCallbackThread#callbackLog]-[197]-[xxl-job, executor TriggerCallbackThread]
----------- xxl-job job callback finish.
[Load Log Finish]
那怎么实现xxl-job的动态创建任务呢?这时候我们最简单的办法是修改源代码,将xxl-job 里面的 JobInfoController
复制一个改成 SimpleJobInfoController
将里面的需要用到的方法加上一个注解
@PermissionLimit(limit = false)
这样在调用的时候就不用登录了,然后将里面的方法修改一下,成为下面的内容
package com.xxl.job.admin.controller;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.thread.JobScheduleHelper;
import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.dao.XxlJobGroupDao;
import com.xxl.job.admin.service.XxlJobService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.util.DateUtil;
import jakarta.annotation.Resource;
/**
* index controller
*
* @author xuxueli 2015-12-19 16:13:16
*/
@Controller
@RequestMapping("/simple/jobinfo")
public class SimpleJobInfoController {
private static Logger logger = LoggerFactory.getLogger(SimpleJobInfoController.class);
@Resource
private XxlJobGroupDao xxlJobGroupDao;
@Resource
private XxlJobService xxlJobService;
@RequestMapping("/remove")
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> remove(@RequestParam("id") int id) {
return xxlJobService.remove(id);
}
@RequestMapping("/stop")
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> pause(@RequestParam("id") int id) {
return xxlJobService.stop(id);
}
@RequestMapping("/trigger")
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> triggerJob(@RequestBody XxlJobInfo jobInfo) {
if (jobInfo.getId() == 0) {
return ReturnT.FAIL;
}
if (jobInfo.getExecutorParam() == null) {
jobInfo.setExecutorParam("");
}
JobTriggerPoolHelper.trigger(jobInfo.getId(), TriggerTypeEnum.MANUAL, -1, null, jobInfo.getExecutorParam(),
null);
return ReturnT.SUCCESS;
}
@RequestMapping("/add")
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> add(XxlJobInfo jobInfo) {
return xxlJobService.add(jobInfo, null);
}
@RequestMapping("/update")
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> update(XxlJobInfo jobInfo) {
return xxlJobService.update(jobInfo, null);
}
@RequestMapping("/start")
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> start(@RequestParam("id") int id) {
return xxlJobService.start(id);
}
@RequestMapping("/nextTriggerTime")
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<List<String>> nextTriggerTime(@RequestBody XxlJobInfo jobInfo) {
XxlJobInfo paramXxlJobInfo = new XxlJobInfo();
paramXxlJobInfo.setScheduleType(jobInfo.getScheduleType());
paramXxlJobInfo.setScheduleConf(jobInfo.getScheduleConf());
List<String> result = new ArrayList<>();
try {
Date lastTime = new Date();
for (int i = 0; i < 5; i++) {
lastTime = JobScheduleHelper.generateNextValidTime(paramXxlJobInfo, lastTime);
if (lastTime != null) {
result.add(DateUtil.formatDateTime(lastTime));
} else {
break;
}
}
} catch (Exception e) {
logger.error("nextTriggerTime error. jobInfo = {}", jobInfo, e);
return new ReturnT<List<String>>(ReturnT.FAIL_CODE,
(I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")) + e.getMessage());
}
return new ReturnT<List<String>>(result);
}
}
这样在调用的时候彻底不用登录了,不过你要搞定这个安全问题。