Merge branch 'refs/heads/zt-test' into test
This commit is contained in:
@@ -3,19 +3,16 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>zt</artifactId>
|
||||
<artifactId>zt-dsc</artifactId>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modules>
|
||||
<module>zt-module-databus-api</module>
|
||||
<module>zt-module-databus-server</module>
|
||||
<module>zt-module-databus-server-app</module>
|
||||
<module>zt-module-databus-client</module>
|
||||
</modules>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>zt-module-databus</artifactId>
|
||||
<artifactId>zt-module-databus-dsc</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>zt-module-databus</artifactId>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>zt-module-databus-api</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
暴露给其它模块调用
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-common</artifactId>
|
||||
</dependency>
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId> <!-- 接口文档:使用最新版本的 Swagger 模型 -->
|
||||
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 参数校验 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- RPC 远程调用相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -1,132 +0,0 @@
|
||||
package com.zt.plat.module.databus.api.data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户数据对象(DataBus)
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "用户数据")
|
||||
public class DatabusAdminUserData implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// ========== 基本信息 ==========
|
||||
|
||||
@Schema(description = "用户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1001")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "zhangsan")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
|
||||
private String nickname;
|
||||
|
||||
@Schema(description = "用户手机号", example = "13800138000")
|
||||
private String mobile;
|
||||
|
||||
@Schema(description = "用户邮箱", example = "zhangsan@example.com")
|
||||
private String email;
|
||||
|
||||
@Schema(description = "用户性别:0-未知 1-男 2-女", example = "1")
|
||||
private Integer sex;
|
||||
|
||||
@Schema(description = "用户头像URL", example = "https://example.com/avatar.jpg")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "状态:0-启用 1-禁用", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "备注", example = "测试用户")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "用户来源类型", example = "1")
|
||||
private Integer userSource;
|
||||
|
||||
// ========== 组织信息 ==========
|
||||
|
||||
@Schema(description = "所属部门ID列表", example = "[100, 101]")
|
||||
private List<Long> deptIds;
|
||||
|
||||
@Schema(description = "所属部门信息列表")
|
||||
private List<DeptSimpleInfo> depts;
|
||||
|
||||
// ========== 岗位信息 ==========
|
||||
|
||||
@Schema(description = "岗位ID列表", example = "[1, 2]")
|
||||
private List<Long> postIds;
|
||||
|
||||
@Schema(description = "岗位信息列表")
|
||||
private List<PostSimpleInfo> posts;
|
||||
|
||||
// ========== 多租户 ==========
|
||||
|
||||
@Schema(description = "租户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long tenantId;
|
||||
|
||||
// ========== 时间信息 ==========
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 部门简要信息
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "部门简要信息")
|
||||
public static class DeptSimpleInfo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "部门ID", example = "100")
|
||||
private Long deptId;
|
||||
|
||||
@Schema(description = "部门编码", example = "DEPT_001")
|
||||
private String deptCode;
|
||||
|
||||
@Schema(description = "部门名称", example = "技术部")
|
||||
private String deptName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 岗位简要信息
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "岗位简要信息")
|
||||
public static class PostSimpleInfo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "岗位ID", example = "1")
|
||||
private Long postId;
|
||||
|
||||
@Schema(description = "岗位编码", example = "CEO")
|
||||
private String postCode;
|
||||
|
||||
@Schema(description = "岗位名称", example = "首席执行官")
|
||||
private String postName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package com.zt.plat.module.databus.api.data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 部门数据对象(DataBus)
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "部门数据")
|
||||
public class DatabusDeptData implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// ========== 基本信息 ==========
|
||||
|
||||
@Schema(description = "部门ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "部门编码", example = "DEPT_001")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "技术部")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "部门简称", example = "技术")
|
||||
private String shortName;
|
||||
|
||||
@Schema(description = "父部门ID(顶级为0)", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Long parentId;
|
||||
|
||||
@Schema(description = "排序号", example = "1")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "状态:0-启用 1-禁用", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer status;
|
||||
|
||||
// ========== 部门类型 ==========
|
||||
|
||||
@Schema(description = "部门类型:28-公司 26-部门", example = "26")
|
||||
private Integer deptType;
|
||||
|
||||
@Schema(description = "是否集团", example = "false")
|
||||
private Boolean isGroup;
|
||||
|
||||
@Schema(description = "是否公司", example = "false")
|
||||
private Boolean isCompany;
|
||||
|
||||
@Schema(description = "部门来源类型", example = "1")
|
||||
private Integer deptSource;
|
||||
|
||||
// ========== 联系信息 ==========
|
||||
|
||||
@Schema(description = "负责人ID", example = "1001")
|
||||
private Long leaderUserId;
|
||||
|
||||
@Schema(description = "负责人姓名", example = "张三")
|
||||
private String leaderUserName;
|
||||
|
||||
@Schema(description = "联系电话", example = "010-12345678")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "邮箱", example = "tech@example.com")
|
||||
private String email;
|
||||
|
||||
// ========== 多租户 ==========
|
||||
|
||||
@Schema(description = "租户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long tenantId;
|
||||
|
||||
// ========== 时间信息 ==========
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package com.zt.plat.module.databus.api.data;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 岗位数据对象(DataBus)
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DatabusPostData implements Serializable {
|
||||
|
||||
/**
|
||||
* 岗位ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 岗位编码
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 岗位名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
private Integer sort;
|
||||
|
||||
/**
|
||||
* 状态(0正常 1停用)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.zt.plat.module.databus.api.data;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 用户与组织机构关联关系数据对象
|
||||
* <p>
|
||||
* 对应表:system_user_dept
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DatabusUserDeptData implements Serializable {
|
||||
|
||||
/**
|
||||
* 关联关系ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.zt.plat.module.databus.api.data;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 用户与岗位关联关系数据对象
|
||||
* <p>
|
||||
* 对应表:system_user_post
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DatabusUserPostData implements Serializable {
|
||||
|
||||
/**
|
||||
* 关联关系ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 岗位ID
|
||||
*/
|
||||
private Long postId;
|
||||
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
package com.zt.plat.module.databus.api.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.zt.plat.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 新增Databus API 访问日志请求体。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode
|
||||
public class ApiAccessLogCreateReq {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@Schema(description = "主键")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* HTTP 方法
|
||||
*/
|
||||
@Schema(description = "HTTP 方法")
|
||||
@NotNull(message = "HTTP 方法不能为空")
|
||||
private String requestMethod;
|
||||
|
||||
/**
|
||||
* 请求路径
|
||||
*/
|
||||
@Schema(description = "请求路径")
|
||||
@NotNull(message = "请求路径不能为空")
|
||||
private String requestPath;
|
||||
|
||||
/**
|
||||
* 调用使用的应用标识
|
||||
*/
|
||||
@Schema(description = "调用使用的应用标识")
|
||||
@NotNull(message = "调用使用的应用标识不能为空")
|
||||
private String credentialAppId;
|
||||
|
||||
/**
|
||||
* 多租户编号
|
||||
*/
|
||||
@Schema(description = "多租户编号")
|
||||
@NotNull(message = "多租户编号不能为空")
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 查询参数(JSON 字符串)
|
||||
*/
|
||||
@Schema(description = "查询参数(JSON 字符串)")
|
||||
private String requestQuery;
|
||||
|
||||
/**
|
||||
* 请求头信息(JSON 字符串)
|
||||
*/
|
||||
@Schema(description = "请求头信息(JSON 字符串)")
|
||||
private String requestHeaders;
|
||||
|
||||
/**
|
||||
* 请求体(JSON 字符串)
|
||||
*/
|
||||
@Schema(description = "请求体(JSON 字符串)")
|
||||
private String requestBody;
|
||||
|
||||
/**
|
||||
* 响应 HTTP 状态码
|
||||
*/
|
||||
@Schema(description = "响应 HTTP 状态码")
|
||||
private Integer responseStatus;
|
||||
|
||||
/**
|
||||
* 响应提示信息
|
||||
*/
|
||||
@Schema(description = "响应提示信息")
|
||||
private String responseMessage;
|
||||
|
||||
/**
|
||||
* 响应体(JSON 字符串)
|
||||
*/
|
||||
@Schema(description = "响应体(JSON 字符串)")
|
||||
private String responseBody;
|
||||
|
||||
/**
|
||||
* 访问状态:0-成功 1-客户端错误 2-服务端错误 3-未知
|
||||
*/
|
||||
@Schema(description = "访问状态:0-成功 1-客户端错误 2-服务端错误 3-未知")
|
||||
@NotNull(message = "访问状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 业务错误码
|
||||
*/
|
||||
@Schema(description = "业务错误码")
|
||||
private String errorCode;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
@Schema(description = "错误信息")
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* 异常堆栈
|
||||
*/
|
||||
@Schema(description = "异常堆栈")
|
||||
private String exceptionStack;
|
||||
|
||||
/**
|
||||
* 客户端 IP
|
||||
*/
|
||||
@Schema(description = "客户端 IP")
|
||||
private String clientIp;
|
||||
|
||||
/**
|
||||
* User-Agent
|
||||
*/
|
||||
@Schema(description = "User-Agent")
|
||||
private String userAgent;
|
||||
|
||||
/**
|
||||
* 请求耗时(毫秒)
|
||||
*/
|
||||
@Schema(description = "请求耗时(毫秒)")
|
||||
private Long duration;
|
||||
|
||||
/**
|
||||
* 请求时间
|
||||
*/
|
||||
@Schema(description = "请求时间")
|
||||
@JsonSerialize(using = TimestampLocalDateTimeSerializer.class)
|
||||
private LocalDateTime requestTime;
|
||||
|
||||
/**
|
||||
* 响应时间
|
||||
*/
|
||||
@Schema(description = "响应时间")
|
||||
@JsonSerialize(using = TimestampLocalDateTimeSerializer.class)
|
||||
private LocalDateTime responseTime;
|
||||
|
||||
/**
|
||||
* 额外调试信息(JSON 字符串)
|
||||
*/
|
||||
@Schema(description = "额外调试信息(JSON 字符串)")
|
||||
private String extra;
|
||||
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.zt.plat.module.databus.api.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 游标分页请求 DTO
|
||||
* <p>
|
||||
* 用于 Databus 全量同步时的断点续传
|
||||
* 使用 create_time + id 复合游标解决雪花ID非连续问题
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "游标分页请求")
|
||||
public class CursorPageReqDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "游标时间(上一批最后一条数据的创建时间)", example = "2024-01-01T00:00:00")
|
||||
private LocalDateTime cursorTime;
|
||||
|
||||
@Schema(description = "游标ID(上一批最后一条数据的ID,用于同一时间戳内去重)", example = "1234567890")
|
||||
private Long cursorId;
|
||||
|
||||
@Schema(description = "批量大小", example = "100")
|
||||
private Integer batchSize;
|
||||
|
||||
@Schema(description = "租户ID(可选,用于多租户过滤)", example = "1")
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 是否为首次查询(无游标)
|
||||
*/
|
||||
public boolean isFirstPage() {
|
||||
return cursorTime == null && cursorId == null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package com.zt.plat.module.databus.api.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 游标分页结果 DTO
|
||||
* <p>
|
||||
* 用于 Databus 全量同步时的断点续传响应
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "游标分页结果")
|
||||
public class CursorPageResult<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "数据列表")
|
||||
private List<T> list;
|
||||
|
||||
@Schema(description = "下一页游标时间(最后一条数据的创建时间)")
|
||||
private LocalDateTime nextCursorTime;
|
||||
|
||||
@Schema(description = "下一页游标ID(最后一条数据的ID)")
|
||||
private Long nextCursorId;
|
||||
|
||||
@Schema(description = "本次返回的数据量")
|
||||
private Integer count;
|
||||
|
||||
@Schema(description = "是否还有更多数据")
|
||||
private Boolean hasMore;
|
||||
|
||||
@Schema(description = "总数据量(可选,首次查询时返回)")
|
||||
private Long total;
|
||||
|
||||
/**
|
||||
* 构建首页结果
|
||||
*/
|
||||
public static <T> CursorPageResult<T> of(List<T> list, LocalDateTime nextCursorTime,
|
||||
Long nextCursorId, boolean hasMore, Long total) {
|
||||
return CursorPageResult.<T>builder()
|
||||
.list(list)
|
||||
.nextCursorTime(nextCursorTime)
|
||||
.nextCursorId(nextCursorId)
|
||||
.count(list != null ? list.size() : 0)
|
||||
.hasMore(hasMore)
|
||||
.total(total)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建后续页结果
|
||||
*/
|
||||
public static <T> CursorPageResult<T> of(List<T> list, LocalDateTime nextCursorTime,
|
||||
Long nextCursorId, boolean hasMore) {
|
||||
return of(list, nextCursorTime, nextCursorId, hasMore, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建空结果
|
||||
*/
|
||||
public static <T> CursorPageResult<T> empty() {
|
||||
return CursorPageResult.<T>builder()
|
||||
.list(List.of())
|
||||
.count(0)
|
||||
.hasMore(false)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package com.zt.plat.module.databus.api.message;
|
||||
|
||||
import com.zt.plat.module.databus.enums.DatabusEventType;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Databus 全量同步批量消息
|
||||
* <p>
|
||||
* 用于全量同步场景,支持分批传输
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DatabusBatchMessage<T> implements Serializable {
|
||||
|
||||
/**
|
||||
* 消息ID(用于幂等)
|
||||
*/
|
||||
private String messageId;
|
||||
|
||||
/**
|
||||
* 全量同步任务ID
|
||||
*/
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 事件类型
|
||||
*/
|
||||
private DatabusEventType eventType;
|
||||
|
||||
/**
|
||||
* 当前批次号(从1开始)
|
||||
*/
|
||||
private Integer batchNo;
|
||||
|
||||
/**
|
||||
* 总批次数
|
||||
*/
|
||||
private Integer totalBatch;
|
||||
|
||||
/**
|
||||
* 当前批次数据条数
|
||||
*/
|
||||
private Integer count;
|
||||
|
||||
/**
|
||||
* 总数据条数
|
||||
*/
|
||||
private Integer totalCount;
|
||||
|
||||
/**
|
||||
* 是否最后一批
|
||||
*/
|
||||
private Boolean isLastBatch;
|
||||
|
||||
/**
|
||||
* 数据列<E68DAE><E58897>
|
||||
*/
|
||||
private List<T> dataList;
|
||||
|
||||
/**
|
||||
* 消息产生时间
|
||||
*/
|
||||
private LocalDateTime timestamp;
|
||||
|
||||
/**
|
||||
* 来源系统
|
||||
*/
|
||||
private String source;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 创建批量消息
|
||||
*/
|
||||
public static <T> DatabusBatchMessage<T> of(DatabusEventType eventType, String taskId,
|
||||
int batchNo, int totalBatch,
|
||||
List<T> dataList, int totalCount) {
|
||||
DatabusBatchMessage<T> msg = new DatabusBatchMessage<>();
|
||||
msg.setMessageId(java.util.UUID.randomUUID().toString());
|
||||
msg.setTaskId(taskId);
|
||||
msg.setEventType(eventType);
|
||||
msg.setBatchNo(batchNo);
|
||||
msg.setTotalBatch(totalBatch);
|
||||
msg.setCount(dataList != null ? dataList.size() : 0);
|
||||
msg.setTotalCount(totalCount);
|
||||
msg.setIsLastBatch(batchNo >= totalBatch);
|
||||
msg.setDataList(dataList);
|
||||
msg.setTimestamp(LocalDateTime.now());
|
||||
return msg;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package com.zt.plat.module.databus.api.message;
|
||||
|
||||
import com.zt.plat.module.databus.enums.DatabusEventType;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* Databus 增量同步消息
|
||||
* <p>
|
||||
* 业务推送、服务端消费、服务端转发、客户端消费统一使用此消息体
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DatabusMessage<T> implements Serializable {
|
||||
|
||||
/**
|
||||
* 消息ID(用于幂等)
|
||||
*/
|
||||
private String messageId;
|
||||
|
||||
/**
|
||||
* 事件类型
|
||||
*/
|
||||
private DatabusEventType eventType;
|
||||
|
||||
/**
|
||||
* 业务数据ID
|
||||
*/
|
||||
private Long dataId;
|
||||
|
||||
/**
|
||||
* 业务数据(强类型)
|
||||
*/
|
||||
private T data;
|
||||
|
||||
/**
|
||||
* 消息产生时间
|
||||
*/
|
||||
private LocalDateTime timestamp;
|
||||
|
||||
/**
|
||||
* 来源系统
|
||||
*/
|
||||
private String source;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 创建简单消息
|
||||
*/
|
||||
public static <T> DatabusMessage<T> of(DatabusEventType eventType, Long dataId, T data) {
|
||||
DatabusMessage<T> msg = new DatabusMessage<>();
|
||||
msg.setMessageId(java.util.UUID.randomUUID().toString());
|
||||
msg.setEventType(eventType);
|
||||
msg.setDataId(dataId);
|
||||
msg.setData(data);
|
||||
msg.setTimestamp(LocalDateTime.now());
|
||||
return msg;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.zt.plat.module.databus.api.provider;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.module.databus.api.dto.ApiAccessLogCreateReq;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Databus API访问日志接口
|
||||
* 2026/1/20 16:26
|
||||
*/
|
||||
@FeignClient(name = "${databus.provider.log.service:databus-server}")
|
||||
@Tag(name = "RPC 服务 - Databus API访问日志接口")
|
||||
public interface DatabusAccessLogProviderApi {
|
||||
|
||||
String PREFIX = "/databus/api/portal/access-log";
|
||||
|
||||
@PostMapping(PREFIX + "/add")
|
||||
@Operation(summary = "新增访问日志")
|
||||
CommonResult<Boolean> add(@RequestHeader Map<String, String> headers, @RequestBody ApiAccessLogCreateReq req);
|
||||
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.zt.plat.module.databus.api.provider;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.module.databus.api.data.DatabusDeptData;
|
||||
import com.zt.plat.module.databus.api.dto.CursorPageReqDTO;
|
||||
import com.zt.plat.module.databus.api.dto.CursorPageResult;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Databus 部门数据提供者 API
|
||||
* <p>
|
||||
* 供 Databus 调用,获取部门数据用于全量/增量同步
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@FeignClient(name = "${databus.provider.dept.service:system-server}")
|
||||
@Tag(name = "RPC 服务 - Databus 部门数据提供者")
|
||||
public interface DatabusDeptProviderApi {
|
||||
|
||||
String PREFIX = "/rpc/databus/dept";
|
||||
|
||||
/**
|
||||
* 游标分页查询部门数据(用于全量同步)
|
||||
*
|
||||
* @param reqDTO 游标分页请求
|
||||
* @return 部门数据分页结果
|
||||
*/
|
||||
@PostMapping(PREFIX + "/page-by-cursor")
|
||||
@Operation(summary = "游标分页查询部门数据")
|
||||
CommonResult<CursorPageResult<DatabusDeptData>> getPageByCursor(@RequestBody CursorPageReqDTO reqDTO);
|
||||
|
||||
/**
|
||||
* 根据ID查询部门详情(用于增量同步)
|
||||
*
|
||||
* @param id 部门ID
|
||||
* @return 部门数据
|
||||
*/
|
||||
@GetMapping(PREFIX + "/get")
|
||||
@Operation(summary = "查询部门详情")
|
||||
@Parameter(name = "id", description = "部门ID", required = true, example = "100")
|
||||
CommonResult<DatabusDeptData> getById(@RequestParam("id") Long id);
|
||||
|
||||
/**
|
||||
* 批量查询部门详情(用于增量同步批量获取)
|
||||
*
|
||||
* @param ids 部门ID列表
|
||||
* @return 部门数据列表
|
||||
*/
|
||||
@GetMapping(PREFIX + "/list")
|
||||
@Operation(summary = "批量查询部门详情")
|
||||
@Parameter(name = "ids", description = "部门ID列表", required = true, example = "100,101,102")
|
||||
CommonResult<List<DatabusDeptData>> getListByIds(@RequestParam("ids") List<Long> ids);
|
||||
|
||||
/**
|
||||
* 统计部门总数(用于全量同步进度计算)
|
||||
*
|
||||
* @param tenantId 租户ID(可选)
|
||||
* @return 部门总数
|
||||
*/
|
||||
@GetMapping(PREFIX + "/count")
|
||||
@Operation(summary = "统计部门总数")
|
||||
@Parameter(name = "tenantId", description = "租户ID", example = "1")
|
||||
CommonResult<Long> count(@RequestParam(value = "tenantId", required = false) Long tenantId);
|
||||
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.zt.plat.module.databus.api.provider;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.module.databus.api.data.DatabusPostData;
|
||||
import com.zt.plat.module.databus.api.dto.CursorPageReqDTO;
|
||||
import com.zt.plat.module.databus.api.dto.CursorPageResult;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Databus 岗位数据提供者 API
|
||||
* <p>
|
||||
* 供 Databus 调用,获取岗位数据用于全量/增量同步
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@FeignClient(name = "${databus.provider.post.service:system-server}")
|
||||
@Tag(name = "RPC 服务 - Databus 岗位数据提供者")
|
||||
public interface DatabusPostProviderApi {
|
||||
|
||||
String PREFIX = "/rpc/databus/post";
|
||||
|
||||
/**
|
||||
* 游标分页查询岗位数据(用于全量同步)
|
||||
*
|
||||
* @param reqDTO 游标分页请求
|
||||
* @return 岗位数据分页结果
|
||||
*/
|
||||
@PostMapping(PREFIX + "/page-by-cursor")
|
||||
@Operation(summary = "游标分页查询岗位数据")
|
||||
CommonResult<CursorPageResult<DatabusPostData>> getPageByCursor(@RequestBody CursorPageReqDTO reqDTO);
|
||||
|
||||
/**
|
||||
* 根据ID查询岗位详情(用于增量同步)
|
||||
*
|
||||
* @param id 岗位ID
|
||||
* @return 岗位数据
|
||||
*/
|
||||
@GetMapping(PREFIX + "/get")
|
||||
@Operation(summary = "查询岗位详情")
|
||||
@Parameter(name = "id", description = "岗位ID", required = true, example = "1")
|
||||
CommonResult<DatabusPostData> getById(@RequestParam("id") Long id);
|
||||
|
||||
/**
|
||||
* 批量查询岗位详情(用于增量同步批量获取)
|
||||
*
|
||||
* @param ids 岗位ID列表
|
||||
* @return 岗位数据列表
|
||||
*/
|
||||
@GetMapping(PREFIX + "/list")
|
||||
@Operation(summary = "批量查询岗位详情")
|
||||
@Parameter(name = "ids", description = "岗位ID列表", required = true, example = "1,2,3")
|
||||
CommonResult<List<DatabusPostData>> getListByIds(@RequestParam("ids") List<Long> ids);
|
||||
|
||||
/**
|
||||
* 统计岗位总数(用于全量同步进度计算)
|
||||
*
|
||||
* @param tenantId 租户ID(可选)
|
||||
* @return 岗位总数
|
||||
*/
|
||||
@GetMapping(PREFIX + "/count")
|
||||
@Operation(summary = "统计岗位总数")
|
||||
@Parameter(name = "tenantId", description = "租户ID", example = "1")
|
||||
CommonResult<Long> count(@RequestParam(value = "tenantId", required = false) Long tenantId);
|
||||
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.zt.plat.module.databus.api.provider;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.module.databus.api.data.DatabusUserDeptData;
|
||||
import com.zt.plat.module.databus.api.dto.CursorPageReqDTO;
|
||||
import com.zt.plat.module.databus.api.dto.CursorPageResult;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Databus 用户-部门关系数据提供者 API
|
||||
* <p>
|
||||
* 供 Databus 调用,获取用户-部门关联数据用于全量/增量同步
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@FeignClient(name = "${databus.provider.user-dept.service:system-server}")
|
||||
@Tag(name = "RPC 服务 - Databus 用户-部门关系数据提供者")
|
||||
public interface DatabusUserDeptProviderApi {
|
||||
|
||||
String PREFIX = "/rpc/databus/user-dept";
|
||||
|
||||
/**
|
||||
* 游标分页查询用户-部门关系数据(用于全量同步)
|
||||
*
|
||||
* @param reqDTO 游标分页请求
|
||||
* @return 用户-部门关系数据分页结果
|
||||
*/
|
||||
@PostMapping(PREFIX + "/page-by-cursor")
|
||||
@Operation(summary = "游标分页查询用户-部门关系数据")
|
||||
CommonResult<CursorPageResult<DatabusUserDeptData>> getPageByCursor(@RequestBody CursorPageReqDTO reqDTO);
|
||||
|
||||
/**
|
||||
* 根据ID查询用户-部门关系详情(用于增量同步)
|
||||
*
|
||||
* @param id 关系ID
|
||||
* @return 用户-部门关系数据
|
||||
*/
|
||||
@GetMapping(PREFIX + "/get")
|
||||
@Operation(summary = "查询用户-部门关系详情")
|
||||
@Parameter(name = "id", description = "关系ID", required = true, example = "1001")
|
||||
CommonResult<DatabusUserDeptData> getById(@RequestParam("id") Long id);
|
||||
|
||||
/**
|
||||
* 批量查询用户-部门关系详情(用于增量同步批量获取)
|
||||
*
|
||||
* @param ids 关系ID列表
|
||||
* @return 用户-部门关系数据列表
|
||||
*/
|
||||
@GetMapping(PREFIX + "/list")
|
||||
@Operation(summary = "批量查询用户-部门关系详情")
|
||||
@Parameter(name = "ids", description = "关系ID列表", required = true, example = "1001,1002,1003")
|
||||
CommonResult<List<DatabusUserDeptData>> getListByIds(@RequestParam("ids") List<Long> ids);
|
||||
|
||||
/**
|
||||
* 统计用户-部门关系总数(用于全量同步进度计算)
|
||||
*
|
||||
* @param tenantId 租户ID(可选)
|
||||
* @return 用户-部门关系总数
|
||||
*/
|
||||
@GetMapping(PREFIX + "/count")
|
||||
@Operation(summary = "统计用户-部门关系总数")
|
||||
@Parameter(name = "tenantId", description = "租户ID", example = "1")
|
||||
CommonResult<Long> count(@RequestParam(value = "tenantId", required = false) Long tenantId);
|
||||
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.zt.plat.module.databus.api.provider;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.module.databus.api.data.DatabusUserPostData;
|
||||
import com.zt.plat.module.databus.api.dto.CursorPageReqDTO;
|
||||
import com.zt.plat.module.databus.api.dto.CursorPageResult;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Databus 用户-岗位关系数据提供者 API
|
||||
* <p>
|
||||
* 供 Databus 调用,获取用户-岗位关联数据用于全量/增量同步
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@FeignClient(name = "${databus.provider.user-post.service:system-server}")
|
||||
@Tag(name = "RPC 服务 - Databus 用户-岗位关系数据提供者")
|
||||
public interface DatabusUserPostProviderApi {
|
||||
|
||||
String PREFIX = "/rpc/databus/user-post";
|
||||
|
||||
/**
|
||||
* 游标分页查询用户-岗位关系数据(用于全量同步)
|
||||
*
|
||||
* @param reqDTO 游标分页请求
|
||||
* @return 用户-岗位关系数据分页结果
|
||||
*/
|
||||
@PostMapping(PREFIX + "/page-by-cursor")
|
||||
@Operation(summary = "游标分页查询用户-岗位关系数据")
|
||||
CommonResult<CursorPageResult<DatabusUserPostData>> getPageByCursor(@RequestBody CursorPageReqDTO reqDTO);
|
||||
|
||||
/**
|
||||
* 根据ID查询用户-岗位关系详情(用于增量同步)
|
||||
*
|
||||
* @param id 关系ID
|
||||
* @return 用户-岗位关系数据
|
||||
*/
|
||||
@GetMapping(PREFIX + "/get")
|
||||
@Operation(summary = "查询用户-岗位关系详情")
|
||||
@Parameter(name = "id", description = "关系ID", required = true, example = "1001")
|
||||
CommonResult<DatabusUserPostData> getById(@RequestParam("id") Long id);
|
||||
|
||||
/**
|
||||
* 批量查询用户-岗位关系详情(用于增量同步批量获取)
|
||||
*
|
||||
* @param ids 关系ID列表
|
||||
* @return 用户-岗位关系数据列表
|
||||
*/
|
||||
@GetMapping(PREFIX + "/list")
|
||||
@Operation(summary = "批量查询用户-岗位关系详情")
|
||||
@Parameter(name = "ids", description = "关系ID列表", required = true, example = "1001,1002,1003")
|
||||
CommonResult<List<DatabusUserPostData>> getListByIds(@RequestParam("ids") List<Long> ids);
|
||||
|
||||
/**
|
||||
* 统计用户-岗位关系总数(用于全量同步进度计算)
|
||||
*
|
||||
* @param tenantId 租户ID(可选)
|
||||
* @return 用户-岗位关系总数
|
||||
*/
|
||||
@GetMapping(PREFIX + "/count")
|
||||
@Operation(summary = "统计用户-岗位关系总数")
|
||||
@Parameter(name = "tenantId", description = "租户ID", example = "1")
|
||||
CommonResult<Long> count(@RequestParam(value = "tenantId", required = false) Long tenantId);
|
||||
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.zt.plat.module.databus.api.provider;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.module.databus.api.data.DatabusAdminUserData;
|
||||
import com.zt.plat.module.databus.api.dto.CursorPageReqDTO;
|
||||
import com.zt.plat.module.databus.api.dto.CursorPageResult;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Databus 用户数据提供者 API
|
||||
* <p>
|
||||
* 供 Databus 调用,获取用户数据用于全量/增量同步
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@FeignClient(name = "${databus.provider.user.service:system-server}")
|
||||
@Tag(name = "RPC 服务 - Databus 用户数据提供者")
|
||||
public interface DatabusUserProviderApi {
|
||||
|
||||
String PREFIX = "/rpc/databus/user";
|
||||
|
||||
/**
|
||||
* 游标分页查询用户数据(用于全量同步)
|
||||
*
|
||||
* @param reqDTO 游标分页请求
|
||||
* @return 用户数据分页结果
|
||||
*/
|
||||
@PostMapping(PREFIX + "/page-by-cursor")
|
||||
@Operation(summary = "游标分页查询用户数据")
|
||||
CommonResult<CursorPageResult<DatabusAdminUserData>> getPageByCursor(@RequestBody CursorPageReqDTO reqDTO);
|
||||
|
||||
/**
|
||||
* 根据ID查询用户详情(用于增量同步)
|
||||
*
|
||||
* @param id 用户ID
|
||||
* @return 用户数据
|
||||
*/
|
||||
@GetMapping(PREFIX + "/get")
|
||||
@Operation(summary = "查询用户详情")
|
||||
@Parameter(name = "id", description = "用户ID", required = true, example = "1001")
|
||||
CommonResult<DatabusAdminUserData> getById(@RequestParam("id") Long id);
|
||||
|
||||
/**
|
||||
* 批量查询用户详情(用于增量同步批量获取)
|
||||
*
|
||||
* @param ids 用户ID列表
|
||||
* @return 用户数据列表
|
||||
*/
|
||||
@GetMapping(PREFIX + "/list")
|
||||
@Operation(summary = "批量查询用户详情")
|
||||
@Parameter(name = "ids", description = "用户ID列表", required = true, example = "1001,1002,1003")
|
||||
CommonResult<List<DatabusAdminUserData>> getListByIds(@RequestParam("ids") List<Long> ids);
|
||||
|
||||
/**
|
||||
* 统计用户总数(用于全量同步进度计算)
|
||||
*
|
||||
* @param tenantId 租户ID(可选)
|
||||
* @return 用户总数
|
||||
*/
|
||||
@GetMapping(PREFIX + "/count")
|
||||
@Operation(summary = "统计用户总数")
|
||||
@Parameter(name = "tenantId", description = "租户ID", example = "1")
|
||||
CommonResult<Long> count(@RequestParam(value = "tenantId", required = false) Long tenantId);
|
||||
|
||||
}
|
||||
@@ -1,402 +0,0 @@
|
||||
package com.zt.plat.module.databus.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Databus 事件类型枚举
|
||||
* <p>
|
||||
* 三级结构: 模块_数据类型_操作
|
||||
* <p>
|
||||
* Topic 命名规则:
|
||||
* - 业务推送到服务端: {topicBase}-{module}-{entity}-{action}
|
||||
* - 服务端转发到客户端: {topicBase}-{module}-{entity}-{action}-{clientCode}
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DatabusEventType {
|
||||
|
||||
// ==================== SYSTEM 系统模块 ====================
|
||||
|
||||
/**
|
||||
* 用户-创建
|
||||
*/
|
||||
SYSTEM_USER_CREATE("system", "user", "create", "用户创建"),
|
||||
|
||||
/**
|
||||
* 用户-更新
|
||||
*/
|
||||
SYSTEM_USER_UPDATE("system", "user", "update", "用户更新"),
|
||||
|
||||
/**
|
||||
* 用户-删除
|
||||
*/
|
||||
SYSTEM_USER_DELETE("system", "user", "delete", "用户删除"),
|
||||
|
||||
/**
|
||||
* 用户-全量同步
|
||||
*/
|
||||
SYSTEM_USER_FULL("system", "user", "full", "用户全量同步"),
|
||||
|
||||
/**
|
||||
* 组织机构-创建
|
||||
*/
|
||||
SYSTEM_ORG_CREATE("system", "org", "create", "组织机构创建"),
|
||||
|
||||
/**
|
||||
* 组织机构-更新
|
||||
*/
|
||||
SYSTEM_ORG_UPDATE("system", "org", "update", "组织机构更新"),
|
||||
|
||||
/**
|
||||
* 组织机构-删除
|
||||
*/
|
||||
SYSTEM_ORG_DELETE("system", "org", "delete", "组织机构删除"),
|
||||
|
||||
/**
|
||||
* 组织机构-全量同步
|
||||
*/
|
||||
SYSTEM_ORG_FULL("system", "org", "full", "组织机构全量同步"),
|
||||
|
||||
/**
|
||||
* 部门-创建(新命名,推荐使用)
|
||||
*/
|
||||
SYSTEM_DEPT_CREATE("system", "dept", "create", "部门创建"),
|
||||
|
||||
/**
|
||||
* 部门-更新(新命名,推荐使用)
|
||||
*/
|
||||
SYSTEM_DEPT_UPDATE("system", "dept", "update", "部门更新"),
|
||||
|
||||
/**
|
||||
* 部门-删除(新命名,推荐使用)
|
||||
*/
|
||||
SYSTEM_DEPT_DELETE("system", "dept", "delete", "部门删除"),
|
||||
|
||||
/**
|
||||
* 部门-全量同步(新命名,推荐使用)
|
||||
*/
|
||||
SYSTEM_DEPT_FULL("system", "dept", "full", "部门全量同步"),
|
||||
|
||||
/**
|
||||
* 岗位-创建
|
||||
*/
|
||||
SYSTEM_POST_CREATE("system", "post", "create", "岗位创建"),
|
||||
|
||||
/**
|
||||
* 岗位-更新
|
||||
*/
|
||||
SYSTEM_POST_UPDATE("system", "post", "update", "岗位更新"),
|
||||
|
||||
/**
|
||||
* 岗位-删除
|
||||
*/
|
||||
SYSTEM_POST_DELETE("system", "post", "delete", "岗位删除"),
|
||||
|
||||
/**
|
||||
* 岗位-全量同步
|
||||
*/
|
||||
SYSTEM_POST_FULL("system", "post", "full", "岗位全量同步"),
|
||||
|
||||
/**
|
||||
* 用户-部门关系-创建
|
||||
*/
|
||||
SYSTEM_USER_DEPT_CREATE("system", "user-dept", "create", "用户-部门关系创建"),
|
||||
|
||||
/**
|
||||
* 用户-部门关系-更新
|
||||
*/
|
||||
SYSTEM_USER_DEPT_UPDATE("system", "user-dept", "update", "用户-部门关系更新"),
|
||||
|
||||
/**
|
||||
* 用户-部门关系-删除
|
||||
*/
|
||||
SYSTEM_USER_DEPT_DELETE("system", "user-dept", "delete", "用户-部门关系删除"),
|
||||
|
||||
/**
|
||||
* 用户-部门关系-全量同步
|
||||
*/
|
||||
SYSTEM_USER_DEPT_FULL("system", "user-dept", "full", "用户-部门关系全量同步"),
|
||||
|
||||
/**
|
||||
* 用户-岗位关系-创建
|
||||
*/
|
||||
SYSTEM_USER_POST_CREATE("system", "user-post", "create", "用户-岗位关系创建"),
|
||||
|
||||
/**
|
||||
* 用户-岗位关系-更新
|
||||
*/
|
||||
SYSTEM_USER_POST_UPDATE("system", "user-post", "update", "用户-岗位关系更新"),
|
||||
|
||||
/**
|
||||
* 用户-岗位关系-删除
|
||||
*/
|
||||
SYSTEM_USER_POST_DELETE("system", "user-post", "delete", "用户-岗位关系删除"),
|
||||
|
||||
/**
|
||||
* 用户-岗位关系-全量同步
|
||||
*/
|
||||
SYSTEM_USER_POST_FULL("system", "user-post", "full", "用户-岗位关系全量同步"),
|
||||
|
||||
/**
|
||||
* @deprecated 已拆分为 SYSTEM_USER_DEPT_* 和 SYSTEM_USER_POST_*,保留用于向后兼容
|
||||
*/
|
||||
@Deprecated
|
||||
SYSTEM_USER_RELATION_CREATE("system", "user-relation", "create", "用户关联创建"),
|
||||
|
||||
/**
|
||||
* @deprecated 已拆分为 SYSTEM_USER_DEPT_* 和 SYSTEM_USER_POST_*,保留用于向后兼容
|
||||
*/
|
||||
@Deprecated
|
||||
SYSTEM_USER_RELATION_UPDATE("system", "user-relation", "update", "用户关联更新"),
|
||||
|
||||
/**
|
||||
* @deprecated 已拆分为 SYSTEM_USER_DEPT_* 和 SYSTEM_USER_POST_*,保留用于向后兼容
|
||||
*/
|
||||
@Deprecated
|
||||
SYSTEM_USER_RELATION_DELETE("system", "user-relation", "delete", "用户关联删除"),
|
||||
|
||||
/**
|
||||
* @deprecated 已拆分为 SYSTEM_USER_DEPT_* 和 SYSTEM_USER_POST_*,保留用于向后兼容
|
||||
*/
|
||||
@Deprecated
|
||||
SYSTEM_USER_RELATION_FULL("system", "user-relation", "full", "用户关联全量同步"),
|
||||
|
||||
/**
|
||||
* 基础数据-全量同步(组合编排事件)
|
||||
* <p>
|
||||
* 按依赖顺序触发以下全量同步:
|
||||
* 1. 组织机构(SYSTEM_DEPT_FULL)
|
||||
* 2. 岗位(SYSTEM_POST_FULL)
|
||||
* 3. 用户(SYSTEM_USER_FULL)
|
||||
* 4. 用户-部门关系(SYSTEM_USER_DEPT_FULL)
|
||||
* 5. 用户-岗位关系(SYSTEM_USER_POST_FULL)
|
||||
* <p>
|
||||
* 注意:本事件只负责触发,实际数据同步由5个独立的全量同步任务完成
|
||||
*/
|
||||
SYSTEM_BASE_DATA_FULL("system", "base-data", "full", "基础数据全量同步"),
|
||||
|
||||
/**
|
||||
* 角色-创建
|
||||
*/
|
||||
SYSTEM_ROLE_CREATE("system", "role", "create", "角色创建"),
|
||||
|
||||
/**
|
||||
* 角色-更新
|
||||
*/
|
||||
SYSTEM_ROLE_UPDATE("system", "role", "update", "角色更新"),
|
||||
|
||||
/**
|
||||
* 角色-删除
|
||||
*/
|
||||
SYSTEM_ROLE_DELETE("system", "role", "delete", "角色删除"),
|
||||
|
||||
/**
|
||||
* 角色-全量同步
|
||||
*/
|
||||
SYSTEM_ROLE_FULL("system", "role", "full", "角色全量同步"),
|
||||
|
||||
/**
|
||||
* 字典-创建
|
||||
*/
|
||||
SYSTEM_DICT_CREATE("system", "dict", "create", "字典创建"),
|
||||
|
||||
/**
|
||||
* 字典-更新
|
||||
*/
|
||||
SYSTEM_DICT_UPDATE("system", "dict", "update", "字典更新"),
|
||||
|
||||
/**
|
||||
* 字典-删除
|
||||
*/
|
||||
SYSTEM_DICT_DELETE("system", "dict", "delete", "字典删除"),
|
||||
|
||||
/**
|
||||
* 字典-全量同步
|
||||
*/
|
||||
SYSTEM_DICT_FULL("system", "dict", "full", "字典全量同步"),
|
||||
|
||||
// ==================== BASE 基础模块 ====================
|
||||
|
||||
/**
|
||||
* 物料-创建
|
||||
*/
|
||||
BASE_MATERIAL_CREATE("base", "material", "create", "物料创建"),
|
||||
|
||||
/**
|
||||
* 物料-更新
|
||||
*/
|
||||
BASE_MATERIAL_UPDATE("base", "material", "update", "物料更新"),
|
||||
|
||||
/**
|
||||
* 物料-删除
|
||||
*/
|
||||
BASE_MATERIAL_DELETE("base", "material", "delete", "物料删除"),
|
||||
|
||||
/**
|
||||
* 物料-全量同步
|
||||
*/
|
||||
BASE_MATERIAL_FULL("base", "material", "full", "物料全量同步"),
|
||||
|
||||
/**
|
||||
* 供应商-创建
|
||||
*/
|
||||
BASE_SUPPLIER_CREATE("base", "supplier", "create", "供应商创建"),
|
||||
|
||||
/**
|
||||
* 供应商-更新
|
||||
*/
|
||||
BASE_SUPPLIER_UPDATE("base", "supplier", "update", "供应商更新"),
|
||||
|
||||
/**
|
||||
* 供应商-删除
|
||||
*/
|
||||
BASE_SUPPLIER_DELETE("base", "supplier", "delete", "供应商删除"),
|
||||
|
||||
/**
|
||||
* 供应商-全量同步
|
||||
*/
|
||||
BASE_SUPPLIER_FULL("base", "supplier", "full", "供应商全量同步"),
|
||||
|
||||
/**
|
||||
* 客户-创建
|
||||
*/
|
||||
BASE_CUSTOMER_CREATE("base", "customer", "create", "客户创建"),
|
||||
|
||||
/**
|
||||
* 客户-更新
|
||||
*/
|
||||
BASE_CUSTOMER_UPDATE("base", "customer", "update", "客户更新"),
|
||||
|
||||
/**
|
||||
* 客户-删除
|
||||
*/
|
||||
BASE_CUSTOMER_DELETE("base", "customer", "delete", "客户删除"),
|
||||
|
||||
/**
|
||||
* 客户-全量同步
|
||||
*/
|
||||
BASE_CUSTOMER_FULL("base", "customer", "full", "客户全量同步"),
|
||||
|
||||
;
|
||||
|
||||
/**
|
||||
* 模块编码
|
||||
*/
|
||||
private final String module;
|
||||
|
||||
/**
|
||||
* 实体编码
|
||||
*/
|
||||
private final String entity;
|
||||
|
||||
/**
|
||||
* 操作编码
|
||||
*/
|
||||
private final String action;
|
||||
|
||||
/**
|
||||
* 事件名称
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* 获取Topic后缀(不含topicBase和clientCode)
|
||||
* 格式: {module}-{entity}-{action}
|
||||
*/
|
||||
public String getTopicSuffix() {
|
||||
return String.format("%s-%s-%s", module, entity, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取完整Topic名称(服务端转发用 - 统一消费者架构)
|
||||
* <p>
|
||||
* 新架构:所有事件类型都推送到同一个客户端 Topic,通过消息体中的 eventType 字段区分
|
||||
* 格式: {topicBase}-{clientCode}
|
||||
* 示例: databus-sync-hwc-test
|
||||
*/
|
||||
public String getTopic(String topicBase, String clientCode) {
|
||||
return String.format("%s-%s", topicBase, clientCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取完整Topic名称(业务推送用,不带clientCode)
|
||||
* 格式: {topicBase}-{module}-{entity}-{action}
|
||||
*/
|
||||
public String getTopic(String topicBase) {
|
||||
return String.format("%s-%s-%s-%s", topicBase, module, entity, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据Topic后缀获取枚举
|
||||
*
|
||||
* @param topicSuffix Topic后缀(格式: module-entity-action)
|
||||
* @return 枚举值,未找到返回null
|
||||
*/
|
||||
public static DatabusEventType getByTopicSuffix(String topicSuffix) {
|
||||
if (topicSuffix == null) {
|
||||
return null;
|
||||
}
|
||||
for (DatabusEventType type : values()) {
|
||||
if (type.getTopicSuffix().equalsIgnoreCase(topicSuffix)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据模块、实体、操作获取枚举
|
||||
*
|
||||
* @param module 模块编码
|
||||
* @param entity 实体编码
|
||||
* @param action 操作编码
|
||||
* @return 枚举值,未找到返回null
|
||||
*/
|
||||
public static DatabusEventType getByModuleEntityAction(String module, String entity, String action) {
|
||||
for (DatabusEventType type : values()) {
|
||||
if (type.getModule().equalsIgnoreCase(module)
|
||||
&& type.getEntity().equalsIgnoreCase(entity)
|
||||
&& type.getAction().equalsIgnoreCase(action)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据事件类型名称获取枚举
|
||||
* <p>
|
||||
* 支持大写下划线格式,如: SYSTEM_POST_FULL
|
||||
*
|
||||
* @param eventType 事件类型名称(枚举常量名)
|
||||
* @return 枚举值,未找到返回null
|
||||
*/
|
||||
public static DatabusEventType getByEventType(String eventType) {
|
||||
if (eventType == null || eventType.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return DatabusEventType.valueOf(eventType);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为全量同步事件
|
||||
*/
|
||||
public boolean isFullSync() {
|
||||
return "full".equalsIgnoreCase(this.action);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为增量同步事件
|
||||
*/
|
||||
public boolean isIncrementalSync() {
|
||||
return !isFullSync();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.zt.plat.module.databus.enums;
|
||||
|
||||
import com.zt.plat.framework.common.exception.ErrorCode;
|
||||
|
||||
/**
|
||||
* databus 错误码枚举类
|
||||
*
|
||||
* databus 系统,使用 1-xxx-xxx-xxx 段
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
public interface ErrorCodeConstants {
|
||||
|
||||
// ========== 示例模块 1-001-000-000 ==========
|
||||
ErrorCode EXAMPLE_NOT_EXISTS = new ErrorCode(1_001_000_001, "示例不存在");
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>zt-module-databus</artifactId>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<artifactId>zt-module-databus-client</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
Databus client, 提供调用第三方服务的能力并记录调用日志。
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-module-databus-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,241 +0,0 @@
|
||||
package com.zt.plat.module.databus.client;
|
||||
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.http.Method;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.module.databus.api.dto.ApiAccessLogCreateReq;
|
||||
import com.zt.plat.module.databus.api.provider.DatabusAccessLogProviderApi;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 数据总线提供的 http 客户端, 通过此客户端发起接口调用,会自动记录请求日志到数据总线
|
||||
* 2026/1/20 09:44
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class DatabusClient {
|
||||
|
||||
/**
|
||||
* 多租户编号
|
||||
*/
|
||||
@Value("${zt.plat.databus.client.tenantId:1}")
|
||||
private Long tenantId;
|
||||
|
||||
@Resource
|
||||
private DatabusAccessLogProviderApi databusAccessLogProviderApi;
|
||||
|
||||
private static final int MAX_TEXT_LENGTH = 4000;
|
||||
|
||||
/**
|
||||
* 发送 get 请求
|
||||
* @param urlString 仅接口地址,不带参数,参数由data提供
|
||||
* @param data 请求参数
|
||||
* @param headers 请求头
|
||||
* @return 响应结果
|
||||
*/
|
||||
public String get(String urlString, Map<String, Object> data, Map<String, String> headers, String appId, String authToken) {
|
||||
return doRequest(urlString, data, headers, Method.GET, appId, authToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 post 请求
|
||||
* @param urlString 仅接口地址,不带参数,参数由data提供
|
||||
* @param data 请求数据
|
||||
* @param headers 请求头
|
||||
* @return 响应结果
|
||||
*/
|
||||
public String post(String urlString, Map<String, Object> data, Map<String, String> headers, String appId, String authToken) {
|
||||
return doRequest(urlString, data, headers, Method.POST, appId, authToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 put 请求
|
||||
* @param urlString 仅接口地址,不带参数,参数由data提供
|
||||
* @param data 请求数据
|
||||
* @param headers 请求头
|
||||
* @return 响应结果
|
||||
*/
|
||||
public String put(String urlString, Map<String, Object> data, Map<String, String> headers, String appId, String authToken) {
|
||||
return doRequest(urlString, data, headers, Method.PUT, appId, authToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 delete 请求
|
||||
* @param urlString 仅接口地址,不带参数,参数由data提供
|
||||
* @param data 请求数据
|
||||
* @param headers 请求头
|
||||
* @return 响应结果
|
||||
*/
|
||||
public String delete(String urlString, Map<String, Object> data, Map<String, String> headers, String appId, String authToken) {
|
||||
return doRequest(urlString, data, headers, Method.DELETE, appId, authToken);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 发送请求到门户(token模式,不证书加密)
|
||||
* @param urlString 仅接口地址,不带参数,参数由data提供
|
||||
* @param data 请求数据
|
||||
* @param headers 请求头
|
||||
* @param method 请求方式,默认为 GET
|
||||
* @return 响应结果
|
||||
*/
|
||||
public String doRequest(String urlString, Map<String, Object> data, Map<String, String> headers, Method method, String appId, String authToken) {
|
||||
if (method == null) {
|
||||
method = Method.GET;
|
||||
}
|
||||
Assert.hasText(urlString, "接口地址不能为空");
|
||||
HttpRequest request;
|
||||
ApiAccessLogCreateReq logReq = new ApiAccessLogCreateReq();
|
||||
if (Method.GET.equals(method) || Method.DELETE.equals(method)) {
|
||||
logReq.setRequestQuery(JSONUtil.toJsonStr(data));
|
||||
} else {
|
||||
logReq.setRequestBody(JSONUtil.toJsonStr(data));
|
||||
}
|
||||
request = HttpUtil.createRequest(method, urlString).form(data);
|
||||
if (headers != null && !headers.isEmpty()) {
|
||||
for (Map.Entry<String, String> entry : headers.entrySet()) {
|
||||
request.header(entry.getKey(), entry.getValue(), true);
|
||||
}
|
||||
}
|
||||
|
||||
logReq.setTenantId(tenantId);
|
||||
|
||||
logReq.setRequestMethod(method.name());
|
||||
logReq.setRequestPath(urlString);
|
||||
logReq.setCredentialAppId(appId);
|
||||
logReq.setRequestHeaders(JSONUtil.toJsonStr(headers));
|
||||
logReq.setUserAgent(request.header("User-Agent"));
|
||||
String result;
|
||||
logReq.setRequestTime(LocalDateTime.now());
|
||||
long requestTime = System.currentTimeMillis();
|
||||
try (HttpResponse response = request.execute()) {
|
||||
logReq.setDuration(System.currentTimeMillis() - requestTime);
|
||||
logReq.setResponseTime(LocalDateTime.now());
|
||||
result = response.body();
|
||||
logReq.setResponseStatus(response.getStatus());
|
||||
logReq.setResponseBody(result);
|
||||
logReq.setStatus(resolveStatus(response.getStatus()));
|
||||
Map<String, String> errorCodeAndMsg = extractErrorCodeAndMsg(result, response.getStatus());
|
||||
logReq.setErrorCode(errorCodeAndMsg.get("errorCode"));
|
||||
logReq.setErrorMessage(errorCodeAndMsg.get("errorMessage"));
|
||||
addAccessLog(logReq, appId, authToken);
|
||||
} catch (Exception e) {
|
||||
// 错误的日志服务端记录了,这里就不再记录了
|
||||
// logReq.setStatus(1);
|
||||
// logReq.setExceptionStack(buildStackTrace( e));
|
||||
// addAccessLog(logReq, appId, authToken);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void addAccessLog(ApiAccessLogCreateReq logReq, String appId, String authToken) {
|
||||
String nonce = randomNonce();
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("tenant-id", String.valueOf(tenantId));
|
||||
headers.put("ZT-App-Id", appId);
|
||||
headers.put("ZT-Timestamp", Long.toString(System.currentTimeMillis()));
|
||||
headers.put("ZT-Nonce", nonce);
|
||||
headers.put("ZT-Auth-Token", authToken);
|
||||
CommonResult<Boolean> response = databusAccessLogProviderApi.add(headers, logReq);
|
||||
if (response.getCode() != 0) {
|
||||
throw new RuntimeException("添加访问日志失败: " + response);
|
||||
}
|
||||
}
|
||||
|
||||
private static String randomNonce() {
|
||||
return UUID.randomUUID().toString().replace("-", "");
|
||||
}
|
||||
|
||||
private String buildStackTrace(Throwable throwable) {
|
||||
try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) {
|
||||
throwable.printStackTrace(pw);
|
||||
return truncate(sw.toString());
|
||||
} catch (Exception ex) {
|
||||
return throwable.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private Integer resolveStatus(Integer httpStatus) {
|
||||
if (httpStatus == null) {
|
||||
return 3;
|
||||
}
|
||||
if (httpStatus >= 200 && httpStatus < 400) {
|
||||
return 0;
|
||||
}
|
||||
if (httpStatus >= 400 && httpStatus < 500) {
|
||||
return 1;
|
||||
}
|
||||
if (httpStatus >= 500) {
|
||||
return 2;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
private Map<String, String> extractErrorCodeAndMsg(String responseBody, Integer responseStatus) {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
if (!isErrorStatus(responseStatus)) {
|
||||
return result;
|
||||
}
|
||||
if (JSONUtil.isTypeJSONObject(responseBody)) {
|
||||
JSONObject map = JSONUtil.parseObj(responseBody);
|
||||
Object errorCode = firstNonNull(map.get("errorCode"), map.get("code"));
|
||||
errorCode = errorCode == null ? null : truncate(String.valueOf(errorCode));
|
||||
if (errorCode != null) {
|
||||
result.put("errorCode", errorCode.toString());
|
||||
}
|
||||
Object message = firstNonNull(map.get("errorMessage"), map.get("message"));
|
||||
if (message != null) {
|
||||
message = truncate(String.valueOf(message));
|
||||
result.put("errorMessage", message.toString());
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private boolean isErrorStatus(Integer responseStatus) {
|
||||
return responseStatus != null && responseStatus >= 400;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private <T> T firstNonNull(T... candidates) {
|
||||
if (candidates == null) {
|
||||
return null;
|
||||
}
|
||||
for (T candidate : candidates) {
|
||||
if (candidate != null) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String truncate(String text) {
|
||||
if (!StringUtils.hasText(text)) {
|
||||
return text;
|
||||
}
|
||||
if (text.length() <= MAX_TEXT_LENGTH) {
|
||||
return text;
|
||||
}
|
||||
return text.substring(0, MAX_TEXT_LENGTH);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.zt.plat.module.databus.client;
|
||||
|
||||
/**
|
||||
*
|
||||
* 2026/1/21 10:48
|
||||
*/
|
||||
|
||||
import com.zt.plat.module.databus.api.provider.DatabusAccessLogProviderApi;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableFeignClients(clients = {DatabusAccessLogProviderApi.class})
|
||||
public class RpcConfiguration {
|
||||
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.zt.plat.module.databus.client.DatabusClient,\
|
||||
com.zt.plat.module.databus.client.RpcConfiguration
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.zt.plat.module.databus;
|
||||
|
||||
import com.zt.plat.module.databus.client.DatabusClient;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
/**
|
||||
*
|
||||
* 2026/1/20 14:29
|
||||
*/
|
||||
@SpringBootTest(classes = TestApplication.class)
|
||||
public class DatabusClientTest {
|
||||
|
||||
@Autowired
|
||||
private DatabusClient databusClient;
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
String result = databusClient.get("https://www.baidu.com/", null, null, "jwyw2", "a5d7cf609c0b47038ea405c660726ee9");
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package com.zt.plat.module.databus;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
/**
|
||||
*
|
||||
* 2026/1/20 14:26
|
||||
*/
|
||||
@SpringBootTest
|
||||
@SpringBootApplication(exclude = {
|
||||
DataSourceAutoConfiguration.class,
|
||||
DataSourceTransactionManagerAutoConfiguration.class,
|
||||
HibernateJpaAutoConfiguration.class,
|
||||
JdbcTemplateAutoConfiguration.class,
|
||||
})
|
||||
public class TestApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(TestApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
spring:
|
||||
cloud:
|
||||
nacos:
|
||||
server-addr: 172.16.46.63:30848 # Nacos 服务器地址
|
||||
username: nacos # Nacos 账号
|
||||
password: P@ssword25 # Nacos 密码
|
||||
discovery: # 【配置中心】配置项
|
||||
namespace: klw # 命名空间。这里使用 maven Profile 资源过滤进行动态替换
|
||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
||||
metadata:
|
||||
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
||||
@@ -4,7 +4,7 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>zt-module-databus</artifactId>
|
||||
<artifactId>zt-module-databus-dsc</artifactId>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
@@ -24,6 +24,12 @@
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Test 测试相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
|
||||
@@ -1,195 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>zt-module-databus</artifactId>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<artifactId>zt-module-databus-server</artifactId>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
Databus 模块。
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Cloud 基础 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-env</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 依赖服务 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-module-system-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-module-infra-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-module-databus-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- DataBus Server Starter -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-databus-server</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 业务组件 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-biz-data-permission</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-biz-tenant</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- DB 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-mybatis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- RPC 远程调用相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-rpc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Registry 注册中心相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Config 配置中心相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Job 定时任务相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-job</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 消息队列相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-mq</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Test 测试相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-excel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 监控相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-monitor</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-biz-business</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Integration & Flow Orchestration -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-http</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-scripting</artifactId>
|
||||
</dependency>
|
||||
<!-- Reactive HTTP client for internal REST orchestration -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Expression evaluation & caching utilities -->
|
||||
<dependency>
|
||||
<groupId>com.ibm.jsonata4java</groupId>
|
||||
<artifactId>JSONata4Java</artifactId>
|
||||
<version>2.5.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mvel</groupId>
|
||||
<artifactId>mvel2</artifactId>
|
||||
<version>2.5.2.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Testing support -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>mockwebserver</artifactId>
|
||||
<version>4.12.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-databus-client</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -1,45 +0,0 @@
|
||||
package com.zt.plat.module.databus.api;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.util.monitor.TracerUtils;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
import com.zt.plat.framework.common.util.servlet.ServletUtils;
|
||||
import com.zt.plat.module.databus.api.dto.ApiAccessLogCreateReq;
|
||||
import com.zt.plat.module.databus.api.provider.DatabusAccessLogProviderApi;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiAccessLogDO;
|
||||
import com.zt.plat.module.databus.service.gateway.ApiAccessLogService;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
*
|
||||
* 2026/1/21 10:05
|
||||
*/
|
||||
@RestController
|
||||
public class DatabusAccessLogProviderApiImpl implements DatabusAccessLogProviderApi {
|
||||
|
||||
@Resource
|
||||
private ApiAccessLogService apiAccessLogService;
|
||||
|
||||
@Override
|
||||
@PermitAll
|
||||
public CommonResult<Boolean> add(Map<String, String> headers, ApiAccessLogCreateReq req) {
|
||||
ApiAccessLogDO logDO = new ApiAccessLogDO();
|
||||
BeanUtils.copyProperties(req, logDO);
|
||||
logDO.setTraceId(TracerUtils.getTraceId());
|
||||
logDO.setClientIp(ServletUtils.getClientIP());
|
||||
logDO.setCreateTime(LocalDateTime.now());
|
||||
logDO.setUpdateTime(LocalDateTime.now());
|
||||
logDO.setCreator("1");
|
||||
logDO.setUpdater("1");
|
||||
|
||||
apiAccessLogService.create(logDO);
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.convert.ApiAccessLogConvert;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.accesslog.ApiAccessLogPageReqVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.accesslog.ApiAccessLogRespVO;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiAccessLogDO;
|
||||
import com.zt.plat.module.databus.service.gateway.ApiAccessLogService;
|
||||
import com.zt.plat.module.databus.service.gateway.ApiDefinitionService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
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;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* Databus API 访问日志控制器。
|
||||
*/
|
||||
@Tag(name = "管理后台 - Databus API 访问日志")
|
||||
@RestController
|
||||
@RequestMapping("/databus/gateway/access-log")
|
||||
@Validated
|
||||
public class ApiAccessLogController {
|
||||
|
||||
@Resource
|
||||
private ApiAccessLogService apiAccessLogService;
|
||||
|
||||
@Resource
|
||||
private ApiDefinitionService apiDefinitionService;
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获取访问日志详情")
|
||||
@Parameter(name = "id", description = "日志编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('databus:gateway:access-log:query')")
|
||||
public CommonResult<ApiAccessLogRespVO> get(@RequestParam("id") Long id) {
|
||||
ApiAccessLogDO logDO = apiAccessLogService.get(id);
|
||||
ApiAccessLogRespVO respVO = ApiAccessLogConvert.INSTANCE.convert(logDO);
|
||||
enrichDefinitionInfo(respVO);
|
||||
return success(respVO);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "分页查询访问日志")
|
||||
@PreAuthorize("@ss.hasPermission('databus:gateway:access-log:query')")
|
||||
public CommonResult<PageResult<ApiAccessLogRespVO>> page(@Valid ApiAccessLogPageReqVO pageReqVO) {
|
||||
PageResult<ApiAccessLogDO> pageResult = apiAccessLogService.getPage(pageReqVO);
|
||||
PageResult<ApiAccessLogRespVO> result = ApiAccessLogConvert.INSTANCE.convertPage(pageResult);
|
||||
enrichDefinitionInfo(result.getList());
|
||||
return success(result);
|
||||
}
|
||||
|
||||
private void enrichDefinitionInfo(List<ApiAccessLogRespVO> list) {
|
||||
// 对分页结果批量补充 API 描述,使用本地缓存减少重复查询
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return;
|
||||
}
|
||||
Map<String, String> cache = new HashMap<>(list.size());
|
||||
list.forEach(item -> {
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
String cacheKey = buildCacheKey(item.getApiCode(), item.getApiVersion());
|
||||
if (!cache.containsKey(cacheKey)) {
|
||||
cache.put(cacheKey, resolveApiDescription(item.getApiCode(), item.getApiVersion()));
|
||||
}
|
||||
item.setApiDescription(cache.get(cacheKey));
|
||||
});
|
||||
}
|
||||
|
||||
private void enrichDefinitionInfo(ApiAccessLogRespVO item) {
|
||||
// 单条数据同样需要补全描述信息
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
item.setApiDescription(resolveApiDescription(item.getApiCode(), item.getApiVersion()));
|
||||
}
|
||||
|
||||
private String resolveApiDescription(String apiCode, String apiVersion) {
|
||||
if (!StringUtils.hasText(apiCode)) {
|
||||
return null;
|
||||
}
|
||||
String normalizedVersion = StringUtils.hasText(apiVersion) ? apiVersion.trim() : apiVersion;
|
||||
// 通过网关定义服务补全 API 描述,提升页面可读性
|
||||
return apiDefinitionService.findByCodeAndVersionIncludingInactive(apiCode, normalizedVersion)
|
||||
.map(aggregate -> aggregate.getDefinition() != null ? aggregate.getDefinition().getDescription() : null)
|
||||
.filter(StringUtils::hasText)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private String buildCacheKey(String apiCode, String apiVersion) {
|
||||
// 组合唯一键,避免重复查询相同的 API 描述
|
||||
return (apiCode == null ? "" : apiCode) + "#" + (apiVersion == null ? "" : apiVersion);
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.convert.ApiClientCredentialConvert;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.credential.ApiClientCredentialPageReqVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.credential.ApiClientCredentialRespVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.credential.ApiClientCredentialSaveReqVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.credential.ApiClientCredentialSimpleRespVO;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiClientCredentialDO;
|
||||
import com.zt.plat.module.databus.service.gateway.ApiAnonymousUserService;
|
||||
import com.zt.plat.module.databus.service.gateway.ApiClientCredentialService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
import static org.springframework.util.CollectionUtils.isEmpty;
|
||||
|
||||
@Tag(name = "管理后台 - API 客户端凭证")
|
||||
@RestController
|
||||
@RequestMapping("/databus/gateway/credential")
|
||||
@RequiredArgsConstructor
|
||||
@Validated
|
||||
public class ApiClientCredentialController {
|
||||
|
||||
private final ApiClientCredentialService credentialService;
|
||||
private final ApiAnonymousUserService anonymousUserService;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "分页查询客户端凭证")
|
||||
public CommonResult<PageResult<ApiClientCredentialRespVO>> page(ApiClientCredentialPageReqVO reqVO) {
|
||||
PageResult<ApiClientCredentialDO> page = credentialService.getPage(reqVO);
|
||||
PageResult<ApiClientCredentialRespVO> respPage = ApiClientCredentialConvert.INSTANCE.convertPage(page);
|
||||
populateAnonymousInfo(respPage.getList());
|
||||
return success(respPage);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "查询凭证详情")
|
||||
public CommonResult<ApiClientCredentialRespVO> get(@RequestParam("id") Long id) {
|
||||
ApiClientCredentialDO credential = credentialService.get(id);
|
||||
ApiClientCredentialRespVO respVO = ApiClientCredentialConvert.INSTANCE.convert(credential);
|
||||
populateAnonymousInfo(List.of(respVO));
|
||||
return success(respVO);
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "新增客户端凭证")
|
||||
public CommonResult<Long> create(@Valid @RequestBody ApiClientCredentialSaveReqVO reqVO) {
|
||||
return success(credentialService.create(reqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新客户端凭证")
|
||||
public CommonResult<Boolean> update(@Valid @RequestBody ApiClientCredentialSaveReqVO reqVO) {
|
||||
credentialService.update(reqVO);
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除客户端凭证")
|
||||
public CommonResult<Boolean> delete(@RequestParam("id") Long id) {
|
||||
credentialService.delete(id);
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
@GetMapping("/list-simple")
|
||||
@Operation(summary = "获取启用的凭证列表(精简)")
|
||||
public CommonResult<List<ApiClientCredentialSimpleRespVO>> listSimple() {
|
||||
List<ApiClientCredentialDO> list = credentialService.listEnabled();
|
||||
return success(ApiClientCredentialConvert.INSTANCE.convertSimpleList(list));
|
||||
}
|
||||
|
||||
private void populateAnonymousInfo(List<ApiClientCredentialRespVO> list) {
|
||||
if (isEmpty(list)) {
|
||||
return;
|
||||
}
|
||||
list.stream()
|
||||
.filter(item -> Boolean.TRUE.equals(item.getAllowAnonymous()) && item.getAnonymousUserId() != null)
|
||||
.forEach(item -> anonymousUserService.find(item.getAnonymousUserId())
|
||||
.ifPresent(details -> item.setAnonymousUserNickname(details.getNickname())));
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway;
|
||||
|
||||
import com.zt.plat.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.convert.ApiDefinitionConvert;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.definition.ApiDefinitionDetailRespVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.definition.ApiDefinitionPageReqVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.definition.ApiDefinitionSaveReqVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.definition.ApiDefinitionSummaryRespVO;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiDefinitionDO;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.core.IntegrationFlowManager;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.domain.ApiDefinitionAggregate;
|
||||
import com.zt.plat.module.databus.service.gateway.ApiDefinitionService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
import static com.zt.plat.module.databus.service.gateway.impl.GatewayServiceErrorCodeConstants.API_DEFINITION_NOT_FOUND;
|
||||
|
||||
@Tag(name = "管理后台 - API 定义管理")
|
||||
@RestController
|
||||
@RequestMapping("/databus/gateway/definition")
|
||||
@RequiredArgsConstructor
|
||||
@Validated
|
||||
public class ApiDefinitionController {
|
||||
|
||||
private final ApiDefinitionService apiDefinitionService;
|
||||
private final IntegrationFlowManager integrationFlowManager;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "分页查询 API 定义")
|
||||
public CommonResult<PageResult<ApiDefinitionSummaryRespVO>> getDefinitionPage(@Valid ApiDefinitionPageReqVO reqVO) {
|
||||
PageResult<ApiDefinitionDO> pageResult = apiDefinitionService.getPage(reqVO);
|
||||
return success(ApiDefinitionConvert.INSTANCE.convertPage(pageResult));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
@Operation(summary = "获取 API 定义详情")
|
||||
public CommonResult<ApiDefinitionDetailRespVO> getDefinition(@PathVariable("id") Long id) {
|
||||
ApiDefinitionAggregate aggregate = apiDefinitionService.findById(id)
|
||||
.orElseThrow(() -> ServiceExceptionUtil.exception(API_DEFINITION_NOT_FOUND));
|
||||
return success(ApiDefinitionConvert.INSTANCE.convert(aggregate));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@Operation(summary = "创建 API 定义")
|
||||
public CommonResult<Long> createDefinition(@Valid @RequestBody ApiDefinitionSaveReqVO reqVO) {
|
||||
Long id = apiDefinitionService.create(reqVO);
|
||||
integrationFlowManager.refresh(reqVO.getApiCode(), reqVO.getVersion());
|
||||
return success(id);
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
@Operation(summary = "更新 API 定义")
|
||||
public CommonResult<Boolean> updateDefinition(@Valid @RequestBody ApiDefinitionSaveReqVO reqVO) {
|
||||
ApiDefinitionAggregate before = apiDefinitionService.findById(reqVO.getId())
|
||||
.orElseThrow(() -> ServiceExceptionUtil.exception(API_DEFINITION_NOT_FOUND));
|
||||
apiDefinitionService.update(reqVO);
|
||||
integrationFlowManager.refresh(before.getDefinition().getApiCode(), before.getDefinition().getVersion());
|
||||
integrationFlowManager.refresh(reqVO.getApiCode(), reqVO.getVersion());
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(summary = "删除 API 定义")
|
||||
public CommonResult<Boolean> deleteDefinition(@PathVariable("id") Long id) {
|
||||
ApiDefinitionAggregate aggregate = apiDefinitionService.findById(id)
|
||||
.orElseThrow(() -> ServiceExceptionUtil.exception(API_DEFINITION_NOT_FOUND));
|
||||
apiDefinitionService.delete(id);
|
||||
integrationFlowManager.refresh(aggregate.getDefinition().getApiCode(), aggregate.getDefinition().getVersion());
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.convert.ApiDefinitionConvert;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.ApiGatewayInvokeReqVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.definition.ApiDefinitionDetailRespVO;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.core.ApiGatewayExecutionService;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.core.IntegrationFlowManager;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.model.ApiGatewayResponse;
|
||||
import com.zt.plat.module.databus.service.gateway.ApiDefinitionService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - API 门户")
|
||||
@RestController
|
||||
@RequestMapping("/databus/gateway")
|
||||
@RequiredArgsConstructor
|
||||
public class ApiGatewayController {
|
||||
|
||||
private final ApiGatewayExecutionService executionService;
|
||||
private final ApiDefinitionService apiDefinitionService;
|
||||
private final IntegrationFlowManager integrationFlowManager;
|
||||
|
||||
@PostMapping(value = "/invoke", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "测试调用 API 编排")
|
||||
public ResponseEntity<ApiGatewayResponse> invoke(@RequestBody ApiGatewayInvokeReqVO reqVO) {
|
||||
return executionService.invokeForDebug(reqVO);
|
||||
}
|
||||
|
||||
@GetMapping("/definitions")
|
||||
@Operation(summary = "获取当前已发布 API 配置")
|
||||
public CommonResult<List<ApiDefinitionDetailRespVO>> listDefinitions() {
|
||||
List<ApiDefinitionDetailRespVO> definitions = apiDefinitionService.loadActiveDefinitions().stream()
|
||||
.map(ApiDefinitionConvert.INSTANCE::convert)
|
||||
.collect(Collectors.toList());
|
||||
return success(definitions);
|
||||
}
|
||||
|
||||
@PostMapping("/cache/refresh")
|
||||
@Operation(summary = "刷新 API 缓存")
|
||||
public CommonResult<Boolean> refreshCache() {
|
||||
apiDefinitionService.refreshAllCache();
|
||||
integrationFlowManager.refreshAll();
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway;
|
||||
|
||||
import com.zt.plat.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.convert.ApiPolicyRateLimitConvert;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.policy.ApiPolicyPageReqVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.policy.ApiPolicyRespVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.policy.ApiPolicySaveReqVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.policy.ApiPolicySimpleRespVO;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiPolicyRateLimitDO;
|
||||
import com.zt.plat.module.databus.service.gateway.ApiPolicyRateLimitService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
import static com.zt.plat.module.databus.service.gateway.impl.GatewayServiceErrorCodeConstants.API_POLICY_NOT_FOUND;
|
||||
|
||||
@Tag(name = "管理后台 - 网关限流策略")
|
||||
@RestController
|
||||
@RequestMapping("/databus/gateway/policy/rate-limit")
|
||||
@RequiredArgsConstructor
|
||||
@Validated
|
||||
public class ApiPolicyRateLimitController {
|
||||
|
||||
private final ApiPolicyRateLimitService rateLimitService;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "分页查询限流策略")
|
||||
public CommonResult<PageResult<ApiPolicyRespVO>> getRateLimitPolicyPage(@Valid ApiPolicyPageReqVO reqVO) {
|
||||
PageResult<ApiPolicyRateLimitDO> pageResult = rateLimitService.getPage(reqVO);
|
||||
return success(ApiPolicyRateLimitConvert.INSTANCE.convertPage(pageResult));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
@Operation(summary = "查询限流策略详情")
|
||||
public CommonResult<ApiPolicyRespVO> getRateLimitPolicy(@PathVariable("id") Long id) {
|
||||
ApiPolicyRateLimitDO policy = rateLimitService.get(id)
|
||||
.orElseThrow(() -> ServiceExceptionUtil.exception(API_POLICY_NOT_FOUND));
|
||||
return success(ApiPolicyRateLimitConvert.INSTANCE.convert(policy));
|
||||
}
|
||||
|
||||
@GetMapping("/simple-list")
|
||||
@Operation(summary = "获取限流策略精简列表")
|
||||
public CommonResult<List<ApiPolicySimpleRespVO>> getRateLimitPolicySimpleList() {
|
||||
List<ApiPolicyRateLimitDO> list = rateLimitService.getSimpleList();
|
||||
return success(ApiPolicyRateLimitConvert.INSTANCE.convertSimpleList(list));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@Operation(summary = "创建限流策略")
|
||||
public CommonResult<Long> createRateLimitPolicy(@Valid @RequestBody ApiPolicySaveReqVO reqVO) {
|
||||
Long id = rateLimitService.create(reqVO);
|
||||
return success(id);
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
@Operation(summary = "更新限流策略")
|
||||
public CommonResult<Boolean> updateRateLimitPolicy(@Valid @RequestBody ApiPolicySaveReqVO reqVO) {
|
||||
rateLimitService.update(reqVO);
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(summary = "删除限流策略")
|
||||
public CommonResult<Boolean> deleteRateLimitPolicy(@PathVariable("id") Long id) {
|
||||
rateLimitService.delete(id);
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.convert.ApiVersionConvert;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.definition.ApiDefinitionSaveReqVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.version.ApiVersionCompareRespVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.version.ApiVersionDetailRespVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.version.ApiVersionPageReqVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.version.ApiVersionRespVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.version.ApiVersionRollbackReqVO;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiVersionDO;
|
||||
import com.zt.plat.module.databus.service.gateway.ApiVersionService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* API 版本历史控制器。
|
||||
*/
|
||||
@Tag(name = "管理后台 - API 版本历史")
|
||||
@RestController
|
||||
@RequestMapping("/databus/gateway/version")
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class ApiVersionController {
|
||||
|
||||
@Resource
|
||||
private ApiVersionService apiVersionService;
|
||||
|
||||
@Resource
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获取 API 版本详情")
|
||||
@Parameter(name = "id", description = "版本编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('databus:gateway:version:query')")
|
||||
public CommonResult<ApiVersionDetailRespVO> getVersion(@RequestParam("id") Long id) {
|
||||
ApiVersionDO versionDO = apiVersionService.getVersion(id);
|
||||
ApiVersionDetailRespVO respVO = ApiVersionConvert.INSTANCE.convertDetail(versionDO);
|
||||
|
||||
// 反序列化快照数据
|
||||
if (versionDO.getSnapshotData() != null) {
|
||||
try {
|
||||
ApiDefinitionSaveReqVO snapshot = objectMapper.readValue(versionDO.getSnapshotData(), ApiDefinitionSaveReqVO.class);
|
||||
respVO.setSnapshotData(snapshot);
|
||||
} catch (JsonProcessingException ex) {
|
||||
log.error("反序列化版本快照失败, versionId={}", id, ex);
|
||||
}
|
||||
}
|
||||
|
||||
return success(respVO);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "分页查询 API 版本列表")
|
||||
@PreAuthorize("@ss.hasPermission('databus:gateway:version:query')")
|
||||
public CommonResult<PageResult<ApiVersionRespVO>> getVersionPage(@Valid ApiVersionPageReqVO pageReqVO) {
|
||||
PageResult<ApiVersionDO> pageResult = apiVersionService.getVersionPage(pageReqVO);
|
||||
return success(ApiVersionConvert.INSTANCE.convertPage(pageResult));
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "查询指定 API 的全部版本")
|
||||
@PreAuthorize("@ss.hasPermission('databus:gateway:version:query')")
|
||||
public CommonResult<java.util.List<ApiVersionRespVO>> getVersionList(@RequestParam("apiId") Long apiId) {
|
||||
return success(ApiVersionConvert.INSTANCE.convertList(apiVersionService.getVersionListByApiId(apiId)));
|
||||
}
|
||||
|
||||
@PutMapping("/rollback")
|
||||
@Operation(summary = "回滚到指定版本")
|
||||
@PreAuthorize("@ss.hasPermission('databus:gateway:version:rollback')")
|
||||
public CommonResult<Boolean> rollbackToVersion(@Valid @RequestBody ApiVersionRollbackReqVO reqVO) {
|
||||
apiVersionService.rollbackToVersion(reqVO.getId(), reqVO.getRemark());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/compare")
|
||||
@Operation(summary = "对比两个版本差异")
|
||||
@PreAuthorize("@ss.hasPermission('databus:gateway:version:query')")
|
||||
public CommonResult<ApiVersionCompareRespVO> compareVersions(
|
||||
@RequestParam("sourceId") Long sourceId,
|
||||
@RequestParam("targetId") Long targetId) {
|
||||
return success(apiVersionService.compareVersions(sourceId, targetId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.convert;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.accesslog.ApiAccessLogRespVO;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiAccessLogDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface ApiAccessLogConvert {
|
||||
|
||||
ApiAccessLogConvert INSTANCE = Mappers.getMapper(ApiAccessLogConvert.class);
|
||||
|
||||
@Mapping(target = "statusDesc", expression = "java(statusDesc(bean.getStatus()))")
|
||||
@Mapping(target = "responseStatusText", expression = "java(resolveHttpStatusText(bean.getResponseStatus()))")
|
||||
ApiAccessLogRespVO convert(ApiAccessLogDO bean);
|
||||
|
||||
List<ApiAccessLogRespVO> convertList(List<ApiAccessLogDO> list);
|
||||
|
||||
default PageResult<ApiAccessLogRespVO> convertPage(PageResult<ApiAccessLogDO> page) {
|
||||
if (page == null) {
|
||||
return PageResult.empty();
|
||||
}
|
||||
PageResult<ApiAccessLogRespVO> result = new PageResult<>();
|
||||
result.setList(convertList(page.getList()));
|
||||
result.setTotal(page.getTotal());
|
||||
return result;
|
||||
}
|
||||
|
||||
default String statusDesc(Integer status) {
|
||||
// 将数字状态码转换为中文描述,方便前端直接展示
|
||||
if (status == null) {
|
||||
return "未知";
|
||||
}
|
||||
return switch (status) {
|
||||
case 0 -> "成功";
|
||||
case 1 -> "客户端错误";
|
||||
case 2 -> "服务端错误";
|
||||
default -> "未知";
|
||||
};
|
||||
}
|
||||
|
||||
default String resolveHttpStatusText(Integer status) {
|
||||
// 统一使用 Spring 的 HttpStatus 解析出标准文案
|
||||
if (status == null) {
|
||||
return null;
|
||||
}
|
||||
HttpStatus resolved = HttpStatus.resolve(status);
|
||||
return resolved != null ? resolved.getReasonPhrase() : null;
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.convert;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.credential.ApiClientCredentialRespVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.credential.ApiClientCredentialSimpleRespVO;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiClientCredentialDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mapper
|
||||
public interface ApiClientCredentialConvert {
|
||||
|
||||
ApiClientCredentialConvert INSTANCE = Mappers.getMapper(ApiClientCredentialConvert.class);
|
||||
|
||||
ApiClientCredentialRespVO convert(ApiClientCredentialDO bean);
|
||||
|
||||
List<ApiClientCredentialRespVO> convertList(List<ApiClientCredentialDO> list);
|
||||
|
||||
default PageResult<ApiClientCredentialRespVO> convertPage(PageResult<ApiClientCredentialDO> page) {
|
||||
if (page == null) {
|
||||
return PageResult.empty();
|
||||
}
|
||||
PageResult<ApiClientCredentialRespVO> result = new PageResult<>();
|
||||
result.setList(convertList(page.getList()));
|
||||
result.setTotal(page.getTotal());
|
||||
return result;
|
||||
}
|
||||
|
||||
default List<ApiClientCredentialSimpleRespVO> convertSimpleList(List<ApiClientCredentialDO> list) {
|
||||
return list == null ? List.of() : list.stream().map(item -> {
|
||||
ApiClientCredentialSimpleRespVO vo = new ApiClientCredentialSimpleRespVO();
|
||||
vo.setId(item.getId());
|
||||
vo.setAppId(item.getAppId());
|
||||
vo.setAppName(item.getAppName());
|
||||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.convert;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.definition.*;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiDefinitionDO;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiStepDO;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiTransformDO;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.domain.ApiCredentialBinding;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.domain.ApiDefinitionAggregate;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.domain.ApiFlowPublication;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.domain.ApiStepDefinition;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.domain.ApiTransformDefinition;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mapper
|
||||
public interface ApiDefinitionConvert {
|
||||
|
||||
ApiDefinitionConvert INSTANCE = Mappers.getMapper(ApiDefinitionConvert.class);
|
||||
|
||||
ApiDefinitionSummaryRespVO convert(ApiDefinitionDO bean);
|
||||
|
||||
List<ApiDefinitionSummaryRespVO> convertList(List<ApiDefinitionDO> list);
|
||||
|
||||
default PageResult<ApiDefinitionSummaryRespVO> convertPage(PageResult<ApiDefinitionDO> page) {
|
||||
if (page == null) {
|
||||
return PageResult.empty();
|
||||
}
|
||||
PageResult<ApiDefinitionSummaryRespVO> result = new PageResult<>();
|
||||
List<ApiDefinitionSummaryRespVO> list = convertList(page.getList());
|
||||
result.setList(list == null ? new ArrayList<>() : list);
|
||||
result.setTotal(page.getTotal());
|
||||
return result;
|
||||
}
|
||||
|
||||
default ApiDefinitionDetailRespVO convert(ApiDefinitionAggregate aggregate) {
|
||||
if (aggregate == null) {
|
||||
return null;
|
||||
}
|
||||
ApiDefinitionDetailRespVO detail = BeanUtils.toBean(aggregate.getDefinition(), ApiDefinitionDetailRespVO.class);
|
||||
detail.setApiLevelTransforms(convertTransforms(aggregate.getDefinition().getId(), aggregate.getApiLevelTransforms().values()));
|
||||
detail.setSteps(convertSteps(aggregate.getSteps()));
|
||||
detail.setPublication(convert(aggregate.getPublication()));
|
||||
detail.setCredentialBindings(convertCredentialBindings(aggregate.getCredentialBindings()));
|
||||
detail.setCredentialIds(detail.getCredentialBindings().stream()
|
||||
.map(ApiCredentialBindingRespVO::getCredentialId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList()));
|
||||
return detail;
|
||||
}
|
||||
|
||||
default List<ApiDefinitionStepRespVO> convertSteps(List<ApiStepDefinition> steps) {
|
||||
if (CollUtil.isEmpty(steps)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return steps.stream()
|
||||
.sorted(Comparator.comparing(step -> step.getStep().getStepOrder() == null ? Integer.MAX_VALUE : step.getStep().getStepOrder()))
|
||||
.map(step -> {
|
||||
ApiDefinitionStepRespVO resp = BeanUtils.toBean(step.getStep(), ApiDefinitionStepRespVO.class);
|
||||
resp.setTransforms(convertStepTransforms(step.getStep().getApiId(), step.getStep().getId(), step.getTransforms()));
|
||||
return resp;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
default List<ApiDefinitionTransformRespVO> convertTransforms(Long apiId, Collection<ApiTransformDefinition> transforms) {
|
||||
if (CollUtil.isEmpty(transforms)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return transforms.stream()
|
||||
.sorted(Comparator.comparing(ApiTransformDefinition::getPhase, Comparator.nullsLast(String::compareTo)))
|
||||
.map(transform -> {
|
||||
ApiDefinitionTransformRespVO resp = BeanUtils.toBean(transform, ApiDefinitionTransformRespVO.class);
|
||||
resp.setApiId(apiId);
|
||||
resp.setStepId(null);
|
||||
return resp;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
default List<ApiDefinitionTransformRespVO> convertStepTransforms(Long apiId, Long stepId, List<ApiTransformDefinition> transforms) {
|
||||
if (CollUtil.isEmpty(transforms)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return transforms.stream()
|
||||
.sorted(Comparator.comparing(ApiTransformDefinition::getPhase, Comparator.nullsLast(String::compareTo)))
|
||||
.map(transform -> {
|
||||
ApiDefinitionTransformRespVO resp = BeanUtils.toBean(transform, ApiDefinitionTransformRespVO.class);
|
||||
resp.setApiId(apiId);
|
||||
resp.setStepId(stepId);
|
||||
return resp;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
default ApiDefinitionPublicationRespVO convert(ApiFlowPublication publication) {
|
||||
return publication == null ? null : BeanUtils.toBean(publication, ApiDefinitionPublicationRespVO.class);
|
||||
}
|
||||
|
||||
default List<ApiCredentialBindingRespVO> convertCredentialBindings(List<ApiCredentialBinding> bindings) {
|
||||
if (CollUtil.isEmpty(bindings)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return bindings.stream()
|
||||
.map(binding -> BeanUtils.toBean(binding, ApiCredentialBindingRespVO.class))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换步骤列表(DO -> SaveReqVO)
|
||||
*/
|
||||
default List<ApiDefinitionStepSaveReqVO> convertStepList(List<ApiStepDO> steps) {
|
||||
if (CollUtil.isEmpty(steps)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return steps.stream()
|
||||
.sorted(Comparator.comparing(step -> step.getStepOrder() == null ? Integer.MAX_VALUE : step.getStepOrder()))
|
||||
.map(step -> BeanUtils.toBean(step, ApiDefinitionStepSaveReqVO.class))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换变换列表(DO -> SaveReqVO)
|
||||
*/
|
||||
default List<ApiDefinitionTransformSaveReqVO> convertTransformList(List<ApiTransformDO> transforms) {
|
||||
if (CollUtil.isEmpty(transforms)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return transforms.stream()
|
||||
.map(transform -> BeanUtils.toBean(transform, ApiDefinitionTransformSaveReqVO.class))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.convert;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.policy.ApiPolicyRespVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.policy.ApiPolicySimpleRespVO;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiPolicyRateLimitDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface ApiPolicyRateLimitConvert {
|
||||
|
||||
ApiPolicyRateLimitConvert INSTANCE = Mappers.getMapper(ApiPolicyRateLimitConvert.class);
|
||||
|
||||
ApiPolicyRespVO convert(ApiPolicyRateLimitDO bean);
|
||||
|
||||
List<ApiPolicyRespVO> convertList(List<ApiPolicyRateLimitDO> list);
|
||||
|
||||
PageResult<ApiPolicyRespVO> convertPage(PageResult<ApiPolicyRateLimitDO> page);
|
||||
|
||||
List<ApiPolicySimpleRespVO> convertSimpleList(List<ApiPolicyRateLimitDO> list);
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.convert;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.version.ApiVersionDetailRespVO;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.version.ApiVersionRespVO;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiVersionDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* API 版本历史 Convert。
|
||||
*/
|
||||
@Mapper
|
||||
public interface ApiVersionConvert {
|
||||
|
||||
ApiVersionConvert INSTANCE = Mappers.getMapper(ApiVersionConvert.class);
|
||||
|
||||
ApiVersionRespVO convert(ApiVersionDO bean);
|
||||
|
||||
PageResult<ApiVersionRespVO> convertPage(PageResult<ApiVersionDO> page);
|
||||
|
||||
List<ApiVersionRespVO> convertList(List<ApiVersionDO> list);
|
||||
|
||||
@Mapping(target = "snapshotData", ignore = true)
|
||||
ApiVersionDetailRespVO convertDetail(ApiVersionDO bean);
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class ApiGatewayInvokeReqVO {
|
||||
|
||||
@Schema(description = "API 编码", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String apiCode;
|
||||
|
||||
@Schema(description = "API 版本", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String version;
|
||||
|
||||
@Schema(description = "请求头,可选")
|
||||
private Map<String, String> headers = new HashMap<>();
|
||||
|
||||
@Schema(description = "请求参数,可选")
|
||||
private Map<String, Object> queryParams = new HashMap<>();
|
||||
|
||||
@Schema(description = "请求体")
|
||||
private Object payload;
|
||||
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.accesslog;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.zt.plat.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
/**
|
||||
* Databus API 访问日志分页查询 VO。
|
||||
*/
|
||||
@Schema(description = "管理后台 - Databus API 访问日志分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ApiAccessLogPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "追踪 ID", example = "c8a3d52f-42c8-4b5d-9e26-8c2cc89f6bb5")
|
||||
private String traceId;
|
||||
|
||||
@Schema(description = "API 编码", example = "user.query")
|
||||
private String apiCode;
|
||||
|
||||
@Schema(description = "API 版本", example = "v1")
|
||||
private String apiVersion;
|
||||
|
||||
@Schema(description = "HTTP 方法", example = "POST")
|
||||
private String requestMethod;
|
||||
|
||||
@Schema(description = "响应 HTTP 状态", example = "200")
|
||||
private Integer responseStatus;
|
||||
|
||||
@Schema(description = "访问状态", example = "0")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "客户端 IP", example = "192.168.0.10")
|
||||
private String clientIp;
|
||||
|
||||
@Schema(description = "租户编号", example = "1")
|
||||
private Long tenantId;
|
||||
|
||||
@Schema(description = "请求路径", example = "/gateway/api/user/query")
|
||||
private String requestPath;
|
||||
|
||||
@Schema(description = "应用标识", example = "app-portal-01")
|
||||
private String credentialAppId;
|
||||
|
||||
@Schema(description = "凭证主键", example = "10086")
|
||||
private Long credentialId;
|
||||
|
||||
@Schema(description = "请求时间区间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] requestTime;
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.accesslog;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* Databus API 访问日志 Response VO。
|
||||
*/
|
||||
@Schema(description = "管理后台 - Databus API 访问日志 Response VO")
|
||||
@Data
|
||||
public class ApiAccessLogRespVO {
|
||||
|
||||
@Schema(description = "日志编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "追踪 ID", example = "c8a3d52f-42c8-4b5d-9e26-8c2cc89f6bb5")
|
||||
private String traceId;
|
||||
|
||||
@Schema(description = "API 编码", example = "user.query")
|
||||
private String apiCode;
|
||||
|
||||
@Schema(description = "API 描述", example = "用户查询服务")
|
||||
private String apiDescription;
|
||||
|
||||
@Schema(description = "API 版本", example = "v1")
|
||||
private String apiVersion;
|
||||
|
||||
@Schema(description = "HTTP 方法", example = "POST")
|
||||
private String requestMethod;
|
||||
|
||||
@Schema(description = "请求路径", example = "/gateway/api/user/query")
|
||||
private String requestPath;
|
||||
|
||||
@Schema(description = "应用标识", example = "app-portal-01")
|
||||
private String credentialAppId;
|
||||
|
||||
@Schema(description = "凭证主键", example = "10086")
|
||||
private Long credentialId;
|
||||
|
||||
@Schema(description = "查询参数(JSON)")
|
||||
private String requestQuery;
|
||||
|
||||
@Schema(description = "请求头(JSON)")
|
||||
private String requestHeaders;
|
||||
|
||||
@Schema(description = "请求体(JSON)")
|
||||
private String requestBody;
|
||||
|
||||
@Schema(description = "响应 HTTP 状态", example = "200")
|
||||
private Integer responseStatus;
|
||||
|
||||
@Schema(description = "响应 HTTP 状态说明", example = "OK")
|
||||
private String responseStatusText;
|
||||
|
||||
@Schema(description = "响应提示", example = "OK")
|
||||
private String responseMessage;
|
||||
|
||||
@Schema(description = "响应体(JSON)")
|
||||
private String responseBody;
|
||||
|
||||
@Schema(description = "访问状态", example = "0")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "访问状态展示文案", example = "成功")
|
||||
private String statusDesc;
|
||||
|
||||
@Schema(description = "错误码", example = "DAT-001")
|
||||
private String errorCode;
|
||||
|
||||
@Schema(description = "错误信息", example = "API 调用失败")
|
||||
private String errorMessage;
|
||||
|
||||
@Schema(description = "异常堆栈")
|
||||
private String exceptionStack;
|
||||
|
||||
@Schema(description = "客户端 IP", example = "192.168.0.10")
|
||||
private String clientIp;
|
||||
|
||||
@Schema(description = "User-Agent")
|
||||
private String userAgent;
|
||||
|
||||
@Schema(description = "租户编号", example = "1")
|
||||
private Long tenantId;
|
||||
|
||||
@Schema(description = "请求耗时(毫秒)", example = "123")
|
||||
private Long duration;
|
||||
|
||||
@Schema(description = "请求时间")
|
||||
private LocalDateTime requestTime;
|
||||
|
||||
@Schema(description = "响应时间")
|
||||
private LocalDateTime responseTime;
|
||||
|
||||
@Schema(description = "执行步骤(JSON)")
|
||||
private String stepResults;
|
||||
|
||||
@Schema(description = "额外调试信息(JSON)")
|
||||
private String extra;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.credential;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Schema(description = "管理后台 - API 客户端凭证分页查询 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApiClientCredentialPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "关键字,匹配 appId 或名称", example = "databus-app")
|
||||
private String keyword;
|
||||
|
||||
@Schema(description = "是否启用")
|
||||
private Boolean enabled;
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.credential;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - API 客户端凭证 Response VO")
|
||||
@Data
|
||||
public class ApiClientCredentialRespVO {
|
||||
|
||||
@Schema(description = "记录编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "应用标识", example = "databus-app")
|
||||
private String appId;
|
||||
|
||||
@Schema(description = "应用名称", example = "数据总线默认应用")
|
||||
private String appName;
|
||||
|
||||
@Schema(description = "加密密钥", example = "MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY=")
|
||||
private String encryptionKey;
|
||||
|
||||
@Schema(description = "加密算法", example = "AES")
|
||||
private String encryptionType;
|
||||
|
||||
@Schema(description = "签名算法", example = "MD5")
|
||||
private String signatureType;
|
||||
|
||||
@Schema(description = "是否启用", example = "true")
|
||||
private Boolean enabled;
|
||||
|
||||
@Schema(description = "备注", example = "默认应用凭证")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "允许匿名访问", example = "false")
|
||||
private Boolean allowAnonymous;
|
||||
|
||||
@Schema(description = "匿名访问固定用户 ID", example = "1024")
|
||||
private Long anonymousUserId;
|
||||
|
||||
@Schema(description = "匿名访问固定用户昵称", example = "张三")
|
||||
private String anonymousUserNickname;
|
||||
|
||||
@Schema(description = "是否启用加密", example = "true")
|
||||
private Boolean enableEncryption;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "最后更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.credential;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - API 客户端凭证保存 Request VO")
|
||||
@Data
|
||||
public class ApiClientCredentialSaveReqVO {
|
||||
|
||||
@Schema(description = "记录编号,仅更新时必填", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "应用标识", example = "databus-app")
|
||||
@NotBlank(message = "应用标识不能为空")
|
||||
private String appId;
|
||||
|
||||
@Schema(description = "应用名称", example = "数据总线默认应用")
|
||||
private String appName;
|
||||
|
||||
@Schema(description = "加密密钥", example = "MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY=")
|
||||
@NotBlank(message = "加密密钥不能为空")
|
||||
private String encryptionKey;
|
||||
|
||||
@Schema(description = "加密算法", example = "AES")
|
||||
@NotBlank(message = "加密算法不能为空")
|
||||
private String encryptionType;
|
||||
|
||||
@Schema(description = "签名算法", example = "MD5")
|
||||
@NotBlank(message = "签名算法不能为空")
|
||||
private String signatureType;
|
||||
|
||||
@Schema(description = "是否启用", example = "true")
|
||||
@NotNull(message = "启用状态不能为空")
|
||||
private Boolean enabled;
|
||||
|
||||
@Schema(description = "备注", example = "默认应用凭证")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "允许匿名访问", example = "false")
|
||||
@NotNull(message = "匿名访问标识不能为空")
|
||||
private Boolean allowAnonymous;
|
||||
|
||||
@Schema(description = "匿名访问固定用户 ID", example = "1024")
|
||||
private Long anonymousUserId;
|
||||
|
||||
@Schema(description = "是否启用加密", example = "true")
|
||||
@NotNull(message = "启用加密标识不能为空")
|
||||
private Boolean enableEncryption;
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.credential;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - API 客户端凭证精简 Response VO")
|
||||
@Data
|
||||
public class ApiClientCredentialSimpleRespVO {
|
||||
|
||||
@Schema(description = "记录编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "应用标识", example = "databus-app")
|
||||
private String appId;
|
||||
|
||||
@Schema(description = "应用名称", example = "数据总线默认应用")
|
||||
private String appName;
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.definition;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ApiCredentialBindingRespVO {
|
||||
|
||||
@Schema(description = "凭证主键", example = "10086")
|
||||
private Long credentialId;
|
||||
|
||||
@Schema(description = "应用标识", example = "app-portal-01")
|
||||
private String appId;
|
||||
|
||||
@Schema(description = "应用名称")
|
||||
private String appName;
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.definition;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Schema(description = "管理后台 - API 定义详情 Response VO")
|
||||
public class ApiDefinitionDetailRespVO {
|
||||
|
||||
@Schema(description = "主键", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "租户标识", example = "1")
|
||||
private String tenantId;
|
||||
|
||||
@Schema(description = "API 编码", example = "order.create")
|
||||
private String apiCode;
|
||||
|
||||
@Schema(description = "API 版本", example = "v1")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "HTTP 方法", example = "POST")
|
||||
private String httpMethod;
|
||||
|
||||
@Schema(description = "状态", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "限流策略编号")
|
||||
private Long rateLimitId;
|
||||
|
||||
@Schema(description = "响应模板(JSON)")
|
||||
private String responseTemplate;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creator;
|
||||
|
||||
@Schema(description = "更新人")
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "API 级别变换列表")
|
||||
private List<ApiDefinitionTransformRespVO> apiLevelTransforms = new ArrayList<>();
|
||||
|
||||
@Schema(description = "授权凭证 ID 列表")
|
||||
private List<Long> credentialIds = new ArrayList<>();
|
||||
|
||||
@Schema(description = "授权凭证详情列表")
|
||||
private List<ApiCredentialBindingRespVO> credentialBindings = new ArrayList<>();
|
||||
|
||||
@Schema(description = "步骤列表")
|
||||
private List<ApiDefinitionStepRespVO> steps = new ArrayList<>();
|
||||
|
||||
@Schema(description = "发布信息")
|
||||
private ApiDefinitionPublicationRespVO publication;
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.definition;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Schema(description = "管理后台 - API 定义分页查询 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApiDefinitionPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "关键字,匹配编码或描述", example = "order")
|
||||
private String keyword;
|
||||
|
||||
@Schema(description = "API 状态", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "HTTP 方法", example = "POST")
|
||||
private String httpMethod;
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.definition;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "管理后台 - API 发布信息 Response VO")
|
||||
public class ApiDefinitionPublicationRespVO {
|
||||
|
||||
@Schema(description = "发布记录主键", example = "4001")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "发布标签", example = "release-20231001")
|
||||
private String releaseTag;
|
||||
|
||||
@Schema(description = "快照内容(JSON)")
|
||||
private String snapshot;
|
||||
|
||||
@Schema(description = "状态", example = "RELEASED")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "是否当前生效")
|
||||
private Boolean active;
|
||||
|
||||
@Schema(description = "描述")
|
||||
private String description;
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.definition;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Schema(description = "管理后台 - API 定义保存 Request VO")
|
||||
public class ApiDefinitionSaveReqVO {
|
||||
|
||||
@Schema(description = "主键", example = "1001")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "API 编码", example = "order.create")
|
||||
@NotBlank(message = "API 编码不能为空")
|
||||
private String apiCode;
|
||||
|
||||
@Schema(description = "API 版本", example = "v1")
|
||||
@NotBlank(message = "API 版本不能为空")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "HTTP 方法", example = "POST")
|
||||
@NotBlank(message = "HTTP 方法不能为空")
|
||||
private String httpMethod;
|
||||
|
||||
@Schema(description = "API 状态", example = "1")
|
||||
@NotNull(message = "API 状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "限流策略编号")
|
||||
private Long rateLimitId;
|
||||
|
||||
@Schema(description = "响应模板(JSON)")
|
||||
private String responseTemplate;
|
||||
|
||||
@Schema(description = "API 级别变换列表")
|
||||
@Valid
|
||||
private List<ApiDefinitionTransformSaveReqVO> apiLevelTransforms = new ArrayList<>();
|
||||
|
||||
@Schema(description = "授权的客户端凭证 ID 列表")
|
||||
private List<Long> credentialIds = new ArrayList<>();
|
||||
|
||||
@Schema(description = "步骤列表")
|
||||
@NotEmpty(message = "编排步骤不能为空")
|
||||
@Valid
|
||||
private List<ApiDefinitionStepSaveReqVO> steps = new ArrayList<>();
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.definition;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Schema(description = "管理后台 - API 编排步骤详情 Response VO")
|
||||
public class ApiDefinitionStepRespVO {
|
||||
|
||||
@Schema(description = "步骤主键", example = "21001")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "所属 API 主键", example = "1024")
|
||||
private Long apiId;
|
||||
|
||||
@Schema(description = "步骤序号", example = "1")
|
||||
private Integer stepOrder;
|
||||
|
||||
@Schema(description = "并行分组")
|
||||
private String parallelGroup;
|
||||
|
||||
@Schema(description = "步骤类型", example = "HTTP")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "目标端点")
|
||||
private String targetEndpoint;
|
||||
|
||||
@Schema(description = "请求映射表达式(JSON)")
|
||||
private String requestMappingExpr;
|
||||
|
||||
@Schema(description = "响应映射表达式(JSON)")
|
||||
private String responseMappingExpr;
|
||||
|
||||
@Schema(description = "超时时间(毫秒)")
|
||||
private Long timeout;
|
||||
|
||||
@Schema(description = "降级策略(JSON)")
|
||||
private String fallbackStrategy;
|
||||
|
||||
@Schema(description = "条件表达式")
|
||||
private String conditionExpr;
|
||||
|
||||
@Schema(description = "是否出错终止")
|
||||
private Boolean stopOnError;
|
||||
|
||||
@Schema(description = "步骤级变换列表")
|
||||
private List<ApiDefinitionTransformRespVO> transforms = new ArrayList<>();
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.definition;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Schema(description = "管理后台 - API 编排步骤保存 Request VO")
|
||||
public class ApiDefinitionStepSaveReqVO {
|
||||
|
||||
@Schema(description = "步骤主键", example = "21001")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "步骤序号", example = "1")
|
||||
@NotNull(message = "步骤序号不能为空")
|
||||
private Integer stepOrder;
|
||||
|
||||
@Schema(description = "并行分组")
|
||||
private String parallelGroup;
|
||||
|
||||
@Schema(description = "步骤类型", example = "HTTP")
|
||||
@NotBlank(message = "步骤类型不能为空")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "目标端点", example = "https://api.demo.com/order")
|
||||
private String targetEndpoint;
|
||||
|
||||
@Schema(description = "请求映射表达式(JSON)")
|
||||
private String requestMappingExpr;
|
||||
|
||||
@Schema(description = "响应映射表达式(JSON)")
|
||||
private String responseMappingExpr;
|
||||
|
||||
@Schema(description = "超时时间(毫秒),缺省 20000(20s)", example = "20000")
|
||||
private Long timeout;
|
||||
|
||||
@Schema(description = "降级策略(JSON)")
|
||||
private String fallbackStrategy;
|
||||
|
||||
@Schema(description = "条件表达式")
|
||||
private String conditionExpr;
|
||||
|
||||
@Schema(description = "是否出错终止")
|
||||
private Boolean stopOnError;
|
||||
|
||||
@Schema(description = "步骤级变换列表")
|
||||
@Valid
|
||||
private List<ApiDefinitionTransformSaveReqVO> transforms = new ArrayList<>();
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.definition;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Schema(description = "管理后台 - API 定义分页列表 Response VO")
|
||||
public class ApiDefinitionSummaryRespVO {
|
||||
|
||||
@Schema(description = "主键", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "API 编码", example = "order.create")
|
||||
private String apiCode;
|
||||
|
||||
@Schema(description = "API 版本", example = "v1")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "HTTP 方法", example = "POST")
|
||||
private String httpMethod;
|
||||
|
||||
@Schema(description = "状态", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creator;
|
||||
|
||||
@Schema(description = "更新人")
|
||||
private String updater;
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.definition;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "管理后台 - API 变换详情 Response VO")
|
||||
public class ApiDefinitionTransformRespVO {
|
||||
|
||||
@Schema(description = "变换主键", example = "31001")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "所属 API 主键", example = "1024")
|
||||
private Long apiId;
|
||||
|
||||
@Schema(description = "所属步骤主键", example = "21001")
|
||||
private Long stepId;
|
||||
|
||||
@Schema(description = "阶段", example = "REQUEST")
|
||||
private String phase;
|
||||
|
||||
@Schema(description = "表达式类型", example = "SPEL")
|
||||
private String expressionType;
|
||||
|
||||
@Schema(description = "表达式内容", example = "#{payload}")
|
||||
private String expression;
|
||||
|
||||
@Schema(description = "描述")
|
||||
private String description;
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.definition;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "管理后台 - API 变换保存 Request VO")
|
||||
public class ApiDefinitionTransformSaveReqVO {
|
||||
|
||||
@Schema(description = "变换主键", example = "31001")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "阶段", example = "REQUEST")
|
||||
@NotBlank(message = "变换阶段不能为空")
|
||||
private String phase;
|
||||
|
||||
@Schema(description = "表达式类型", example = "SPEL")
|
||||
@NotBlank(message = "表达式类型不能为空")
|
||||
private String expressionType;
|
||||
|
||||
@Schema(description = "表达式内容", example = "#{payload}")
|
||||
@NotBlank(message = "表达式内容不能为空")
|
||||
private String expression;
|
||||
|
||||
@Schema(description = "描述")
|
||||
private String description;
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.policy;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Base VO for policy definitions shared by request/response objects.
|
||||
*/
|
||||
@Data
|
||||
public class ApiPolicyBaseVO {
|
||||
|
||||
@Schema(description = "策略名称", example = "JWT")
|
||||
@NotBlank(message = "策略名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "策略类型", example = "JWT")
|
||||
@NotBlank(message = "策略类型不能为空")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "策略配置(JSON)", example = "{\"issuer\":\"iam\"}")
|
||||
private String config;
|
||||
|
||||
@Schema(description = "策略描述", example = "JWT 认证策略")
|
||||
private String description;
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.policy;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* Policy search conditions with pagination.
|
||||
*/
|
||||
@Schema(description = "管理后台 - 策略分页查询 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApiPolicyPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "关键字(名称/描述)", example = "JWT")
|
||||
private String keyword;
|
||||
|
||||
@Schema(description = "策略类型", example = "JWT")
|
||||
private String type;
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.policy;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* Policy detail response VO.
|
||||
*/
|
||||
@Schema(description = "管理后台 - 策略详情 Response VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApiPolicyRespVO extends ApiPolicyBaseVO {
|
||||
|
||||
@Schema(description = "策略编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "创建人", example = "admin")
|
||||
private String creator;
|
||||
|
||||
@Schema(description = "修改人", example = "admin")
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "最后更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.policy;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* Policy create/update request VO.
|
||||
*/
|
||||
@Schema(description = "管理后台 - 策略保存 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApiPolicySaveReqVO extends ApiPolicyBaseVO {
|
||||
|
||||
@Schema(description = "策略编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.policy;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Policy simple response VO used by dropdowns.
|
||||
*/
|
||||
@Schema(description = "管理后台 - 策略精简 Response VO")
|
||||
@Data
|
||||
public class ApiPolicySimpleRespVO {
|
||||
|
||||
@Schema(description = "策略编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "策略名称", example = "JWT")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "策略类型", example = "JWT")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "策略描述")
|
||||
private String description;
|
||||
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.version;
|
||||
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.definition.ApiDefinitionSaveReqVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* API 版本对比 Response VO。
|
||||
*/
|
||||
@Schema(description = "管理后台 - API 版本对比 Response VO")
|
||||
@Data
|
||||
public class ApiVersionCompareRespVO {
|
||||
|
||||
@Schema(description = "源版本 ID", example = "1001")
|
||||
private Long sourceVersionId;
|
||||
|
||||
@Schema(description = "源版本号", example = "2")
|
||||
private Integer sourceVersionNumber;
|
||||
|
||||
@Schema(description = "源版本描述")
|
||||
private String sourceDescription;
|
||||
|
||||
@Schema(description = "源版本操作人")
|
||||
private String sourceOperator;
|
||||
|
||||
@Schema(description = "源版本创建时间")
|
||||
private LocalDateTime sourceCreateTime;
|
||||
|
||||
@Schema(description = "目标版本 ID", example = "1002")
|
||||
private Long targetVersionId;
|
||||
|
||||
@Schema(description = "目标版本号", example = "3")
|
||||
private Integer targetVersionNumber;
|
||||
|
||||
@Schema(description = "目标版本描述")
|
||||
private String targetDescription;
|
||||
|
||||
@Schema(description = "目标版本操作人")
|
||||
private String targetOperator;
|
||||
|
||||
@Schema(description = "目标版本创建时间")
|
||||
private LocalDateTime targetCreateTime;
|
||||
|
||||
@Schema(description = "源版本快照")
|
||||
private ApiDefinitionSaveReqVO sourceSnapshot;
|
||||
|
||||
@Schema(description = "目标版本快照")
|
||||
private ApiDefinitionSaveReqVO targetSnapshot;
|
||||
|
||||
@Schema(description = "两者是否完全一致")
|
||||
private Boolean same;
|
||||
|
||||
@Schema(description = "字段差异列表")
|
||||
private List<FieldDiff> differences;
|
||||
|
||||
@Data
|
||||
public static class FieldDiff {
|
||||
|
||||
@Schema(description = "差异字段路径", example = "/steps[0]/targetEndpoint")
|
||||
private String path;
|
||||
|
||||
@Schema(description = "源版本值")
|
||||
private String sourceValue;
|
||||
|
||||
@Schema(description = "目标版本值")
|
||||
private String targetValue;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.version;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* API 版本历史创建 Request VO。
|
||||
*/
|
||||
@Schema(description = "管理后台 - API 版本历史创建 Request VO")
|
||||
@Data
|
||||
public class ApiVersionCreateReqVO {
|
||||
|
||||
@Schema(description = "API 定义 ID", required = true, example = "1024")
|
||||
@NotNull(message = "API 定义 ID 不能为空")
|
||||
private Long apiId;
|
||||
|
||||
@Schema(description = "版本号", required = true, example = "v1.0.0")
|
||||
@NotBlank(message = "版本号不能为空")
|
||||
private String versionNumber;
|
||||
|
||||
@Schema(description = "版本描述", example = "初始版本")
|
||||
private String description;
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.version;
|
||||
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.definition.ApiDefinitionSaveReqVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* API 版本详情 Response VO。
|
||||
* 包含完整的 API 定义快照数据。
|
||||
*/
|
||||
@Schema(description = "管理后台 - API 版本详情 Response VO")
|
||||
@Data
|
||||
public class ApiVersionDetailRespVO {
|
||||
|
||||
@Schema(description = "主键", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "API 定义 ID", example = "1001")
|
||||
private Long apiId;
|
||||
|
||||
@Schema(description = "版本号", example = "1")
|
||||
private Integer versionNumber;
|
||||
|
||||
@Schema(description = "版本描述", example = "初始版本")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "是否为当前版本", example = "true")
|
||||
private Boolean isCurrent;
|
||||
|
||||
@Schema(description = "操作人", example = "admin")
|
||||
private String operator;
|
||||
|
||||
@Schema(description = "API 定义快照数据")
|
||||
private ApiDefinitionSaveReqVO snapshotData;
|
||||
|
||||
@Schema(description = "创建者", example = "admin")
|
||||
private String creator;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "租户编号", example = "1")
|
||||
private Long tenantId;
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.version;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.zt.plat.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
/**
|
||||
* API 版本历史分页查询 VO。
|
||||
*/
|
||||
@Schema(description = "管理后台 - API 版本历史分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class ApiVersionPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "API 定义 ID", required = true, example = "1024")
|
||||
private Long apiId;
|
||||
|
||||
@Schema(description = "版本号", example = "1")
|
||||
private Integer versionNumber;
|
||||
|
||||
@Schema(description = "创建时间区间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.version;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* API 版本历史 Response VO。
|
||||
*/
|
||||
@Schema(description = "管理后台 - API 版本历史 Response VO")
|
||||
@Data
|
||||
public class ApiVersionRespVO {
|
||||
|
||||
@Schema(description = "主键", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "API 定义 ID", example = "1001")
|
||||
private Long apiId;
|
||||
|
||||
@Schema(description = "版本号", example = "1")
|
||||
private Integer versionNumber;
|
||||
|
||||
@Schema(description = "版本描述", example = "初始版本")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "是否为当前版本", example = "true")
|
||||
private Boolean isCurrent;
|
||||
|
||||
@Schema(description = "操作人", example = "admin")
|
||||
private String operator;
|
||||
|
||||
@Schema(description = "创建者", example = "admin")
|
||||
private String creator;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "租户编号", example = "1")
|
||||
private Long tenantId;
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.zt.plat.module.databus.controller.admin.gateway.vo.version;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* API 版本回滚 Request VO。
|
||||
*/
|
||||
@Schema(description = "管理后台 - API 版本回滚 Request VO")
|
||||
@Data
|
||||
public class ApiVersionRollbackReqVO {
|
||||
|
||||
@Schema(description = "待回滚的版本 ID", required = true, example = "1024")
|
||||
@NotNull(message = "版本 ID 不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "回滚备注", example = "回滚到版本 v5")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
package com.zt.plat.module.databus.dal.dataobject.gateway;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zt.plat.framework.tenant.core.db.TenantBaseDO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* Databus API 访问日志数据对象。
|
||||
*
|
||||
* <p>用于记录 API 编排网关的请求与响应详情,便于审计与问题排查。</p>
|
||||
*/
|
||||
@TableName("databus_api_access_log")
|
||||
@KeySequence("databus_api_access_log_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApiAccessLogDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 请求追踪标识,对应 {@link com.zt.plat.framework.common.util.monitor.TracerUtils#getTraceId()}
|
||||
*/
|
||||
private String traceId;
|
||||
|
||||
/**
|
||||
* API 编码
|
||||
*/
|
||||
private String apiCode;
|
||||
|
||||
/**
|
||||
* API 版本
|
||||
*/
|
||||
private String apiVersion;
|
||||
|
||||
/**
|
||||
* HTTP 方法
|
||||
*/
|
||||
private String requestMethod;
|
||||
|
||||
/**
|
||||
* 请求路径
|
||||
*/
|
||||
private String requestPath;
|
||||
|
||||
/**
|
||||
* 调用使用的应用标识
|
||||
*/
|
||||
private String credentialAppId;
|
||||
|
||||
/**
|
||||
* 调用使用的凭证主键
|
||||
*/
|
||||
private Long credentialId;
|
||||
|
||||
/**
|
||||
* 查询参数(JSON 字符串)
|
||||
*/
|
||||
private String requestQuery;
|
||||
|
||||
/**
|
||||
* 请求头信息(JSON 字符串)
|
||||
*/
|
||||
private String requestHeaders;
|
||||
|
||||
/**
|
||||
* 请求体(JSON 字符串)
|
||||
*/
|
||||
private String requestBody;
|
||||
|
||||
/**
|
||||
* 响应 HTTP 状态码
|
||||
*/
|
||||
private Integer responseStatus;
|
||||
|
||||
/**
|
||||
* 响应提示信息
|
||||
*/
|
||||
private String responseMessage;
|
||||
|
||||
/**
|
||||
* 响应体(JSON 字符串)
|
||||
*/
|
||||
private String responseBody;
|
||||
|
||||
/**
|
||||
* 访问状态:0-成功 1-客户端错误 2-服务端错误 3-未知
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 业务错误码
|
||||
*/
|
||||
private String errorCode;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* 异常堆栈
|
||||
*/
|
||||
private String exceptionStack;
|
||||
|
||||
/**
|
||||
* 客户端 IP
|
||||
*/
|
||||
private String clientIp;
|
||||
|
||||
/**
|
||||
* User-Agent
|
||||
*/
|
||||
private String userAgent;
|
||||
|
||||
/**
|
||||
* 请求耗时(毫秒)
|
||||
*/
|
||||
private Long duration;
|
||||
|
||||
/**
|
||||
* 请求时间
|
||||
*/
|
||||
private LocalDateTime requestTime;
|
||||
|
||||
/**
|
||||
* 响应时间
|
||||
*/
|
||||
private LocalDateTime responseTime;
|
||||
|
||||
/**
|
||||
* 执行步骤结果(JSON 字符串)
|
||||
*/
|
||||
private String stepResults;
|
||||
|
||||
/**
|
||||
* 额外调试信息(JSON 字符串)
|
||||
*/
|
||||
private String extra;
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.zt.plat.module.databus.dal.dataobject.gateway;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zt.plat.framework.mybatis.core.dataobject.BaseDO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* API 客户端凭证,用于维护 appId 与加解密配置的关联关系。
|
||||
*/
|
||||
@Data
|
||||
@TableName("databus_api_client_credential")
|
||||
@KeySequence("databus_api_client_credential_seq")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApiClientCredentialDO extends BaseDO {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
private String appId;
|
||||
|
||||
private String appName;
|
||||
|
||||
private String encryptionKey;
|
||||
|
||||
private String encryptionType;
|
||||
|
||||
private String signatureType;
|
||||
|
||||
private Boolean enabled;
|
||||
|
||||
private String remark;
|
||||
|
||||
private Boolean allowAnonymous;
|
||||
|
||||
private Long anonymousUserId;
|
||||
|
||||
private Boolean enableEncryption;
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package com.zt.plat.module.databus.dal.dataobject.gateway;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zt.plat.framework.mybatis.core.dataobject.BaseDO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* API 与客户端凭证的授权关联。
|
||||
*/
|
||||
@Data
|
||||
@TableName("databus_api_definition_credential")
|
||||
@KeySequence("databus_api_definition_credential_seq")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApiDefinitionCredentialDO extends BaseDO {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* API 主键
|
||||
*/
|
||||
private Long apiId;
|
||||
|
||||
/**
|
||||
* 客户端凭证主键
|
||||
*/
|
||||
private Long credentialId;
|
||||
|
||||
/**
|
||||
* 绑定时的应用标识冗余,便于快速校验
|
||||
*/
|
||||
private String appId;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.zt.plat.module.databus.dal.dataobject.gateway;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zt.plat.framework.tenant.core.db.TenantBaseDO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* API definition data object describing external API metadata and policies.
|
||||
*/
|
||||
@TableName("databus_api_definition")
|
||||
@KeySequence("databus_api_definition_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApiDefinitionDO extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
private String apiCode;
|
||||
|
||||
private String httpMethod;
|
||||
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* API status, see {@code ApiPublishStatusEnum}.
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
private String description;
|
||||
|
||||
private Long rateLimitId;
|
||||
|
||||
private String responseTemplate;
|
||||
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package com.zt.plat.module.databus.dal.dataobject.gateway;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zt.plat.framework.tenant.core.db.TenantBaseDO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* Publication record for API flow snapshots and gray releases.
|
||||
*/
|
||||
@TableName("databus_api_flow_publish")
|
||||
@KeySequence("databus_api_flow_publish_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApiFlowPublishDO extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
private Long apiId;
|
||||
|
||||
private String releaseTag;
|
||||
|
||||
private String snapshot;
|
||||
|
||||
private String status;
|
||||
|
||||
private Boolean active;
|
||||
|
||||
private String description;
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.zt.plat.module.databus.dal.dataobject.gateway;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zt.plat.framework.tenant.core.db.TenantBaseDO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* Rate limit policy definition stored in database.
|
||||
*/
|
||||
@TableName("databus_policy_rate_limit")
|
||||
@KeySequence("databus_policy_rate_limit_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApiPolicyRateLimitDO extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String type;
|
||||
|
||||
private String config;
|
||||
|
||||
private String description;
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package com.zt.plat.module.databus.dal.dataobject.gateway;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zt.plat.framework.tenant.core.db.TenantBaseDO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* API orchestration step definition.
|
||||
*/
|
||||
@TableName("databus_api_step")
|
||||
@KeySequence("databus_api_step_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApiStepDO extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
private Long apiId;
|
||||
|
||||
private Integer stepOrder;
|
||||
|
||||
private String parallelGroup;
|
||||
|
||||
private String type;
|
||||
|
||||
private String targetEndpoint;
|
||||
|
||||
private String requestMappingExpr;
|
||||
|
||||
private String responseMappingExpr;
|
||||
|
||||
private Long transformId;
|
||||
|
||||
private Long timeout;
|
||||
|
||||
private String fallbackStrategy;
|
||||
|
||||
private String conditionExpr;
|
||||
|
||||
private Boolean stopOnError;
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package com.zt.plat.module.databus.dal.dataobject.gateway;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zt.plat.framework.tenant.core.db.TenantBaseDO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* API request/response transformation expressions.
|
||||
*/
|
||||
@TableName("databus_api_transform")
|
||||
@KeySequence("databus_api_transform_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApiTransformDO extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
private Long apiId;
|
||||
|
||||
private Long stepId;
|
||||
|
||||
private String phase;
|
||||
|
||||
private String expressionType;
|
||||
|
||||
private String expression;
|
||||
|
||||
private String description;
|
||||
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package com.zt.plat.module.databus.dal.dataobject.gateway;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zt.plat.framework.tenant.core.db.TenantBaseDO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* API 版本历史数据对象
|
||||
*
|
||||
* <p>每次修改 API 配置时自动创建新版本记录,支持完整的版本历史追溯和回滚。</p>
|
||||
* <p>版本号自动递增,不可删除,保留完整的历史记录链。</p>
|
||||
*/
|
||||
@TableName("databus_api_version")
|
||||
@KeySequence("databus_api_version_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApiVersionDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* API 定义 ID
|
||||
*/
|
||||
private Long apiId;
|
||||
|
||||
/**
|
||||
* 版本号(自动递增,从 1 开始)
|
||||
*/
|
||||
private Integer versionNumber;
|
||||
|
||||
/**
|
||||
* API 完整定义快照(JSON 格式,包含 definition、steps、transforms 等)
|
||||
*/
|
||||
private String snapshotData;
|
||||
|
||||
/**
|
||||
* 版本描述/变更说明
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 是否为当前版本(最新使用的版本)
|
||||
*/
|
||||
private Boolean isCurrent;
|
||||
|
||||
/**
|
||||
* 操作人
|
||||
*/
|
||||
private String operator;
|
||||
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package com.zt.plat.module.databus.dal.mapper.gateway;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.version.ApiVersionPageReqVO;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiVersionDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* API 版本历史 Mapper
|
||||
*/
|
||||
@Mapper
|
||||
public interface ApiVersionMapper extends BaseMapperX<ApiVersionDO> {
|
||||
|
||||
/**
|
||||
* 分页查询版本历史
|
||||
*/
|
||||
default PageResult<ApiVersionDO> selectPage(ApiVersionPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<ApiVersionDO>()
|
||||
.eqIfPresent(ApiVersionDO::getApiId, reqVO.getApiId())
|
||||
.eqIfPresent(ApiVersionDO::getVersionNumber, reqVO.getVersionNumber())
|
||||
.betweenIfPresent(ApiVersionDO::getCreateTime, reqVO.getCreateTime())
|
||||
.orderByDesc(ApiVersionDO::getVersionNumber));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定 API 的所有版本历史
|
||||
*/
|
||||
default List<ApiVersionDO> selectListByApiId(Long apiId) {
|
||||
return selectList(new LambdaQueryWrapperX<ApiVersionDO>()
|
||||
.eq(ApiVersionDO::getApiId, apiId)
|
||||
.orderByDesc(ApiVersionDO::getVersionNumber));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定 API 的当前版本
|
||||
*/
|
||||
default ApiVersionDO selectCurrentByApiId(Long apiId) {
|
||||
return selectOne(new LambdaQueryWrapperX<ApiVersionDO>()
|
||||
.eq(ApiVersionDO::getApiId, apiId)
|
||||
.eq(ApiVersionDO::getIsCurrent, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定 API 的最大版本号
|
||||
*/
|
||||
default Integer selectMaxVersionNumber(Long apiId) {
|
||||
ApiVersionDO maxVersion = selectOne(new LambdaQueryWrapperX<ApiVersionDO>()
|
||||
.eq(ApiVersionDO::getApiId, apiId)
|
||||
.orderByDesc(ApiVersionDO::getVersionNumber)
|
||||
.last("LIMIT 1"));
|
||||
return maxVersion != null ? maxVersion.getVersionNumber() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将所有版本标记为非当前版本
|
||||
*/
|
||||
default void markAllAsNotCurrent(Long apiId) {
|
||||
UpdateWrapper<ApiVersionDO> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("api_id", apiId)
|
||||
.set("is_current", false);
|
||||
update(null, updateWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定版本
|
||||
*/
|
||||
default ApiVersionDO selectByApiIdAndVersionNumber(Long apiId, Integer versionNumber) {
|
||||
return selectOne(new LambdaQueryWrapperX<ApiVersionDO>()
|
||||
.eq(ApiVersionDO::getApiId, apiId)
|
||||
.eq(ApiVersionDO::getVersionNumber, versionNumber));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.zt.plat.module.databus.dal.mysql.gateway;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.accesslog.ApiAccessLogPageReqVO;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiAccessLogDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface ApiAccessLogMapper extends BaseMapperX<ApiAccessLogDO> {
|
||||
|
||||
default PageResult<ApiAccessLogDO> selectPage(ApiAccessLogPageReqVO reqVO) {
|
||||
LambdaQueryWrapperX<ApiAccessLogDO> query = new LambdaQueryWrapperX<ApiAccessLogDO>()
|
||||
.likeIfPresent(ApiAccessLogDO::getTraceId, reqVO.getTraceId())
|
||||
.eqIfPresent(ApiAccessLogDO::getApiCode, reqVO.getApiCode())
|
||||
.eqIfPresent(ApiAccessLogDO::getApiVersion, reqVO.getApiVersion())
|
||||
.eqIfPresent(ApiAccessLogDO::getRequestMethod, reqVO.getRequestMethod())
|
||||
.eqIfPresent(ApiAccessLogDO::getResponseStatus, reqVO.getResponseStatus())
|
||||
.eqIfPresent(ApiAccessLogDO::getStatus, reqVO.getStatus())
|
||||
.likeIfPresent(ApiAccessLogDO::getClientIp, reqVO.getClientIp())
|
||||
.eqIfPresent(ApiAccessLogDO::getCredentialAppId, reqVO.getCredentialAppId())
|
||||
.eqIfPresent(ApiAccessLogDO::getCredentialId, reqVO.getCredentialId())
|
||||
.eqIfPresent(ApiAccessLogDO::getTenantId, reqVO.getTenantId())
|
||||
.likeIfPresent(ApiAccessLogDO::getRequestPath, reqVO.getRequestPath());
|
||||
if (ArrayUtil.isNotEmpty(reqVO.getRequestTime()) && reqVO.getRequestTime().length == 2) {
|
||||
query.between(ApiAccessLogDO::getRequestTime, reqVO.getRequestTime()[0], reqVO.getRequestTime()[1]);
|
||||
}
|
||||
return selectPage(reqVO, query.orderByDesc(ApiAccessLogDO::getRequestTime)
|
||||
.orderByDesc(ApiAccessLogDO::getId));
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package com.zt.plat.module.databus.dal.mysql.gateway;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.credential.ApiClientCredentialPageReqVO;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiClientCredentialDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Mapper
|
||||
public interface ApiClientCredentialMapper extends BaseMapperX<ApiClientCredentialDO> {
|
||||
|
||||
default Optional<ApiClientCredentialDO> selectByAppId(String appId) {
|
||||
if (StrUtil.isBlank(appId)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
LambdaQueryWrapperX<ApiClientCredentialDO> query = new LambdaQueryWrapperX<>();
|
||||
query.eq(ApiClientCredentialDO::getAppId, appId)
|
||||
.eq(ApiClientCredentialDO::getDeleted, false);
|
||||
return Optional.ofNullable(selectOne(query));
|
||||
}
|
||||
|
||||
default PageResult<ApiClientCredentialDO> selectPage(ApiClientCredentialPageReqVO reqVO) {
|
||||
LambdaQueryWrapperX<ApiClientCredentialDO> query = new LambdaQueryWrapperX<>();
|
||||
if (StrUtil.isNotBlank(reqVO.getKeyword())) {
|
||||
String keyword = reqVO.getKeyword();
|
||||
query.and(wrapper -> wrapper.like(ApiClientCredentialDO::getAppId, keyword)
|
||||
.or().like(ApiClientCredentialDO::getAppName, keyword));
|
||||
}
|
||||
query.eqIfPresent(ApiClientCredentialDO::getEnabled, reqVO.getEnabled())
|
||||
.eq(ApiClientCredentialDO::getDeleted, false)
|
||||
.orderByDesc(ApiClientCredentialDO::getUpdateTime)
|
||||
.orderByDesc(ApiClientCredentialDO::getId);
|
||||
return selectPage(reqVO, query);
|
||||
}
|
||||
|
||||
default List<ApiClientCredentialDO> selectEnabledList() {
|
||||
return selectList(new LambdaQueryWrapperX<ApiClientCredentialDO>()
|
||||
.eq(ApiClientCredentialDO::getEnabled, true)
|
||||
.eq(ApiClientCredentialDO::getDeleted, false)
|
||||
.orderByAsc(ApiClientCredentialDO::getAppId));
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.zt.plat.module.databus.dal.mysql.gateway;
|
||||
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiDefinitionCredentialDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface ApiDefinitionCredentialMapper extends BaseMapperX<ApiDefinitionCredentialDO> {
|
||||
|
||||
default List<ApiDefinitionCredentialDO> selectByApiId(Long apiId) {
|
||||
return selectList(new LambdaQueryWrapperX<ApiDefinitionCredentialDO>()
|
||||
.eq(ApiDefinitionCredentialDO::getApiId, apiId));
|
||||
}
|
||||
|
||||
default void deleteByApiId(Long apiId) {
|
||||
delete(new LambdaQueryWrapperX<ApiDefinitionCredentialDO>()
|
||||
.eq(ApiDefinitionCredentialDO::getApiId, apiId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 API 逻辑删除已有绑定,保留操作记录。
|
||||
*/
|
||||
default void logicDeleteByApiId(Long apiId) {
|
||||
ApiDefinitionCredentialDO entity = new ApiDefinitionCredentialDO();
|
||||
entity.setDeleted(Boolean.TRUE);
|
||||
update(entity, new LambdaQueryWrapperX<ApiDefinitionCredentialDO>()
|
||||
.eq(ApiDefinitionCredentialDO::getApiId, apiId));
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package com.zt.plat.module.databus.dal.mysql.gateway;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.definition.ApiDefinitionPageReqVO;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiDefinitionDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Mapper
|
||||
public interface ApiDefinitionMapper extends BaseMapperX<ApiDefinitionDO> {
|
||||
|
||||
default Optional<ApiDefinitionDO> selectByCodeAndVersion(String apiCode, String version) {
|
||||
return Optional.ofNullable(selectOne(ApiDefinitionDO::getApiCode, apiCode,
|
||||
ApiDefinitionDO::getVersion, version,
|
||||
ApiDefinitionDO::getDeleted, false));
|
||||
}
|
||||
|
||||
default List<ApiDefinitionDO> selectActiveDefinitions(List<Integer> statusList) {
|
||||
return selectList(new LambdaQueryWrapperX<ApiDefinitionDO>()
|
||||
.inIfPresent(ApiDefinitionDO::getStatus, statusList)
|
||||
.eq(ApiDefinitionDO::getDeleted, false));
|
||||
}
|
||||
|
||||
default PageResult<ApiDefinitionDO> selectPage(ApiDefinitionPageReqVO reqVO) {
|
||||
LambdaQueryWrapperX<ApiDefinitionDO> query = new LambdaQueryWrapperX<>();
|
||||
if (StrUtil.isNotBlank(reqVO.getKeyword())) {
|
||||
String keyword = reqVO.getKeyword();
|
||||
query.and(wrapper -> wrapper.like(ApiDefinitionDO::getApiCode, keyword)
|
||||
.or().like(ApiDefinitionDO::getDescription, keyword));
|
||||
}
|
||||
query.eqIfPresent(ApiDefinitionDO::getStatus, reqVO.getStatus())
|
||||
.eqIfPresent(ApiDefinitionDO::getHttpMethod, reqVO.getHttpMethod())
|
||||
.orderByDesc(ApiDefinitionDO::getUpdateTime)
|
||||
.orderByDesc(ApiDefinitionDO::getId);
|
||||
return selectPage(reqVO, query);
|
||||
}
|
||||
|
||||
default Long selectCountByRateLimitPolicyId(Long policyId) {
|
||||
if (policyId == null) {
|
||||
return 0L;
|
||||
}
|
||||
return selectCount(new LambdaQueryWrapperX<ApiDefinitionDO>()
|
||||
.eq(ApiDefinitionDO::getRateLimitId, policyId)
|
||||
.eq(ApiDefinitionDO::getDeleted, false));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.zt.plat.module.databus.dal.mysql.gateway;
|
||||
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiFlowPublishDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Mapper
|
||||
public interface ApiFlowPublishMapper extends BaseMapperX<ApiFlowPublishDO> {
|
||||
|
||||
default Optional<ApiFlowPublishDO> selectActiveByApiId(Long apiId) {
|
||||
return Optional.ofNullable(selectOne(new LambdaQueryWrapperX<ApiFlowPublishDO>()
|
||||
.eq(ApiFlowPublishDO::getApiId, apiId)
|
||||
.eq(ApiFlowPublishDO::getActive, true)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package com.zt.plat.module.databus.dal.mysql.gateway;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.zt.plat.module.databus.controller.admin.gateway.vo.policy.ApiPolicyPageReqVO;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiPolicyRateLimitDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface ApiPolicyRateLimitMapper extends BaseMapperX<ApiPolicyRateLimitDO> {
|
||||
|
||||
default PageResult<ApiPolicyRateLimitDO> selectPage(ApiPolicyPageReqVO reqVO) {
|
||||
LambdaQueryWrapperX<ApiPolicyRateLimitDO> query = new LambdaQueryWrapperX<>();
|
||||
if (StrUtil.isNotBlank(reqVO.getKeyword())) {
|
||||
String keyword = reqVO.getKeyword();
|
||||
query.and(wrapper -> wrapper.like(ApiPolicyRateLimitDO::getName, keyword)
|
||||
.or().like(ApiPolicyRateLimitDO::getDescription, keyword));
|
||||
}
|
||||
query.eqIfPresent(ApiPolicyRateLimitDO::getType, reqVO.getType())
|
||||
.eq(ApiPolicyRateLimitDO::getDeleted, false)
|
||||
.orderByDesc(ApiPolicyRateLimitDO::getUpdateTime)
|
||||
.orderByDesc(ApiPolicyRateLimitDO::getId);
|
||||
return selectPage(reqVO, query);
|
||||
}
|
||||
|
||||
default List<ApiPolicyRateLimitDO> selectSimpleList() {
|
||||
return selectList(new LambdaQueryWrapperX<ApiPolicyRateLimitDO>()
|
||||
.eq(ApiPolicyRateLimitDO::getDeleted, false)
|
||||
.orderByDesc(ApiPolicyRateLimitDO::getUpdateTime)
|
||||
.orderByDesc(ApiPolicyRateLimitDO::getId));
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.zt.plat.module.databus.dal.mysql.gateway;
|
||||
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiStepDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface ApiStepMapper extends BaseMapperX<ApiStepDO> {
|
||||
|
||||
default List<ApiStepDO> selectByApiId(Long apiId) {
|
||||
return selectList(new LambdaQueryWrapperX<ApiStepDO>()
|
||||
.eq(ApiStepDO::getApiId, apiId)
|
||||
.orderByAsc(ApiStepDO::getParallelGroup)
|
||||
.orderByAsc(ApiStepDO::getStepOrder));
|
||||
}
|
||||
|
||||
default void deleteByApiId(Long apiId) {
|
||||
delete(new LambdaQueryWrapperX<ApiStepDO>()
|
||||
.eq(ApiStepDO::getApiId, apiId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.zt.plat.module.databus.dal.mysql.gateway;
|
||||
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiTransformDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface ApiTransformMapper extends BaseMapperX<ApiTransformDO> {
|
||||
|
||||
default List<ApiTransformDO> selectByApiId(Long apiId) {
|
||||
return selectList(new LambdaQueryWrapperX<ApiTransformDO>()
|
||||
.eq(ApiTransformDO::getApiId, apiId));
|
||||
}
|
||||
|
||||
default List<ApiTransformDO> selectByStepId(Long stepId) {
|
||||
return selectList(new LambdaQueryWrapperX<ApiTransformDO>()
|
||||
.eq(ApiTransformDO::getStepId, stepId));
|
||||
}
|
||||
|
||||
default List<ApiTransformDO> selectApiLevelTransforms(Long apiId) {
|
||||
return selectList(new LambdaQueryWrapperX<ApiTransformDO>()
|
||||
.eq(ApiTransformDO::getApiId, apiId)
|
||||
.isNull(ApiTransformDO::getStepId));
|
||||
}
|
||||
|
||||
default void deleteByApiId(Long apiId) {
|
||||
delete(new LambdaQueryWrapperX<ApiTransformDO>()
|
||||
.eq(ApiTransformDO::getApiId, apiId));
|
||||
}
|
||||
|
||||
default void deleteByStepId(Long stepId) {
|
||||
delete(new LambdaQueryWrapperX<ApiTransformDO>()
|
||||
.eq(ApiTransformDO::getStepId, stepId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.zt.plat.module.databus.enums.gateway;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* External API publish status enumeration.
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum ApiStatusEnum {
|
||||
|
||||
DRAFT(0, "草稿"),
|
||||
ONLINE(1, "已上线"),
|
||||
OFFLINE(2, "已下线"),
|
||||
DEPRECATED(3, "已废弃");
|
||||
|
||||
private final int status;
|
||||
private final String label;
|
||||
|
||||
public static boolean isOnline(Integer status) {
|
||||
return status != null && status == ONLINE.status;
|
||||
}
|
||||
|
||||
public static boolean isDeprecated(Integer status) {
|
||||
return status != null && status == DEPRECATED.status;
|
||||
}
|
||||
|
||||
public static ApiStatusEnum fromStatus(Integer status) {
|
||||
if (status == null) {
|
||||
return null;
|
||||
}
|
||||
for (ApiStatusEnum value : values()) {
|
||||
if (value.status == status) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String labelOf(Integer status) {
|
||||
ApiStatusEnum value = fromStatus(status);
|
||||
return value != null ? value.label : "未知";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.zt.plat.module.databus.enums.gateway;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Step types supported by the unified API portal.
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum ApiStepTypeEnum {
|
||||
|
||||
START,
|
||||
HTTP,
|
||||
RPC,
|
||||
SCRIPT,
|
||||
END;
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.zt.plat.module.databus.enums.gateway;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Supported expression languages for request/response mapping.
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum ExpressionTypeEnum {
|
||||
|
||||
JSON("json");
|
||||
|
||||
private final String code;
|
||||
|
||||
public static ExpressionTypeEnum fromValue(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
String normalized = value.trim().toLowerCase(Locale.ROOT);
|
||||
for (ExpressionTypeEnum type : values()) {
|
||||
if (type.code.equals(normalized) || type.name().equals(normalized.toUpperCase(Locale.ROOT))) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.zt.plat.module.databus.enums.gateway;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Transformation phase enumeration.
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum TransformPhaseEnum {
|
||||
|
||||
REQUEST_PRE,
|
||||
REQUEST_POST,
|
||||
RESPONSE_PRE,
|
||||
RESPONSE_POST,
|
||||
ERROR;
|
||||
|
||||
public static TransformPhaseEnum fromCode(String code) {
|
||||
for (TransformPhaseEnum phase : values()) {
|
||||
if (phase.name().equalsIgnoreCase(code)) {
|
||||
return phase;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
package com.zt.plat.module.databus.framework.integration.config;
|
||||
|
||||
import com.zt.plat.framework.common.util.security.CryptoSignatureUtils;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Configuration properties for the unified API portal.
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "databus.api-portal")
|
||||
public class ApiGatewayProperties {
|
||||
|
||||
public static String APP_ID_HEADER = "ZT-App-Id";
|
||||
public static String TIMESTAMP_HEADER = "ZT-Timestamp";
|
||||
public static String NONCE_HEADER = "ZT-Nonce";
|
||||
public static String SIGNATURE_HEADER = "ZT-Signature";
|
||||
public static final String DEFAULT_BASE_PATH = "/admin-api/databus/api/portal";
|
||||
public static final String LEGACY_BASE_PATH = "/databus/api/portal";
|
||||
|
||||
private String basePath = DEFAULT_BASE_PATH;
|
||||
|
||||
public void setBasePath(String basePath) {
|
||||
if (!StringUtils.hasText(basePath)) {
|
||||
this.basePath = DEFAULT_BASE_PATH;
|
||||
return;
|
||||
}
|
||||
String normalized = basePath.startsWith("/") ? basePath : "/" + basePath;
|
||||
if (LEGACY_BASE_PATH.equals(normalized)) {
|
||||
this.basePath = DEFAULT_BASE_PATH;
|
||||
return;
|
||||
}
|
||||
this.basePath = normalized;
|
||||
}
|
||||
|
||||
public List<String> getAllBasePaths() {
|
||||
Set<String> candidates = new LinkedHashSet<>();
|
||||
candidates.add(basePath);
|
||||
candidates.add(DEFAULT_BASE_PATH);
|
||||
candidates.add(LEGACY_BASE_PATH);
|
||||
return new ArrayList<>(candidates);
|
||||
}
|
||||
|
||||
private List<String> allowedIps = new ArrayList<>();
|
||||
|
||||
private List<String> deniedIps = new ArrayList<>();
|
||||
|
||||
private Security security = new Security();
|
||||
|
||||
private boolean enableTenantHeader = false;
|
||||
|
||||
private String tenantHeader = "ZT-Tenant-Id";
|
||||
|
||||
private boolean enableAudit = true;
|
||||
|
||||
private boolean enableRateLimit = true;
|
||||
|
||||
@Data
|
||||
public static class Security {
|
||||
|
||||
private boolean enabled = true;
|
||||
|
||||
private String signatureType = CryptoSignatureUtils.SIGNATURE_TYPE_MD5;
|
||||
|
||||
private String encryptionType = CryptoSignatureUtils.ENCRYPT_TYPE_AES;
|
||||
|
||||
private long allowedClockSkewSeconds = 300;
|
||||
|
||||
private long nonceTtlSeconds = 600;
|
||||
|
||||
private String nonceRedisKeyPrefix = "databus:gateway:nonce:";
|
||||
|
||||
private boolean requireBodyEncryption = true;
|
||||
|
||||
private boolean encryptResponse = true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.zt.plat.module.databus.framework.integration.config;
|
||||
|
||||
import com.zt.plat.module.databus.enums.gateway.ExpressionTypeEnum;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.expression.ExpressionEvaluatorRegistry;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.expression.JsonataExpressionEvaluator;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Registers expression evaluators with the registry.
|
||||
*/
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class ExpressionConfiguration {
|
||||
|
||||
private final ExpressionEvaluatorRegistry registry;
|
||||
private final JsonataExpressionEvaluator jsonataExpressionEvaluator;
|
||||
|
||||
@PostConstruct
|
||||
public void registerEvaluators() {
|
||||
registry.register(ExpressionTypeEnum.JSON, jsonataExpressionEvaluator);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package com.zt.plat.module.databus.framework.integration.config;
|
||||
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.core.ApiGatewayExecutionService;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.core.ErrorHandlingStrategy;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.security.GatewaySecurityFilter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
import org.springframework.integration.dsl.IntegrationFlow;
|
||||
import org.springframework.integration.http.dsl.Http;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
|
||||
/**
|
||||
* Configures the unified API portal inbound gateway and supporting beans.
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(ApiGatewayProperties.class)
|
||||
@RequiredArgsConstructor
|
||||
public class GatewayIntegrationConfiguration {
|
||||
|
||||
private final ApiGatewayProperties properties;
|
||||
private final ErrorHandlingStrategy errorHandlingStrategy;
|
||||
|
||||
@Bean(name = "apiPortalTaskExecutor")
|
||||
public ThreadPoolTaskExecutor apiPortalTaskExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
executor.setCorePoolSize(8);
|
||||
executor.setMaxPoolSize(32);
|
||||
executor.setQueueCapacity(256);
|
||||
executor.setThreadNamePrefix("api-portal-");
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessagingTemplate apiPortalMessagingTemplate() {
|
||||
return new MessagingTemplate();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<GatewaySecurityFilter> gatewaySecurityFilterRegistration(GatewaySecurityFilter filter) {
|
||||
FilterRegistrationBean<GatewaySecurityFilter> registration = new FilterRegistrationBean<>(filter);
|
||||
registration.setOrder(Ordered.HIGHEST_PRECEDENCE + 10);
|
||||
return registration;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IntegrationFlow apiGatewayInboundFlow(ApiGatewayExecutionService executionService) {
|
||||
String pattern = properties.getBasePath() + "/{apiCode}/{version}";
|
||||
return IntegrationFlow.from(Http.inboundGateway(pattern)
|
||||
.requestMapping(spec -> spec
|
||||
.methods(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, HttpMethod.DELETE, HttpMethod.PATCH))
|
||||
.errorChannel(errorHandlingStrategy.getErrorChannel())
|
||||
.requestPayloadType(String.class)
|
||||
.mappedRequestHeaders("*")
|
||||
.mappedResponseHeaders("*"))
|
||||
.handle(executionService, "mapRequest", endpoint -> endpoint.advice(errorHandlingStrategy.errorForwardingAdvice()))
|
||||
.handle(executionService, "dispatch", endpoint -> endpoint.advice(errorHandlingStrategy.errorForwardingAdvice()))
|
||||
.handle(executionService, "buildResponseEntity", endpoint -> endpoint.advice(errorHandlingStrategy.errorForwardingAdvice()))
|
||||
.get();
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package com.zt.plat.module.databus.framework.integration.gateway.config;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.web.reactive.function.client.WebClientCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
import reactor.netty.resources.ConnectionProvider;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
|
||||
@Configuration
|
||||
public class GatewayWebClientConfiguration {
|
||||
|
||||
private final int maxInMemorySize;
|
||||
private final long maxIdleTimeMillis;
|
||||
private final long evictInBackgroundMillis;
|
||||
private final boolean connectionPoolEnabled;
|
||||
private final ReactorClientHttpConnector httpConnector;
|
||||
private static final Logger log = LoggerFactory.getLogger(GatewayWebClientConfiguration.class);
|
||||
|
||||
public GatewayWebClientConfiguration(
|
||||
@Value("${databus.gateway.web-client.max-in-memory-size:20971520}") int maxInMemorySize,
|
||||
@Value("${databus.gateway.web-client.max-idle-time:45000}") long maxIdleTimeMillis,
|
||||
@Value("${databus.gateway.web-client.evict-in-background-interval:20000}") long evictInBackgroundMillis,
|
||||
@Value("${databus.gateway.web-client.connection-pool-enabled:true}") boolean connectionPoolEnabled) {
|
||||
this.maxInMemorySize = maxInMemorySize;
|
||||
this.maxIdleTimeMillis = maxIdleTimeMillis;
|
||||
this.evictInBackgroundMillis = evictInBackgroundMillis;
|
||||
this.connectionPoolEnabled = connectionPoolEnabled;
|
||||
this.httpConnector = buildConnector();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebClientCustomizer gatewayWebClientCustomizer() {
|
||||
// 统一设置 WebClient 连接器与内存限制,避免各处重复配置
|
||||
return builder -> builder
|
||||
.clientConnector(httpConnector)
|
||||
.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(maxInMemorySize));
|
||||
}
|
||||
|
||||
private ReactorClientHttpConnector buildConnector() {
|
||||
if (connectionPoolEnabled) {
|
||||
// 启用连接池,基于配置设置空闲回收参数
|
||||
ConnectionProvider provider = ConnectionProvider.builder("databus-gateway")
|
||||
.maxIdleTime(Duration.ofMillis(maxIdleTimeMillis))
|
||||
.evictInBackground(Duration.ofMillis(evictInBackgroundMillis))
|
||||
.build();
|
||||
log.info("Databus gateway WebClient 已启用连接池 (maxIdleTime={}ms, evictInterval={}ms)",
|
||||
maxIdleTimeMillis, evictInBackgroundMillis);
|
||||
return new ReactorClientHttpConnector(HttpClient.create(provider).compress(true));
|
||||
}
|
||||
// 关闭连接池,每次请求都会重新建立 TCP 连接
|
||||
log.info("Databus gateway WebClient 已禁用连接池,所有请求将使用全新连接");
|
||||
return new ReactorClientHttpConnector(HttpClient.create().compress(true));
|
||||
}
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
package com.zt.plat.module.databus.framework.integration.gateway.core;
|
||||
|
||||
import com.zt.plat.framework.common.exception.ServiceException;
|
||||
import com.zt.plat.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import com.zt.plat.module.databus.enums.gateway.ExpressionTypeEnum;
|
||||
import com.zt.plat.module.databus.enums.gateway.TransformPhaseEnum;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.domain.ApiDefinitionAggregate;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.domain.ApiStepDefinition;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.expression.ExpressionExecutor;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.expression.ExpressionSpec;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.expression.ExpressionSpecParser;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.expression.GatewayExpressionHelper;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.model.ApiInvocationContext;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.step.StepHandlerFactory;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aopalliance.aop.Advice;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.integration.core.GenericHandler;
|
||||
import org.springframework.integration.dsl.IntegrationFlow;
|
||||
import org.springframework.integration.dsl.IntegrationFlowBuilder;
|
||||
import org.springframework.integration.dsl.MessageChannels;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static com.zt.plat.module.databus.service.gateway.impl.GatewayServiceErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
* 按 API 定义装配动态集成流程。
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class ApiFlowAssembler {
|
||||
|
||||
private final StepHandlerFactory stepHandlerFactory;
|
||||
private final PolicyAdvisorFactory policyAdvisorFactory;
|
||||
private final ErrorHandlingStrategy errorHandlingStrategy;
|
||||
private final MonitoringInterceptor monitoringInterceptor;
|
||||
private final ExpressionExecutor expressionExecutor;
|
||||
@Qualifier("apiPortalTaskExecutor")
|
||||
private final TaskExecutor apiPortalTaskExecutor;
|
||||
|
||||
public ApiFlowRegistration assemble(ApiDefinitionAggregate aggregate) {
|
||||
String inputChannelName = channelName(aggregate);
|
||||
String flowId = flowId(aggregate);
|
||||
IntegrationFlowBuilder builder = IntegrationFlow.from(MessageChannels.direct(inputChannelName)
|
||||
.datatype(ApiInvocationContext.class)
|
||||
.interceptor(monitoringInterceptor))
|
||||
.log(message -> String.format("[API-PORTAL] 进入流程 %s", flowId))
|
||||
.handle(ApiInvocationContext.class,
|
||||
applyTransforms(aggregate, TransformPhaseEnum.REQUEST_PRE),
|
||||
endpoint -> endpoint.advice(errorHandlingStrategy.errorForwardingAdvice()));
|
||||
|
||||
List<FlowSegment> segments = segments(aggregate.getSteps());
|
||||
for (FlowSegment segment : segments) {
|
||||
if (segment instanceof SequentialSegment sequentialSegment) {
|
||||
builder = applySequential(builder, aggregate, sequentialSegment.getStep());
|
||||
} else if (segment instanceof ParallelSegment parallelSegment) {
|
||||
builder = applyParallel(builder, aggregate, parallelSegment);
|
||||
}
|
||||
}
|
||||
|
||||
builder = builder
|
||||
.handle(ApiInvocationContext.class,
|
||||
applyTransforms(aggregate, TransformPhaseEnum.RESPONSE_PRE),
|
||||
endpoint -> endpoint.advice(errorHandlingStrategy.errorForwardingAdvice()))
|
||||
.handle(ApiInvocationContext.class,
|
||||
(payload, headers) -> payload,
|
||||
endpoint -> endpoint.advice(errorHandlingStrategy.errorForwardingAdvice()));
|
||||
|
||||
return ApiFlowRegistration.builder()
|
||||
.flowId(flowId)
|
||||
.inputChannelName(inputChannelName)
|
||||
.flow(builder.get())
|
||||
.build();
|
||||
}
|
||||
|
||||
private GenericHandler<ApiInvocationContext> applyTransforms(ApiDefinitionAggregate aggregate, TransformPhaseEnum phase) {
|
||||
boolean mutateRequest = phase == TransformPhaseEnum.REQUEST_PRE || phase == TransformPhaseEnum.REQUEST_POST;
|
||||
boolean mutateResponse = phase == TransformPhaseEnum.RESPONSE_PRE
|
||||
|| phase == TransformPhaseEnum.RESPONSE_POST
|
||||
|| phase == TransformPhaseEnum.ERROR;
|
||||
return (payload, headers) -> {
|
||||
var transformDefinition = aggregate.getApiLevelTransforms().get(phase.name());
|
||||
if (transformDefinition != null && StringUtils.hasText(transformDefinition.getExpression())) {
|
||||
String rawExpression = transformDefinition.getExpressionType() + "::" + transformDefinition.getExpression();
|
||||
ExpressionSpec spec = ExpressionSpecParser.parse(rawExpression, ExpressionTypeEnum.JSON);
|
||||
try {
|
||||
Object result = expressionExecutor.evaluate(spec, payload, payload.getRequestBody(), headers);
|
||||
GatewayExpressionHelper.applyContextMutations(payload, result, mutateRequest, mutateResponse);
|
||||
} catch (Exception ex) {
|
||||
if (ex instanceof ServiceException serviceException) {
|
||||
throw serviceException;
|
||||
}
|
||||
throw ServiceExceptionUtil.exception(API_TRANSFORM_EVALUATION_FAILED, ex.getMessage());
|
||||
}
|
||||
}
|
||||
return payload;
|
||||
};
|
||||
}
|
||||
|
||||
private IntegrationFlowBuilder applySequential(IntegrationFlowBuilder builder, ApiDefinitionAggregate aggregate, ApiStepDefinition stepDefinition) {
|
||||
GenericHandler<ApiInvocationContext> handler = stepHandlerFactory.build(aggregate, stepDefinition);
|
||||
return builder.handle(ApiInvocationContext.class, handler, endpoint -> {
|
||||
endpoint.advice(errorHandlingStrategy.errorForwardingAdvice());
|
||||
Advice[] advices = policyAdvisorFactory.buildAdvices(aggregate, stepDefinition);
|
||||
if (advices.length > 0) {
|
||||
endpoint.advice(advices);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private IntegrationFlowBuilder applyParallel(IntegrationFlowBuilder builder, ApiDefinitionAggregate aggregate, ParallelSegment segment) {
|
||||
return builder.handle(ApiInvocationContext.class,
|
||||
(payload, headers) -> executeParallel(payload, headers, aggregate, segment),
|
||||
endpoint -> {
|
||||
endpoint.advice(errorHandlingStrategy.errorForwardingAdvice());
|
||||
Advice[] advices = policyAdvisorFactory.buildParallelAdvices(aggregate, segment);
|
||||
if (advices.length > 0) {
|
||||
endpoint.advice(advices);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private ApiInvocationContext executeParallel(ApiInvocationContext context, MessageHeaders headers,
|
||||
ApiDefinitionAggregate aggregate, ParallelSegment segment) {
|
||||
List<CompletableFuture<ApiInvocationContext>> futures = new ArrayList<>();
|
||||
for (ApiStepDefinition step : segment.getSteps()) {
|
||||
GenericHandler<ApiInvocationContext> handler = stepHandlerFactory.build(aggregate, step);
|
||||
ApiInvocationContext childContext = context.copy();
|
||||
futures.add(CompletableFuture.supplyAsync(() -> {
|
||||
handler.handle(childContext, headers);
|
||||
return childContext;
|
||||
}, apiPortalTaskExecutor));
|
||||
}
|
||||
for (CompletableFuture<ApiInvocationContext> future : futures) {
|
||||
try {
|
||||
ApiInvocationContext child = future.get();
|
||||
context.merge(child);
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw ServiceExceptionUtil.exception(API_PARALLEL_INTERRUPTED);
|
||||
} catch (ExecutionException ex) {
|
||||
Throwable cause = ex.getCause();
|
||||
if (cause instanceof ServiceException serviceException) {
|
||||
throw serviceException;
|
||||
}
|
||||
throw ServiceExceptionUtil.exception(API_PARALLEL_FAILED, cause == null ? ex.getMessage() : cause.getMessage());
|
||||
}
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
private List<FlowSegment> segments(List<ApiStepDefinition> steps) {
|
||||
return steps.stream()
|
||||
.sorted(Comparator.comparingInt(step -> step.getStep().getStepOrder() == null ? Integer.MAX_VALUE : step.getStep().getStepOrder()))
|
||||
.collect(ArrayList::new, this::consumeStep, this::combineSegments);
|
||||
}
|
||||
|
||||
private void consumeStep(List<FlowSegment> segments, ApiStepDefinition step) {
|
||||
String parallelGroup = step.getStep().getParallelGroup();
|
||||
if (!StringUtils.hasText(parallelGroup)) {
|
||||
segments.add(new SequentialSegment(step));
|
||||
return;
|
||||
}
|
||||
FlowSegment last = segments.isEmpty() ? null : segments.get(segments.size() - 1);
|
||||
if (last instanceof ParallelSegment parallelSegment && parallelGroup.equals(parallelSegment.getGroup())) {
|
||||
parallelSegment.getSteps().add(step);
|
||||
} else {
|
||||
ParallelSegment newSegment = new ParallelSegment(parallelGroup, new ArrayList<>());
|
||||
newSegment.getSteps().add(step);
|
||||
segments.add(newSegment);
|
||||
}
|
||||
}
|
||||
|
||||
private void combineSegments(List<FlowSegment> target, List<FlowSegment> source) {
|
||||
target.addAll(source);
|
||||
}
|
||||
|
||||
private String channelName(ApiDefinitionAggregate aggregate) {
|
||||
return "api.portal.flow." + aggregate.getDefinition().getApiCode().toLowerCase() + "." + aggregate.getDefinition().getVersion();
|
||||
}
|
||||
|
||||
private String flowId(ApiDefinitionAggregate aggregate) {
|
||||
return "apiPortalFlow:" + aggregate.getDefinition().getApiCode() + ":" + aggregate.getDefinition().getVersion();
|
||||
}
|
||||
|
||||
private interface FlowSegment {
|
||||
}
|
||||
|
||||
@Getter
|
||||
private static final class SequentialSegment implements FlowSegment {
|
||||
private final ApiStepDefinition step;
|
||||
|
||||
private SequentialSegment(ApiStepDefinition step) {
|
||||
this.step = step;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Getter
|
||||
private static final class ParallelSegment implements FlowSegment {
|
||||
private final String group;
|
||||
private final List<ApiStepDefinition> steps;
|
||||
|
||||
private ParallelSegment(String group, List<ApiStepDefinition> steps) {
|
||||
this.group = group;
|
||||
this.steps = steps;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package com.zt.plat.module.databus.framework.integration.gateway.core;
|
||||
|
||||
import com.zt.plat.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.domain.ApiDefinitionAggregate;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.model.ApiInvocationContext;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static com.zt.plat.module.databus.service.gateway.impl.GatewayServiceErrorCodeConstants.API_FLOW_NOT_FOUND;
|
||||
import static com.zt.plat.module.databus.service.gateway.impl.GatewayServiceErrorCodeConstants.API_FLOW_NO_REPLY;
|
||||
|
||||
/**
|
||||
* api 分发.
|
||||
* @author chenbowen
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class ApiFlowDispatcher {
|
||||
|
||||
private final IntegrationFlowManager integrationFlowManager;
|
||||
private final MessagingTemplate messagingTemplate;
|
||||
|
||||
public ApiInvocationContext dispatch(String apiCode, String version, ApiInvocationContext context) {
|
||||
MessageChannel channel = requireInputChannel(apiCode, version);
|
||||
Message<ApiInvocationContext> message = MessageBuilder.withPayload(context)
|
||||
.setHeader("apiCode", apiCode)
|
||||
.setHeader("version", version)
|
||||
.build();
|
||||
Message<?> reply = messagingTemplate.sendAndReceive(channel, message);
|
||||
if (reply == null) {
|
||||
throw ServiceExceptionUtil.exception(API_FLOW_NO_REPLY, apiCode, version);
|
||||
}
|
||||
return (ApiInvocationContext) reply.getPayload();
|
||||
}
|
||||
|
||||
public ApiInvocationContext dispatchWithAggregate(ApiDefinitionAggregate aggregate, ApiInvocationContext context) {
|
||||
IntegrationFlowManager.DebugFlowHandle handle = integrationFlowManager.obtainDebugHandle(aggregate);
|
||||
MessageChannel channel = handle.channel();
|
||||
Message<ApiInvocationContext> message = MessageBuilder.withPayload(context)
|
||||
.setHeader("apiCode", aggregate.getDefinition().getApiCode())
|
||||
.setHeader("version", aggregate.getDefinition().getVersion())
|
||||
.build();
|
||||
try {
|
||||
Message<?> reply = messagingTemplate.sendAndReceive(channel, message);
|
||||
if (reply == null) {
|
||||
throw ServiceExceptionUtil.exception(API_FLOW_NO_REPLY, aggregate.getDefinition().getApiCode(), aggregate.getDefinition().getVersion());
|
||||
}
|
||||
return (ApiInvocationContext) reply.getPayload();
|
||||
} finally {
|
||||
integrationFlowManager.releaseDebugHandle(handle);
|
||||
}
|
||||
}
|
||||
|
||||
private MessageChannel requireInputChannel(String apiCode, String version) {
|
||||
// 未命中时,进行一次兜底补偿查询
|
||||
return integrationFlowManager.locateInputChannel(apiCode, version)
|
||||
.or(() -> {
|
||||
integrationFlowManager.refresh(apiCode, version);
|
||||
return integrationFlowManager.locateInputChannel(apiCode, version);
|
||||
})
|
||||
.orElseThrow(() -> ServiceExceptionUtil.exception(API_FLOW_NOT_FOUND, apiCode, version));
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.zt.plat.module.databus.framework.integration.gateway.core;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
import org.springframework.integration.dsl.IntegrationFlow;
|
||||
|
||||
/**
|
||||
* Metadata returned by the assembler for flow registration.
|
||||
* @author chenbowen
|
||||
*/
|
||||
@Value
|
||||
@Builder
|
||||
public class ApiFlowRegistration {
|
||||
|
||||
String flowId;
|
||||
|
||||
String inputChannelName;
|
||||
|
||||
IntegrationFlow flow;
|
||||
|
||||
}
|
||||
@@ -1,385 +0,0 @@
|
||||
package com.zt.plat.module.databus.framework.integration.gateway.core;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.zt.plat.framework.common.util.monitor.TracerUtils;
|
||||
import com.zt.plat.framework.common.util.servlet.ServletUtils;
|
||||
import com.zt.plat.module.databus.dal.dataobject.gateway.ApiAccessLogDO;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.model.ApiInvocationContext;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.security.CachedBodyHttpServletRequest;
|
||||
import com.zt.plat.module.databus.service.gateway.ApiAccessLogService;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 将 API 调用上下文持久化为访问日志。
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class ApiGatewayAccessLogger {
|
||||
|
||||
public static final String ATTR_LOG_ID = "ApiAccessLogId";
|
||||
public static final String ATTR_EXCEPTION_STACK = "ApiAccessLogExceptionStack";
|
||||
public static final String HEADER_ACCESS_LOG_ID = "X-Databus-AccessLog-Id";
|
||||
private static final String ATTR_REQUEST_START = "ApiAccessLogRequestStart";
|
||||
|
||||
private static final int MAX_TEXT_LENGTH = 4000;
|
||||
|
||||
private final ApiAccessLogService apiAccessLogService;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* 在分发前记录请求信息。
|
||||
*/
|
||||
public void onRequest(ApiInvocationContext context) {
|
||||
try {
|
||||
ApiAccessLogDO logDO = buildRequestSnapshot(context);
|
||||
Long existingLogId = getLogId(context);
|
||||
if (existingLogId != null) {
|
||||
logDO.setId(existingLogId);
|
||||
apiAccessLogService.update(logDO);
|
||||
} else {
|
||||
Long logId = apiAccessLogService.create(logDO);
|
||||
context.getAttributes().put(ATTR_LOG_ID, logId);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
log.warn("记录 API 访问日志开始阶段失败, traceId={}", TracerUtils.getTraceId(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录异常堆栈,便于后续写入日志。
|
||||
*/
|
||||
public void onException(ApiInvocationContext context, Throwable throwable) {
|
||||
if (throwable == null) {
|
||||
return;
|
||||
}
|
||||
context.getAttributes().put(ATTR_EXCEPTION_STACK, buildStackTrace(throwable));
|
||||
}
|
||||
|
||||
/**
|
||||
* 在分发完成后补全日志信息。
|
||||
*/
|
||||
public void onResponse(ApiInvocationContext context) {
|
||||
Long logId = getLogId(context);
|
||||
if (logId == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ApiAccessLogDO update = new ApiAccessLogDO();
|
||||
update.setId(logId);
|
||||
Integer responseStatus = resolveHttpStatus(context);
|
||||
context.setResponseStatus(responseStatus);
|
||||
update.setResponseStatus(responseStatus);
|
||||
String responseMessage = resolveResponseMessage(context, responseStatus);
|
||||
update.setResponseMessage(responseMessage);
|
||||
if (!StringUtils.hasText(context.getResponseMessage()) && StringUtils.hasText(responseMessage)) {
|
||||
context.setResponseMessage(responseMessage);
|
||||
}
|
||||
update.setResponseBody(toJson(context.getResponseBody()));
|
||||
update.setStatus(resolveStatus(responseStatus));
|
||||
update.setErrorCode(extractErrorCode(context.getResponseBody(), responseStatus));
|
||||
update.setErrorMessage(resolveErrorMessage(context, responseStatus));
|
||||
update.setExceptionStack((String) context.getAttributes().get(ATTR_EXCEPTION_STACK));
|
||||
update.setStepResults(toJson(context.getStepResults()));
|
||||
update.setExtra(toJson(buildExtra(context)));
|
||||
update.setResponseTime(LocalDateTime.now());
|
||||
update.setDuration(calculateDuration(context));
|
||||
apiAccessLogService.update(update);
|
||||
} catch (Exception ex) {
|
||||
log.warn("记录 API 访问日志结束阶段失败, traceId={}, logId={}", TracerUtils.getTraceId(), logId, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全过滤阶段的第一时间记录请求元数据,保证被快速拒绝的请求也能查询。
|
||||
*/
|
||||
public Long logEntrance(HttpServletRequest request) {
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
Object existing = request.getAttribute(ATTR_LOG_ID);
|
||||
if (existing instanceof Long logId) {
|
||||
return logId;
|
||||
}
|
||||
try {
|
||||
ApiAccessLogDO logDO = new ApiAccessLogDO();
|
||||
logDO.setTraceId(TracerUtils.getTraceId());
|
||||
logDO.setRequestMethod(request.getMethod());
|
||||
logDO.setRequestPath(request.getRequestURI());
|
||||
logDO.setRequestQuery(truncate(request.getQueryString()));
|
||||
logDO.setRequestHeaders(toJson(collectHeaders(request)));
|
||||
logDO.setClientIp(ServletUtils.getClientIP(request));
|
||||
logDO.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
|
||||
logDO.setStatus(3);
|
||||
logDO.setRequestTime(LocalDateTime.now());
|
||||
logDO.setCreator("");
|
||||
logDO.setUpdater("");
|
||||
Long logId = apiAccessLogService.create(logDO);
|
||||
request.setAttribute(ATTR_LOG_ID, logId);
|
||||
request.setAttribute(ATTR_REQUEST_START, Instant.now());
|
||||
return logId;
|
||||
} catch (Exception ex) {
|
||||
log.warn("记录入口 API 访问日志失败", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 编排前即结束的请求在此补写状态码、耗时等关键信息。
|
||||
*/
|
||||
public void finalizeEarly(HttpServletRequest request, int status, String message) {
|
||||
if (request == null) {
|
||||
return;
|
||||
}
|
||||
Object existing = request.getAttribute(ATTR_LOG_ID);
|
||||
if (!(existing instanceof Long logId)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ApiAccessLogDO update = new ApiAccessLogDO();
|
||||
update.setId(logId);
|
||||
update.setResponseStatus(status);
|
||||
update.setResponseMessage(truncate(message));
|
||||
update.setStatus(resolveStatus(status));
|
||||
update.setResponseTime(LocalDateTime.now());
|
||||
update.setDuration(calculateDuration(request));
|
||||
update.setUpdater("1");
|
||||
apiAccessLogService.update(update);
|
||||
} catch (Exception ex) {
|
||||
log.warn("更新入口 API 访问日志失败, logId={}", logId, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将入口阶段生成的 logId 通过请求头继续传递,供后续流程关联合并。
|
||||
*/
|
||||
public static void propagateLogIdHeader(CachedBodyHttpServletRequest requestWrapper, Long logId) {
|
||||
if (requestWrapper == null || logId == null) {
|
||||
return;
|
||||
}
|
||||
requestWrapper.setHeader(HEADER_ACCESS_LOG_ID, String.valueOf(logId));
|
||||
}
|
||||
|
||||
private Long getLogId(ApiInvocationContext context) {
|
||||
Object value = context.getAttributes().get(ATTR_LOG_ID);
|
||||
return value instanceof Long ? (Long) value : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据编排上下文构建请求侧快照,用于访问日志首段信息。
|
||||
*/
|
||||
private ApiAccessLogDO buildRequestSnapshot(ApiInvocationContext context) {
|
||||
ApiAccessLogDO logDO = new ApiAccessLogDO();
|
||||
logDO.setTraceId(TracerUtils.getTraceId());
|
||||
logDO.setApiCode(context.getApiCode());
|
||||
logDO.setApiVersion(context.getApiVersion());
|
||||
logDO.setRequestMethod(context.getHttpMethod());
|
||||
logDO.setRequestPath(context.getRequestPath());
|
||||
logDO.setRequestQuery(toJson(context.getRequestQueryParams()));
|
||||
logDO.setRequestHeaders(toJson(context.getRequestHeaders()));
|
||||
logDO.setRequestBody(toJson(context.getRequestBody()));
|
||||
logDO.setClientIp(context.getClientIp());
|
||||
logDO.setUserAgent(GatewayHeaderUtils.findFirstHeaderValue(context.getRequestHeaders(), HttpHeaders.USER_AGENT));
|
||||
logDO.setCredentialAppId(context.getCredentialAppId());
|
||||
logDO.setCredentialId(context.getCredentialId());
|
||||
logDO.setStatus(3);
|
||||
logDO.setRequestTime(toLocalDateTime(context.getRequestTime()));
|
||||
logDO.setTenantId(parseTenantId(context.getTenantId()));
|
||||
return logDO;
|
||||
}
|
||||
|
||||
private Long calculateDuration(ApiInvocationContext context) {
|
||||
Instant start = context.getRequestTime();
|
||||
if (start == null) {
|
||||
return null;
|
||||
}
|
||||
return Duration.between(start, Instant.now()).toMillis();
|
||||
}
|
||||
|
||||
private Long calculateDuration(HttpServletRequest request) {
|
||||
Object startAttr = request.getAttribute(ATTR_REQUEST_START);
|
||||
if (startAttr instanceof Instant start) {
|
||||
return Duration.between(start, Instant.now()).toMillis();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Integer resolveStatus(Integer httpStatus) {
|
||||
if (httpStatus == null) {
|
||||
return 3;
|
||||
}
|
||||
if (httpStatus >= 200 && httpStatus < 400) {
|
||||
return 0;
|
||||
}
|
||||
if (httpStatus >= 400 && httpStatus < 500) {
|
||||
return 1;
|
||||
}
|
||||
if (httpStatus >= 500) {
|
||||
return 2;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
private String resolveErrorMessage(ApiInvocationContext context, Integer responseStatus) {
|
||||
if (!isErrorStatus(responseStatus)) {
|
||||
return null;
|
||||
}
|
||||
if (StringUtils.hasText(context.getResponseMessage())) {
|
||||
return truncate(context.getResponseMessage());
|
||||
}
|
||||
Object responseBody = context.getResponseBody();
|
||||
if (responseBody instanceof Map<?, ?> map) {
|
||||
Object message = firstNonNull(map.get("errorMessage"), map.get("message"));
|
||||
if (message != null) {
|
||||
return truncate(String.valueOf(message));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String extractErrorCode(Object responseBody, Integer responseStatus) {
|
||||
if (!isErrorStatus(responseStatus)) {
|
||||
return null;
|
||||
}
|
||||
if (responseBody instanceof Map<?, ?> map) {
|
||||
Object errorCode = firstNonNull(map.get("errorCode"), map.get("code"));
|
||||
return errorCode == null ? null : truncate(String.valueOf(errorCode));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Integer resolveHttpStatus(ApiInvocationContext context) {
|
||||
return context.getResponseStatus();
|
||||
}
|
||||
|
||||
private String resolveResponseMessage(ApiInvocationContext context, Integer responseStatus) {
|
||||
if (responseStatus == null) {
|
||||
return null;
|
||||
}
|
||||
if (StringUtils.hasText(context.getResponseMessage())) {
|
||||
return truncate(context.getResponseMessage());
|
||||
}
|
||||
HttpStatus resolved = HttpStatus.resolve(responseStatus);
|
||||
return resolved != null ? resolved.getReasonPhrase() : null;
|
||||
}
|
||||
|
||||
private boolean isErrorStatus(Integer responseStatus) {
|
||||
return responseStatus != null && responseStatus >= 400;
|
||||
}
|
||||
|
||||
private Map<String, Object> buildExtra(ApiInvocationContext context) {
|
||||
Map<String, Object> extra = new HashMap<>();
|
||||
if (!CollectionUtils.isEmpty(context.getVariables())) {
|
||||
extra.put("variables", context.getVariables());
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(context.getAttributes())) {
|
||||
Map<String, Object> attributes = new HashMap<>(context.getAttributes());
|
||||
attributes.remove(ATTR_LOG_ID);
|
||||
attributes.remove(ATTR_EXCEPTION_STACK);
|
||||
if (!attributes.isEmpty()) {
|
||||
extra.put("attributes", attributes);
|
||||
}
|
||||
}
|
||||
if (CollectionUtils.isEmpty(extra)) {
|
||||
return null;
|
||||
}
|
||||
return extra;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private <T> T firstNonNull(T... candidates) {
|
||||
if (candidates == null) {
|
||||
return null;
|
||||
}
|
||||
for (T candidate : candidates) {
|
||||
if (candidate != null) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String toJson(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof String str) {
|
||||
return truncate(str);
|
||||
}
|
||||
try {
|
||||
return truncate(objectMapper.writeValueAsString(value));
|
||||
} catch (JsonProcessingException ex) {
|
||||
return truncate(String.valueOf(value));
|
||||
}
|
||||
}
|
||||
|
||||
private String truncate(String text) {
|
||||
if (!StringUtils.hasText(text)) {
|
||||
return text;
|
||||
}
|
||||
if (text.length() <= MAX_TEXT_LENGTH) {
|
||||
return text;
|
||||
}
|
||||
return text.substring(0, MAX_TEXT_LENGTH);
|
||||
}
|
||||
|
||||
private Long parseTenantId(String tenantId) {
|
||||
if (!StringUtils.hasText(tenantId)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Long.parseLong(tenantId.trim());
|
||||
} catch (NumberFormatException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private LocalDateTime toLocalDateTime(Instant instant) {
|
||||
if (instant == null) {
|
||||
return null;
|
||||
}
|
||||
return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||
}
|
||||
|
||||
private String buildStackTrace(Throwable throwable) {
|
||||
try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) {
|
||||
throwable.printStackTrace(pw);
|
||||
return truncate(sw.toString());
|
||||
} catch (Exception ex) {
|
||||
return throwable.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> collectHeaders(HttpServletRequest request) {
|
||||
if (request == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, String> headers = new LinkedHashMap<>();
|
||||
Enumeration<String> names = request.getHeaderNames();
|
||||
while (names != null && names.hasMoreElements()) {
|
||||
String name = names.nextElement();
|
||||
Enumeration<String> values = request.getHeaders(name);
|
||||
if (values == null || !values.hasMoreElements()) {
|
||||
continue;
|
||||
}
|
||||
headers.put(name, values.nextElement());
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
package com.zt.plat.module.databus.framework.integration.gateway.core;
|
||||
|
||||
import com.zt.plat.framework.common.exception.ServiceException;
|
||||
import com.zt.plat.module.databus.framework.integration.gateway.model.ApiInvocationContext;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.zt.plat.module.databus.service.gateway.impl.GatewayServiceErrorCodeConstants.API_AUTH_UNAUTHORIZED;
|
||||
import static com.zt.plat.module.databus.service.gateway.impl.GatewayServiceErrorCodeConstants.API_CREDENTIAL_UNAUTHORIZED;
|
||||
import static com.zt.plat.module.databus.service.gateway.impl.GatewayServiceErrorCodeConstants.API_RATE_LIMIT_EXCEEDED;
|
||||
|
||||
/**
|
||||
* Shared error processor that maps exceptions into {@link ApiInvocationContext} responses.
|
||||
*/
|
||||
@Component
|
||||
public class ApiGatewayErrorProcessor {
|
||||
|
||||
/**
|
||||
* Applies the given {@link Throwable} to the context, unwrapping {@link ServiceException}
|
||||
* instances when present and falling back to a generic error payload otherwise.
|
||||
*/
|
||||
public void apply(ApiInvocationContext context, Throwable throwable) {
|
||||
ServiceException serviceException = resolveServiceException(throwable);
|
||||
if (serviceException != null) {
|
||||
applyServiceException(context, serviceException);
|
||||
} else {
|
||||
applyUnexpectedException(context, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
public void applyServiceException(ApiInvocationContext context, ServiceException ex) {
|
||||
String message = StringUtils.hasText(ex.getMessage()) ? ex.getMessage() : "API invocation failed";
|
||||
context.setResponseStatus(resolveHttpStatus(ex, context));
|
||||
context.setResponseMessage(message);
|
||||
if (context.getResponseBody() == null) {
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
if (ex.getCode() != null) {
|
||||
body.put("errorCode", ex.getCode());
|
||||
}
|
||||
body.put("errorMessage", message);
|
||||
context.setResponseBody(body);
|
||||
}
|
||||
}
|
||||
|
||||
public void applyUnexpectedException(ApiInvocationContext context, Throwable throwable) {
|
||||
String message = determineUnexpectedMessage(throwable);
|
||||
context.setResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||
context.setResponseMessage(message);
|
||||
if (context.getResponseBody() == null) {
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.put("errorMessage", message);
|
||||
body.put("exception", throwable.getClass().getSimpleName());
|
||||
context.setResponseBody(body);
|
||||
}
|
||||
}
|
||||
|
||||
public ServiceException resolveServiceException(Throwable throwable) {
|
||||
Throwable current = throwable;
|
||||
while (current != null) {
|
||||
if (current instanceof ServiceException serviceException) {
|
||||
return serviceException;
|
||||
}
|
||||
current = current.getCause();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int resolveHttpStatus(ServiceException ex, ApiInvocationContext context) {
|
||||
if (context.getResponseStatus() != null) {
|
||||
return context.getResponseStatus();
|
||||
}
|
||||
Integer code = ex.getCode();
|
||||
if (code != null) {
|
||||
if (API_AUTH_UNAUTHORIZED.getCode().equals(code)) {
|
||||
return HttpStatus.UNAUTHORIZED.value();
|
||||
}
|
||||
if (API_RATE_LIMIT_EXCEEDED.getCode().equals(code)) {
|
||||
return HttpStatus.TOO_MANY_REQUESTS.value();
|
||||
}
|
||||
if (API_CREDENTIAL_UNAUTHORIZED.getCode().equals(code)) {
|
||||
return HttpStatus.FORBIDDEN.value();
|
||||
}
|
||||
}
|
||||
return HttpStatus.INTERNAL_SERVER_ERROR.value();
|
||||
}
|
||||
|
||||
private String determineUnexpectedMessage(Throwable throwable) {
|
||||
Throwable current = throwable;
|
||||
while (current != null) {
|
||||
if (StringUtils.hasText(current.getMessage())) {
|
||||
return current.getMessage();
|
||||
}
|
||||
current = current.getCause();
|
||||
}
|
||||
return "API invocation encountered an unexpected error";
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user