diff --git a/tacit-common/pom.xml b/common/common-core/pom.xml similarity index 53% rename from tacit-common/pom.xml rename to common/common-core/pom.xml index eab4713..ca0e2da 100644 --- a/tacit-common/pom.xml +++ b/common/common-core/pom.xml @@ -6,42 +6,28 @@ tacit-parent com.tacit 1.0.0-SNAPSHOT + ../../pom.xml 4.0.0 - tacit-common - Tacit Common - Common module for Tacit microservices + common-core + Common Core + Core utilities and global handlers module for Tacit microservices - + + + com.tacit + common-model + ${project.parent.version} + + + org.springframework.boot spring-boot-starter-web - - - com.alibaba.cloud - spring-cloud-starter-alibaba-nacos-discovery - - - com.alibaba.cloud - spring-cloud-starter-alibaba-nacos-config - - - - - org.springframework.cloud - spring-cloud-starter-bootstrap - - - - - org.springframework.cloud - spring-cloud-starter-openfeign - - io.jsonwebtoken @@ -58,19 +44,6 @@ runtime - - - org.projectlombok - lombok - provided - - - - - org.springframework.boot - spring-boot-starter-validation - - org.apache.commons @@ -78,17 +51,6 @@ - - org.junit.jupiter - junit-jupiter-api - test - - - org.junit.jupiter - junit-jupiter-engine - test - - org.junit.jupiter junit-jupiter diff --git a/tacit-common/src/main/java/com/tacit/common/handler/GlobalExceptionHandler.java b/common/common-core/src/main/java/com/tacit/common/handler/GlobalExceptionHandler.java similarity index 99% rename from tacit-common/src/main/java/com/tacit/common/handler/GlobalExceptionHandler.java rename to common/common-core/src/main/java/com/tacit/common/handler/GlobalExceptionHandler.java index e0e64ad..dafe3f4 100644 --- a/tacit-common/src/main/java/com/tacit/common/handler/GlobalExceptionHandler.java +++ b/common/common-core/src/main/java/com/tacit/common/handler/GlobalExceptionHandler.java @@ -69,4 +69,4 @@ public class GlobalExceptionHandler { log.error("系统异常: {}", e.getMessage(), e); return ResponseResult.fail(500, "系统内部错误"); } -} +} \ No newline at end of file diff --git a/tacit-common/src/main/java/com/tacit/common/utils/JwtUtils.java b/common/common-core/src/main/java/com/tacit/common/utils/JwtUtils.java similarity index 80% rename from tacit-common/src/main/java/com/tacit/common/utils/JwtUtils.java rename to common/common-core/src/main/java/com/tacit/common/utils/JwtUtils.java index 6dbe715..e08cb3e 100644 --- a/tacit-common/src/main/java/com/tacit/common/utils/JwtUtils.java +++ b/common/common-core/src/main/java/com/tacit/common/utils/JwtUtils.java @@ -13,8 +13,8 @@ import java.util.Map; @Slf4j public class JwtUtils { -// private static final SecretKey SECRET_KEY = Keys.hmacShaKeyFor(CommonConstant.JWT_SECRET.getBytes(StandardCharsets.UTF_8)); - private static final SecretKey SECRET_KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256); + private static final SecretKey SECRET_KEY = Keys.hmacShaKeyFor(CommonConstant.JWT_SECRET.getBytes(StandardCharsets.UTF_8)); +// private static final SecretKey SECRET_KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256); /** * 生成JWT令牌 @@ -24,13 +24,23 @@ public class JwtUtils { public static String generateToken(Map claims) { Date now = new Date(); Date expireDate = new Date(now.getTime() + CommonConstant.JWT_EXPIRE_TIME); + + log.info("JWT生成参数: claims={}, now={}, expireDate={}, secretKey={}", claims, now, expireDate, SECRET_KEY); - return Jwts.builder() - .setClaims(claims) - .setIssuedAt(now) - .setExpiration(expireDate) - .signWith(SECRET_KEY, SignatureAlgorithm.HS256) - .compact(); + String token = null; + try { + token = Jwts.builder() + .setClaims(claims) + .setIssuedAt(now) + .setExpiration(expireDate) + .signWith(SECRET_KEY, SignatureAlgorithm.HS256) + .compact(); + log.info("JWT生成成功: {}", token); + } catch (Exception e) { + log.error("JWT生成失败: {}", e.getMessage(), e); + } + + return token; } public static Long getUserIdFromToken(String token) { Claims claims = parseToken(token); @@ -118,4 +128,4 @@ public class JwtUtils { return false; } } -} +} \ No newline at end of file diff --git a/tacit-common/src/test/java/com/tacit/common/utils/JwtUtilsTest.java b/common/common-core/src/test/java/com/tacit/common/utils/JwtUtilsTest.java similarity index 86% rename from tacit-common/src/test/java/com/tacit/common/utils/JwtUtilsTest.java rename to common/common-core/src/test/java/com/tacit/common/utils/JwtUtilsTest.java index 258daca..4b953d6 100644 --- a/tacit-common/src/test/java/com/tacit/common/utils/JwtUtilsTest.java +++ b/common/common-core/src/test/java/com/tacit/common/utils/JwtUtilsTest.java @@ -24,7 +24,13 @@ public class JwtUtilsTest { claims.put("userId", 1L); claims.put("username", "testuser"); claims.put("role", "admin"); - token = JwtUtils.generateToken(claims); + try { + System.out.println("Before generateToken: claims = " + claims); + token = JwtUtils.generateToken(claims); + System.out.println("After generateToken: token = " + token); + } catch (Exception e) { + e.printStackTrace(); + } } @Test @@ -70,4 +76,4 @@ public class JwtUtilsTest { String role = JwtUtils.getRoleFromToken(token); assertEquals("admin", role); } -} +} \ No newline at end of file diff --git a/common/common-feign/pom.xml b/common/common-feign/pom.xml new file mode 100644 index 0000000..86eccd6 --- /dev/null +++ b/common/common-feign/pom.xml @@ -0,0 +1,57 @@ + + + + tacit-parent + com.tacit + 1.0.0-SNAPSHOT + ../../pom.xml + + 4.0.0 + + common-feign + Common Feign + Feign clients module for Tacit microservices + + + + + com.tacit + common-model + ${project.parent.version} + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + + org.junit.jupiter + junit-jupiter + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + true + + + + + \ No newline at end of file diff --git a/tacit-common/src/main/java/com/tacit/common/feign/AdminFeignClient.java b/common/common-feign/src/main/java/com/tacit/common/feign/AdminFeignClient.java similarity index 99% rename from tacit-common/src/main/java/com/tacit/common/feign/AdminFeignClient.java rename to common/common-feign/src/main/java/com/tacit/common/feign/AdminFeignClient.java index c488c48..1f8fb51 100644 --- a/tacit-common/src/main/java/com/tacit/common/feign/AdminFeignClient.java +++ b/common/common-feign/src/main/java/com/tacit/common/feign/AdminFeignClient.java @@ -10,4 +10,4 @@ public interface AdminFeignClient { @GetMapping("/user/info/{id}") ResponseResult getUserById(@PathVariable("id") Long id); -} +} \ No newline at end of file diff --git a/tacit-common/src/main/java/com/tacit/common/feign/AppApiFeignClient.java b/common/common-feign/src/main/java/com/tacit/common/feign/AppApiFeignClient.java similarity index 99% rename from tacit-common/src/main/java/com/tacit/common/feign/AppApiFeignClient.java rename to common/common-feign/src/main/java/com/tacit/common/feign/AppApiFeignClient.java index 332add1..3555d93 100644 --- a/tacit-common/src/main/java/com/tacit/common/feign/AppApiFeignClient.java +++ b/common/common-feign/src/main/java/com/tacit/common/feign/AppApiFeignClient.java @@ -10,4 +10,4 @@ public interface AppApiFeignClient { @GetMapping("/user/info/{userId}") ResponseResult getUserInfo(@PathVariable("userId") Long userId); -} +} \ No newline at end of file diff --git a/common/common-model/pom.xml b/common/common-model/pom.xml new file mode 100644 index 0000000..01b3109 --- /dev/null +++ b/common/common-model/pom.xml @@ -0,0 +1,52 @@ + + + + tacit-parent + com.tacit + 1.0.0-SNAPSHOT + ../../pom.xml + + 4.0.0 + + common-model + Common Model + Model, constant and exception module for Tacit microservices + + + + + org.projectlombok + lombok + true + + + + + org.springframework.boot + spring-boot-starter-validation + provided + + + + + org.junit.jupiter + junit-jupiter + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + true + + + + + \ No newline at end of file diff --git a/tacit-common/src/main/java/com/tacit/common/constant/CommonConstant.java b/common/common-model/src/main/java/com/tacit/common/constant/CommonConstant.java similarity index 95% rename from tacit-common/src/main/java/com/tacit/common/constant/CommonConstant.java rename to common/common-model/src/main/java/com/tacit/common/constant/CommonConstant.java index b167652..7c19665 100644 --- a/tacit-common/src/main/java/com/tacit/common/constant/CommonConstant.java +++ b/common/common-model/src/main/java/com/tacit/common/constant/CommonConstant.java @@ -12,7 +12,7 @@ public class CommonConstant { // JWT相关常量 public static final String JWT_HEADER = "Authorization"; public static final String JWT_PREFIX = "Bearer "; - public static final String JWT_SECRET = "tacit_app_secret_key_2024"; + public static final String JWT_SECRET = "tacit_app_secret_key_2024_secure_strong_key_for_jwt_token"; // 7天 public static final Long JWT_EXPIRE_TIME = 7 * 24 * 60 * 60 * 1000L; @@ -24,4 +24,4 @@ public class CommonConstant { // 角色常量 public static final String ROLE_ADMIN = "admin"; public static final String ROLE_USER = "user"; -} +} \ No newline at end of file diff --git a/tacit-common/src/main/java/com/tacit/common/entity/ResponseResult.java b/common/common-model/src/main/java/com/tacit/common/entity/ResponseResult.java similarity index 99% rename from tacit-common/src/main/java/com/tacit/common/entity/ResponseResult.java rename to common/common-model/src/main/java/com/tacit/common/entity/ResponseResult.java index a4db039..9e679bb 100644 --- a/tacit-common/src/main/java/com/tacit/common/entity/ResponseResult.java +++ b/common/common-model/src/main/java/com/tacit/common/entity/ResponseResult.java @@ -48,4 +48,4 @@ public class ResponseResult implements Serializable { public boolean isSuccess() { return this.code == 200; } -} +} \ No newline at end of file diff --git a/tacit-common/src/main/java/com/tacit/common/exception/BusinessException.java b/common/common-model/src/main/java/com/tacit/common/exception/BusinessException.java similarity index 99% rename from tacit-common/src/main/java/com/tacit/common/exception/BusinessException.java rename to common/common-model/src/main/java/com/tacit/common/exception/BusinessException.java index 55f7efa..3ab18fe 100644 --- a/tacit-common/src/main/java/com/tacit/common/exception/BusinessException.java +++ b/common/common-model/src/main/java/com/tacit/common/exception/BusinessException.java @@ -31,4 +31,4 @@ public class BusinessException extends RuntimeException { super(message, cause); this.code = code; } -} +} \ No newline at end of file diff --git a/tacit-common/src/test/java/com/tacit/common/entity/ResponseResultTest.java b/common/common-model/src/test/java/com/tacit/common/entity/ResponseResultTest.java similarity index 99% rename from tacit-common/src/test/java/com/tacit/common/entity/ResponseResultTest.java rename to common/common-model/src/test/java/com/tacit/common/entity/ResponseResultTest.java index 971c856..8aed0fe 100644 --- a/tacit-common/src/test/java/com/tacit/common/entity/ResponseResultTest.java +++ b/common/common-model/src/test/java/com/tacit/common/entity/ResponseResultTest.java @@ -80,4 +80,4 @@ public class ResponseResultTest { assertTrue(toString.contains("操作成功")); // message assertTrue(toString.contains("test")); // data } -} +} \ No newline at end of file diff --git a/common/pom.xml b/common/pom.xml new file mode 100644 index 0000000..62b21f1 --- /dev/null +++ b/common/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + com.tacit + tacit-parent + 1.0.0-SNAPSHOT + + + common + pom + Common Aggregator + Aggregator module for common submodules + + + 21 + 21 + UTF-8 + + + + common-model + common-feign + common-core + xxljob + + + \ No newline at end of file diff --git a/common/xxljob/README.md b/common/xxljob/README.md new file mode 100644 index 0000000..817596a --- /dev/null +++ b/common/xxljob/README.md @@ -0,0 +1,201 @@ +# XXL-Job Starter + +一个基于XXL-Job的Spring Boot Starter,提供自动配置、服务发现和容器部署支持。 + +## 功能特性 + +- ✅ Spring Boot自动配置,简化XXL-Job集成 +- ✅ 支持Nacos服务发现,自动获取XXL-Job Admin地址 +- ✅ 容器部署支持,自动处理IP和端口映射 +- ✅ 执行器地址自动补全协议前缀(http://) +- ✅ 环境变量动态配置,灵活适配不同部署环境 +- ✅ 完善的日志记录和错误处理 + +## 快速开始 + +### 1. 添加依赖 + +在你的Spring Boot项目中添加以下依赖: + +```xml + + com.tacit + xxljob + 1.0.0-SNAPSHOT + +``` + +### 2. 启用XXL-Job + +在Spring Boot主类上添加`@EnableXxlJob`注解: + +```java +@SpringBootApplication +@EnableXxlJob +public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} +``` + +### 3. 配置XXL-Job + +在`application.yml`或`bootstrap.yml`中添加XXL-Job配置: + +```yaml +xxl: + job: + admin: + # XXL-Job Admin地址,多个地址用逗号分隔 + addresses: http://localhost:8080/xxl-job-admin + # 可选,调度中心通讯TOKEN + access-token: default_token + executor: + # 执行器AppName,默认使用spring.application.name + appname: my-xxl-job-executor + # 执行器IP,默认为空表示自动获取 + ip: + # 执行器端口,默认9099 + port: 9999 + # 执行器通讯TOKEN + access-token: default_token + # 执行器日志路径 + log-path: logs/applogs/xxl-job/jobhandler + # 执行器日志保存天数 + log-retention-days: 30 +``` + +### 4. 创建JobHandler + +```java +@Component +public class MyJobHandler { + + @XxlJob("myJobHandler") + public ReturnT execute(String param) throws Exception { + XxlJobLogger.log("XXL-Job, Hello World."); + System.out.println("执行任务: " + param); + return ReturnT.SUCCESS; + } +} +``` + +## 配置说明 + +### 核心配置项 + +| 配置项 | 说明 | 默认值 | +|-------|------|-------| +| xxl.job.admin.addresses | XXL-Job Admin地址 | - | +| xxl.job.admin.access-token | 调度中心通讯TOKEN | - | +| xxl.job.executor.appname | 执行器AppName | spring.application.name | +| xxl.job.executor.ip | 执行器IP | 自动获取 | +| xxl.job.executor.port | 执行器端口 | 9099 | +| xxl.job.executor.access-token | 执行器通讯TOKEN | - | +| xxl.job.executor.log-path | 执行器日志路径 | logs/applogs/xxl-job/jobhandler | +| xxl.job.executor.log-retention-days | 日志保存天数 | 30 | + +### 容器部署环境变量 + +| 环境变量 | 说明 | +|---------|------| +| XXL_JOB_EXECUTOR_IP | 容器真实IP(宿主机IP) | +| XXL_JOB_EXECUTOR_PORT | 容器映射后的真实端口 | +| XXL_JOB_ADMIN_ADDRESSES | XXL-Job Admin地址 | + +## 高级特性 + +### 自动服务发现 + +如果未配置`xxl.job.admin.addresses`,Starter会自动从Nacos注册中心发现XXL-Job Admin服务(服务名包含"xxl-job-admin")。 + +### 容器部署支持 + +在Docker或Kubernetes环境中,执行器会自动处理IP和端口映射: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-executor +spec: + replicas: 1 + template: + spec: + containers: + - name: my-executor + image: my-executor:latest + ports: + - containerPort: 9999 + env: + - name: XXL_JOB_EXECUTOR_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: XXL_JOB_EXECUTOR_PORT + value: "30099" # Kubernetes节点端口 + - name: spring.application.name + value: my-executor +``` + +### 自定义执行器地址 + +```yaml +xxl: + job: + executor: + # 完整的执行器地址,会自动补全协议前缀 + address: 192.168.3.67:9999 + ip: 192.168.3.67 + port: 9999 +``` + +## 常见问题 + +### 1. 执行器注册失败 + +- 检查`xxl.job.admin.addresses`配置是否正确 +- 检查网络连接是否正常 +- 检查防火墙设置 + +### 2. 任务执行失败,提示"no protocol" + +这是因为执行器地址缺少协议前缀导致的,请确保配置的地址包含`http://`前缀,或使用Starter的自动补全功能。 + +### 3. 容器环境下执行器地址不正确 + +请配置`XXL_JOB_EXECUTOR_IP`和`XXL_JOB_EXECUTOR_PORT`环境变量,指定宿主机的IP和映射后的端口。 + +## 开发和贡献 + +### 构建项目 + +```bash +mvn clean install -DskipTests +``` + +### 目录结构 + +``` +src/ +├── main/ +│ ├── java/ +│ │ └── com/tacit/starter/xxljob/ +│ │ ├── annotation/ # 注解类 +│ │ ├── properties/ # 配置属性类 +│ │ └── XxlJobAutoConfiguration.java # 自动配置类 +│ └── resources/ +│ └── META-INF/ +│ └── spring.factories # Spring Boot自动配置入口 +``` + +## 版本依赖 + +- Spring Boot 2.x +- XXL-Job Core 2.5.0 +- Spring Cloud Alibaba Nacos Discovery + +## 许可证 + +MIT License diff --git a/common/xxljob/pom.xml b/common/xxljob/pom.xml new file mode 100644 index 0000000..9b07a88 --- /dev/null +++ b/common/xxljob/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + com.tacit + tacit-parent + 1.0.0-SNAPSHOT + ../../pom.xml + + + xxljob + + + 21 + 21 + UTF-8 + 2.5.0 + + + + + com.xuxueli + xxl-job-core + ${xxl-job.version} + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + org.springframework.boot + spring-boot-autoconfigure + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + \ No newline at end of file diff --git a/common/xxljob/src/main/java/com/tacit/starter/xxljob/XxlJobAutoConfiguration.java b/common/xxljob/src/main/java/com/tacit/starter/xxljob/XxlJobAutoConfiguration.java new file mode 100644 index 0000000..89a82c1 --- /dev/null +++ b/common/xxljob/src/main/java/com/tacit/starter/xxljob/XxlJobAutoConfiguration.java @@ -0,0 +1,129 @@ +package com.tacit.starter.xxljob; + +import com.tacit.starter.xxljob.properties.XxlExecutorProperties; +import com.tacit.starter.xxljob.properties.XxlJobProperties; +import com.xxl.job.core.executor.impl.XxlJobSpringExecutor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.context.annotation.Bean; +import org.springframework.core.env.Environment; +import org.springframework.util.StringUtils; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * @Auther: xia + * @Date: 2026/1/4 13:56 + * @Description: com.tacit.starter.xxljob + * @version: 1.0 + */ +@EnableConfigurationProperties(XxlJobProperties.class) +public class XxlJobAutoConfiguration { + + private Logger log = LoggerFactory.getLogger(XxlJobAutoConfiguration.class); + + /** + * 服务名称 包含 XXL-JOB 则说明是 Admin + */ + private static final String XXL_JOB_ADMIN = "xxl-job-admin"; + + /** + * 配置xxl-job 执行器,提供自动发现 xxl-job 能力 + * + * @param xxlJobProperties xxl 配置 + * @param environment 环境变量 + * @param discoveryClient 注册发现客户端 + * @return XxlJobSpringExecutor + */ + @Bean + public XxlJobSpringExecutor xxlJobSpringExecutor(XxlJobProperties xxlJobProperties, Environment environment, DiscoveryClient discoveryClient) { + XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor(); + XxlExecutorProperties executor = xxlJobProperties.getExecutor(); + // 应用名默认为服务名 + String appName = executor.getAppname(); + if (!StringUtils.hasText(appName)) { + appName = environment.getProperty("spring.application.name"); + } + // 处理执行器通讯TOKEN + String accessToken = executor.getAccessToken(); + // 从环境变量获取 + String envAccessToken = environment.getProperty("xxl.job.accessToken"); + if (StringUtils.hasText(envAccessToken)) { + accessToken = envAccessToken; + } + // 从admin配置获取(如果admin和executor使用相同的token) + String adminAccessToken = xxlJobProperties.getAdmin().getAccessToken(); + if (!StringUtils.hasText(accessToken) && StringUtils.hasText(adminAccessToken)) { + accessToken = adminAccessToken; + } + + xxlJobSpringExecutor.setAppname(appName); + + // 处理执行器IP,支持容器环境下的真实IP获取 + String executorIp = executor.getIp(); + // 优先从环境变量获取容器的真实IP(宿主机IP) + String envIp = environment.getProperty("XXL_JOB_EXECUTOR_IP"); + if (StringUtils.hasText(envIp)) { + executorIp = envIp; + } + xxlJobSpringExecutor.setIp(executorIp); + + // 处理执行器端口,支持容器环境下的端口映射 + Integer executorPort = executor.getPort(); + // 优先从环境变量获取容器映射后的真实端口 + String envPort = environment.getProperty("XXL_JOB_EXECUTOR_PORT"); + if (StringUtils.hasText(envPort)) { + try { + executorPort = Integer.parseInt(envPort); + } catch (NumberFormatException e) { + log.warn("Invalid XXL_JOB_EXECUTOR_PORT value: {}", envPort); + } + } + xxlJobSpringExecutor.setPort(executorPort); + + // 处理执行器地址,确保包含http://协议前缀 + String address = executor.getAddress(); + if (!StringUtils.hasText(address) && StringUtils.hasText(executorIp) && executorPort > 0) { + // 如果没有配置address但配置了IP和端口,自动构建地址 + address = String.format("http://%s:%d", executorIp, executorPort); + } else if (StringUtils.hasText(address) && !address.startsWith("http://") && !address.startsWith("https://")) { + address = "http://" + address; + } + xxlJobSpringExecutor.setAddress(address); + xxlJobSpringExecutor.setAccessToken(accessToken); + xxlJobSpringExecutor.setLogPath(executor.getLogPath()); + xxlJobSpringExecutor.setLogRetentionDays(executor.getLogRetentionDays()); + + // 配置XXL-Job Admin地址 + String adminAddresses = xxlJobProperties.getAdmin().getAddresses(); + if (!StringUtils.hasText(adminAddresses)) { + // 从注册中心自动发现XXL-Job Admin + try { + List serviceIds = discoveryClient.getServices(); + if (serviceIds != null && !serviceIds.isEmpty()) { + List adminUrls = serviceIds.stream() + .filter(serviceId -> serviceId.toLowerCase().contains(XXL_JOB_ADMIN)) + .flatMap(serviceId -> discoveryClient.getInstances(serviceId).stream()) + .map(instance -> String.format("http://%s:%s/xxl-job-admin", instance.getHost(), instance.getPort())) + .distinct() + .collect(Collectors.toList()); + if (!adminUrls.isEmpty()) { + adminAddresses = String.join(",", adminUrls); + log.info("Auto discovered XXL-Job Admin addresses: {}", adminAddresses); + } else { + log.warn("No XXL-Job Admin service found in registry"); + } + } + } catch (Exception e) { + log.error("Failed to discover XXL-Job Admin from registry", e); + } + } + xxlJobSpringExecutor.setAdminAddresses(adminAddresses); + log.info("init-xxlJobSpringExecutor: " + xxlJobSpringExecutor.toString()); + return xxlJobSpringExecutor; + } + +} diff --git a/common/xxljob/src/main/java/com/tacit/starter/xxljob/annotation/EnableXxlJob.java b/common/xxljob/src/main/java/com/tacit/starter/xxljob/annotation/EnableXxlJob.java new file mode 100644 index 0000000..107b93e --- /dev/null +++ b/common/xxljob/src/main/java/com/tacit/starter/xxljob/annotation/EnableXxlJob.java @@ -0,0 +1,25 @@ +package com.tacit.starter.xxljob.annotation; + +import com.tacit.starter.xxljob.XxlJobAutoConfiguration; +import org.springframework.context.annotation.Import; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @Auther: xia + * @Date: 2026/1/4 13:51 + * @Description: com.tacit.starter.xxljob.annotation + * @version: 1.0 + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +@Import({XxlJobAutoConfiguration.class}) +public @interface EnableXxlJob { +} diff --git a/common/xxljob/src/main/java/com/tacit/starter/xxljob/properties/XxlAdminProperties.java b/common/xxljob/src/main/java/com/tacit/starter/xxljob/properties/XxlAdminProperties.java new file mode 100644 index 0000000..fca0906 --- /dev/null +++ b/common/xxljob/src/main/java/com/tacit/starter/xxljob/properties/XxlAdminProperties.java @@ -0,0 +1,22 @@ +package com.tacit.starter.xxljob.properties; + +import lombok.Data; + +/** + * @Auther: xia + * @Date: 2026/1/4 13:54 + * @Description: com.tacit.starter.xxljob.properties + * @version: 1.0 + */ +@Data +public class XxlAdminProperties { + /** + * 调度中心部署跟地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。 执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册; + */ + private String addresses; + + /** + * 调度中心通讯TOKEN [选填]:非空时启用; + */ + private String accessToken; +} diff --git a/common/xxljob/src/main/java/com/tacit/starter/xxljob/properties/XxlExecutorProperties.java b/common/xxljob/src/main/java/com/tacit/starter/xxljob/properties/XxlExecutorProperties.java new file mode 100644 index 0000000..ad74928 --- /dev/null +++ b/common/xxljob/src/main/java/com/tacit/starter/xxljob/properties/XxlExecutorProperties.java @@ -0,0 +1,51 @@ +package com.tacit.starter.xxljob.properties; + + +import lombok.Data; + +/** + * @Auther: xia + * @Date: 2026/1/4 13:56 + * @Description: com.tacit.starter.xxljob.properties + * @version: 1.0 + */ +@Data +public class XxlExecutorProperties { + + /** + * 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册 + */ + private String appname; + + /** + * 服务注册地址,优先使用该配置作为注册地址 为空时使用内嵌服务 ”IP:PORT“ 作为注册地址 从而更灵活的支持容器类型执行器动态IP和动态映射端口问题 + */ + private String address; + + /** + * 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP ,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 + * "调度中心请求并触发任务" + */ + private String ip; + + /** + * 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9099,单机部署多个执行器时,注意要配置不同执行器端口; + */ + private Integer port = 0; + + /** + * 执行器通讯TOKEN [必填]:从配置文件中取不到值时使用默认值; + */ + private String accessToken = ""; + + /** + * 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径; + */ + private String logPath = "logs/applogs/xxl-job/jobhandler"; + + /** + * 执行器日志保存天数 [选填] :值大于3时生效,启用执行器Log文件定期清理功能,否则不生效; + */ + private Integer logRetentionDays = 30; + +} diff --git a/common/xxljob/src/main/java/com/tacit/starter/xxljob/properties/XxlJobProperties.java b/common/xxljob/src/main/java/com/tacit/starter/xxljob/properties/XxlJobProperties.java new file mode 100644 index 0000000..230c4cc --- /dev/null +++ b/common/xxljob/src/main/java/com/tacit/starter/xxljob/properties/XxlJobProperties.java @@ -0,0 +1,23 @@ +package com.tacit.starter.xxljob.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.NestedConfigurationProperty; + +/** + * @Auther: xia + * @Date: 2026/1/4 13:57 + * @Description: com.tacit.starter.xxljob.properties + * @version: 1.0 + */ +@Data +@ConfigurationProperties(prefix = "xxl.job") +public class XxlJobProperties { + + @NestedConfigurationProperty + private XxlAdminProperties admin = new XxlAdminProperties(); + + @NestedConfigurationProperty + private XxlExecutorProperties executor = new XxlExecutorProperties(); + +} diff --git a/common/xxljob/src/main/resources/META-INF/spring.factories b/common/xxljob/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..5f40a8e --- /dev/null +++ b/common/xxljob/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.tacit.starter.xxljob.XxlJobAutoConfiguration \ No newline at end of file diff --git a/pom.xml b/pom.xml index 1b78261..6ccda8d 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ tacit-gateway tacit-admin tacit-app-api - tacit-common + common @@ -31,6 +31,7 @@ 2.1.0 2.3.0 3.14.0 + 5.10.1 @@ -69,13 +70,6 @@ ${mybatis-plus.version} - - - org.projectlombok - lombok - ${lombok.version} - - io.jsonwebtoken @@ -119,7 +113,33 @@ commons-lang3 ${commons-lang3.version} - + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + org.projectlombok + lombok + ${lombok.version} + + @@ -166,6 +186,44 @@ + + + + org.projectlombok + lombok + ${lombok.version} + provided + + + + + org.springframework.boot + spring-boot-starter-test + ${spring-boot.version} + test + + + + + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter.version} + test + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + test + + + + + + org.apache.commons + commons-lang3 + + @@ -217,6 +275,22 @@ UTF-8 + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.5 + + true + --enable-preview + + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + + + diff --git a/tacit-admin/pom.xml b/tacit-admin/pom.xml index c336b1a..85708e7 100644 --- a/tacit-admin/pom.xml +++ b/tacit-admin/pom.xml @@ -53,19 +53,27 @@ springdoc-openapi-starter-webmvc-ui - + com.tacit - tacit-common + common-model ${project.parent.version} - - - org.projectlombok - lombok - ${lombok.version} - provided + com.tacit + common-feign + ${project.parent.version} + + + com.tacit + common-core + ${project.parent.version} + + + + com.tacit + xxljob + ${project.parent.version} @@ -74,12 +82,6 @@ resilience4j-spring-boot3 - - - org.springframework.boot - spring-boot-starter-test - test - diff --git a/tacit-admin/src/main/java/com/tacit/admin/job/TestJob.java b/tacit-admin/src/main/java/com/tacit/admin/job/TestJob.java new file mode 100644 index 0000000..6b03037 --- /dev/null +++ b/tacit-admin/src/main/java/com/tacit/admin/job/TestJob.java @@ -0,0 +1,24 @@ +package com.tacit.admin.job; + + +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.handler.annotation.XxlJob; +import org.springframework.stereotype.Component; + +/** + * @Auther: xia + * @Date: 2026/1/4 15:01 + * @Description: com.tacit.admin.job + * @version: 1.0 + */ +@Component +public class TestJob { + + @XxlJob("myJobHandler") + public ReturnT execute(String param) throws Exception { + System.out.println("执行任务: " + param); + return ReturnT.SUCCESS; + } + + +} diff --git a/tacit-app-api/pom.xml b/tacit-app-api/pom.xml index 8489c1f..c45c6c1 100644 --- a/tacit-app-api/pom.xml +++ b/tacit-app-api/pom.xml @@ -53,27 +53,23 @@ springdoc-openapi-starter-webmvc-ui - + com.tacit - tacit-common + common-model + ${project.parent.version} + + + com.tacit + common-feign + ${project.parent.version} + + + com.tacit + common-core ${project.parent.version} - - - org.projectlombok - lombok - ${lombok.version} - provided - - - - - org.springframework.boot - spring-boot-starter-test - test - diff --git a/tacit-gateway/pom.xml b/tacit-gateway/pom.xml index 12822ba..11a7631 100644 --- a/tacit-gateway/pom.xml +++ b/tacit-gateway/pom.xml @@ -26,28 +26,22 @@ spring-boot-starter-security - + com.tacit - tacit-common + common-model + ${project.parent.version} + + + + com.tacit + common-core ${project.parent.version} org.springframework.boot spring-boot-starter-web - - org.springframework.boot - spring-boot-starter-data-jdbc - - - org.springframework.boot - spring-boot-starter-validation - - - com.zaxxer - HikariCP - @@ -57,20 +51,18 @@ spring-cloud-starter-bootstrap - + - org.projectlombok - lombok - ${lombok.version} - provided + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config - + - org.springframework.boot - spring-boot-starter-test - test + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + diff --git a/tacit-gateway/src/main/java/com/tacit/gateway/filter/JwtAuthenticationFilter.java b/tacit-gateway/src/main/java/com/tacit/gateway/filter/JwtAuthenticationFilter.java index 1e0e8c0..0edcd92 100644 --- a/tacit-gateway/src/main/java/com/tacit/gateway/filter/JwtAuthenticationFilter.java +++ b/tacit-gateway/src/main/java/com/tacit/gateway/filter/JwtAuthenticationFilter.java @@ -5,9 +5,7 @@ import com.tacit.common.utils.JwtUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; -import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; -import org.springframework.core.Ordered; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpRequest; diff --git a/tacit-gateway/src/main/resources/tacit-gateway.yaml b/tacit-gateway/src/main/resources/tacit-gateway.yaml index 556206d..f3a459b 100644 --- a/tacit-gateway/src/main/resources/tacit-gateway.yaml +++ b/tacit-gateway/src/main/resources/tacit-gateway.yaml @@ -48,3 +48,25 @@ logging: org.springframework.http.server.reactive: debug org.springframework.web.reactive: debug reactor.netty: debug + +# XXL-Job Configuration +xxl: + job: + admin: + # XXL-Job Admin地址,多个地址用逗号分隔 + addresses: http://localhost:8085/xxl-job-admin + # 可选,调度中心通讯TOKEN + access-token: default_token + executor: + # 执行器AppName,默认使用spring.application.name + appname: tacit-gateway + # 执行器IP,默认为空表示自动获取 + ip: + # 执行器端口,默认9099 + port: 9999 + # 执行器通讯TOKEN + access-token: default_token + # 执行器日志路径 + log-path: logs/applogs/xxl-job/jobhandler + # 执行器日志保存天数 + log-retention-days: 30