diff --git a/README.MD b/README.MD index 1257ae09..0f716881 100644 --- a/README.MD +++ b/README.MD @@ -80,17 +80,9 @@ https://github.com/odboy-tianjun/cutejava ![CuteFileUpload](./cutejava-front/docs/images/CuteFileUpload.png) - CuteFileDragUpload 支持拖拽上传文件到OSS, 必须结合Minio使用(上传完成后必须销毁组件) ![CuteFileDragUpload](./cutejava-front/docs/images/CuteFileDragUpload.png) -- CutePipelineNode 流水线节点组件 - ![CutePipelineNode](./cutejava-front/docs/images/CutePipelineNode.png) #### 系统模块 - cutejava-framework:系统基础框架。提供核心功能,如:权限、数据权限、异常处理、缓存、工具类、接口限流、接口防重、接口幂等。 -- cutejava-system:系统功能模块。提供用户、角色、菜单、部门、岗位、字典、定时任务、邮件、Minio存储、服务监控等功能 -- cutejava-devops:devops模块,已实现流水线功能。参考阿里云云效,提供流水线功能,可配置流水线任务,并支持任务依赖、任务参数、任务参数校验、任务参数回填。 - -#### 特别鸣谢 - -- 感谢 [elunez](https://github.com/elunez/eladmin-mp) 大佬提供的基础框架 -- 感谢 [aizuda](https://mongoplus.com/) 大佬提供的Mongodb框架 - - 建表参考 'cutejava/doc/mongodb.md' +- cutejava-module-system:系统功能模块。提供用户、角色、菜单、部门、岗位、字典、定时任务、邮件、Minio存储、服务监控等功能 +- cutejava-module-task:串行任务模块,已实现流水线功能。参考阿里云云效,提供流水线功能,可配置流水线任务,并支持任务依赖、任务参数、任务参数校验、任务参数回填。 diff --git a/cutejava-front/src/views/componentsDemo/CuteBusinessDemo.vue b/cutejava-front/src/views/componentsDemo/CuteBusinessDemo.vue index f3859599..2678ddb2 100644 --- a/cutejava-front/src/views/componentsDemo/CuteBusinessDemo.vue +++ b/cutejava-front/src/views/componentsDemo/CuteBusinessDemo.vue @@ -16,7 +16,7 @@ - + 提 交 diff --git a/cutejava-front/src/views/componentsDemo/CuteYamlEditorDemo.vue b/cutejava-front/src/views/componentsDemo/CuteYamlEditorDemo.vue index 7b4a4824..95715647 100644 --- a/cutejava-front/src/views/componentsDemo/CuteYamlEditorDemo.vue +++ b/cutejava-front/src/views/componentsDemo/CuteYamlEditorDemo.vue @@ -68,81 +68,6 @@ export default { ' repositories:\n' + ' # 是否启用Redis存储(关闭防止出现 Multiple Spring Data modules found, entering strict repository configuration mode)\n' + ' enabled: false\n' + - ' datasource:\n' + - ' druid:\n' + - ' db-type: com.alibaba.druid.pool.DruidDataSource\n' + - ' driverClassName: com.p6spy.engine.spy.P6SpyDriver\n' + - ' url: jdbc:p6spy:mysql://192.168.100.128:23306/cutejava?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true\n' + - ' username: root\n' + - ' password: lm,101208..,.\n' + - ' # 初始连接数,建议设置为与最小空闲连接数相同\n' + - ' initial-size: 2\n' + - ' # 最小空闲连接数,保持足够的空闲连接以应对请求\n' + - ' min-idle: 2\n' + - ' # 最大连接数,根据并发需求适当增加\n' + - ' max-active: 8\n' + - ' # 获取连接超时时间(毫秒),调整以满足响应时间要求\n' + - ' max-wait: 3000\n' + - ' # 启用KeepAlive机制,保持长连接\n' + - ' keep-alive: true\n' + - ' # 连接有效性检测间隔时间(毫秒),定期检查连接的健康状态\n' + - ' time-between-eviction-runs-millis: 60000\n' + - ' # 连接在池中最小生存时间(毫秒),确保连接在池中至少存在一段时间\n' + - ' min-evictable-idle-time-millis: 300000\n' + - ' # 连接在池中最大生存时间(毫秒),防止连接在池中停留过长\n' + - ' max-evictable-idle-time-millis: 900000\n' + - ' # 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除\n' + - ' test-while-idle: true\n' + - ' # 指明是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个\n' + - ' test-on-borrow: true\n' + - ' # 是否在归还到池中前进行检验\n' + - ' test-on-return: false\n' + - ' # 停用 com_ping 探活机制\n' + - ' use-ping-method: false\n' + - ' # 检测连接是否有效\n' + - ' validation-query: SELECT 1\n' + - ' # 配置监控统计\n' + - ' web-stat-filter:\n' + - ' enabled: true\n' + - ' url-pattern: /*\n' + - ' # 开启session统计功能\n' + - ' session-stat-enable: true\n' + - ' exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"\n' + - ' # 缺省sessionStatMaxCount是1000个\n' + - ' session-stat-max-count: 1000\n' + - ' stat-view-servlet:\n' + - ' enabled: true\n' + - ' url-pattern: /druid/*\n' + - ' reset-enable: false\n' + - ' filter:\n' + - ' stat:\n' + - ' enabled: true\n' + - ' # 记录慢SQL\n' + - ' log-slow-sql: true\n' + - ' slow-sql-millis: 2000\n' + - ' merge-sql: true\n' + - ' wall:\n' + - ' config:\n' + - ' multi-statement-allow: true\n' + - ' aop-patterns: "cn.odboy.mapper.*,cn.odboy.service.*,cn.odboy.*.mapper.*,cn.odboy.*.service.*"\n' + - ' redis:\n' + - ' database: ${REDIS_DB:1}\n' + - ' host: ${REDIS_HOST:192.168.100.128}\n' + - ' port: ${REDIS_PORT:26379}\n' + - ' password: ${REDIS_PWD:lm,101208..,.}\n' + - ' # 连接超时时间\n' + - ' timeout: 5000\n' + - ' # 连接池配置\n' + - ' lettuce:\n' + - ' pool:\n' + - ' # 连接池最大连接数\n' + - ' max-active: 30\n' + - ' # 连接池最大阻塞等待时间(毫秒),负值表示没有限制\n' + - ' max-wait: -1\n' + - ' # 连接池中的最大空闲连接数\n' + - ' max-idle: 20\n' + - ' # 连接池中的最小空闲连接数\n' + - ' min-idle: 1\n' + 'mybatis-plus:\n' + ' configuration:\n' + ' # 开启 Mybatis 二级缓存,默认为 true\n' + @@ -174,19 +99,6 @@ export default { ' # 是否控制台 print mybatisplus-plus 的 LOGO\n' + ' banner: true\n' + 'app:\n' + - ' # 密码加密传输,前端公钥加密,后端私钥解密\n' + - ' rsa:\n' + - ' private-key: MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A==\n' + - ' # 鉴权\n' + - ' jwt:\n' + - ' # 必须使用最少88位的Base64对该令牌进行编码\n' + - ' base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI=\n' + - ' # 令牌过期时间 此处单位/毫秒 ,默认4小时,可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html\n' + - ' token-validity-in-seconds: 14400000\n' + - ' # token 续期检查时间范围(默认30分钟,单位毫秒),在token即将过期的一段时间内用户操作了,则给用户的token续期\n' + - ' detect: 1800000\n' + - ' # 续期时间范围,默认1小时,单位毫秒\n' + - ' renew: 3600000\n' + ' # 登录\n' + ' login:\n' + ' # 是否限制单用户登录\n' + @@ -235,8 +147,8 @@ export default { ' minio:\n' + ' endpoint: http://192.168.100.128:9000\n' + ' bucketName: cutejava\n' + - ' accessKey: 8o5oVzqvKby5TzaGcfmx\n' + - ' secretKey: 8BiK5UbmvXGJNVQ98CGiohHzT1N1FMRZqHRdJllj\n' + + ' accessKey: xxxxxx\n' + + ' secretKey: xxxxxx\n' + ' captcha:\n' + ' expireTime: 300\n' + '## 启用debug\n' + diff --git a/cutejava/cutejava-framework/src/main/java/cn/odboy/framework/redis/RedissonConfiguration.java b/cutejava/cutejava-framework/src/main/java/cn/odboy/framework/redis/RedissonConfiguration.java index 9b0463e6..597ea7c9 100644 --- a/cutejava/cutejava-framework/src/main/java/cn/odboy/framework/redis/RedissonConfiguration.java +++ b/cutejava/cutejava-framework/src/main/java/cn/odboy/framework/redis/RedissonConfiguration.java @@ -1,97 +1,97 @@ -/* - * Copyright 2021-2025 Odboy - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package cn.odboy.framework.redis; - -import cn.hutool.core.util.StrUtil; -import cn.odboy.util.CsSystemUtil; -import lombok.extern.slf4j.Slf4j; -import org.redisson.Redisson; -import org.redisson.api.RedissonClient; -import org.redisson.client.codec.StringCodec; -import org.redisson.config.Config; -import org.redisson.config.EqualJitterDelay; -import org.redisson.config.SingleServerConfig; -import org.redisson.config.TransportMode; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import java.time.Duration; - -@Slf4j -@Configuration -@AutoConfigureBefore(RedisAutoConfiguration.class) -public class RedissonConfiguration { - - @Value("${spring.redis.host}") - private String redisHost; - - @Value("${spring.redis.port}") - private int redisPort; - - @Value("${spring.redis.database}") - private int redisDatabase; - - @Value("${spring.redis.password:}") - private String redisPassword; - - @Value("${spring.redis.timeout:5000}") - private int timeout; - - @Value("${spring.redis.lettuce.pool.max-active:64}") - private int connectionPoolSize; - - @Value("${spring.redis.lettuce.pool.min-idle:16}") - private int connectionMinimumIdleSize; - - @Bean - public RedissonClient redissonClient() { - Config config = new Config(); - config.setThreads(CsSystemUtil.getCpuCount()); - config.setNettyThreads(0); - config.setCodec(new StringCodec()); - config.setTransportMode(TransportMode.NIO); - SingleServerConfig singleServerConfig = config.useSingleServer(); - singleServerConfig.setAddress("redis://" + redisHost + ":" + redisPort); - singleServerConfig.setDatabase(redisDatabase); - singleServerConfig.setTimeout(timeout); - singleServerConfig.setConnectionPoolSize(connectionPoolSize); - singleServerConfig.setConnectionMinimumIdleSize(connectionMinimumIdleSize); - if (StrUtil.isNotBlank(redisPassword)) { - singleServerConfig.setPassword(redisPassword); - } - singleServerConfig.setIdleConnectionTimeout(10000); - singleServerConfig.setConnectTimeout(10000); - singleServerConfig.setTimeout(3000); - singleServerConfig.setRetryAttempts(3); - // singleServerConfig.setRetryInterval(1500); - singleServerConfig.setRetryDelay(new EqualJitterDelay(Duration.ofSeconds(3), Duration.ofSeconds(5))); - singleServerConfig.setSubscriptionsPerConnection(5); - singleServerConfig.setSubscriptionConnectionMinimumIdleSize(1); - singleServerConfig.setSubscriptionConnectionPoolSize(50); - singleServerConfig.setConnectionMinimumIdleSize(32); - singleServerConfig.setConnectionPoolSize(64); - singleServerConfig.setDnsMonitoringInterval(5000); - RedissonClient redissonClient = Redisson.create(config); - log.info("Redisson客户端 初始化完毕"); - return redissonClient; - } -} - - +///* +// * Copyright 2021-2025 Odboy +// * +// * Licensed under the Apache License, Version 2.0 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +//package cn.odboy.framework.redis; +// +//import cn.hutool.core.util.StrUtil; +//import cn.odboy.util.CsSystemUtil; +//import lombok.extern.slf4j.Slf4j; +//import org.redisson.Redisson; +//import org.redisson.api.RedissonClient; +//import org.redisson.client.codec.StringCodec; +//import org.redisson.config.Config; +//import org.redisson.config.EqualJitterDelay; +//import org.redisson.config.SingleServerConfig; +//import org.redisson.config.TransportMode; +//import org.springframework.beans.factory.annotation.Value; +//import org.springframework.boot.autoconfigure.AutoConfigureBefore; +//import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +// +//import java.time.Duration; +// +//@Slf4j +//@Configuration +//@AutoConfigureBefore(RedisAutoConfiguration.class) +//public class RedissonConfiguration { +// +// @Value("${spring.redis.host}") +// private String redisHost; +// +// @Value("${spring.redis.port}") +// private int redisPort; +// +// @Value("${spring.redis.database}") +// private int redisDatabase; +// +// @Value("${spring.redis.password:}") +// private String redisPassword; +// +// @Value("${spring.redis.timeout:5000}") +// private int timeout; +// +// @Value("${spring.redis.lettuce.pool.max-active:64}") +// private int connectionPoolSize; +// +// @Value("${spring.redis.lettuce.pool.min-idle:16}") +// private int connectionMinimumIdleSize; +// +// @Bean +// public RedissonClient redissonClient() { +// Config config = new Config(); +// config.setThreads(CsSystemUtil.getCpuCount()); +// config.setNettyThreads(0); +// config.setCodec(new StringCodec()); +// config.setTransportMode(TransportMode.NIO); +// SingleServerConfig singleServerConfig = config.useSingleServer(); +// singleServerConfig.setAddress("redis://" + redisHost + ":" + redisPort); +// singleServerConfig.setDatabase(redisDatabase); +// singleServerConfig.setTimeout(timeout); +// singleServerConfig.setConnectionPoolSize(connectionPoolSize); +// singleServerConfig.setConnectionMinimumIdleSize(connectionMinimumIdleSize); +// if (StrUtil.isNotBlank(redisPassword)) { +// singleServerConfig.setPassword(redisPassword); +// } +// singleServerConfig.setIdleConnectionTimeout(10000); +// singleServerConfig.setConnectTimeout(10000); +// singleServerConfig.setTimeout(3000); +// singleServerConfig.setRetryAttempts(3); +// // singleServerConfig.setRetryInterval(1500); +// singleServerConfig.setRetryDelay(new EqualJitterDelay(Duration.ofSeconds(3), Duration.ofSeconds(5))); +// singleServerConfig.setSubscriptionsPerConnection(5); +// singleServerConfig.setSubscriptionConnectionMinimumIdleSize(1); +// singleServerConfig.setSubscriptionConnectionPoolSize(50); +// singleServerConfig.setConnectionMinimumIdleSize(32); +// singleServerConfig.setConnectionPoolSize(64); +// singleServerConfig.setDnsMonitoringInterval(5000); +// RedissonClient redissonClient = Redisson.create(config); +// log.info("Redisson客户端 初始化完毕"); +// return redissonClient; +// } +//} +// +// diff --git a/cutejava/cutejava-framework/src/main/java/cn/odboy/util/CsDateUtil.java b/cutejava/cutejava-framework/src/main/java/cn/odboy/util/CsDateUtil.java index c4f6d019..7278e0bc 100644 --- a/cutejava/cutejava-framework/src/main/java/cn/odboy/util/CsDateUtil.java +++ b/cutejava/cutejava-framework/src/main/java/cn/odboy/util/CsDateUtil.java @@ -22,6 +22,12 @@ import lombok.experimental.UtilityClass; import java.util.Date; +/** + * 时间相关工具 + * + * @author odboy + * @date 2025-10-01 + */ @UtilityClass public class CsDateUtil { /** @@ -50,4 +56,95 @@ public class CsDateUtil { public static String getNowDateStr() { return DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN); } + + /** + * 格式化到毫秒 + * + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return 格式化后的时间,X天X时X分X秒X毫秒 + */ + public static String formatMillsDuration(Date startTime, Date endTime) { + if (startTime == null || endTime == null) { + // 什么都不返回 + return ""; + } + + long betweenSeconds = DateUtil.between(startTime, endTime, cn.hutool.core.date.DateUnit.SECOND); + + long days = betweenSeconds / (24 * 60 * 60); + long hours = (betweenSeconds % (24 * 60 * 60)) / (60 * 60); + long minutes = (betweenSeconds % (60 * 60)) / 60; + long seconds = betweenSeconds % 60; + + StringBuilder result = new StringBuilder(); + + if (days > 0) { + result.append(days).append("天"); + } + + if (hours > 0) { + result.append(hours).append("时"); + } + + if (minutes > 0) { + result.append(minutes).append("分"); + } + + if (seconds > 0 || result.length() == 0) { + result.append(seconds).append("秒"); + } + + return result.toString(); + } + + /** + * 格式化到秒 + * + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return 格式化后的时间,X天X时X分X秒 + */ + public static String formatSecondsDuration(Date startTime, Date endTime) { + if (startTime == null || endTime == null) { + // 什么都不返回 + return ""; + } + + long betweenMs = DateUtil.betweenMs(startTime, endTime); + long days = betweenMs / (24 * 60 * 60 * 1000); + long hours = (betweenMs % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000); + long minutes = (betweenMs % (60 * 60 * 1000)) / (60 * 1000); + long seconds = (betweenMs % (60 * 1000)) / 1000; + long milliseconds = betweenMs % 1000; + + StringBuilder result = new StringBuilder(); + + if (days > 0) { + result.append(days).append("天"); + } + + if (hours > 0) { + result.append(hours).append("时"); + } + + if (minutes > 0) { + result.append(minutes).append("分"); + } + + if (seconds > 0) { + result.append(seconds).append("秒"); + } + + if (milliseconds > 0) { + result.append(milliseconds).append("毫秒"); + } + + // 如果所有单位都是0,则显示0毫秒 + if (result.length() == 0) { + result.append("0毫秒"); + } + + return result.toString(); + } } diff --git a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/constant/TaskStatusEnum.java b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/constant/TaskStatusEnum.java index bf4d20f6..6f09f6c4 100644 --- a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/constant/TaskStatusEnum.java +++ b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/constant/TaskStatusEnum.java @@ -32,4 +32,13 @@ public enum TaskStatusEnum { Fail("fail", "执行失败"); private final String code; private final String name; + + public static String getDesc(String code) { + for (TaskStatusEnum taskStatusEnum : TaskStatusEnum.values()) { + if (taskStatusEnum.code.equals(code)) { + return taskStatusEnum.getName(); + } + } + return code; + } } diff --git a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/controller/TaskTestsController.java b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/controller/TaskTestsController.java index e76ddba8..8a43cfdb 100644 --- a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/controller/TaskTestsController.java +++ b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/controller/TaskTestsController.java @@ -20,12 +20,14 @@ import cn.odboy.annotation.AnonymousAccess; import cn.odboy.task.constant.TaskChangeTypeEnum; import cn.odboy.task.core.TaskManage; import cn.odboy.task.dal.dataobject.TaskInstanceInfoTb; +import cn.odboy.task.dal.model.TaskInstanceInfoVo; import com.alibaba.fastjson2.JSON; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @Slf4j @@ -38,7 +40,7 @@ public class TaskTestsController { @AnonymousAccess @GetMapping(value = "/testCreate") public ResponseEntity testCreate() { - TaskInstanceInfoTb instanceInfo = taskManage.createJob("cutejava", TaskChangeTypeEnum.AppApply, "java", "daily", "cutejava", "功能测试", null); + TaskInstanceInfoTb instanceInfo = taskManage.createJob("cutejava", TaskChangeTypeEnum.AppContainerDeploy, "java", "daily", "cutejava", "功能测试", null); log.info("任务创建成功,实例为:{}", JSON.toJSONString(instanceInfo)); return ResponseEntity.ok(instanceInfo); } @@ -46,7 +48,7 @@ public class TaskTestsController { @AnonymousAccess @GetMapping(value = "/testCreateAfterStop") public ResponseEntity testCreateAfterStop() { - TaskInstanceInfoTb instanceInfo = taskManage.createJob("cutejava", TaskChangeTypeEnum.AppApply, "java", "daily", "cutejava", "功能测试", null); + TaskInstanceInfoTb instanceInfo = taskManage.createJob("cutejava", TaskChangeTypeEnum.AppContainerDeploy, "java", "daily", "cutejava", "功能测试", null); log.info("任务创建成功,实例为:{}", JSON.toJSONString(instanceInfo)); ThreadUtil.execAsync(() -> { ThreadUtil.safeSleep(5000); @@ -54,4 +56,23 @@ public class TaskTestsController { }); return ResponseEntity.ok(null); } + + @AnonymousAccess + @GetMapping(value = "/testRetry") + public ResponseEntity testRetry(@RequestParam Long instanceId, @RequestParam String retryNodeCode) { + TaskInstanceInfoTb instanceInfo = taskManage.retryJob(instanceId, retryNodeCode); + log.info("任务重试成功,实例为:{}", JSON.toJSONString(instanceInfo)); + return ResponseEntity.ok(null); + } + + @AnonymousAccess + @GetMapping(value = "/last") + public ResponseEntity testLast() { + String contextName = "cutejava"; + String language = "java"; + String changeType = TaskChangeTypeEnum.AppContainerDeploy.getCode(); + String envAlias = "daily"; + TaskInstanceInfoVo instanceInfo = taskManage.getLastInfo(contextName, language, envAlias, changeType); + return ResponseEntity.ok(instanceInfo); + } } diff --git a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/core/TaskJobBean.java b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/core/TaskJobBean.java index de71717c..f493157d 100644 --- a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/core/TaskJobBean.java +++ b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/core/TaskJobBean.java @@ -18,12 +18,13 @@ package cn.odboy.task.core; import cn.hutool.core.util.StrUtil; import cn.odboy.framework.context.CsSpringBeanHolder; +import cn.odboy.framework.exception.web.BadRequestException; import cn.odboy.task.dal.dataobject.TaskInstanceDetailTb; -import cn.odboy.task.dal.model.TaskTemplateInfoVo; +import cn.odboy.task.dal.dataobject.TaskInstanceInfoTb; import cn.odboy.task.dal.model.TaskTemplateNodeVo; import cn.odboy.task.service.TaskInstanceDetailService; import cn.odboy.task.service.TaskInstanceInfoService; -import cn.odboy.task.service.TaskTemplateInfoService; +import cn.odboy.task.service.TaskInstanceStepDetailService; import com.alibaba.fastjson2.JSON; import lombok.extern.slf4j.Slf4j; import org.quartz.InterruptableJob; @@ -53,44 +54,115 @@ public class TaskJobBean extends QuartzJobBean implements InterruptableJob { // ========================== 获取代理类 ========================== TaskInstanceInfoService taskInstanceInfoService = CsSpringBeanHolder.getBean(TaskInstanceInfoService.class); TaskInstanceDetailService taskInstanceDetailService = CsSpringBeanHolder.getBean(TaskInstanceDetailService.class); - TaskTemplateInfoService taskTemplateInfoService = CsSpringBeanHolder.getBean(TaskTemplateInfoService.class); // ========================== 获取参数 ========================== JobDataMap dataMap = context.getMergedJobDataMap(); long id = dataMap.getLong("id"); - // 应用名、资源类型 - String contextName = dataMap.getString("contextName"); - // 开发语言、资源版本 - String language = dataMap.getString("language"); - String envAlias = dataMap.getString("envAlias"); // ========================== 获取任务编排模板 ========================== - TaskTemplateInfoVo taskInstanceInfoVo = taskTemplateInfoService.getTemplateInfoByECL(envAlias, contextName, language); - if (taskInstanceInfoVo == null) { - taskInstanceInfoService.fastFailWithMessage(id, "没有查询到任务编排模板"); - return; - } - String templateInfo = taskInstanceInfoVo.getTemplateInfo(); + TaskInstanceInfoTb taskInstanceInfoVo = taskInstanceInfoService.getById(id); + String templateInfo = taskInstanceInfoVo.getTemplate(); List taskTemplateNodeVos = JSON.parseArray(templateInfo, TaskTemplateNodeVo.class); - if (taskTemplateNodeVos == null || taskTemplateNodeVos.isEmpty()) { - taskInstanceInfoService.fastFailWithMessage(id, "没有查询到任务编排明细"); - return; + // ========================== 判断是否重试任务 ========================== + String retryNodeCode = dataMap.getString("retryNodeCode"); + if (StrUtil.isBlank(retryNodeCode)) { + executeNormalTask(taskInstanceInfoService, taskInstanceDetailService, id, dataMap, taskTemplateNodeVos); + } else { + executeRetryTask(taskInstanceInfoService, taskInstanceDetailService, id, dataMap, taskTemplateNodeVos, retryNodeCode); } + } + + /** + * 执行普通任务(非重试任务) + * + * @param taskInstanceInfoService 任务实例信息服务 + * @param taskInstanceDetailService 任务实例明细服务 + * @param id 任务实例ID + * @param dataMap 数据映射 + * @param taskTemplateNodeVos 模板节点列表 + */ + private void executeNormalTask(TaskInstanceInfoService taskInstanceInfoService, TaskInstanceDetailService taskInstanceDetailService, long id, JobDataMap dataMap, List taskTemplateNodeVos) { // ========================== 初始化执行明细 ========================== - List taskInstanceDetails = new ArrayList<>(); - for (TaskTemplateNodeVo taskTemplateNodeVo : taskTemplateNodeVos) { - TaskInstanceDetailTb taskInstanceDetail = new TaskInstanceDetailTb(); - taskInstanceDetail.setInstanceId(id); - taskInstanceDetail.setFinishTime(null); - taskInstanceDetail.setBizCode(taskTemplateNodeVo.getCode()); - taskInstanceDetail.setBizName(taskTemplateNodeVo.getName()); - taskInstanceDetail.setExecuteInfo("未开始"); - taskInstanceDetail.setExecuteStatus("pending"); - taskInstanceDetails.add(taskInstanceDetail); - } + List taskInstanceDetails = taskTemplateNodeVos.stream().map(taskTemplateNodeVo -> buildTaskInstanceDetail(id, taskTemplateNodeVo)).collect(Collectors.toList()); taskInstanceDetailService.saveBatch(taskInstanceDetails); Map codeIdMap = taskInstanceDetails.stream().collect(Collectors.toMap(TaskInstanceDetailTb::getBizCode, TaskInstanceDetailTb::getId)); // ========================== 顺序执行 ========================== + executeTaskSteps(taskInstanceInfoService, taskInstanceDetailService, id, dataMap, taskTemplateNodeVos, codeIdMap); + } + + /** + * 执行重试任务 + * + * @param taskInstanceInfoService 任务实例信息服务 + * @param taskInstanceDetailService 任务实例明细服务 + * @param id 任务实例ID + * @param dataMap 数据映射 + * @param taskTemplateNodeVos 模板节点列表 + * @param retryNodeCode 重试节点编码 + */ + private void executeRetryTask(TaskInstanceInfoService taskInstanceInfoService, TaskInstanceDetailService taskInstanceDetailService, long id, JobDataMap dataMap, List taskTemplateNodeVos, String retryNodeCode) { + boolean isFound = false; + // ========================== 初始化执行明细 ========================== + List taskInstanceDetails = new ArrayList<>(); + List taskTemplateNodeRetryList = new ArrayList<>(); + for (TaskTemplateNodeVo taskTemplateNodeVo : taskTemplateNodeVos) { + if (isFound) { + taskInstanceDetails.add(buildTaskInstanceDetail(id, taskTemplateNodeVo)); + taskTemplateNodeRetryList.add(taskTemplateNodeVo); + continue; + } + if (taskTemplateNodeVo.getCode().equals(retryNodeCode)) { + if (!taskTemplateNodeVo.getRetry()) { + throw new BadRequestException("节点 '" + taskTemplateNodeVo.getName() + "' 不支持重试"); + } + taskInstanceDetails.add(buildTaskInstanceDetail(id, taskTemplateNodeVo)); + taskTemplateNodeRetryList.add(taskTemplateNodeVo); + isFound = true; + } + } + TaskInstanceStepDetailService taskInstanceStepDetailService = CsSpringBeanHolder.getBean(TaskInstanceStepDetailService.class); + List bizCodeList = taskInstanceDetails.stream().map(TaskInstanceDetailTb::getBizCode).distinct().collect(Collectors.toList()); + List taskInstanceDetailTbs = taskInstanceDetailService.queryByInstanceIdAndBizCodeList(id, bizCodeList); + List taskInstanceDetailIds = taskInstanceDetailTbs.stream().map(TaskInstanceDetailTb::getId).collect(Collectors.toList()); + // 根据ID删除明细 + taskInstanceDetailService.removeByIds(taskInstanceDetailIds); + // 根据明细删除步骤 + taskInstanceStepDetailService.removeByInstanceDetailIds(taskInstanceDetailIds); + taskInstanceDetailService.saveBatch(taskInstanceDetails); + Map codeIdMap = taskInstanceDetails.stream().collect(Collectors.toMap(TaskInstanceDetailTb::getBizCode, TaskInstanceDetailTb::getId)); + // ========================== 顺序执行 ========================== + executeTaskSteps(taskInstanceInfoService, taskInstanceDetailService, id, dataMap, taskTemplateNodeRetryList, codeIdMap); + } + + /** + * 构建任务实例明细对象 + * + * @param id 实例ID + * @param taskTemplateNodeVo 模板节点 + * @return 任务实例明细对象 + */ + private TaskInstanceDetailTb buildTaskInstanceDetail(long id, TaskTemplateNodeVo taskTemplateNodeVo) { + TaskInstanceDetailTb taskInstanceDetail = new TaskInstanceDetailTb(); + taskInstanceDetail.setInstanceId(id); + taskInstanceDetail.setFinishTime(null); + taskInstanceDetail.setBizCode(taskTemplateNodeVo.getCode()); + taskInstanceDetail.setBizName(taskTemplateNodeVo.getName()); + taskInstanceDetail.setExecuteInfo("未开始"); + taskInstanceDetail.setExecuteStatus("pending"); + return taskInstanceDetail; + } + + /** + * 执行任务步骤 + * + * @param taskInstanceInfoService 任务实例信息服务 + * @param taskInstanceDetailService 任务实例明细服务 + * @param id 实例ID + * @param dataMap 数据映射 + * @param taskTemplateNodes 需要执行的任务节点列表 + * @param codeIdMap 节点编码与明细ID映射 + */ + private void executeTaskSteps(TaskInstanceInfoService taskInstanceInfoService, TaskInstanceDetailService taskInstanceDetailService, Long id, JobDataMap dataMap, List taskTemplateNodes, Map codeIdMap) { try { - for (TaskTemplateNodeVo taskTemplateNodeVo : taskTemplateNodeVos) { + for (TaskTemplateNodeVo taskTemplateNodeVo : taskTemplateNodes) { String code = taskTemplateNodeVo.getCode(); try { TaskStepExecutor executor = CsSpringBeanHolder.getBean("taskStep" + getBeanAlias(code)); @@ -124,3 +196,146 @@ public class TaskJobBean extends QuartzJobBean implements InterruptableJob { } } } + + +//@Slf4j +//public class TaskJobBean extends QuartzJobBean implements InterruptableJob { +// private Thread subMainThread = null; +// +// private String getBeanAlias(String code) { +// // node_init +// String[] s = code.split("_"); +// return Arrays.stream(s).map(StrUtil::upperFirst).collect(Collectors.joining()); +// } +// +// @Override +// public void executeInternal(JobExecutionContext context) { +// this.subMainThread = Thread.currentThread(); +// // ========================== 获取代理类 ========================== +// TaskInstanceInfoService taskInstanceInfoService = CsSpringBeanHolder.getBean(TaskInstanceInfoService.class); +// TaskInstanceDetailService taskInstanceDetailService = CsSpringBeanHolder.getBean(TaskInstanceDetailService.class); +// // ========================== 获取参数 ========================== +// JobDataMap dataMap = context.getMergedJobDataMap(); +// long id = dataMap.getLong("id"); +// // ========================== 获取任务编排模板 ========================== +// TaskInstanceInfoTb taskInstanceInfoVo = taskInstanceInfoService.getById(id); +// String templateInfo = taskInstanceInfoVo.getTemplate(); +// List taskTemplateNodeVos = JSON.parseArray(templateInfo, TaskTemplateNodeVo.class); +// // ========================== 判断是否重试任务 ========================== +// String retryNodeCode = dataMap.getString("retryNodeCode"); +// if (StrUtil.isBlank(retryNodeCode)) { +// // ========================== 初始化执行明细 ========================== +// List taskInstanceDetails = new ArrayList<>(); +// for (TaskTemplateNodeVo taskTemplateNodeVo : taskTemplateNodeVos) { +// TaskInstanceDetailTb taskInstanceDetail = new TaskInstanceDetailTb(); +// taskInstanceDetail.setInstanceId(id); +// taskInstanceDetail.setFinishTime(null); +// taskInstanceDetail.setBizCode(taskTemplateNodeVo.getCode()); +// taskInstanceDetail.setBizName(taskTemplateNodeVo.getName()); +// taskInstanceDetail.setExecuteInfo("未开始"); +// taskInstanceDetail.setExecuteStatus("pending"); +// taskInstanceDetails.add(taskInstanceDetail); +// } +// taskInstanceDetailService.saveBatch(taskInstanceDetails); +// Map codeIdMap = taskInstanceDetails.stream().collect(Collectors.toMap(TaskInstanceDetailTb::getBizCode, TaskInstanceDetailTb::getId)); +// // ========================== 顺序执行 ========================== +// try { +// for (TaskTemplateNodeVo taskTemplateNodeVo : taskTemplateNodeVos) { +// String code = taskTemplateNodeVo.getCode(); +// try { +// TaskStepExecutor executor = CsSpringBeanHolder.getBean("taskStep" + getBeanAlias(code)); +// executor.execute(codeIdMap.getOrDefault(code, null), dataMap, taskTemplateNodeVo, new TaskStepCallback() { +// @Override +// public void onStart() { +// taskInstanceDetailService.fastStart(id, code, dataMap); +// } +// +// @Override +// public void onFinish(String executeInfo) { +// taskInstanceDetailService.fastSuccessWithInfo(id, code, executeInfo); +// } +// }); +// } catch (Exception e) { +// taskInstanceDetailService.fastFailWithInfo(id, code, e.getMessage()); +// throw new RuntimeException(e); +// } +// } +// taskInstanceInfoService.fastSuccessWithData(id, dataMap); +// } catch (Exception e) { +// log.error("任务执行失败", e); +// taskInstanceInfoService.fastFailWithMessageData(id, e.getMessage(), dataMap); +// } +// } else { +// boolean isFound = false; +// // ========================== 初始化执行明细 ========================== +// List taskInstanceDetails = new ArrayList<>(); +// List taskTemplateNodeRetrys = new ArrayList<>(); +// for (TaskTemplateNodeVo taskTemplateNodeVo : taskTemplateNodeVos) { +// if (isFound) { +// TaskInstanceDetailTb taskInstanceDetail = new TaskInstanceDetailTb(); +// taskInstanceDetail.setInstanceId(id); +// taskInstanceDetail.setFinishTime(null); +// taskInstanceDetail.setBizCode(taskTemplateNodeVo.getCode()); +// taskInstanceDetail.setBizName(taskTemplateNodeVo.getName()); +// taskInstanceDetail.setExecuteInfo("未开始"); +// taskInstanceDetail.setExecuteStatus("pending"); +// taskInstanceDetails.add(taskInstanceDetail); +// taskTemplateNodeRetrys.add(taskTemplateNodeVo); +// continue; +// } +// if (taskTemplateNodeVo.getCode().equals(retryNodeCode)) { +// if (!taskTemplateNodeVo.getRetry()) { +// throw new BadRequestException("节点 " + retryNodeCode + "不支持重试"); +// } +// TaskInstanceDetailTb taskInstanceDetail = new TaskInstanceDetailTb(); +// taskInstanceDetail.setInstanceId(id); +// taskInstanceDetail.setFinishTime(null); +// taskInstanceDetail.setBizCode(taskTemplateNodeVo.getCode()); +// taskInstanceDetail.setBizName(taskTemplateNodeVo.getName()); +// taskInstanceDetail.setExecuteInfo("未开始"); +// taskInstanceDetail.setExecuteStatus("pending"); +// taskInstanceDetails.add(taskInstanceDetail); +// taskTemplateNodeRetrys.add(taskTemplateNodeVo); +// isFound = true; +// } +// } +// taskInstanceDetailService.removeByInstanceIdAndBizCodeList(id, taskInstanceDetails.stream().map(TaskInstanceDetailTb::getBizCode).distinct().collect(Collectors.toList())); +// taskInstanceDetailService.saveBatch(taskInstanceDetails); +// Map codeIdMap = taskInstanceDetails.stream().collect(Collectors.toMap(TaskInstanceDetailTb::getBizCode, TaskInstanceDetailTb::getId)); +// // ========================== 顺序执行 ========================== +// try { +// for (TaskTemplateNodeVo taskTemplateNodeVo : taskTemplateNodeRetrys) { +// String code = taskTemplateNodeVo.getCode(); +// try { +// TaskStepExecutor executor = CsSpringBeanHolder.getBean("taskStep" + getBeanAlias(code)); +// executor.execute(codeIdMap.getOrDefault(code, null), dataMap, taskTemplateNodeVo, new TaskStepCallback() { +// @Override +// public void onStart() { +// taskInstanceDetailService.fastStart(id, code, dataMap); +// } +// +// @Override +// public void onFinish(String executeInfo) { +// taskInstanceDetailService.fastSuccessWithInfo(id, code, executeInfo); +// } +// }); +// } catch (Exception e) { +// taskInstanceDetailService.fastFailWithInfo(id, code, e.getMessage()); +// throw new RuntimeException(e); +// } +// } +// taskInstanceInfoService.fastSuccessWithData(id, dataMap); +// } catch (Exception e) { +// log.error("任务执行失败", e); +// taskInstanceInfoService.fastFailWithMessageData(id, e.getMessage(), dataMap); +// } +// } +// } +// +// @Override +// public void interrupt() { +// if (subMainThread != null) { +// subMainThread.stop(); +// } +// } +//} diff --git a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/core/TaskManage.java b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/core/TaskManage.java index 00b04f94..2c438abc 100644 --- a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/core/TaskManage.java +++ b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/core/TaskManage.java @@ -15,11 +15,20 @@ */ package cn.odboy.task.core; +import cn.hutool.core.bean.BeanUtil; import cn.odboy.framework.exception.web.BadRequestException; import cn.odboy.task.constant.TaskChangeTypeEnum; import cn.odboy.task.constant.TaskStatusEnum; +import cn.odboy.task.dal.dataobject.TaskInstanceDetailTb; import cn.odboy.task.dal.dataobject.TaskInstanceInfoTb; +import cn.odboy.task.dal.model.TaskInstanceInfoVo; +import cn.odboy.task.dal.model.TaskInstanceNodeVo; +import cn.odboy.task.dal.model.TaskTemplateInfoVo; +import cn.odboy.task.dal.model.TaskTemplateNodeVo; +import cn.odboy.task.service.TaskInstanceDetailService; import cn.odboy.task.service.TaskInstanceInfoService; +import cn.odboy.task.service.TaskTemplateInfoService; +import cn.odboy.util.CsDateUtil; import com.alibaba.fastjson2.JSON; import lombok.extern.slf4j.Slf4j; import org.quartz.*; @@ -28,7 +37,9 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.util.ArrayList; import java.util.Date; +import java.util.List; @Slf4j @Component @@ -36,44 +47,62 @@ public class TaskManage { @Resource private Scheduler scheduler; @Autowired + private TaskTemplateInfoService taskTemplateInfoService; + @Autowired private TaskInstanceInfoService taskInstanceInfoService; + @Autowired + private TaskInstanceDetailService taskInstanceDetailService; /** * 创建任务单 * - * @param contextName 上下文名称,这里特指应用名 - * @param changeType 变更类型 - * @param envAlias 环境别名 - * @param source 来源 - * @param reason 变更原因 - * @param dataMap 任务参数 + * @param contextName 上下文名称,这里特指应用名 + * @param changeTypeEnum 变更类型 + * @param envAlias 环境别名 + * @param source 来源 + * @param reason 变更原因 + * @param dataMap 任务参数 */ @Transactional(rollbackFor = Exception.class) - public TaskInstanceInfoTb createJob(String contextName, TaskChangeTypeEnum changeType, String language, String envAlias, String source, String reason, JobDataMap dataMap) { + public TaskInstanceInfoTb createJob(String contextName, TaskChangeTypeEnum changeTypeEnum, String language, String envAlias, String source, String reason, JobDataMap dataMap) { if (dataMap == null) { dataMap = new JobDataMap(); } + // ========================== 获取任务编排模板 ========================== + TaskTemplateInfoVo taskInstanceInfoVo = taskTemplateInfoService.getTemplateInfoByECL(envAlias, contextName, language, changeTypeEnum.getCode()); + if (taskInstanceInfoVo == null) { + throw new BadRequestException("没有查询到任务编排模板"); + } + String templateInfo = taskInstanceInfoVo.getTemplateInfo(); + List taskTemplateNodeVos = JSON.parseArray(templateInfo, TaskTemplateNodeVo.class); + if (taskTemplateNodeVos == null || taskTemplateNodeVos.isEmpty()) { + throw new BadRequestException("没有查询到任务编排明细"); + } // ========================== 传递参数 ========================== // 应用名、资源类型 dataMap.put("contextName", contextName); // 开发语言、资源版本 dataMap.put("language", language); dataMap.put("envAlias", envAlias); + // 变更类型 + dataMap.put("changeType", changeTypeEnum.getCode()); // ========================== 创建任务 ========================== TaskInstanceInfoTb newInstance = new TaskInstanceInfoTb(); newInstance.setContextName(contextName); - newInstance.setChangeType(changeType.getCode()); + newInstance.setLanguage(language); + newInstance.setChangeType(changeTypeEnum.getCode()); newInstance.setEnvAlias(envAlias); newInstance.setStatus(TaskStatusEnum.Running.getCode()); newInstance.setFinishTime(null); newInstance.setSource(source); newInstance.setReason(reason); + newInstance.setTemplate(templateInfo); newInstance.setJobData(JSON.toJSONString(dataMap)); taskInstanceInfoService.save(newInstance); dataMap.put("id", newInstance.getId()); // ========================== 执行任务 ========================== - JobKey jobKey = JobKey.jobKey(changeType.getCode(), contextName); - TriggerKey triggerKey = TriggerKey.triggerKey(changeType.getCode(), contextName); + JobKey jobKey = JobKey.jobKey(changeTypeEnum.getCode(), contextName); + TriggerKey triggerKey = TriggerKey.triggerKey(changeTypeEnum.getCode(), contextName); JobDetail jobDetail = JobBuilder.newJob(TaskJobBean.class).withIdentity(jobKey).usingJobData(dataMap).build(); Trigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).startNow().build(); try { @@ -114,4 +143,89 @@ public class TaskManage { throw new RuntimeException(e); } } + + @Transactional(rollbackFor = Exception.class) + public TaskInstanceInfoTb retryJob(Long id, String retryNodeCode) { + // ========================== 查询任务 ========================== + TaskInstanceInfoTb taskInstanceInfoTb = taskInstanceInfoService.getById(id); + if (taskInstanceInfoTb == null) { + throw new BadRequestException("任务不存在"); + } + // ========================== 失败的任务才能重试 ========================== + if (TaskStatusEnum.Success.getCode().equals(taskInstanceInfoTb.getStatus())) { + throw new BadRequestException("任务已执行完毕,无法重试"); + } + // 参数重放 + JobDataMap dataMap = JSON.parseObject(taskInstanceInfoTb.getJobData(), JobDataMap.class); + if (dataMap == null) { + dataMap = new JobDataMap(); + } + taskInstanceInfoTb.setStatus(TaskStatusEnum.Running.getCode()); + taskInstanceInfoTb.setFinishTime(null); + taskInstanceInfoService.updateById(taskInstanceInfoTb); + // ========================== 执行任务 ========================== + dataMap.put("retryNodeCode", retryNodeCode); + String changeType = taskInstanceInfoTb.getChangeType(); + String contextName = taskInstanceInfoTb.getContextName(); + JobKey jobKey = JobKey.jobKey(changeType, contextName); + TriggerKey triggerKey = TriggerKey.triggerKey(changeType, contextName); + JobDetail jobDetail = JobBuilder.newJob(TaskJobBean.class).withIdentity(jobKey).usingJobData(dataMap).build(); + Trigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).startNow().build(); + try { + scheduler.scheduleJob(jobDetail, cronTrigger); + } catch (ObjectAlreadyExistsException e) { + throw new BadRequestException("任务已存在,跳过加载"); + } catch (SchedulerException e) { + log.error("任务执行失败", e); + throw new BadRequestException(e); + } + return taskInstanceInfoTb; + } + + public TaskInstanceInfoVo getLastInfo(String contextName, String language, String envAlias, String changeType) { + TaskInstanceInfoVo record = new TaskInstanceInfoVo(); + + TaskInstanceInfoTb historyInstance = taskInstanceInfoService.getLastHistoryInstance(contextName, language, envAlias, changeType); + if (historyInstance == null) { + // 仅返回模板 + TaskTemplateInfoVo templateInfo = taskTemplateInfoService.getTemplateInfoByECL(envAlias, contextName, language, changeType); + record.setTemplate(templateInfo.getTemplateInfo()); + return record; + } + + record = BeanUtil.copyProperties(historyInstance, TaskInstanceInfoVo.class); + record.setHistory(buildNodeList(record)); + + TaskInstanceInfoTb runningInstance = taskInstanceInfoService.getLastRunningInstance(contextName, language, envAlias, changeType); + if (runningInstance != null) { + TaskInstanceInfoVo taskInstanceInfoVo = BeanUtil.copyProperties(runningInstance, TaskInstanceInfoVo.class); + record.setCurrent(buildNodeList(taskInstanceInfoVo)); + } + return record; + } + + private List buildNodeList(TaskInstanceInfoVo record) { + List records = new ArrayList<>(); + + // 节点明细 + List taskInstanceDetails = taskInstanceDetailService.queryByInstanceId(record.getId()); + for (TaskInstanceDetailTb taskInstanceDetail : taskInstanceDetails) { + TaskInstanceNodeVo instanceNodeVo = new TaskInstanceNodeVo(); + instanceNodeVo.setCode(taskInstanceDetail.getBizCode()); + instanceNodeVo.setName(taskInstanceDetail.getBizName()); + instanceNodeVo.setStartTime(taskInstanceDetail.getStartTime()); + instanceNodeVo.setFinishTime(taskInstanceDetail.getFinishTime()); + if (taskInstanceDetail.getFinishTime() == null) { + instanceNodeVo.setDurationDesc(CsDateUtil.formatSecondsDuration(taskInstanceDetail.getStartTime(), new Date())); + } else { + instanceNodeVo.setDurationDesc(CsDateUtil.formatSecondsDuration(taskInstanceDetail.getStartTime(), taskInstanceDetail.getFinishTime())); + } + instanceNodeVo.setRunningDesc(taskInstanceDetail.getExecuteInfo()); + instanceNodeVo.setStatus(taskInstanceDetail.getExecuteStatus()); + instanceNodeVo.setStatusDesc(TaskStatusEnum.getDesc(taskInstanceDetail.getExecuteStatus())); + records.add(instanceNodeVo); + } + + return records; + } } diff --git a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/dal/dataobject/TaskInstanceInfoTb.java b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/dal/dataobject/TaskInstanceInfoTb.java index 23f9982e..737026c7 100644 --- a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/dal/dataobject/TaskInstanceInfoTb.java +++ b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/dal/dataobject/TaskInstanceInfoTb.java @@ -72,6 +72,13 @@ public class TaskInstanceInfoTb extends CsObject { @TableField("context_name") private String contextName; + /** + * 语言 + */ + @ApiModelProperty("语言") + @TableField("`language`") + private String language; + /** * 变更类型 */ @@ -114,6 +121,13 @@ public class TaskInstanceInfoTb extends CsObject { @ApiModelProperty("变更原因") private String reason; + /** + * 任务模板 + */ + @TableField("template") + @ApiModelProperty("template") + private String template; + /** * QuartzJob参数 */ diff --git a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/dal/model/TaskInstanceInfoVo.java b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/dal/model/TaskInstanceInfoVo.java new file mode 100644 index 00000000..0bfdff33 --- /dev/null +++ b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/dal/model/TaskInstanceInfoVo.java @@ -0,0 +1,26 @@ +package cn.odboy.task.dal.model; + +import cn.odboy.task.dal.dataobject.TaskInstanceInfoTb; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +/** + * 任务实例数据 + * + * @author odboy + * @date 2025-10-01 + */ +@Getter +@Setter +public class TaskInstanceInfoVo extends TaskInstanceInfoTb { + /** + * 进行中 + */ + private List current; + /** + * 历史已完成或异常 + */ + private List history; +} diff --git a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/dal/model/TaskInstanceNodeVo.java b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/dal/model/TaskInstanceNodeVo.java new file mode 100644 index 00000000..645f748d --- /dev/null +++ b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/dal/model/TaskInstanceNodeVo.java @@ -0,0 +1,65 @@ +/* + * Copyright 2021-2025 Odboy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.odboy.task.dal.model; + +import cn.odboy.base.CsObject; +import lombok.Getter; +import lombok.Setter; + +import java.util.Date; + +/** + * 任务节点数据 + * + * @author odboy + */ +@Getter +@Setter +public class TaskInstanceNodeVo extends CsObject { + /** + * 业务编码 + */ + protected String code; + /** + * 业务名称 + */ + protected String name; + /** + * 开始时间 + */ + protected Date startTime; + /** + * 完成时间 + */ + protected Date finishTime; + /** + * 耗时多久 + */ + protected String durationDesc; + /** + * 进行中描述 + */ + protected String runningDesc; + /** + * 节点状态编码 + */ + protected String status; + /** + * 节点状态描述 + */ + protected String statusDesc; +} diff --git a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/dal/mysql/TaskTemplateInfoMapper.java b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/dal/mysql/TaskTemplateInfoMapper.java index e22d17ef..e646614e 100644 --- a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/dal/mysql/TaskTemplateInfoMapper.java +++ b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/dal/mysql/TaskTemplateInfoMapper.java @@ -31,5 +31,17 @@ import org.apache.ibatis.annotations.Param; */ @Mapper public interface TaskTemplateInfoMapper extends BaseMapper { - TaskTemplateInfoVo selectTemplateInfoByECL(@Param("envAlias") String envAlias, @Param("contextName") String contextName, @Param("language") String language); + /** + * @param envAlias 环境别称 + * @param contextName 应用名称、资源类型 + * @param language 语言、版本 + * @param changeType 变更类型 + * @return / + */ + TaskTemplateInfoVo selectTemplateInfoByECL( + @Param("envAlias") String envAlias, + @Param("contextName") String contextName, + @Param("language") String language, + @Param("changeType") String changeType + ); } diff --git a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/TaskInstanceDetailService.java b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/TaskInstanceDetailService.java index bb6657d6..38712322 100644 --- a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/TaskInstanceDetailService.java +++ b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/TaskInstanceDetailService.java @@ -19,6 +19,8 @@ import cn.odboy.task.dal.dataobject.TaskInstanceDetailTb; import com.baomidou.mybatisplus.extension.service.IService; import org.quartz.JobDataMap; +import java.util.List; + /** *

* 任务实例明细 服务类 @@ -30,7 +32,11 @@ import org.quartz.JobDataMap; public interface TaskInstanceDetailService extends IService { void fastFailWithInfo(Long instanceId, String code, String message); - void fastSuccessWithInfo(Long id, String code, String executeInfo); + void fastSuccessWithInfo(Long instanceId, String code, String executeInfo); - void fastStart(Long id, String code, JobDataMap dataMap); + void fastStart(Long instanceId, String code, JobDataMap dataMap); + + List queryByInstanceIdAndBizCodeList(Long instanceId, List bizCodes); + + List queryByInstanceId(Long instanceId); } diff --git a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/TaskInstanceInfoService.java b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/TaskInstanceInfoService.java index 8f3032ce..57c6d53c 100644 --- a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/TaskInstanceInfoService.java +++ b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/TaskInstanceInfoService.java @@ -36,4 +36,7 @@ public interface TaskInstanceInfoService extends IService { void fastSuccessWithData(Long id, JobDataMap dataMap); + TaskInstanceInfoTb getLastRunningInstance(String contextName, String language, String envAlias, String changeType); + + TaskInstanceInfoTb getLastHistoryInstance(String contextName, String language, String envAlias, String changeType); } diff --git a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/TaskInstanceStepDetailService.java b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/TaskInstanceStepDetailService.java index 77017f0f..ad88278c 100644 --- a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/TaskInstanceStepDetailService.java +++ b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/TaskInstanceStepDetailService.java @@ -18,6 +18,8 @@ package cn.odboy.task.service; import cn.odboy.task.dal.dataobject.TaskInstanceStepDetailTb; import com.baomidou.mybatisplus.extension.service.IService; +import java.util.List; + /** *

* 任务实例步骤明细 服务类 @@ -42,4 +44,11 @@ public interface TaskInstanceStepDetailService extends IService instanceDetailIds); } diff --git a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/TaskTemplateInfoService.java b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/TaskTemplateInfoService.java index 203bbf10..6277818a 100644 --- a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/TaskTemplateInfoService.java +++ b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/TaskTemplateInfoService.java @@ -28,5 +28,5 @@ import com.baomidou.mybatisplus.extension.service.IService; * @since 2025-09-28 */ public interface TaskTemplateInfoService extends IService { - TaskTemplateInfoVo getTemplateInfoByECL(String envAlias, String contextName, String language); + TaskTemplateInfoVo getTemplateInfoByECL(String envAlias, String contextName, String language, String changeType); } diff --git a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/impl/TaskInstanceDetailServiceImpl.java b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/impl/TaskInstanceDetailServiceImpl.java index 0f28d509..7df32720 100644 --- a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/impl/TaskInstanceDetailServiceImpl.java +++ b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/impl/TaskInstanceDetailServiceImpl.java @@ -15,6 +15,7 @@ */ package cn.odboy.task.service.impl; +import cn.hutool.core.collection.CollUtil; import cn.odboy.task.constant.TaskStatusEnum; import cn.odboy.task.dal.dataobject.TaskInstanceDetailTb; import cn.odboy.task.dal.mysql.TaskInstanceDetailMapper; @@ -25,6 +26,7 @@ import org.quartz.JobDataMap; import org.springframework.stereotype.Service; import java.util.Date; +import java.util.List; /** *

@@ -40,12 +42,10 @@ public class TaskInstanceDetailServiceImpl extends ServiceImpl queryByInstanceIdAndBizCodeList(Long instanceId, List bizCodeList) { + if (CollUtil.isEmpty(bizCodeList)) { + return CollUtil.newArrayList(); + } + return lambdaQuery().eq(TaskInstanceDetailTb::getInstanceId, instanceId).in(TaskInstanceDetailTb::getBizCode, bizCodeList).list(); + } + + @Override + public List queryByInstanceId(Long instanceId) { + return lambdaQuery().eq(TaskInstanceDetailTb::getInstanceId, instanceId).orderByAsc(TaskInstanceDetailTb::getId).list(); } } diff --git a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/impl/TaskInstanceInfoServiceImpl.java b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/impl/TaskInstanceInfoServiceImpl.java index eeb5ce7b..8c08acd4 100644 --- a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/impl/TaskInstanceInfoServiceImpl.java +++ b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/impl/TaskInstanceInfoServiceImpl.java @@ -80,4 +80,28 @@ public class TaskInstanceInfoServiceImpl extends ServiceImpl * 任务实例步骤明细 服务实现类 @@ -52,4 +56,14 @@ public class TaskInstanceStepDetailServiceImpl extends ServiceImpl instanceDetailIds) { + if (CollUtil.isEmpty(instanceDetailIds)) { + return; + } + remove(new LambdaQueryWrapper() + .in(TaskInstanceStepDetailTb::getInstanceDetailId, instanceDetailIds) + ); + } } diff --git a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/impl/TaskTemplateInfoServiceImpl.java b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/impl/TaskTemplateInfoServiceImpl.java index 75d56b63..2a8ed83f 100644 --- a/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/impl/TaskTemplateInfoServiceImpl.java +++ b/cutejava/cutejava-module-task/src/main/java/cn/odboy/task/service/impl/TaskTemplateInfoServiceImpl.java @@ -34,7 +34,7 @@ import org.springframework.stereotype.Service; public class TaskTemplateInfoServiceImpl extends ServiceImpl implements TaskTemplateInfoService { @Override - public TaskTemplateInfoVo getTemplateInfoByECL(String envAlias, String contextName, String language) { - return baseMapper.selectTemplateInfoByECL(envAlias, contextName, language); + public TaskTemplateInfoVo getTemplateInfoByECL(String envAlias, String contextName, String language, String changeType) { + return baseMapper.selectTemplateInfoByECL(envAlias, contextName, language, changeType); } } diff --git a/cutejava/cutejava-module-task/src/main/resources/mapper/TaskTemplateInfoMapper.xml b/cutejava/cutejava-module-task/src/main/resources/mapper/TaskTemplateInfoMapper.xml index 875f5edb..b0f24dbd 100644 --- a/cutejava/cutejava-module-task/src/main/resources/mapper/TaskTemplateInfoMapper.xml +++ b/cutejava/cutejava-module-task/src/main/resources/mapper/TaskTemplateInfoMapper.xml @@ -14,5 +14,6 @@ WHERE t1.context_name = #{contextName} AND t2.env_alias = #{envAlias} AND t2.`language` = #{language} + AND t2.`change_type` = #{changeType} diff --git a/cutejava/cutejava-starter/src/main/resources/application-dev.yml b/cutejava/cutejava-starter/src/main/resources/application-dev.yml index 3a924d91..2e6d6c94 100644 --- a/cutejava/cutejava-starter/src/main/resources/application-dev.yml +++ b/cutejava/cutejava-starter/src/main/resources/application-dev.yml @@ -53,10 +53,10 @@ spring: druid: db-type: com.alibaba.druid.pool.DruidDataSource # sql监控 - # driverClassName: com.p6spy.engine.spy.P6SpyDriver - # url: jdbc:p6spy:mysql://192.168.100.128:23306/cutejava?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true - driverClassName: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://192.168.100.128:23306/cutejava?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true + driverClassName: com.p6spy.engine.spy.P6SpyDriver + url: jdbc:p6spy:mysql://192.168.100.128:23306/cutejava?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true +# driverClassName: com.mysql.cj.jdbc.Driver +# url: jdbc:mysql://192.168.100.128:23306/cutejava?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true username: root password: kd123456 # 初始连接数,建议设置为与最小空闲连接数相同 diff --git a/cutejava/docs/mysql/cleardb.sql b/cutejava/docs/mysql/cleardb.sql deleted file mode 100644 index 6f331f1e..00000000 --- a/cutejava/docs/mysql/cleardb.sql +++ /dev/null @@ -1,17 +0,0 @@ -TRUNCATE TABLE system_operation_log; -TRUNCATE TABLE system_oss_storage; -TRUNCATE TABLE system_quartz_log; -TRUNCATE TABLE task_instance_info; -TRUNCATE TABLE task_instance_detail; -TRUNCATE TABLE task_instance_step_detail; -update system_dept set create_by='admin', update_by='admin', create_time = '2021-03-20 22:04:13', update_time = '2021-03-20 22:04:13'; -update system_dict set create_by='admin', update_by='admin', create_time = '2021-03-20 22:04:13', update_time = '2021-03-20 22:04:13'; -update system_dict_detail set create_by='admin', update_by='admin', create_time = '2021-03-20 22:04:13', update_time = '2021-03-20 22:04:13'; -update system_job set create_by='admin', update_by='admin', create_time = '2021-03-20 22:04:13', update_time = '2021-03-20 22:04:13'; -update system_local_storage set create_by='admin', update_by='admin', create_time = '2021-03-20 22:04:13', update_time = '2021-03-20 22:04:13'; -update system_menu set create_by='admin', update_by='admin', create_time = '2021-03-20 22:04:13', update_time = '2021-03-20 22:04:13'; -update system_quartz_job set create_by='admin', update_by='admin', create_time = '2021-03-20 22:04:13', update_time = '2021-03-20 22:04:13'; -update system_role set create_by='admin', update_by='admin', create_time = '2021-03-20 22:04:13', update_time = '2021-03-20 22:04:13'; -update system_user set create_by='admin', update_by='admin', create_time = '2021-03-20 22:04:13', update_time = '2021-03-20 22:04:13'; -update task_pipeline_config set create_by='admin', create_time = '2021-03-20 22:04:13'; -update task_template_info set create_by='admin', create_time = '2021-03-20 22:04:13'; \ No newline at end of file diff --git a/cutejava/docs/mysql/cutejava.sql b/cutejava/docs/mysql/cutejava.sql index 9d8405f4..cc90ea2e 100644 --- a/cutejava/docs/mysql/cutejava.sql +++ b/cutejava/docs/mysql/cutejava.sql @@ -10,8 +10,6 @@ Target Server Type : MySQL Target Server Version : 80025 (8.0.25) File Encoding : 65001 - - Date: 09/10/2025 12:25:16 */ SET NAMES utf8mb4; @@ -26,7 +24,7 @@ CREATE TABLE `demo_time_table_copy1` ( `create_time` datetime NOT NULL COMMENT '创建时间', `update_time` datetime NOT NULL COMMENT '修改时间', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of demo_time_table_copy1 @@ -44,7 +42,7 @@ CREATE TABLE `demo_user_time_logic_table` ( `update_time` datetime NOT NULL COMMENT '修改时间', `available` tinyint(1) NOT NULL DEFAULT 1 COMMENT '数据有效性', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of demo_user_time_logic_table @@ -61,7 +59,7 @@ CREATE TABLE `demo_user_time_table` ( `update_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '修改人', `update_time` datetime NOT NULL COMMENT '修改时间', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of demo_user_time_table @@ -221,7 +219,7 @@ CREATE TABLE `qrtz_scheduler_state` ( -- Records of qrtz_scheduler_state -- ---------------------------- INSERT INTO `qrtz_scheduler_state` VALUES ('ClusteredScheduler', 'DESKTOP-FM44BLS1742558233429', 1742558255052, 20000); -INSERT INTO `qrtz_scheduler_state` VALUES ('cutejava', 'auto', 1759044047208, 10000); +INSERT INTO `qrtz_scheduler_state` VALUES ('cutejava', 'auto', 1760951912083, 10000); -- ---------------------------- -- Table structure for qrtz_simple_triggers @@ -355,7 +353,7 @@ CREATE TABLE `system_dict` ( `create_time` datetime NULL DEFAULT NULL COMMENT '创建日期', `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '数据字典' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '数据字典' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of system_dict @@ -363,6 +361,7 @@ CREATE TABLE `system_dict` ( INSERT INTO `system_dict` VALUES (1, 'user_status', '用户状态', 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); INSERT INTO `system_dict` VALUES (4, 'dept_status', '部门状态', 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); INSERT INTO `system_dict` VALUES (5, 'job_status', '岗位状态', 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict` VALUES (8, 'test_status', '测试状态', 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); -- ---------------------------- -- Table structure for system_dict_detail @@ -380,7 +379,7 @@ CREATE TABLE `system_dict_detail` ( `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`) USING BTREE, INDEX `idx_dict_id`(`dict_id` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '数据字典详情' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 29 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '数据字典详情' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of system_dict_detail @@ -391,6 +390,28 @@ INSERT INTO `system_dict_detail` VALUES (3, 4, '启用', 'true', 1, 'admin', 'ad INSERT INTO `system_dict_detail` VALUES (4, 4, '停用', 'false', 2, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); INSERT INTO `system_dict_detail` VALUES (5, 5, '启用', 'true', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); INSERT INTO `system_dict_detail` VALUES (6, 5, '停用', 'false', 2, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (7, 8, '打瞌睡01', 'ks01', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (8, 8, '打瞌睡2', 'ks02', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (9, 8, '打瞌睡3', 'ks03', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (10, 8, '打瞌睡4', 'ks04', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (11, 8, '打瞌睡5', 'ks05', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (12, 8, '打瞌睡6', 'ks06', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (13, 8, '打瞌睡7', 'ks07', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (14, 8, '打瞌睡8', 'ks08', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (15, 8, '打瞌睡9', 'ks09', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (16, 8, '打瞌睡10', 'ks10', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (17, 8, '打瞌睡11', 'ks11', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (18, 8, '打瞌睡12', 'ks12', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (19, 8, '打瞌睡13', 'ks13', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (20, 8, '打瞌睡14', 'ks14', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (21, 8, '打瞌睡15', 'ks15', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (22, 8, '打瞌睡16', 'ks16', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (23, 8, '打瞌睡17', 'ks17', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (24, 8, '打瞌睡18', 'ks18', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (25, 8, '打瞌睡19', 'ks19', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (26, 8, '打瞌睡20', 'ks20', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (27, 8, '打瞌睡21', 'ks21', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); +INSERT INTO `system_dict_detail` VALUES (28, 8, '打瞌睡22', 'ks22', 1, 'admin', 'admin', '2021-03-20 22:04:13', '2021-03-20 22:04:13'); -- ---------------------------- -- Table structure for system_email_config @@ -571,7 +592,7 @@ CREATE TABLE `system_operation_log` ( `exception_detail` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL, `create_time` datetime NOT NULL, PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '审计日志' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '审计日志' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of system_operation_log @@ -654,7 +675,7 @@ CREATE TABLE `system_quartz_log` ( `exception_detail` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '异常详情', `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '定时任务日志' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '定时任务日志' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of system_quartz_log @@ -793,12 +814,19 @@ INSERT INTO `system_roles_menus` VALUES (121, 2); INSERT INTO `system_roles_menus` VALUES (122, 1); INSERT INTO `system_roles_menus` VALUES (122, 2); INSERT INTO `system_roles_menus` VALUES (125, 1); +INSERT INTO `system_roles_menus` VALUES (125, 2); INSERT INTO `system_roles_menus` VALUES (126, 1); +INSERT INTO `system_roles_menus` VALUES (126, 2); INSERT INTO `system_roles_menus` VALUES (127, 1); +INSERT INTO `system_roles_menus` VALUES (127, 2); INSERT INTO `system_roles_menus` VALUES (128, 1); +INSERT INTO `system_roles_menus` VALUES (128, 2); INSERT INTO `system_roles_menus` VALUES (129, 1); +INSERT INTO `system_roles_menus` VALUES (129, 2); INSERT INTO `system_roles_menus` VALUES (130, 1); +INSERT INTO `system_roles_menus` VALUES (130, 2); INSERT INTO `system_roles_menus` VALUES (132, 1); +INSERT INTO `system_roles_menus` VALUES (132, 2); -- ---------------------------- -- Table structure for system_user @@ -1203,12 +1231,14 @@ CREATE TABLE `task_instance_info` ( `create_time` datetime NOT NULL COMMENT '创建时间', `update_time` datetime NOT NULL COMMENT '修改时间', `context_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '名称', + `language` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '语言', `change_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '变更类型', `env_alias` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '环境别名', `status` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '状态(running进行中 success成功 fail失败)', `finish_time` datetime NULL DEFAULT NULL COMMENT '完成时间', `source` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '来源', `reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '变更原因', + `template` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '任务模板', `job_data` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'QuartzJob参数', `error_message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '异常信息', PRIMARY KEY (`id`) USING BTREE diff --git a/cutejava/pom.xml b/cutejava/pom.xml index 83083559..dc6528d1 100644 --- a/cutejava/pom.xml +++ b/cutejava/pom.xml @@ -106,12 +106,12 @@ spring-boot-starter-data-redis - - - org.redisson - redisson - 3.50.0 - + + + + + +