diff --git a/pom.xml b/pom.xml
index 1ee06fb24..9f1641dd0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,165 +2,165 @@
- 4.0.0
+ 4.0.0
- com.xkcoding
- spring-boot-demo
- 1.0.0-SNAPSHOT
-
- spring-boot-demo-helloworld
- spring-boot-demo-properties
- spring-boot-demo-actuator
- spring-boot-demo-admin-client
- spring-boot-demo-admin-server
- spring-boot-demo-logback
- spring-boot-demo-log-aop
- spring-boot-demo-exception-handler
- spring-boot-demo-template-freemarker
- spring-boot-demo-template-thymeleaf
- spring-boot-demo-template-beetl
- spring-boot-demo-template-enjoy
- spring-boot-demo-orm-jdbctemplate
- spring-boot-demo-orm-jpa
- spring-boot-demo-orm-mybatis
- spring-boot-demo-orm-mybatis-mapper-page
- spring-boot-demo-orm-mybatis-plus
- spring-boot-demo-orm-beetlsql
- spring-boot-demo-upload
- spring-boot-demo-cache-redis
- spring-boot-demo-cache-ehcache
- spring-boot-demo-email
- spring-boot-demo-task
- spring-boot-demo-task-quartz
- spring-boot-demo-swagger
- spring-boot-demo-swagger-beauty
- spring-boot-demo-rbac-security
- spring-boot-demo-rbac-shiro
- spring-boot-demo-session
- spring-boot-demo-oauth
- spring-boot-demo-social
- spring-boot-demo-zookeeper
- spring-boot-demo-mq-rabbitmq
- spring-boot-demo-mq-rocketmq
- spring-boot-demo-mq-kafka
- spring-boot-demo-websocket
- spring-boot-demo-websocket-socketio
- spring-boot-demo-ureport2
- spring-boot-demo-uflo
- spring-boot-demo-urule
- spring-boot-demo-activiti
- spring-boot-demo-async
- spring-boot-demo-dubbo
- spring-boot-demo-war
- spring-boot-demo-elasticsearch
- spring-boot-demo-mongodb
- spring-boot-demo-neo4j
- spring-boot-demo-docker
- spring-boot-demo-multi-datasource-jpa
- spring-boot-demo-multi-datasource-mybatis
- spring-boot-demo-sharding-jdbc
- spring-boot-demo-tio
- spring-boot-demo-codegen
- spring-boot-demo-graylog
- spring-boot-demo-task-xxl-job
-
- pom
+ com.xkcoding
+ spring-boot-demo
+ 1.0.0-SNAPSHOT
+
+ spring-boot-demo-helloworld
+ spring-boot-demo-properties
+ spring-boot-demo-actuator
+ spring-boot-demo-admin-client
+ spring-boot-demo-admin-server
+ spring-boot-demo-logback
+ spring-boot-demo-log-aop
+ spring-boot-demo-exception-handler
+ spring-boot-demo-template-freemarker
+ spring-boot-demo-template-thymeleaf
+ spring-boot-demo-template-beetl
+ spring-boot-demo-template-enjoy
+ spring-boot-demo-orm-jdbctemplate
+ spring-boot-demo-orm-jpa
+ spring-boot-demo-orm-mybatis
+ spring-boot-demo-orm-mybatis-mapper-page
+ spring-boot-demo-orm-mybatis-plus
+ spring-boot-demo-orm-beetlsql
+ spring-boot-demo-upload
+ spring-boot-demo-cache-redis
+ spring-boot-demo-cache-ehcache
+ spring-boot-demo-email
+ spring-boot-demo-task
+ spring-boot-demo-task-quartz
+ spring-boot-demo-task-xxl-job
+ spring-boot-demo-swagger
+ spring-boot-demo-swagger-beauty
+ spring-boot-demo-rbac-security
+ spring-boot-demo-rbac-shiro
+ spring-boot-demo-session
+ spring-boot-demo-oauth
+ spring-boot-demo-social
+ spring-boot-demo-zookeeper
+ spring-boot-demo-mq-rabbitmq
+ spring-boot-demo-mq-rocketmq
+ spring-boot-demo-mq-kafka
+ spring-boot-demo-websocket
+ spring-boot-demo-websocket-socketio
+ spring-boot-demo-ureport2
+ spring-boot-demo-uflo
+ spring-boot-demo-urule
+ spring-boot-demo-activiti
+ spring-boot-demo-async
+ spring-boot-demo-dubbo
+ spring-boot-demo-war
+ spring-boot-demo-elasticsearch
+ spring-boot-demo-mongodb
+ spring-boot-demo-neo4j
+ spring-boot-demo-docker
+ spring-boot-demo-multi-datasource-jpa
+ spring-boot-demo-multi-datasource-mybatis
+ spring-boot-demo-sharding-jdbc
+ spring-boot-demo-tio
+ spring-boot-demo-codegen
+ spring-boot-demo-graylog
+
+ pom
- spring-boot-demo
- http://xkcoding.com
+ spring-boot-demo
+ http://xkcoding.com
-
- UTF-8
- UTF-8
- 1.8
- 1.8
- 1.8
- 2.1.0.RELEASE
- 8.0.12
- 4.5.1
- 27.0.1-jre
- 1.20
-
+
+ UTF-8
+ UTF-8
+ 1.8
+ 1.8
+ 1.8
+ 2.1.0.RELEASE
+ 8.0.12
+ 4.5.1
+ 27.0.1-jre
+ 1.20
+
-
-
-
- org.springframework.boot
- spring-boot-dependencies
- ${spring.boot.version}
- pom
- import
-
-
- mysql
- mysql-connector-java
- ${mysql.version}
-
-
-
- cn.hutool
- hutool-all
- ${hutool.version}
-
-
-
- com.google.guava
- guava
- ${guava.version}
-
-
-
- eu.bitwalker
- UserAgentUtils
- ${user.agent.version}
-
-
-
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring.boot.version}
+ pom
+ import
+
+
+ mysql
+ mysql-connector-java
+ ${mysql.version}
+
+
+
+ cn.hutool
+ hutool-all
+ ${hutool.version}
+
+
+
+ com.google.guava
+ guava
+ ${guava.version}
+
+
+
+ eu.bitwalker
+ UserAgentUtils
+ ${user.agent.version}
+
+
+
-
-
-
-
- maven-clean-plugin
- 3.0.0
-
-
- maven-resources-plugin
- 3.0.2
-
-
- maven-compiler-plugin
- 3.7.0
-
-
- maven-surefire-plugin
- 2.20.1
-
-
- maven-jar-plugin
- 3.0.2
-
-
- maven-install-plugin
- 2.5.2
-
-
- maven-deploy-plugin
- 2.8.2
-
-
- org.springframework.boot
- spring-boot-maven-plugin
- ${spring.boot.version}
-
-
-
- repackage
-
-
-
-
-
-
-
+
+
+
+
+ maven-clean-plugin
+ 3.0.0
+
+
+ maven-resources-plugin
+ 3.0.2
+
+
+ maven-compiler-plugin
+ 3.7.0
+
+
+ maven-surefire-plugin
+ 2.20.1
+
+
+ maven-jar-plugin
+ 3.0.2
+
+
+ maven-install-plugin
+ 2.5.2
+
+
+ maven-deploy-plugin
+ 2.8.2
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring.boot.version}
+
+
+
+ repackage
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-boot-demo-task-xxl-job/README.md b/spring-boot-demo-task-xxl-job/README.md
new file mode 100644
index 000000000..96c8bb25d
--- /dev/null
+++ b/spring-boot-demo-task-xxl-job/README.md
@@ -0,0 +1,488 @@
+# spring-boot-demo-task-xxl-job
+
+> 此 demo 主要演示了 Spring Boot 如何集成 XXL-JOB 实现分布式定时任务,并提供绕过 `xxl-job-admin` 对定时任务的管理的方法,包括定时任务列表,触发器列表,新增定时任务,删除定时任务,停止定时任务,启动定时任务,修改定时任务,手动触发定时任务。
+
+## 1. xxl-job-admin调度中心
+
+> https://github.com/xuxueli/xxl-job.git
+
+克隆 调度中心代码
+
+```bash
+$ git clone https://github.com/xuxueli/xxl-job.git
+```
+
+### 1.1. 创建调度中心的表结构
+
+数据库脚本地址:`/xxl-job/doc/db/tables_xxl_job.sql`
+
+### 1.2. 修改 application.properties
+
+```properties
+server.port=18080
+
+spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?Unicode=true&characterEncoding=UTF-8&useSSL=false
+spring.datasource.username=root
+spring.datasource.password=root
+```
+
+### 1.3. 修改日志配置文件 logback.xml
+
+```xml
+
+```
+
+### 1.4. 启动调度中心
+
+Run `XxlJobAdminApplication`
+
+默认用户名密码:admin/admin
+
+![image-20190808105554414](https://static.xkcoding.com/spring-boot-demo/2019-08-08-025555.png)
+
+![image-20190808105628852](https://static.xkcoding.com/spring-boot-demo/2019-08-08-025629.png)
+
+## 2. 编写执行器项目
+
+### 2.1. pom.xml
+
+```xml
+
+
+ 4.0.0
+
+ spring-boot-demo-task-xxl-job
+ 1.0.0-SNAPSHOT
+ jar
+
+ spring-boot-demo-task-xxl-job
+ Demo project for Spring Boot
+
+
+ com.xkcoding
+ spring-boot-demo
+ 1.0.0-SNAPSHOT
+
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ 2.1.0
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+
+
+ com.xuxueli
+ xxl-job-core
+ ${xxl-job.version}
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ cn.hutool
+ hutool-all
+
+
+
+ com.google.guava
+ guava
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+ spring-boot-demo-task-xxl-job
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+```
+
+### 2.2. 编写 配置类 XxlJobProps.java
+
+```java
+/**
+ *
+ * xxl-job 配置
+ *
+ *
+ * @author yangkai.shen
+ * @date Created in 2019-08-07 10:25
+ */
+@Data
+@ConfigurationProperties(prefix = "xxl.job")
+public class XxlJobProps {
+ /**
+ * 调度中心配置
+ */
+ private XxlJobAdminProps admin;
+
+ /**
+ * 执行器配置
+ */
+ private XxlJobExecutorProps executor;
+
+ /**
+ * 与调度中心交互的accessToken
+ */
+ private String accessToken;
+
+ @Data
+ public static class XxlJobAdminProps {
+ /**
+ * 调度中心地址
+ */
+ private String address;
+ }
+
+ @Data
+ public static class XxlJobExecutorProps {
+ /**
+ * 执行器名称
+ */
+ private String appName;
+
+ /**
+ * 执行器 IP
+ */
+ private String ip;
+
+ /**
+ * 执行器端口
+ */
+ private int port;
+
+ /**
+ * 执行器日志
+ */
+ private String logPath;
+
+ /**
+ * 执行器日志保留天数,-1
+ */
+ private int logRetentionDays;
+ }
+}
+```
+
+### 2.3. 编写配置文件 application.yml
+
+```yaml
+server:
+ port: 8080
+ servlet:
+ context-path: /demo
+xxl:
+ job:
+ # 执行器通讯TOKEN [选填]:非空时启用;
+ access-token:
+ admin:
+ # 调度中心部署跟地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
+ address: http://localhost:18080/xxl-job-admin
+ executor:
+ # 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
+ app-name: spring-boot-demo-task-xxl-job-executor
+ # 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
+ ip:
+ # 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
+ port: 9999
+ # 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
+ log-path: logs/spring-boot-demo-task-xxl-job/task-log
+ # 执行器日志保存天数 [选填] :值大于3时生效,启用执行器Log文件定期清理功能,否则不生效;
+ log-retention-days: -1
+```
+
+### 2.4. 编写自动装配类 XxlConfig.java
+
+```java
+/**
+ *
+ * xxl-job 自动装配
+ *
+ *
+ * @author yangkai.shen
+ * @date Created in 2019-08-07 10:20
+ */
+@Slf4j
+@Configuration
+@EnableConfigurationProperties(XxlJobProps.class)
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+public class XxlJobConfig {
+ private final XxlJobProps xxlJobProps;
+
+ @Bean(initMethod = "start", destroyMethod = "destroy")
+ public XxlJobSpringExecutor xxlJobExecutor() {
+ log.info(">>>>>>>>>>> xxl-job config init.");
+ XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
+ xxlJobSpringExecutor.setAdminAddresses(xxlJobProps.getAdmin().getAddress());
+ xxlJobSpringExecutor.setAccessToken(xxlJobProps.getAccessToken());
+ xxlJobSpringExecutor.setAppName(xxlJobProps.getExecutor().getAppName());
+ xxlJobSpringExecutor.setIp(xxlJobProps.getExecutor().getIp());
+ xxlJobSpringExecutor.setPort(xxlJobProps.getExecutor().getPort());
+ xxlJobSpringExecutor.setLogPath(xxlJobProps.getExecutor().getLogPath());
+ xxlJobSpringExecutor.setLogRetentionDays(xxlJobProps.getExecutor().getLogRetentionDays());
+
+ return xxlJobSpringExecutor;
+ }
+
+}
+```
+
+### 2.5. 编写具体的定时逻辑 DemoTask.java
+
+```java
+/**
+ *
+ * 测试定时任务
+ *
+ *
+ * @author yangkai.shen
+ * @date Created in 2019-08-07 10:15
+ */
+@Slf4j
+@Component
+@JobHandler("demoTask")
+public class DemoTask extends IJobHandler {
+
+ /**
+ * execute handler, invoked when executor receives a scheduling request
+ *
+ * @param param 定时任务参数
+ * @return 执行状态
+ * @throws Exception 任务异常
+ */
+ @Override
+ public ReturnT execute(String param) throws Exception {
+ // 可以动态获取传递过来的参数,根据参数不同,当前调度的任务不同
+ log.info("【param】= {}", param);
+ XxlJobLogger.log("demo task run at : {}", DateUtil.now());
+ return RandomUtil.randomInt(1, 11) % 2 == 0 ? SUCCESS : FAIL;
+ }
+}
+```
+
+### 2.6. 启动执行器
+
+Run `SpringBootDemoTaskXxlJobApplication`
+
+## 3. 配置定时任务
+
+### 3.1. 将启动的执行器添加到调度中心
+
+执行器管理 - 新增执行器
+
+![image-20190808105910203](https://static.xkcoding.com/spring-boot-demo/2019-08-08-025910.png)
+
+### 3.2. 添加定时任务
+
+任务管理 - 新增 - 保存
+
+![image-20190808110127956](https://static.xkcoding.com/spring-boot-demo/2019-08-08-030128.png)
+
+### 3.3. 启停定时任务
+
+任务列表的操作列,拥有以下操作:执行、启动/停止、日志、编辑、删除
+
+执行:单次触发任务,不影响定时逻辑
+
+启动:启动定时任务
+
+停止:停止定时任务
+
+日志:查看当前任务执行日志
+
+编辑:更新定时任务
+
+删除:删除定时任务
+
+## 4. 使用API添加定时任务
+
+> 实际场景中,如果添加定时任务都需要手动在 xxl-job-admin 去操作,这样可能比较麻烦,用户更希望在自己的页面,添加定时任务参数、定时调度表达式,然后通过 API 的方式添加定时任务
+
+### 4.1. 改造xxl-job-admin
+
+#### 4.1.1. 修改 JobGroupController.java
+
+```java
+...
+// 添加执行器列表
+@RequestMapping("/list")
+@ResponseBody
+// 去除权限校验
+@PermissionLimit(limit = false)
+public ReturnT> list(){
+ return new ReturnT<>(xxlJobGroupDao.findAll());
+}
+...
+```
+
+#### 4.1.2. 修改 JobInfoController.java
+
+```java
+// 分别在 pageList、add、update、remove、pause、start、triggerJob 方法上添加注解,去除权限校验
+@PermissionLimit(limit = false)
+```
+
+### 4.2. 改造 执行器项目
+
+#### 4.2.1. 添加手动触发类
+
+```java
+/**
+ *
+ * 手动操作 xxl-job
+ *
+ *
+ * @author yangkai.shen
+ * @date Created in 2019-08-07 14:58
+ */
+@Slf4j
+@RestController
+@RequestMapping("/xxl-job")
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+public class ManualOperateController {
+ private final static String baseUri = "http://127.0.0.1:18080/xxl-job-admin";
+ private final static String JOB_INFO_URI = "/jobinfo";
+ private final static String JOB_GROUP_URI = "/jobgroup";
+
+ /**
+ * 任务组列表,xxl-job叫做触发器列表
+ */
+ @GetMapping("/group")
+ public String xxlJobGroup() {
+ HttpResponse execute = HttpUtil.createGet(baseUri + JOB_GROUP_URI + "/list").execute();
+ log.info("【execute】= {}", execute);
+ return execute.body();
+ }
+
+ /**
+ * 分页任务列表
+ * @param page 当前页,第一页 -> 0
+ * @param size 每页条数,默认10
+ * @return 分页任务列表
+ */
+ @GetMapping("/list")
+ public String xxlJobList(Integer page, Integer size) {
+ Map jobInfo = Maps.newHashMap();
+ jobInfo.put("start", page != null ? page : 0);
+ jobInfo.put("length", size != null ? size : 10);
+ jobInfo.put("jobGroup", 2);
+ jobInfo.put("triggerStatus", -1);
+
+ HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + "/pageList").form(jobInfo).execute();
+ log.info("【execute】= {}", execute);
+ return execute.body();
+ }
+
+ /**
+ * 测试手动保存任务
+ */
+ @GetMapping("/add")
+ public String xxlJobAdd() {
+ Map jobInfo = Maps.newHashMap();
+ jobInfo.put("jobGroup", 2);
+ jobInfo.put("jobCron", "0 0/1 * * * ? *");
+ jobInfo.put("jobDesc", "手动添加的任务");
+ jobInfo.put("author", "admin");
+ jobInfo.put("executorRouteStrategy", "ROUND");
+ jobInfo.put("executorHandler", "demoTask");
+ jobInfo.put("executorParam", "手动添加的任务的参数");
+ jobInfo.put("executorBlockStrategy", ExecutorBlockStrategyEnum.SERIAL_EXECUTION);
+ jobInfo.put("glueType", GlueTypeEnum.BEAN);
+
+ HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + "/add").form(jobInfo).execute();
+ log.info("【execute】= {}", execute);
+ return execute.body();
+ }
+
+ /**
+ * 测试手动触发一次任务
+ */
+ @GetMapping("/trigger")
+ public String xxlJobTrigger() {
+ Map jobInfo = Maps.newHashMap();
+ jobInfo.put("id", 4);
+ jobInfo.put("executorParam", JSONUtil.toJsonStr(jobInfo));
+
+ HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + "/trigger").form(jobInfo).execute();
+ log.info("【execute】= {}", execute);
+ return execute.body();
+ }
+
+ /**
+ * 测试手动删除任务
+ */
+ @GetMapping("/remove")
+ public String xxlJobRemove() {
+ Map jobInfo = Maps.newHashMap();
+ jobInfo.put("id", 4);
+
+ HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + "/remove").form(jobInfo).execute();
+ log.info("【execute】= {}", execute);
+ return execute.body();
+ }
+
+ /**
+ * 测试手动停止任务
+ */
+ @GetMapping("/stop")
+ public String xxlJobStop() {
+ Map jobInfo = Maps.newHashMap();
+ jobInfo.put("id", 4);
+
+ HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + "/stop").form(jobInfo).execute();
+ log.info("【execute】= {}", execute);
+ return execute.body();
+ }
+
+ /**
+ * 测试手动停止任务
+ */
+ @GetMapping("/start")
+ public String xxlJobStart() {
+ Map jobInfo = Maps.newHashMap();
+ jobInfo.put("id", 4);
+
+ HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + "/start").form(jobInfo).execute();
+ log.info("【execute】= {}", execute);
+ return execute.body();
+ }
+
+}
+```
+
+> 后端其余代码请 clone 本项目,查看具体代码
+
+## 参考
+
+- [《分布式任务调度平台xxl-job》](http://www.xuxueli.com/xxl-job/#/)
+
diff --git a/spring-boot-demo-task-xxl-job/pom.xml b/spring-boot-demo-task-xxl-job/pom.xml
index d222bc110..efa96568c 100644
--- a/spring-boot-demo-task-xxl-job/pom.xml
+++ b/spring-boot-demo-task-xxl-job/pom.xml
@@ -35,11 +35,6 @@
true
-
- mysql
- mysql-connector-java
-
-
com.xuxueli