feat(databus): 完成阶段一+二-数据契约层与数据提供者
阶段一:数据契约层(任务 1-16) - 新增 DatabusDeptData, DatabusAdminUserData, DatabusPostData 数据对象 - 新增 CursorPageReqDTO, CursorPageResult 游标分页 DTO - 新增 DatabusDeptProviderApi, DatabusUserProviderApi, DatabusPostProviderApi Feign 接口 - 修改 system-api pom.xml 添加 databus-api 依赖 阶段二:数据提供者实现(任务 17-38) - 新增 DatabusDeptProviderApiImpl, DatabusUserProviderApiImpl, DatabusPostProviderApiImpl Feign 接口实现 - 实现游标分页查询(基于 cursorTime + cursorId 复合游标) - 新增 DatabusDeptChangeMessage, DatabusUserChangeMessage, DatabusPostChangeMessage MQ 消息类 - 新增 DatabusChangeProducer 消息生产者(支持部门、用户、岗位三实体) - 修改 DeptServiceImpl, AdminUserServiceImpl, PostServiceImpl 添加事件发布 技术要点: - 游标分页:cursorTime + cursorId 复合游标解决雪花ID乱序问题 - 事件发布:create/update/delete 操作后异步发送 MQ 消息 - 数据聚合:用户数据包含部门和岗位简要信息 Ref: docs/databus/implementation-checklist.md 任务 1-38
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,90 @@
|
||||
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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
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);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
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);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
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);
|
||||
|
||||
}
|
||||
@@ -22,6 +22,13 @@
|
||||
<artifactId>zt-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- DataBus API -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-module-databus-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId> <!-- 接口文档:使用最新版本的 Swagger 模型 -->
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user