This commit is contained in:
maimaishu
2026-01-12 11:06:07 +08:00
11 changed files with 132 additions and 60 deletions

View File

@@ -1590,8 +1590,8 @@ INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon
INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5005, 'AI 工作流测试', 'ai:workflow:test', 3, 5, 5000, '', '', '', '', 0, '1', '1', '1', '1', '2025-03-30 10:29:41', '1', '2025-03-30 10:29:41', '0'); INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5005, 'AI 工作流测试', 'ai:workflow:test', 3, 5, 5000, '', '', '', '', 0, '1', '1', '1', '1', '2025-03-30 10:29:41', '1', '2025-03-30 10:29:41', '0');
INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5009, '仪表盘设计器', '', 2, 1, 1281, 'jimu-bi', 'fa:y-combinator', 'report/jmreport/bi', 'JimuBI', 0, '1', '1', '1', '1', '2025-05-03 09:57:15', '1', '2025-05-03 10:02:05', '0'); INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5009, '仪表盘设计器', '', 2, 1, 1281, 'jimu-bi', 'fa:y-combinator', 'report/jmreport/bi', 'JimuBI', 0, '1', '1', '1', '1', '2025-05-03 09:57:15', '1', '2025-05-03 10:02:05', '0');
INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5010, '租户切换', 'system:tenant:visit', 3, 999, 1138, '', '', '', '', 0, '1', '1', '1', '1', '2025-05-05 15:25:32', '1', '2025-05-05 15:25:32', '0'); INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5010, '租户切换', 'system:tenant:visit', 3, 999, 1138, '', '', '', '', 0, '1', '1', '1', '1', '2025-05-05 15:25:32', '1', '2025-05-05 15:25:32', '0');
INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5013, '公司切换', 'system:company:visit', 3, 100, 103, '', '', '', '', 0, '1', '1', '1', '1', '2025-12-05 09:00:00', '1', '2025-12-05 09:00:00', '0'); INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5013, '公司切换', 'system:company:visit', 3, 100, 0, '', '', '', '', 0, '1', '1', '1', '1', '2025-12-05 09:00:00', '1', '2025-12-05 09:00:00', '0');
INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5014, '部门切换', 'system:dept:visit', 3, 101, 103, '', '', '', '', 0, '1', '1', '1', '1', '2025-12-05 09:00:00', '1', '2025-12-05 09:00:00', '0'); INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5014, '部门切换', 'system:dept:visit', 3, 101, 0, '', '', '', '', 0, '1', '1', '1', '1', '2025-12-05 09:00:00', '1', '2025-12-05 09:00:00', '0');
insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1953701540574969857, '系统序列号管理', '', 2, 0, 1, 'sequence', '', 'system/sequence/index', 'Sequence', 0, 1, 1, 1, '', '2025-08-08 14:38:20.455625', '', '2025-08-08 14:38:20.455626', 0); insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1953701540574969857, '系统序列号管理', '', 2, 0, 1, 'sequence', '', 'system/sequence/index', 'Sequence', 0, 1, 1, 1, '', '2025-08-08 14:38:20.455625', '', '2025-08-08 14:38:20.455626', 0);
insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1953706417225150470, '系统序列号导出', 'system:sequence:export', 3, 5, 1953701540574969857, '', '', '', null, 0, 1, 1, 1, '', '2025-08-08 14:38:20.580376', '', '2025-08-08 14:38:20.580377', 0); insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1953706417225150470, '系统序列号导出', 'system:sequence:export', 3, 5, 1953701540574969857, '', '', '', null, 0, 1, 1, 1, '', '2025-08-08 14:38:20.580376', '', '2025-08-08 14:38:20.580377', 0);
insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1953706417225150469, '系统序列号删除', 'system:sequence:delete', 3, 4, 1953701540574969857, '', '', '', null, 0, 1, 1, 1, '', '2025-08-08 14:38:20.553819', '', '2025-08-08 14:38:20.553820', 0); insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1953706417225150469, '系统序列号删除', 'system:sequence:delete', 3, 4, 1953701540574969857, '', '', '', null, 0, 1, 1, 1, '', '2025-08-08 14:38:20.553819', '', '2025-08-08 14:38:20.553820', 0);

View File

@@ -1,4 +1,4 @@
CREATE TABLE "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG" CREATE TABLE "DATABUS_API_ACCESS_LOG"
( (
"ID" BIGINT NOT NULL, "ID" BIGINT NOT NULL,
"TRACE_ID" VARCHAR(64) DEFAULT NULL, "TRACE_ID" VARCHAR(64) DEFAULT NULL,
@@ -23,52 +23,52 @@ CREATE TABLE "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG"
"RESPONSE_TIME" DATETIME(6) DEFAULT NULL, "RESPONSE_TIME" DATETIME(6) DEFAULT NULL,
"STEP_RESULTS" TEXT, "STEP_RESULTS" TEXT,
"EXTRA" TEXT, "EXTRA" TEXT,
"CREATOR" VARCHAR(64) DEFAULT '' NOT NULL, "CREATOR" VARCHAR(64) DEFAULT NULL,
"CREATE_TIME" DATETIME(6) DEFAULT CURRENT_TIMESTAMP NOT NULL, "CREATE_TIME" DATETIME(6) DEFAULT CURRENT_TIMESTAMP NOT NULL,
"UPDATER" VARCHAR(64) DEFAULT '' NOT NULL, "UPDATER" VARCHAR(64) DEFAULT NULL,
"UPDATE_TIME" DATETIME(6) DEFAULT CURRENT_TIMESTAMP NOT NULL, "UPDATE_TIME" DATETIME(6) DEFAULT CURRENT_TIMESTAMP NOT NULL,
"DELETED" BIT DEFAULT '0' NOT NULL, "DELETED" BIT DEFAULT '0' NOT NULL,
"TENANT_ID" BIGINT DEFAULT 0 NOT NULL, "TENANT_ID" BIGINT DEFAULT 0 NOT NULL,
NOT CLUSTER PRIMARY KEY("ID")) STORAGE(ON "MAIN", CLUSTERBTR) ; NOT CLUSTER PRIMARY KEY("ID")) STORAGE(ON "MAIN", CLUSTERBTR) ;
COMMENT ON TABLE "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG IS 'Databus API 访问日志表'; COMMENT ON TABLE DATABUS_API_ACCESS_LOG IS 'Databus API 访问日志表';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."API_CODE" IS 'API 编码'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."API_CODE" IS 'API 编码';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."API_VERSION" IS 'API 版本'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."API_VERSION" IS 'API 版本';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."CLIENT_IP" IS '客户端 IP'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."CLIENT_IP" IS '客户端 IP';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."CREATE_TIME" IS '创建时间'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."CREATE_TIME" IS '创建时间';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."CREATOR" IS '创建者'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."CREATOR" IS '创建者';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."DELETED" IS '是否删除'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."DELETED" IS '是否删除';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."DURATION" IS '请求耗时(毫秒)'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."DURATION" IS '请求耗时(毫秒)';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."ERROR_CODE" IS '业务错误码'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."ERROR_CODE" IS '业务错误码';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."ERROR_MESSAGE" IS '错误信息'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."ERROR_MESSAGE" IS '错误信息';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."EXCEPTION_STACK" IS '异常堆栈'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."EXCEPTION_STACK" IS '异常堆栈';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."EXTRA" IS '额外调试信息JSON 字符串)'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."EXTRA" IS '额外调试信息JSON 字符串)';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."ID" IS '日志主键'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."ID" IS '日志主键';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."REQUEST_BODY" IS '请求体JSON 字符串)'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."REQUEST_BODY" IS '请求体JSON 字符串)';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."REQUEST_HEADERS" IS '请求头JSON 字符串)'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."REQUEST_HEADERS" IS '请求头JSON 字符串)';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."REQUEST_METHOD" IS '请求方法'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."REQUEST_METHOD" IS '请求方法';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."REQUEST_PATH" IS '请求路径'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."REQUEST_PATH" IS '请求路径';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."REQUEST_QUERY" IS '请求查询参数JSON 字符串)'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."REQUEST_QUERY" IS '请求查询参数JSON 字符串)';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."REQUEST_TIME" IS '请求时间'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."REQUEST_TIME" IS '请求时间';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."RESPONSE_BODY" IS '响应体JSON 字符串)'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."RESPONSE_BODY" IS '响应体JSON 字符串)';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."RESPONSE_MESSAGE" IS '响应提示信息'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."RESPONSE_MESSAGE" IS '响应提示信息';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."RESPONSE_STATUS" IS '响应 HTTP 状态码'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."RESPONSE_STATUS" IS '响应 HTTP 状态码';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."RESPONSE_TIME" IS '响应时间'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."RESPONSE_TIME" IS '响应时间';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."STATUS" IS '访问状态0-成功 1-客户端错误 2-服务端错误 3-未知'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."STATUS" IS '访问状态0-成功 1-客户端错误 2-服务端错误 3-未知';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."STEP_RESULTS" IS '执行步骤结果JSON 字符串)'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."STEP_RESULTS" IS '执行步骤结果JSON 字符串)';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."TENANT_ID" IS '租户编号'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."TENANT_ID" IS '租户编号';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."TRACE_ID" IS '追踪 ID'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."TRACE_ID" IS '追踪 ID';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."UPDATER" IS '更新者'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."UPDATER" IS '更新者';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."UPDATE_TIME" IS '更新时间'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."UPDATE_TIME" IS '更新时间';
COMMENT ON COLUMN "RUOYI-VUE-PRO".DATABUS_API_ACCESS_LOG."USER_AGENT" IS 'User-Agent'; COMMENT ON COLUMN DATABUS_API_ACCESS_LOG."USER_AGENT" IS 'User-Agent';
CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_TRACE" ON "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG"("TRACE_ID" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ; CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_TRACE" ON "DATABUS_API_ACCESS_LOG"("TRACE_ID" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;
CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_CODE" ON "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG"("API_CODE" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ; CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_CODE" ON "DATABUS_API_ACCESS_LOG"("API_CODE" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;
CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_METHOD" ON "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG"("REQUEST_METHOD" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ; CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_METHOD" ON "DATABUS_API_ACCESS_LOG"("REQUEST_METHOD" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;
CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_STATUS" ON "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG"("STATUS" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ; CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_STATUS" ON "DATABUS_API_ACCESS_LOG"("STATUS" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;
CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_RESP_STATUS" ON "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG"("RESPONSE_STATUS" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ; CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_RESP_STATUS" ON "DATABUS_API_ACCESS_LOG"("RESPONSE_STATUS" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;
CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_REQUEST_TIME" ON "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG"("REQUEST_TIME" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ; CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_REQUEST_TIME" ON "DATABUS_API_ACCESS_LOG"("REQUEST_TIME" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;
CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_CLIENT_IP" ON "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG"("CLIENT_IP" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ; CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_CLIENT_IP" ON "DATABUS_API_ACCESS_LOG"("CLIENT_IP" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;
CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_TENANT" ON "RUOYI-VUE-PRO"."DATABUS_API_ACCESS_LOG"("TENANT_ID" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ; CREATE OR REPLACE INDEX "IDX_DATABUS_API_ACCESS_LOG_TENANT" ON "DATABUS_API_ACCESS_LOG"("TENANT_ID" ASC) STORAGE(ON "MAIN", CLUSTERBTR) ;

View File

@@ -21,9 +21,11 @@ public class ZtBusinessAutoConfiguration implements WebMvcConfigurer {
public void addInterceptors(InterceptorRegistry registry) { public void addInterceptors(InterceptorRegistry registry) {
// 拦截所有 url统一进行业务与文件上传请求头校验 // 拦截所有 url统一进行业务与文件上传请求头校验
registry.addInterceptor(new BusinessHeaderInterceptor()) registry.addInterceptor(new BusinessHeaderInterceptor())
.addPathPatterns("/**"); .addPathPatterns("/**")
.excludePathPatterns("/get*");
registry.addInterceptor(new FileUploadHeaderInterceptor()) registry.addInterceptor(new FileUploadHeaderInterceptor())
.addPathPatterns("/**"); .addPathPatterns("/**")
.excludePathPatterns("/get*");
} }
@Bean @Bean

View File

@@ -128,6 +128,8 @@ public class ApiGatewayAccessLogger {
logDO.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT)); logDO.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
logDO.setStatus(3); logDO.setStatus(3);
logDO.setRequestTime(LocalDateTime.now()); logDO.setRequestTime(LocalDateTime.now());
logDO.setCreator("");
logDO.setUpdater("");
Long logId = apiAccessLogService.create(logDO); Long logId = apiAccessLogService.create(logDO);
request.setAttribute(ATTR_LOG_ID, logId); request.setAttribute(ATTR_LOG_ID, logId);
request.setAttribute(ATTR_REQUEST_START, Instant.now()); request.setAttribute(ATTR_REQUEST_START, Instant.now());

View File

@@ -46,9 +46,9 @@ public class HttpStepHandler implements ApiStepHandler {
private final WebClient.Builder webClientBuilder; private final WebClient.Builder webClientBuilder;
private final ExpressionExecutor expressionExecutor; private final ExpressionExecutor expressionExecutor;
private static final Duration RETRY_DELAY = Duration.ofMillis(200); private static final Duration RETRY_DELAY = Duration.ofSeconds(5);
private static final int RETRY_ATTEMPTS = 3; private static final int RETRY_ATTEMPTS = 5;
private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(20); private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(40);
private static final Set<String> DEFAULT_FORWARDED_HEADERS = Set.of( private static final Set<String> DEFAULT_FORWARDED_HEADERS = Set.of(
"authorization", "authorization",

View File

@@ -6,6 +6,7 @@ import cn.hutool.http.HttpUtil;
import com.zt.plat.framework.common.util.spring.SpringUtils; import com.zt.plat.framework.common.util.spring.SpringUtils;
import com.zt.plat.module.infra.framework.file.core.client.AbstractFileClient; import com.zt.plat.module.infra.framework.file.core.client.AbstractFileClient;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
@@ -22,6 +23,7 @@ import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignReques
import java.net.URI; import java.net.URI;
import java.time.Duration; import java.time.Duration;
import java.util.concurrent.TimeUnit;
/** /**
* 基于 S3 协议的文件客户端,实现 MinIO、阿里云、腾讯云、七牛云、华为云等云服务 * 基于 S3 协议的文件客户端,实现 MinIO、阿里云、腾讯云、七牛云、华为云等云服务
@@ -32,6 +34,15 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
private static final Duration DEFAULT_PRESIGNED_EXPIRATION = Duration.ofHours(24); private static final Duration DEFAULT_PRESIGNED_EXPIRATION = Duration.ofHours(24);
private static final String PRESIGN_EXPIRE_SECONDS_PROPERTY = "zt.file.download-expire-seconds"; private static final String PRESIGN_EXPIRE_SECONDS_PROPERTY = "zt.file.download-expire-seconds";
/**
* Redis 缓存 key 前缀:文件预签名 URL
*/
private static final String CACHE_KEY_PREFIX = "file:presigned:url:";
/**
* Redis 缓存时间50 分钟
*/
private static final long CACHE_EXPIRE_MINUTES = 50L;
/** /**
* 生成临时下载地址(预签名下载 URL * 生成临时下载地址(预签名下载 URL
* @param path 文件路径 * @param path 文件路径
@@ -45,6 +56,17 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
return StringUtils.EMPTY; return StringUtils.EMPTY;
} }
// 1. 尝试从 Redis 缓存中获取
String cacheKey = CACHE_KEY_PREFIX + path;
RedisTemplate<String, Object> redis = getRedisTemplate();
if (redis != null) {
Object cachedUrl = redis.opsForValue().get(cacheKey);
if (cachedUrl instanceof String) {
return (String) cachedUrl;
}
}
// 2. 缓存未命中,调用 S3 生成预签名 URL
// 使用 S3 官方支持的 responseCacheControl 参数,强制浏览器和代理不缓存 // 使用 S3 官方支持的 responseCacheControl 参数,强制浏览器和代理不缓存
GetObjectRequest.Builder getObjectRequestBuilder = GetObjectRequest.builder() GetObjectRequest.Builder getObjectRequestBuilder = GetObjectRequest.builder()
.bucket(config.getBucket()) .bucket(config.getBucket())
@@ -54,12 +76,37 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
.signatureDuration(realExpiration) .signatureDuration(realExpiration)
.getObjectRequest(getObjectRequestBuilder.build()) .getObjectRequest(getObjectRequestBuilder.build())
.build(); .build();
return presigner.presignGetObject(getObjectPresignRequest).url().toString(); String presignedUrl = presigner.presignGetObject(getObjectPresignRequest).url().toString();
// 3. 将生成的 URL 存入 Redis 缓存
if (redis != null && presignedUrl != null && !presignedUrl.isEmpty()) {
redis.opsForValue().set(cacheKey, presignedUrl, CACHE_EXPIRE_MINUTES, TimeUnit.MINUTES);
}
return presignedUrl;
}
/**
* 获取 RedisTemplate 实例(延迟加载,避免初始化时循环依赖)
*/
@SuppressWarnings("unchecked")
private RedisTemplate<String, Object> getRedisTemplate() {
if (redisTemplate == null) {
try {
redisTemplate = SpringUtils.getBean("redisTemplate", RedisTemplate.class);
} catch (Exception e) {
// Redis 不可用时,不影响正常功能,只是不使用缓存
return null;
}
}
return redisTemplate;
} }
private S3Client client; private S3Client client;
private S3Presigner presigner; private S3Presigner presigner;
private RedisTemplate<String,Object> redisTemplate;
public S3FileClient(Long id, S3FileClientConfig config) { public S3FileClient(Long id, S3FileClientConfig config) {
super(id, config); super(id, config);
} }
@@ -115,6 +162,13 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
.key(path) .key(path)
.build(); .build();
client.deleteObject(deleteRequest); client.deleteObject(deleteRequest);
// 删除文件后,清除对应的缓存
String cacheKey = CACHE_KEY_PREFIX + path;
RedisTemplate<String, Object> redis = getRedisTemplate();
if (redis != null) {
redis.delete(cacheKey);
}
} }
@Override @Override

View File

@@ -41,7 +41,7 @@ public class DatabusDeptProviderApiImpl implements DatabusDeptProviderApi {
public CommonResult<CursorPageResult<DatabusDeptData>> getPageByCursor(CursorPageReqDTO reqDTO) { public CommonResult<CursorPageResult<DatabusDeptData>> getPageByCursor(CursorPageReqDTO reqDTO) {
// 构建游标查询条件 // 构建游标查询条件
LambdaQueryWrapper<DeptDO> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<DeptDO> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DeptDO::getDeptSource, 3);
// 游标条件create_time > cursorTime OR (create_time = cursorTime AND id > cursorId) // 游标条件create_time > cursorTime OR (create_time = cursorTime AND id > cursorId)
if (!reqDTO.isFirstPage()) { if (!reqDTO.isFirstPage()) {
queryWrapper.and(w -> w queryWrapper.and(w -> w
@@ -105,6 +105,7 @@ public class DatabusDeptProviderApiImpl implements DatabusDeptProviderApi {
Long total = null; Long total = null;
if (reqDTO.isFirstPage()) { if (reqDTO.isFirstPage()) {
LambdaQueryWrapper<DeptDO> countWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<DeptDO> countWrapper = new LambdaQueryWrapper<>();
countWrapper.eq(DeptDO::getDeptSource, 3);
if (reqDTO.getTenantId() != null) { if (reqDTO.getTenantId() != null) {
countWrapper.eq(DeptDO::getTenantId, reqDTO.getTenantId()); countWrapper.eq(DeptDO::getTenantId, reqDTO.getTenantId());
} }
@@ -175,6 +176,7 @@ public class DatabusDeptProviderApiImpl implements DatabusDeptProviderApi {
@Override @Override
public CommonResult<Long> count(Long tenantId) { public CommonResult<Long> count(Long tenantId) {
LambdaQueryWrapper<DeptDO> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<DeptDO> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DeptDO::getDeptSource, 3);
if (tenantId != null) { if (tenantId != null) {
queryWrapper.eq(DeptDO::getTenantId, tenantId); queryWrapper.eq(DeptDO::getTenantId, tenantId);
} }

View File

@@ -54,8 +54,8 @@ public class DatabusUserProviderApiImpl implements DatabusUserProviderApi {
// 构建游标查询条件 // 构建游标查询条件
LambdaQueryWrapper<AdminUserDO> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<AdminUserDO> queryWrapper = new LambdaQueryWrapper<>();
// ⚠️ 只同步 userSource = 2 的用户 // ⚠️ 只同步 userSource = 3 的用户
queryWrapper.eq(AdminUserDO::getUserSource, 2); queryWrapper.eq(AdminUserDO::getUserSource, 3);
// 游标条件create_time > cursorTime OR (create_time = cursorTime AND id > cursorId) // 游标条件create_time > cursorTime OR (create_time = cursorTime AND id > cursorId)
if (!reqDTO.isFirstPage()) { if (!reqDTO.isFirstPage()) {
@@ -103,8 +103,8 @@ public class DatabusUserProviderApiImpl implements DatabusUserProviderApi {
Long total = null; Long total = null;
if (reqDTO.isFirstPage()) { if (reqDTO.isFirstPage()) {
LambdaQueryWrapper<AdminUserDO> countWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<AdminUserDO> countWrapper = new LambdaQueryWrapper<>();
// ⚠️ 只统计 userSource = 2 的用户 // ⚠️ 只统计 userSource = 3 的用户
countWrapper.eq(AdminUserDO::getUserSource, 2); countWrapper.eq(AdminUserDO::getUserSource, 3);
if (reqDTO.getTenantId() != null) { if (reqDTO.getTenantId() != null) {
countWrapper.eq(AdminUserDO::getTenantId, reqDTO.getTenantId()); countWrapper.eq(AdminUserDO::getTenantId, reqDTO.getTenantId());
} }
@@ -148,8 +148,8 @@ public class DatabusUserProviderApiImpl implements DatabusUserProviderApi {
@Override @Override
public CommonResult<Long> count(Long tenantId) { public CommonResult<Long> count(Long tenantId) {
LambdaQueryWrapper<AdminUserDO> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<AdminUserDO> queryWrapper = new LambdaQueryWrapper<>();
// ⚠️ 只统计 userSource = 2 的用户 // ⚠️ 只统计 userSource = 3 的用户
queryWrapper.eq(AdminUserDO::getUserSource, 2); queryWrapper.eq(AdminUserDO::getUserSource, 3);
if (tenantId != null) { if (tenantId != null) {
queryWrapper.eq(AdminUserDO::getTenantId, tenantId); queryWrapper.eq(AdminUserDO::getTenantId, tenantId);
} }

View File

@@ -58,6 +58,13 @@ public class UserRespVO{
@DictFormat(DictTypeConstants.USER_SEX) @DictFormat(DictTypeConstants.USER_SEX)
private Integer sex; private Integer sex;
@Schema(description = "用户来源,参见 UserSourceEnum 枚举类", example = "1")
private Integer userSource;
@Schema(description = "用户来源标签", example = "外部用户")
@ExcelProperty("用户来源")
private String userSourceLabel;
@Schema(description = "用户头像", example = "123456789") @Schema(description = "用户头像", example = "123456789")
private String avatar; private String avatar;

View File

@@ -12,6 +12,7 @@ import com.zt.plat.module.system.dal.dataobject.dept.DeptDO;
import com.zt.plat.module.system.dal.dataobject.dept.PostDO; import com.zt.plat.module.system.dal.dataobject.dept.PostDO;
import com.zt.plat.module.system.dal.dataobject.permission.RoleDO; import com.zt.plat.module.system.dal.dataobject.permission.RoleDO;
import com.zt.plat.module.system.dal.dataobject.user.AdminUserDO; import com.zt.plat.module.system.dal.dataobject.user.AdminUserDO;
import com.zt.plat.module.system.enums.user.UserSourceEnum;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
@@ -32,6 +33,10 @@ public interface UserConvert {
default UserRespVO convert(AdminUserDO user) { default UserRespVO convert(AdminUserDO user) {
UserRespVO vo = BeanUtils.toBean(user, UserRespVO.class); UserRespVO vo = BeanUtils.toBean(user, UserRespVO.class);
vo.setAvatar(user.getAvatar()); vo.setAvatar(user.getAvatar());
if (user.getUserSource() != null) {
UserSourceEnum sourceEnum = UserSourceEnum.of(user.getUserSource());
vo.setUserSourceLabel(sourceEnum != null ? sourceEnum.getName() : null);
}
if (user.getDeptIds() != null) { if (user.getDeptIds() != null) {
vo.setDeptIds(CollectionUtils.convertList(user.getDeptIds(), Long::longValue)); vo.setDeptIds(CollectionUtils.convertList(user.getDeptIds(), Long::longValue));
} }

View File

@@ -59,7 +59,7 @@ public interface UserDeptMapper extends BaseMapperX<UserDeptDO> {
@Select("<script>" + @Select("<script>" +
"SELECT ud.* FROM system_user_dept ud " + "SELECT ud.* FROM system_user_dept ud " +
"INNER JOIN system_users u ON ud.user_id = u.id " + "INNER JOIN system_users u ON ud.user_id = u.id " +
"WHERE u.user_source = 2 " + "WHERE u.user_source = 3 " +
"AND ud.deleted = 0 " + "AND ud.deleted = 0 " +
"<if test='tenantId != null'> AND ud.tenant_id = #{tenantId} </if>" + "<if test='tenantId != null'> AND ud.tenant_id = #{tenantId} </if>" +
"<if test='cursorTime != null'>" + "<if test='cursorTime != null'>" +
@@ -75,14 +75,14 @@ public interface UserDeptMapper extends BaseMapperX<UserDeptDO> {
@Param("limit") Integer limit); @Param("limit") Integer limit);
/** /**
* 统计用户-部门关系数量(只统计 userSource = 2 的用户) * 统计用户-部门关系数量(只统计 userSource = 3 的用户)
* @param tenantId 租户ID可选 * @param tenantId 租户ID可选
* @return 数量 * @return 数量
*/ */
@Select("<script>" + @Select("<script>" +
"SELECT COUNT(*) FROM system_user_dept ud " + "SELECT COUNT(*) FROM system_user_dept ud " +
"INNER JOIN system_users u ON ud.user_id = u.id " + "INNER JOIN system_users u ON ud.user_id = u.id " +
"WHERE u.user_source = 2 " + "WHERE u.user_source = 3 " +
"AND ud.deleted = 0 " + "AND ud.deleted = 0 " +
"<if test='tenantId != null'> AND ud.tenant_id = #{tenantId} </if>" + "<if test='tenantId != null'> AND ud.tenant_id = #{tenantId} </if>" +
"</script>") "</script>")