提交 961d09b4 作者: 方治民

feat: 新增 XXL-JOB 模块,一些配置功能优化

上级 10be9b57
...@@ -39,6 +39,7 @@ npm cache clean --force ...@@ -39,6 +39,7 @@ npm cache clean --force
- [x] WebSocket 模块 - [x] WebSocket 模块
- [x] 通用字典管理模块 - [x] 通用字典管理模块
- [x] 通用文件上传模块,支持对图片/PDF/MP3/MP4 等文件进行预处理 - [x] 通用文件上传模块,支持对图片/PDF/MP3/MP4 等文件进行预处理
- [ ] 大文件分片上传,扩展支持本地、MinIO、阿里云 OSS、腾讯云 COS 等 - [x] XXL-JOB 定时任务模块
- [ ] XXL-JOB 定时任务模块 - [x] 大文件分片上传
- [ ] 文件上传扩展支持本地、MinIO、阿里云 OSS、腾讯云 COS 等 [x-file-storage](https://github.com/dromara/x-file-storage)
- [ ] 更合理的模块拆分,更好的模块解耦 - [ ] 更合理的模块拆分,更好的模块解耦
...@@ -47,6 +47,9 @@ dependencies { ...@@ -47,6 +47,9 @@ dependencies {
// Optional: Redis // Optional: Redis
implementation project(":basic-common:redis") implementation project(":basic-common:redis")
// Optional: XXL-JOB
implementation project(":basic-common:job")
// Optional: Doc // Optional: Doc
implementation project(":basic-common:doc") implementation project(":basic-common:doc")
......
/**
* @author Jim
* @version 0.1
* 2024/5/11 14:11
*/
package com.yiring.app.job;
// 任务调度包
// 通常用于存放 XXL-JOB、SpringTask 的任务调度器
# 任务调度
xxl:
job:
enabled: true
admin-addresses: http://192.168.0.156:8080/xxl-job-admin
access-token: local
executor-app-name: xyh-app-preview
...@@ -16,7 +16,7 @@ spring: ...@@ -16,7 +16,7 @@ spring:
max-file-size: 1024MB max-file-size: 1024MB
max-request-size: 1048MB max-request-size: 1048MB
profiles: profiles:
include: auth, conf-patch #, monitor include: auth, conf-patch #, conf-xxl-job, monitor
active: dev-postgresql active: dev-postgresql
# DEBUG # DEBUG
......
...@@ -19,7 +19,7 @@ import org.aspectj.lang.JoinPoint; ...@@ -19,7 +19,7 @@ import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature; import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.env.Environment; import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.ZSetOperations; import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
...@@ -37,7 +37,9 @@ import org.springframework.stereotype.Component; ...@@ -37,7 +37,9 @@ import org.springframework.stereotype.Component;
public class RateLimiterAspect { public class RateLimiterAspect {
final Redis redis; final Redis redis;
final Environment environment;
@Value("${sa-token.token-name:}")
String tokenName;
/** /**
* 带有注解的方法之前执行 * 带有注解的方法之前执行
...@@ -67,7 +69,7 @@ public class RateLimiterAspect { ...@@ -67,7 +69,7 @@ public class RateLimiterAspect {
Long currentCount = zSetOperations.zCard(key); Long currentCount = zSetOperations.zCard(key);
// 限流判断 // 限流判断
if (Objects.nonNull(currentCount) && currentCount > count) { if (Objects.nonNull(currentCount) && currentCount > count) {
log.warn("[Request RateLimit] 接口限流, Key: {}, count: {}, currentCount: {}", key, count, currentCount); log.warn("[Request RateLimit] Key: {}, count: {}, currentCount: {}", key, count, currentCount);
throw Status.TOO_MANY_REQUESTS.exception(); throw Status.TOO_MANY_REQUESTS.exception();
} }
} }
...@@ -82,7 +84,6 @@ public class RateLimiterAspect { ...@@ -82,7 +84,6 @@ public class RateLimiterAspect {
sb.append(Commons.getClientIpAddress(request)); sb.append(Commons.getClientIpAddress(request));
// 考虑登录用户的 token // 考虑登录用户的 token
String tokenName = environment.getProperty("sa-token.token-name");
if (StrUtil.isNotBlank(tokenName)) { if (StrUtil.isNotBlank(tokenName)) {
// 1. 优先从请求头中获取 token // 1. 优先从请求头中获取 token
String token = request.getHeader(tokenName); String token = request.getHeader(tokenName);
......
...@@ -25,6 +25,7 @@ import org.springframework.boot.CommandLineRunner; ...@@ -25,6 +25,7 @@ import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile; import org.springframework.context.annotation.Profile;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
...@@ -40,11 +41,15 @@ import org.springframework.web.method.HandlerMethod; ...@@ -40,11 +41,15 @@ import org.springframework.web.method.HandlerMethod;
*/ */
@Slf4j @Slf4j
@Order(value = 9999999)
@Profile("!prod") @Profile("!prod")
@Configuration @Configuration
@RequiredArgsConstructor @RequiredArgsConstructor
public class SwaggerConfig implements CommandLineRunner { public class SwaggerConfig implements CommandLineRunner {
@Value("${server.address:}")
String serverAddress;
@Value("${spring.application.name}") @Value("${spring.application.name}")
String applicationName; String applicationName;
...@@ -186,7 +191,6 @@ public class SwaggerConfig implements CommandLineRunner { ...@@ -186,7 +191,6 @@ public class SwaggerConfig implements CommandLineRunner {
@Override @Override
public void run(String... args) { public void run(String... args) {
LinkedHashSet<String> ips = new LinkedHashSet<>(); LinkedHashSet<String> ips = new LinkedHashSet<>();
String serverAddress = environment.getProperty("server.address");
if (StrUtil.isBlank(serverAddress)) { if (StrUtil.isBlank(serverAddress)) {
ips.addAll(NetUtil.localIpv4s()); ips.addAll(NetUtil.localIpv4s());
} else { } else {
......
plugins {
id 'java-library'
}
dependencies {
implementation project(":basic-common:core")
implementation project(":basic-common:i18n")
implementation 'org.springframework.boot:spring-boot-starter-aop'
// xxl-job
api "com.xuxueli:xxl-job-core:${xxlJobVersion}"
// hutool-core
implementation "cn.hutool:hutool-core:${hutoolVersion}"
}
/* (C) 2021 YiRing, Inc. */
package com.yiring.common.aspect;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
* XxlJob 注解切面
*
* @author ifzm
* @version 0.1
*/
@Slf4j
@Aspect
@Component
public class XxlJobAspect {
@Pointcut("@annotation(com.xxl.job.core.handler.annotation.XxlJob)")
public void log() {}
@Around("log()")
public Object around(ProceedingJoinPoint point) throws Throwable {
try {
return point.proceed();
} catch (Exception e) {
log.error("[XxlJob] Execute Error: {}", e.getMessage(), e);
throw e;
}
}
}
/* (C) 2024 YiRing, Inc. */
package com.yiring.common.config;
import lombok.AccessLevel;
import lombok.Data;
import lombok.experimental.FieldDefaults;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @author Jim
*/
@Data
@FieldDefaults(level = AccessLevel.PRIVATE)
@Configuration
@ConfigurationProperties(prefix = "xxl.job")
public class XxlJobConfig {
/**
* 是否启用,true: 启用,false: 禁用
* 默认值:false
*/
boolean enabled = false;
/**
* 调度中心部署跟地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
*/
String adminAddresses;
/**
* 执行器通讯TOKEN [选填]:非空时启用;
*/
String accessToken;
/**
* 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
*/
String executorAppName;
/**
* 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
*/
String executorAddress;
/**
* 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
*/
String executorIp;
/**
* 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
*/
int executorPort = 9999;
/**
* 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
*/
String executorLogPath;
/**
* 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
*/
int executorLogRetentionDays = 3;
}
/* (C) 2021 YiRing, Inc. */
package com.yiring.common.config;
import cn.hutool.core.lang.Console;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import lombok.AccessLevel;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
/**
* Swagger Config
*
* @author ifzm
* @version 0.1
* 2019/3/11 19:13
*/
@Slf4j
@Data
@FieldDefaults(level = AccessLevel.PRIVATE)
@Order(value = 9999998)
@Configuration
@ConditionalOnProperty(prefix = "xxl.job", value = "enabled", havingValue = "true")
@RequiredArgsConstructor
public class XxlJobConfiguration implements CommandLineRunner {
final XxlJobConfig xxlJobConfig;
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(xxlJobConfig.getAdminAddresses());
xxlJobSpringExecutor.setAppname(xxlJobConfig.getExecutorAppName());
xxlJobSpringExecutor.setAddress(xxlJobConfig.getExecutorAddress());
xxlJobSpringExecutor.setIp(xxlJobConfig.getExecutorIp());
xxlJobSpringExecutor.setPort(xxlJobConfig.getExecutorPort());
xxlJobSpringExecutor.setAccessToken(xxlJobConfig.getAccessToken());
xxlJobSpringExecutor.setLogPath(xxlJobConfig.getExecutorLogPath());
xxlJobSpringExecutor.setLogRetentionDays(xxlJobConfig.getExecutorLogRetentionDays());
return xxlJobSpringExecutor;
}
@Override
public void run(String... args) {
Console.log("\n\t⌛ Task Scheduler (XXL-JOB): \n\t\t> {}", xxlJobConfig.getAdminAddresses());
}
}
plugins {
id 'java-library'
}
dependencies { dependencies {
implementation 'org.springframework.boot:spring-boot-starter-aop' implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-web'
......
/* (C) 2022 YiRing, Inc. */ /* (C) 2022 YiRing, Inc. */
package com.yiring.websocket.config; package com.yiring.websocket.config;
import cn.hutool.core.convert.Convert;
import cn.hutool.extra.spring.SpringUtil; import cn.hutool.extra.spring.SpringUtil;
import com.yiring.common.core.Redis; import com.yiring.common.core.Redis;
import com.yiring.websocket.constant.RedisKey; import com.yiring.websocket.constant.RedisKey;
...@@ -11,6 +10,7 @@ import jakarta.annotation.PostConstruct; ...@@ -11,6 +10,7 @@ import jakarta.annotation.PostConstruct;
import java.util.Objects; import java.util.Objects;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.amqp.RabbitProperties; import org.springframework.boot.autoconfigure.amqp.RabbitProperties;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration; import org.springframework.messaging.simp.config.ChannelRegistration;
...@@ -38,13 +38,14 @@ public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer { ...@@ -38,13 +38,14 @@ public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer {
final ClientInboundChannelInterceptor clientInboundChannelInterceptor; final ClientInboundChannelInterceptor clientInboundChannelInterceptor;
final ClientOutboundChannelInterceptor clientOutboundChannelInterceptor; final ClientOutboundChannelInterceptor clientOutboundChannelInterceptor;
public static Integer stompPort; @Value("${spring.rabbitmq.stomp-port:}")
public Integer stompPort;
public static boolean stompMode; public static boolean stompMode;
public static String mode; public static String mode;
@PostConstruct @PostConstruct
public void init() { public void init() {
stompPort = Convert.toInt(SpringUtil.getProperty("spring.rabbitmq.stomp-port"));
stompMode = Objects.nonNull(stompPort); stompMode = Objects.nonNull(stompPort);
mode = stompMode ? "STOMP" : "Simple"; mode = stompMode ? "STOMP" : "Simple";
} }
......
...@@ -21,6 +21,7 @@ include 'basic-common:doc' ...@@ -21,6 +21,7 @@ include 'basic-common:doc'
include 'basic-common:minio' include 'basic-common:minio'
include 'basic-common:redis' include 'basic-common:redis'
include 'basic-common:i18n' include 'basic-common:i18n'
include 'basic-common:job'
gitHooks { extension -> gitHooks { extension ->
extension.with { extension.with {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论