From cea886c9b26e1777723798fdee6985825b2910fa Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Mon, 22 Dec 2025 09:51:05 +0800 Subject: [PATCH 1/2] =?UTF-8?q?update=EF=BC=9A=E8=B0=83=E6=95=B4=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=90=8C=E6=AD=A5=E7=94=A8=E6=88=B7-=E9=83=A8?= =?UTF-8?q?=E9=97=A8=EF=BC=8C=E7=94=A8=E6=88=B7-=E5=B2=97=E4=BD=8D?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E9=A1=BA=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../provider/UserDeptDataFeignProvider.java | 81 ++++++++++ .../provider/UserPostDataFeignProvider.java | 81 ++++++++++ .../provider/DatabusUserDeptProviderApi.java | 71 ++++++++ .../provider/DatabusUserPostProviderApi.java | 71 ++++++++ .../rpc/config/RpcConfiguration.java | 9 +- .../DatabusUserDeptProviderApiImpl.java | 151 ++++++++++++++++++ .../DatabusUserPostProviderApiImpl.java | 139 ++++++++++++++++ .../module/system/api/dept/PostApiImpl.java | 4 + 8 files changed, 604 insertions(+), 3 deletions(-) create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserDeptDataFeignProvider.java create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserPostDataFeignProvider.java create mode 100644 zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserDeptProviderApi.java create mode 100644 zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserPostProviderApi.java create mode 100644 zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java create mode 100644 zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserDeptDataFeignProvider.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserDeptDataFeignProvider.java new file mode 100644 index 00000000..81f3bcf2 --- /dev/null +++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserDeptDataFeignProvider.java @@ -0,0 +1,81 @@ +package com.zt.plat.framework.databus.server.provider; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.framework.databus.server.core.provider.DataProvider; +import com.zt.plat.framework.databus.server.core.provider.DataProviderRegistry; +import com.zt.plat.module.databus.api.dto.CursorPageReqDTO; +import com.zt.plat.module.databus.api.dto.CursorPageResult; +import com.zt.plat.module.databus.api.data.DatabusUserDeptData; +import com.zt.plat.module.databus.api.provider.DatabusUserDeptProviderApi; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +/** + * 用户-部门关系数据提供者 + */ +@Slf4j +@Component +public class UserDeptDataFeignProvider implements DataProvider { + + public static final String PROVIDER_TYPE = "USER_DEPT"; + + @Resource + private DatabusUserDeptProviderApi userDeptProviderApi; + + @Resource + private DataProviderRegistry dataProviderRegistry; + + @PostConstruct + public void init() { + dataProviderRegistry.register(this); + } + + @Override + public String getProviderType() { + return PROVIDER_TYPE; + } + + @Override + public CursorPageData getPageByCursor(LocalDateTime cursorTime, Long cursorId, + int batchSize, Long tenantId) { + CursorPageReqDTO reqDTO = CursorPageReqDTO.builder() + .cursorTime(cursorTime) + .cursorId(cursorId) + .batchSize(batchSize) + .tenantId(tenantId) + .build(); + + CommonResult> result = userDeptProviderApi.getPageByCursor(reqDTO); + if (!result.isSuccess()) { + throw new RuntimeException("获取用户-部门关系数据失败: " + result.getMsg()); + } + + CursorPageResult pageResult = result.getData(); + return CursorPageData.of( + pageResult.getList(), + pageResult.getNextCursorTime(), + pageResult.getNextCursorId(), + pageResult.getCount(), + Boolean.TRUE.equals(pageResult.getHasMore()), + (pageResult.getTotal() != null ? pageResult.getTotal() : 0L) + ); + } + + @Override + public long count(Long tenantId) { + CommonResult result = userDeptProviderApi.count(tenantId); + if (!result.isSuccess()) { + throw new RuntimeException("获取用户-部门关系总数失败: " + result.getMsg()); + } + return result.getData(); + } + + @Override + public Long extractUid(DatabusUserDeptData data) { + return data.getId(); + } +} diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserPostDataFeignProvider.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserPostDataFeignProvider.java new file mode 100644 index 00000000..b7df241a --- /dev/null +++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserPostDataFeignProvider.java @@ -0,0 +1,81 @@ +package com.zt.plat.framework.databus.server.provider; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.framework.databus.server.core.provider.DataProvider; +import com.zt.plat.framework.databus.server.core.provider.DataProviderRegistry; +import com.zt.plat.module.databus.api.dto.CursorPageReqDTO; +import com.zt.plat.module.databus.api.dto.CursorPageResult; +import com.zt.plat.module.databus.api.data.DatabusUserPostData; +import com.zt.plat.module.databus.api.provider.DatabusUserPostProviderApi; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +/** + * 用户-岗位关系数据提供者 + */ +@Slf4j +@Component +public class UserPostDataFeignProvider implements DataProvider { + + public static final String PROVIDER_TYPE = "USER_POST"; + + @Resource + private DatabusUserPostProviderApi userPostProviderApi; + + @Resource + private DataProviderRegistry dataProviderRegistry; + + @PostConstruct + public void init() { + dataProviderRegistry.register(this); + } + + @Override + public String getProviderType() { + return PROVIDER_TYPE; + } + + @Override + public CursorPageData getPageByCursor(LocalDateTime cursorTime, Long cursorId, + int batchSize, Long tenantId) { + CursorPageReqDTO reqDTO = CursorPageReqDTO.builder() + .cursorTime(cursorTime) + .cursorId(cursorId) + .batchSize(batchSize) + .tenantId(tenantId) + .build(); + + CommonResult> result = userPostProviderApi.getPageByCursor(reqDTO); + if (!result.isSuccess()) { + throw new RuntimeException("获取用户-岗位关系数据失败: " + result.getMsg()); + } + + CursorPageResult pageResult = result.getData(); + return CursorPageData.of( + pageResult.getList(), + pageResult.getNextCursorTime(), + pageResult.getNextCursorId(), + pageResult.getCount(), + Boolean.TRUE.equals(pageResult.getHasMore()), + (pageResult.getTotal() != null ? pageResult.getTotal() : 0L) + ); + } + + @Override + public long count(Long tenantId) { + CommonResult result = userPostProviderApi.count(tenantId); + if (!result.isSuccess()) { + throw new RuntimeException("获取用户-岗位关系总数失败: " + result.getMsg()); + } + return result.getData(); + } + + @Override + public Long extractUid(DatabusUserPostData data) { + return data.getId(); + } +} diff --git a/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserDeptProviderApi.java b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserDeptProviderApi.java new file mode 100644 index 00000000..5e393626 --- /dev/null +++ b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserDeptProviderApi.java @@ -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.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 + *

+ * 供 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> getPageByCursor(@RequestBody CursorPageReqDTO reqDTO); + + /** + * 根据ID查询用户-部门关系详情(用于增量同步) + * + * @param id 关系ID + * @return 用户-部门关系数据 + */ + @GetMapping(PREFIX + "/get") + @Operation(summary = "查询用户-部门关系详情") + @Parameter(name = "id", description = "关系ID", required = true, example = "1001") + CommonResult 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> getListByIds(@RequestParam("ids") List ids); + + /** + * 统计用户-部门关系总数(用于全量同步进度计算) + * + * @param tenantId 租户ID(可选) + * @return 用户-部门关系总数 + */ + @GetMapping(PREFIX + "/count") + @Operation(summary = "统计用户-部门关系总数") + @Parameter(name = "tenantId", description = "租户ID", example = "1") + CommonResult count(@RequestParam(value = "tenantId", required = false) Long tenantId); + +} diff --git a/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserPostProviderApi.java b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserPostProviderApi.java new file mode 100644 index 00000000..6e00365d --- /dev/null +++ b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserPostProviderApi.java @@ -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.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 + *

+ * 供 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> getPageByCursor(@RequestBody CursorPageReqDTO reqDTO); + + /** + * 根据ID查询用户-岗位关系详情(用于增量同步) + * + * @param id 关系ID + * @return 用户-岗位关系数据 + */ + @GetMapping(PREFIX + "/get") + @Operation(summary = "查询用户-岗位关系详情") + @Parameter(name = "id", description = "关系ID", required = true, example = "1001") + CommonResult 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> getListByIds(@RequestParam("ids") List ids); + + /** + * 统计用户-岗位关系总数(用于全量同步进度计算) + * + * @param tenantId 租户ID(可选) + * @return 用户-岗位关系总数 + */ + @GetMapping(PREFIX + "/count") + @Operation(summary = "统计用户-岗位关系总数") + @Parameter(name = "tenantId", description = "租户ID", example = "1") + CommonResult count(@RequestParam(value = "tenantId", required = false) Long tenantId); + +} diff --git a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java index 32e911e1..c62e2b2d 100644 --- a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java +++ b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java @@ -4,6 +4,8 @@ import com.zt.plat.framework.common.biz.system.oauth2.OAuth2TokenCommonApi; import com.zt.plat.module.databus.api.provider.DatabusDeptProviderApi; import com.zt.plat.module.databus.api.provider.DatabusPostProviderApi; import com.zt.plat.module.databus.api.provider.DatabusUserProviderApi; +import com.zt.plat.module.databus.api.provider.DatabusUserDeptProviderApi; +import com.zt.plat.module.databus.api.provider.DatabusUserPostProviderApi; import com.zt.plat.module.system.api.dept.DeptApi; import com.zt.plat.module.system.api.dept.PostApi; import com.zt.plat.module.system.api.user.AdminUserApi; @@ -21,9 +23,10 @@ import org.springframework.context.annotation.Configuration; DatabusDeptProviderApi.class, DatabusUserProviderApi.class, DatabusPostProviderApi.class, - PostApi.class, - DeptApi.class, - AdminUserApi.class, + DatabusUserDeptProviderApi.class, + DatabusUserPostProviderApi.class, + PostApi.class, + DeptApi.class, }) public class RpcConfiguration { } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java new file mode 100644 index 00000000..15b375eb --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java @@ -0,0 +1,151 @@ +package com.zt.plat.module.system.api.databus; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +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 com.zt.plat.module.databus.api.provider.DatabusUserDeptProviderApi; +import com.zt.plat.module.system.dal.dataobject.userdept.UserDeptDO; +import com.zt.plat.module.system.dal.mysql.userdept.UserDeptMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static com.zt.plat.framework.common.pojo.CommonResult.success; + +/** + * Databus 用户-部门关系数据提供者 API 实现 + * + * @author ZT + */ +@Slf4j +@RestController +@Validated +public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderApi { + + @Resource + private UserDeptMapper userDeptMapper; + + @Override + public CommonResult> getPageByCursor(CursorPageReqDTO reqDTO) { + // 构建游标查询条件 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + + // 游标条件:create_time > cursorTime OR (create_time = cursorTime AND id > cursorId) + if (!reqDTO.isFirstPage()) { + queryWrapper.and(w -> w + .gt(UserDeptDO::getCreateTime, reqDTO.getCursorTime()) + .or(o -> o + .eq(UserDeptDO::getCreateTime, reqDTO.getCursorTime()) + .gt(UserDeptDO::getId, reqDTO.getCursorId()) + ) + ); + } + + // 租户过滤(如果指定) + if (reqDTO.getTenantId() != null) { + queryWrapper.eq(UserDeptDO::getTenantId, reqDTO.getTenantId()); + } + + // 按 create_time, id 升序排列,确保顺序稳定 + queryWrapper.orderByAsc(UserDeptDO::getCreateTime) + .orderByAsc(UserDeptDO::getId); + + // 多查一条判断是否有更多数据 + int limit = reqDTO.getBatchSize() != null ? reqDTO.getBatchSize() : 100; + queryWrapper.last("LIMIT " + (limit + 1)); + + List list = userDeptMapper.selectList(queryWrapper); + + // 判断是否有更多 + boolean hasMore = list.size() > limit; + if (hasMore) { + list = list.subList(0, limit); + } + + if (CollUtil.isEmpty(list)) { + return success(CursorPageResult.empty()); + } + + // 转换为同步数据 + List dataList = list.stream() + .map(this::convertToData) + .collect(Collectors.toList()); + + // 获取最后一条数据的游标 + UserDeptDO last = list.get(list.size() - 1); + + // 首次查询时返回总数 + Long total = null; + if (reqDTO.isFirstPage()) { + LambdaQueryWrapper countWrapper = new LambdaQueryWrapper<>(); + if (reqDTO.getTenantId() != null) { + countWrapper.eq(UserDeptDO::getTenantId, reqDTO.getTenantId()); + } + total = userDeptMapper.selectCount(countWrapper); + } + + return success(CursorPageResult.of( + dataList, + last.getCreateTime(), + last.getId(), + hasMore, + total + )); + } + + @Override + public CommonResult getById(Long id) { + UserDeptDO userDept = userDeptMapper.selectById(id); + if (userDept == null) { + return success(null); + } + return success(convertToData(userDept)); + } + + @Override + public CommonResult> getListByIds(List ids) { + if (CollUtil.isEmpty(ids)) { + return success(Collections.emptyList()); + } + + List list = userDeptMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(list)) { + return success(Collections.emptyList()); + } + + return success(list.stream() + .map(this::convertToData) + .collect(Collectors.toList())); + } + + @Override + public CommonResult count(Long tenantId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + if (tenantId != null) { + queryWrapper.eq(UserDeptDO::getTenantId, tenantId); + } + return success(userDeptMapper.selectCount(queryWrapper)); + } + + /** + * 将 UserDeptDO 转换为 DatabusUserDeptData + */ + private DatabusUserDeptData convertToData(UserDeptDO userDept) { + return DatabusUserDeptData.builder() + .id(userDept.getId()) + .userId(userDept.getUserId()) + .deptId(userDept.getDeptId()) + .tenantId(userDept.getTenantId()) + .remark(userDept.getRemark()) + .build(); + } + +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java new file mode 100644 index 00000000..96db8704 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java @@ -0,0 +1,139 @@ +package com.zt.plat.module.system.api.databus; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +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 com.zt.plat.module.databus.api.provider.DatabusUserPostProviderApi; +import com.zt.plat.module.system.dal.dataobject.dept.UserPostDO; +import com.zt.plat.module.system.dal.mysql.dept.UserPostMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static com.zt.plat.framework.common.pojo.CommonResult.success; + +/** + * Databus 用户-岗位关系数据提供者 API 实现 + * + * @author ZT + */ +@Slf4j +@RestController +@Validated +public class DatabusUserPostProviderApiImpl implements DatabusUserPostProviderApi { + + @Resource + private UserPostMapper userPostMapper; + + @Override + public CommonResult> getPageByCursor(CursorPageReqDTO reqDTO) { + // 构建游标查询条件 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + + // 游标条件:create_time > cursorTime OR (create_time = cursorTime AND id > cursorId) + if (!reqDTO.isFirstPage()) { + queryWrapper.and(w -> w + .gt(UserPostDO::getCreateTime, reqDTO.getCursorTime()) + .or(o -> o + .eq(UserPostDO::getCreateTime, reqDTO.getCursorTime()) + .gt(UserPostDO::getId, reqDTO.getCursorId()) + ) + ); + } + + // 注意:UserPostDO 没有租户字段,忽略 tenantId 过滤 + + // 按 create_time, id 升序排列,确保顺序稳定 + queryWrapper.orderByAsc(UserPostDO::getCreateTime) + .orderByAsc(UserPostDO::getId); + + // 多查一条判断是否有更多数据 + int limit = reqDTO.getBatchSize() != null ? reqDTO.getBatchSize() : 100; + queryWrapper.last("LIMIT " + (limit + 1)); + + List list = userPostMapper.selectList(queryWrapper); + + // 判断是否有更多 + boolean hasMore = list.size() > limit; + if (hasMore) { + list = list.subList(0, limit); + } + + if (CollUtil.isEmpty(list)) { + return success(CursorPageResult.empty()); + } + + // 转换为同步数据 + List dataList = list.stream() + .map(this::convertToData) + .collect(Collectors.toList()); + + // 获取最后一条数据的游标 + UserPostDO last = list.get(list.size() - 1); + + // 首次查询时返回总数 + Long total = null; + if (reqDTO.isFirstPage()) { + total = userPostMapper.selectCount(new LambdaQueryWrapper<>()); + } + + return success(CursorPageResult.of( + dataList, + last.getCreateTime(), + last.getId(), + hasMore, + total + )); + } + + @Override + public CommonResult getById(Long id) { + UserPostDO userPost = userPostMapper.selectById(id); + if (userPost == null) { + return success(null); + } + return success(convertToData(userPost)); + } + + @Override + public CommonResult> getListByIds(List ids) { + if (CollUtil.isEmpty(ids)) { + return success(Collections.emptyList()); + } + + List list = userPostMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(list)) { + return success(Collections.emptyList()); + } + + return success(list.stream() + .map(this::convertToData) + .collect(Collectors.toList())); + } + + @Override + public CommonResult count(Long tenantId) { + // 注意:UserPostDO 没有租户字段,返回全量总数 + return success(userPostMapper.selectCount(new LambdaQueryWrapper<>())); + } + + /** + * 将 UserPostDO 转换为 DatabusUserPostData + */ + private DatabusUserPostData convertToData(UserPostDO userPost) { + return DatabusUserPostData.builder() + .id(userPost.getId()) + .userId(userPost.getUserId()) + .postId(userPost.getPostId()) + .build(); + } + +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java index 40c7e22b..97cf029e 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java @@ -10,6 +10,7 @@ import com.zt.plat.module.system.controller.admin.dept.vo.post.PostSaveReqVO; import com.zt.plat.module.system.dal.dataobject.dept.PostDO; import com.zt.plat.module.system.service.dept.PostService; import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RestController; @@ -20,6 +21,7 @@ import java.util.List; import static com.zt.plat.framework.common.pojo.CommonResult.success; +@Slf4j @RestController // 提供 RESTful API 接口,给 Feign 调用 @Validated public class PostApiImpl implements PostApi { @@ -36,6 +38,7 @@ public class PostApiImpl implements PostApi { @Override public CommonResult updatePost(PostSaveReqDTO updateReqVO) { + log.error("ssssssssss"); PostSaveReqVO reqVO = BeanUtils.toBean(updateReqVO, PostSaveReqVO.class); postService.updatePost(reqVO); return success(true); @@ -49,6 +52,7 @@ public class PostApiImpl implements PostApi { @Override public CommonResult getPost(Long id) { + log.error("cccccccc"+id); PostDO post = postService.getPost(id); return success(BeanUtils.toBean(post, PostRespDTO.class)); } From 0bdded447a97926ac90a8be7ad1a5ed7934fbac3 Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Mon, 22 Dec 2025 11:03:15 +0800 Subject: [PATCH 2/2] =?UTF-8?q?update=EF=BC=9A=E8=B0=83=E6=95=B4=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=90=8C=E6=AD=A5=E7=94=A8=E6=88=B7-=E9=83=A8?= =?UTF-8?q?=E9=97=A8=EF=BC=8C=E7=94=A8=E6=88=B7-=E5=B2=97=E4=BD=8D?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E9=A1=BA=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../userdept/UserDeptSyncServiceImpl.java | 85 ++++++++++++++----- .../userpost/UserPostSyncServiceImpl.java | 84 +++++++++++++----- .../consumer/DatabusUserChangeConsumer.java | 10 ++- .../rpc/config/RpcConfiguration.java | 4 + .../system/api/userdept/UserDeptApi.java | 64 ++++++++++++++ .../api/userdept/dto/UserDeptRespDTO.java | 31 +++++++ .../api/userdept/dto/UserDeptSaveReqDTO.java | 26 ++++++ .../system/api/userpost/UserPostApi.java | 64 ++++++++++++++ .../api/userpost/dto/UserPostRespDTO.java | 28 ++++++ .../api/userpost/dto/UserPostSaveReqDTO.java | 23 +++++ .../DatabusUserDeptProviderApiImpl.java | 48 +++-------- .../DatabusUserPostProviderApiImpl.java | 36 +++----- .../databus/DatabusUserProviderApiImpl.java | 7 ++ .../system/dal/mysql/dept/UserPostMapper.java | 43 ++++++++++ .../dal/mysql/userdept/UserDeptMapper.java | 43 ++++++++++ 15 files changed, 494 insertions(+), 102 deletions(-) create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptRespDTO.java create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptSaveReqDTO.java create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostRespDTO.java create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostSaveReqDTO.java diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java index 9027e379..04f16ae4 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java +++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java @@ -1,56 +1,101 @@ package com.zt.plat.framework.databus.client.handler.userdept; import com.zt.plat.module.databus.api.data.DatabusUserDeptData; +import com.zt.plat.module.system.api.userdept.UserDeptApi; +import com.zt.plat.module.system.api.userdept.dto.UserDeptSaveReqDTO; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; /** - * 用户-部门关系同步服务实现 + * 用户-部门关系同步服务实现(通过 Feign API 调用远程服务) *

* 使用条件: * 1. zt.databus.sync.client.enabled=true + * 2. 系统中存在 UserDeptApi 接口(Feign 客户端) *

- * 注意:由于用户-部门关系通常集成在用户管理中,此实现为占位符。 - * 分公司可以根据实际情况: - * 1. 自定义实现此接口,直接操作本地数据库 - * 2. 或者通过用户管理 API 间接处理关联关系 + * 如果分公司需要自定义实现,可以创建自己的 UserDeptSyncService Bean, + * 此默认实现会自动失效(@ConditionalOnMissingBean) * * @author ZT */ @Slf4j @Service @ConditionalOnProperty(prefix = "zt.databus.sync.client", name = "enabled", havingValue = "true") +@ConditionalOnClass(name = "com.zt.plat.module.system.api.userdept.UserDeptApi") public class UserDeptSyncServiceImpl implements UserDeptSyncService { + @Autowired(required = false) + private UserDeptApi userDeptApi; // Feign 远程调用接口 + @Override public void create(DatabusUserDeptData data) { - log.info("[UserDeptSync] 收到创建用户-部门关系请求, userId={}, deptId={}", - data.getUserId(), data.getDeptId()); - log.warn("[UserDeptSync] 用户-部门关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法,通过本地 API 或直接数据库操作完成同步 + if (userDeptApi == null) { + log.warn("[UserDeptSync] UserDeptApi未注入,跳过创建用户-部门关系, userId={}", data.getUserId()); + return; + } + UserDeptSaveReqDTO dto = buildUserDeptDTO(data); + userDeptApi.createUserDept(dto).checkError(); + log.info("[UserDeptSync] 用户-部门关系创建成功, userId={}, deptId={}", data.getUserId(), data.getDeptId()); } @Override public void update(DatabusUserDeptData data) { - log.info("[UserDeptSync] 收到更新用户-部门关系请求, userId={}, deptId={}", - data.getUserId(), data.getDeptId()); - log.warn("[UserDeptSync] 用户-部门关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法 + if (userDeptApi == null) { + log.warn("[UserDeptSync] UserDeptApi未注入,跳过更新用户-部门关系, userId={}", data.getUserId()); + return; + } + UserDeptSaveReqDTO dto = buildUserDeptDTO(data); + userDeptApi.updateUserDept(dto).checkError(); + log.info("[UserDeptSync] 用户-部门关系更新成功, userId={}, deptId={}", data.getUserId(), data.getDeptId()); } @Override public void delete(Long id) { - log.info("[UserDeptSync] 收到删除用户-部门关系请求, id={}", id); - log.warn("[UserDeptSync] 用户-部门关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法 + if (userDeptApi == null) { + log.warn("[UserDeptSync] UserDeptApi未注入,跳过删除用户-部门关系, id={}", id); + return; + } + userDeptApi.deleteUserDept(id).checkError(); + log.info("[UserDeptSync] 用户-部门关系删除成功, id={}", id); } @Override public void fullSync(DatabusUserDeptData data) { - log.info("[UserDeptSync] 收到全量同步用户-部门关系请求, userId={}, deptId={}", - data.getUserId(), data.getDeptId()); - log.warn("[UserDeptSync] 用户-部门关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法,逻辑:存在则更新,不存在则插入 + if (userDeptApi == null) { + log.warn("[UserDeptSync] UserDeptApi未注入,跳过全量同步用户-部门关系, userId={}", data.getUserId()); + return; + } + UserDeptSaveReqDTO dto = buildUserDeptDTO(data); + try { + // 尝试获取,存在则更新,不存在则创建 + var existing = userDeptApi.getUserDept(dto.getId()); + if (existing.isSuccess() && existing.getData() != null) { + userDeptApi.updateUserDept(dto).checkError(); + log.info("[UserDeptSync] 用户-部门关系全量同步-更新成功, id={}", dto.getId()); + } else { + userDeptApi.createUserDept(dto).checkError(); + log.info("[UserDeptSync] 用户-部门关系全量同步-创建成功, id={}", dto.getId()); + } + } catch (Exception e) { + // 获取失败,尝试创建 + log.warn("[UserDeptSync] 用户-部门关系获取失败,尝试创建, id={}", dto.getId()); + userDeptApi.createUserDept(dto).checkError(); + log.info("[UserDeptSync] 用户-部门关系全量同步-创建成功, id={}", dto.getId()); + } + } + + /** + * 构建用户部门关系 DTO(用于 Feign 调用) + */ + private UserDeptSaveReqDTO buildUserDeptDTO(DatabusUserDeptData data) { + UserDeptSaveReqDTO dto = new UserDeptSaveReqDTO(); + dto.setId(data.getId()); + dto.setUserId(data.getUserId()); + dto.setDeptId(data.getDeptId()); + dto.setRemark(data.getRemark()); + return dto; } } diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java index b41d6ac8..01eb2b4b 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java +++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java @@ -1,56 +1,100 @@ package com.zt.plat.framework.databus.client.handler.userpost; import com.zt.plat.module.databus.api.data.DatabusUserPostData; +import com.zt.plat.module.system.api.userpost.UserPostApi; +import com.zt.plat.module.system.api.userpost.dto.UserPostSaveReqDTO; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; /** - * 用户-岗位关系同步服务实现 + * 用户-岗位关系同步服务实现(通过 Feign API 调用远程服务) *

* 使用条件: * 1. zt.databus.sync.client.enabled=true + * 2. 系统中存在 UserPostApi 接口(Feign 客户端) *

- * 注意:由于用户-岗位关系通常集成在用户管理中,此实现为占位符。 - * 分公司可以根据实际情况: - * 1. 自定义实现此接口,直接操作本地数据库 - * 2. 或者通过用户管理 API 间接处理关联关系 + * 如果分公司需要自定义实现,可以创建自己的 UserPostSyncService Bean, + * 此默认实现会自动失效(@ConditionalOnMissingBean) * * @author ZT */ @Slf4j @Service @ConditionalOnProperty(prefix = "zt.databus.sync.client", name = "enabled", havingValue = "true") +@ConditionalOnClass(name = "com.zt.plat.module.system.api.userpost.UserPostApi") public class UserPostSyncServiceImpl implements UserPostSyncService { + @Autowired(required = false) + private UserPostApi userPostApi; // Feign 远程调用接口 + @Override public void create(DatabusUserPostData data) { - log.info("[UserPostSync] 收到创建用户-岗位关系请求, userId={}, postId={}", - data.getUserId(), data.getPostId()); - log.warn("[UserPostSync] 用户-岗位关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法,通过本地 API 或直接数据库操作完成同步 + if (userPostApi == null) { + log.warn("[UserPostSync] UserPostApi未注入,跳过创建用户-岗位关系, userId={}", data.getUserId()); + return; + } + UserPostSaveReqDTO dto = buildUserPostDTO(data); + userPostApi.createUserPost(dto).checkError(); + log.info("[UserPostSync] 用户-岗位关系创建成功, userId={}, postId={}", data.getUserId(), data.getPostId()); } @Override public void update(DatabusUserPostData data) { - log.info("[UserPostSync] 收到更新用户-岗位关系请求, userId={}, postId={}", - data.getUserId(), data.getPostId()); - log.warn("[UserPostSync] 用户-岗位关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法 + if (userPostApi == null) { + log.warn("[UserPostSync] UserPostApi未注入,跳过更新用户-岗位关系, userId={}", data.getUserId()); + return; + } + UserPostSaveReqDTO dto = buildUserPostDTO(data); + userPostApi.updateUserPost(dto).checkError(); + log.info("[UserPostSync] 用户-岗位关系更新成功, userId={}, postId={}", data.getUserId(), data.getPostId()); } @Override public void delete(Long id) { - log.info("[UserPostSync] 收到删除用户-岗位关系请求, id={}", id); - log.warn("[UserPostSync] 用户-岗位关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法 + if (userPostApi == null) { + log.warn("[UserPostSync] UserPostApi未注入,跳过删除用户-岗位关系, id={}", id); + return; + } + userPostApi.deleteUserPost(id).checkError(); + log.info("[UserPostSync] 用户-岗位关系删除成功, id={}", id); } @Override public void fullSync(DatabusUserPostData data) { - log.info("[UserPostSync] 收到全量同步用户-岗位关系请求, userId={}, postId={}", - data.getUserId(), data.getPostId()); - log.warn("[UserPostSync] 用户-岗位关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法,逻辑:存在则更新,不存在则插入 + if (userPostApi == null) { + log.warn("[UserPostSync] UserPostApi未注入,跳过全量同步用户-岗位关系, userId={}", data.getUserId()); + return; + } + UserPostSaveReqDTO dto = buildUserPostDTO(data); + try { + // 尝试获取,存在则更新,不存在则创建 + var existing = userPostApi.getUserPost(dto.getId()); + if (existing.isSuccess() && existing.getData() != null) { + userPostApi.updateUserPost(dto).checkError(); + log.info("[UserPostSync] 用户-岗位关系全量同步-更新成功, id={}", dto.getId()); + } else { + userPostApi.createUserPost(dto).checkError(); + log.info("[UserPostSync] 用户-岗位关系全量同步-创建成功, id={}", dto.getId()); + } + } catch (Exception e) { + // 获取失败,尝试创建 + log.warn("[UserPostSync] 用户-岗位关系获取失败,尝试创建, id={}", dto.getId()); + userPostApi.createUserPost(dto).checkError(); + log.info("[UserPostSync] 用户-岗位关系全量同步-创建成功, id={}", dto.getId()); + } + } + + /** + * 构建用户岗位关系 DTO(用于 Feign 调用) + */ + private UserPostSaveReqDTO buildUserPostDTO(DatabusUserPostData data) { + UserPostSaveReqDTO dto = new UserPostSaveReqDTO(); + dto.setId(data.getId()); + dto.setUserId(data.getUserId()); + dto.setPostId(data.getPostId()); + return dto; } } diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/consumer/DatabusUserChangeConsumer.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/consumer/DatabusUserChangeConsumer.java index dd3a52e0..43fd8e97 100644 --- a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/consumer/DatabusUserChangeConsumer.java +++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/consumer/DatabusUserChangeConsumer.java @@ -34,7 +34,15 @@ public class DatabusUserChangeConsumer implements RocketMQListener dataMap = new HashMap<>(); diff --git a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java index c62e2b2d..d79beb52 100644 --- a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java +++ b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java @@ -9,6 +9,8 @@ import com.zt.plat.module.databus.api.provider.DatabusUserPostProviderApi; import com.zt.plat.module.system.api.dept.DeptApi; import com.zt.plat.module.system.api.dept.PostApi; import com.zt.plat.module.system.api.user.AdminUserApi; +import com.zt.plat.module.system.api.userdept.UserDeptApi; +import com.zt.plat.module.system.api.userpost.UserPostApi; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Configuration; @@ -27,6 +29,8 @@ import org.springframework.context.annotation.Configuration; DatabusUserPostProviderApi.class, PostApi.class, DeptApi.class, + UserDeptApi.class, + UserPostApi.class, }) public class RpcConfiguration { } diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java new file mode 100644 index 00000000..d48c6b69 --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java @@ -0,0 +1,64 @@ +package com.zt.plat.module.system.api.userdept; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.module.system.api.userdept.dto.UserDeptRespDTO; +import com.zt.plat.module.system.api.userdept.dto.UserDeptSaveReqDTO; +import com.zt.plat.module.system.enums.ApiConstants; +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.Collection; +import java.util.List; + +/** + * 用户-部门关系 Feign API + * + * @author ZT + */ +@FeignClient(name = ApiConstants.NAME) +@Tag(name = "RPC 服务 - 用户部门关系") +public interface UserDeptApi { + + String PREFIX = ApiConstants.PREFIX + "/user-dept"; + + @PostMapping(PREFIX + "/create") + @Operation(summary = "新增用户部门关系") + CommonResult createUserDept(@RequestBody UserDeptSaveReqDTO reqVO); + + @PutMapping(PREFIX + "/update") + @Operation(summary = "修改用户部门关系") + CommonResult updateUserDept(@RequestBody UserDeptSaveReqDTO reqVO); + + @DeleteMapping(PREFIX + "/delete") + @Operation(summary = "删除用户部门关系") + @Parameter(name = "id", description = "关系编号", example = "1", required = true) + CommonResult deleteUserDept(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/get") + @Operation(summary = "通过ID查询用户部门关系") + @Parameter(name = "id", description = "关系编号", example = "1", required = true) + CommonResult getUserDept(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/list-by-user-id") + @Operation(summary = "通过用户ID查询用户部门关系列表") + @Parameter(name = "userId", description = "用户编号", example = "1", required = true) + CommonResult> getUserDeptListByUserId(@RequestParam("userId") Long userId); + + @GetMapping(PREFIX + "/list-by-dept-id") + @Operation(summary = "通过部门ID查询用户部门关系列表") + @Parameter(name = "deptId", description = "部门编号", example = "1", required = true) + CommonResult> getUserDeptListByDeptId(@RequestParam("deptId") Long deptId); + + @DeleteMapping(PREFIX + "/delete-by-user-id") + @Operation(summary = "通过用户ID删除用户部门关系") + @Parameter(name = "userId", description = "用户编号", example = "1", required = true) + CommonResult deleteUserDeptByUserId(@RequestParam("userId") Long userId); + + @DeleteMapping(PREFIX + "/delete-by-dept-id") + @Operation(summary = "通过部门ID删除用户部门关系") + @Parameter(name = "deptId", description = "部门编号", example = "1", required = true) + CommonResult deleteUserDeptByDeptId(@RequestParam("deptId") Long deptId); +} diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptRespDTO.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptRespDTO.java new file mode 100644 index 00000000..5a558b90 --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptRespDTO.java @@ -0,0 +1,31 @@ +package com.zt.plat.module.system.api.userdept.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 用户部门关系 Response DTO + * + * @author ZT + */ +@Schema(description = "RPC 服务 - 用户部门关系 Response DTO") +@Data +public class UserDeptRespDTO { + + @Schema(description = "关系编号", example = "1024") + private Long id; + + @Schema(description = "用户编号", example = "1") + private Long userId; + + @Schema(description = "部门编号", example = "100") + private Long deptId; + + @Schema(description = "备注", example = "主部门") + private String remark; + + @Schema(description = "创建时间") + private LocalDateTime createTime; +} diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptSaveReqDTO.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptSaveReqDTO.java new file mode 100644 index 00000000..b18f2a56 --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptSaveReqDTO.java @@ -0,0 +1,26 @@ +package com.zt.plat.module.system.api.userdept.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 用户部门关系创建/修改 Request DTO + * + * @author ZT + */ +@Schema(description = "RPC 服务 - 用户部门关系创建/修改 Request DTO") +@Data +public class UserDeptSaveReqDTO { + + @Schema(description = "关系编号", example = "1024") + private Long id; + + @Schema(description = "用户编号", example = "1", required = true) + private Long userId; + + @Schema(description = "部门编号", example = "100", required = true) + private Long deptId; + + @Schema(description = "备注", example = "主部门") + private String remark; +} diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java new file mode 100644 index 00000000..a58e09cb --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java @@ -0,0 +1,64 @@ +package com.zt.plat.module.system.api.userpost; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.module.system.api.userpost.dto.UserPostRespDTO; +import com.zt.plat.module.system.api.userpost.dto.UserPostSaveReqDTO; +import com.zt.plat.module.system.enums.ApiConstants; +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.Collection; +import java.util.List; + +/** + * 用户-岗位关系 Feign API + * + * @author ZT + */ +@FeignClient(name = ApiConstants.NAME) +@Tag(name = "RPC 服务 - 用户岗位关系") +public interface UserPostApi { + + String PREFIX = ApiConstants.PREFIX + "/user-post"; + + @PostMapping(PREFIX + "/create") + @Operation(summary = "新增用户岗位关系") + CommonResult createUserPost(@RequestBody UserPostSaveReqDTO reqVO); + + @PutMapping(PREFIX + "/update") + @Operation(summary = "修改用户岗位关系") + CommonResult updateUserPost(@RequestBody UserPostSaveReqDTO reqVO); + + @DeleteMapping(PREFIX + "/delete") + @Operation(summary = "删除用户岗位关系") + @Parameter(name = "id", description = "关系编号", example = "1", required = true) + CommonResult deleteUserPost(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/get") + @Operation(summary = "通过ID查询用户岗位关系") + @Parameter(name = "id", description = "关系编号", example = "1", required = true) + CommonResult getUserPost(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/list-by-user-id") + @Operation(summary = "通过用户ID查询用户岗位关系列表") + @Parameter(name = "userId", description = "用户编号", example = "1", required = true) + CommonResult> getUserPostListByUserId(@RequestParam("userId") Long userId); + + @GetMapping(PREFIX + "/list-by-post-id") + @Operation(summary = "通过岗位ID查询用户岗位关系列表") + @Parameter(name = "postId", description = "岗位编号", example = "1", required = true) + CommonResult> getUserPostListByPostId(@RequestParam("postId") Long postId); + + @DeleteMapping(PREFIX + "/delete-by-user-id") + @Operation(summary = "通过用户ID删除用户岗位关系") + @Parameter(name = "userId", description = "用户编号", example = "1", required = true) + CommonResult deleteUserPostByUserId(@RequestParam("userId") Long userId); + + @DeleteMapping(PREFIX + "/delete-by-post-id") + @Operation(summary = "通过岗位ID删除用户岗位关系") + @Parameter(name = "postId", description = "岗位编号", example = "1", required = true) + CommonResult deleteUserPostByPostId(@RequestParam("postId") Long postId); +} diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostRespDTO.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostRespDTO.java new file mode 100644 index 00000000..e7251a61 --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostRespDTO.java @@ -0,0 +1,28 @@ +package com.zt.plat.module.system.api.userpost.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 用户岗位关系 Response DTO + * + * @author ZT + */ +@Schema(description = "RPC 服务 - 用户岗位关系 Response DTO") +@Data +public class UserPostRespDTO { + + @Schema(description = "关系编号", example = "1024") + private Long id; + + @Schema(description = "用户编号", example = "1") + private Long userId; + + @Schema(description = "岗位编号", example = "100") + private Long postId; + + @Schema(description = "创建时间") + private LocalDateTime createTime; +} diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostSaveReqDTO.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostSaveReqDTO.java new file mode 100644 index 00000000..4ad5af68 --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostSaveReqDTO.java @@ -0,0 +1,23 @@ +package com.zt.plat.module.system.api.userpost.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 用户岗位关系创建/修改 Request DTO + * + * @author ZT + */ +@Schema(description = "RPC 服务 - 用户岗位关系创建/修改 Request DTO") +@Data +public class UserPostSaveReqDTO { + + @Schema(description = "关系编号", example = "1024") + private Long id; + + @Schema(description = "用户编号", example = "1", required = true) + private Long userId; + + @Schema(description = "岗位编号", example = "100", required = true) + private Long postId; +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java index 15b375eb..3a461df9 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java @@ -35,34 +35,16 @@ public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderAp @Override public CommonResult> getPageByCursor(CursorPageReqDTO reqDTO) { - // 构建游标查询条件 - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - - // 游标条件:create_time > cursorTime OR (create_time = cursorTime AND id > cursorId) - if (!reqDTO.isFirstPage()) { - queryWrapper.and(w -> w - .gt(UserDeptDO::getCreateTime, reqDTO.getCursorTime()) - .or(o -> o - .eq(UserDeptDO::getCreateTime, reqDTO.getCursorTime()) - .gt(UserDeptDO::getId, reqDTO.getCursorId()) - ) - ); - } - - // 租户过滤(如果指定) - if (reqDTO.getTenantId() != null) { - queryWrapper.eq(UserDeptDO::getTenantId, reqDTO.getTenantId()); - } - - // 按 create_time, id 升序排列,确保顺序稳定 - queryWrapper.orderByAsc(UserDeptDO::getCreateTime) - .orderByAsc(UserDeptDO::getId); - // 多查一条判断是否有更多数据 int limit = reqDTO.getBatchSize() != null ? reqDTO.getBatchSize() : 100; - queryWrapper.last("LIMIT " + (limit + 1)); - List list = userDeptMapper.selectList(queryWrapper); + // ⚠️ 使用关联查询,只查询 userSource = 2 的用户的部门关系 + List list = userDeptMapper.selectPageByCursorWithUserSource( + reqDTO.isFirstPage() ? null : reqDTO.getCursorTime(), + reqDTO.isFirstPage() ? null : reqDTO.getCursorId(), + reqDTO.getTenantId(), + limit + 1 + ); // 判断是否有更多 boolean hasMore = list.size() > limit; @@ -82,14 +64,11 @@ public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderAp // 获取最后一条数据的游标 UserDeptDO last = list.get(list.size() - 1); - // 首次查询时返回总数 + // 首次查询时返���总数 Long total = null; if (reqDTO.isFirstPage()) { - LambdaQueryWrapper countWrapper = new LambdaQueryWrapper<>(); - if (reqDTO.getTenantId() != null) { - countWrapper.eq(UserDeptDO::getTenantId, reqDTO.getTenantId()); - } - total = userDeptMapper.selectCount(countWrapper); + // ⚠️ 只统计 userSource = 2 的用户的部门关系 + total = userDeptMapper.countWithUserSource(reqDTO.getTenantId()); } return success(CursorPageResult.of( @@ -128,11 +107,8 @@ public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderAp @Override public CommonResult count(Long tenantId) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - if (tenantId != null) { - queryWrapper.eq(UserDeptDO::getTenantId, tenantId); - } - return success(userDeptMapper.selectCount(queryWrapper)); + // ⚠️ 只统计 userSource = 2 的用户的部门关系 + return success(userDeptMapper.countWithUserSource(tenantId)); } /** diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java index 96db8704..faabe471 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java @@ -35,31 +35,16 @@ public class DatabusUserPostProviderApiImpl implements DatabusUserPostProviderAp @Override public CommonResult> getPageByCursor(CursorPageReqDTO reqDTO) { - // 构建游标查询条件 - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - - // 游标条件:create_time > cursorTime OR (create_time = cursorTime AND id > cursorId) - if (!reqDTO.isFirstPage()) { - queryWrapper.and(w -> w - .gt(UserPostDO::getCreateTime, reqDTO.getCursorTime()) - .or(o -> o - .eq(UserPostDO::getCreateTime, reqDTO.getCursorTime()) - .gt(UserPostDO::getId, reqDTO.getCursorId()) - ) - ); - } - - // 注意:UserPostDO 没有租户字段,忽略 tenantId 过滤 - - // 按 create_time, id 升序排列,确保顺序稳定 - queryWrapper.orderByAsc(UserPostDO::getCreateTime) - .orderByAsc(UserPostDO::getId); - // 多查一条判断是否有更多数据 int limit = reqDTO.getBatchSize() != null ? reqDTO.getBatchSize() : 100; - queryWrapper.last("LIMIT " + (limit + 1)); - List list = userPostMapper.selectList(queryWrapper); + // ⚠️ 使用关联查询,只查询 userSource = 2 的用户的岗位关系 + List list = userPostMapper.selectPageByCursorWithUserSource( + reqDTO.isFirstPage() ? null : reqDTO.getCursorTime(), + reqDTO.isFirstPage() ? null : reqDTO.getCursorId(), + reqDTO.getTenantId(), + limit + 1 + ); // 判断是否有更多 boolean hasMore = list.size() > limit; @@ -82,7 +67,8 @@ public class DatabusUserPostProviderApiImpl implements DatabusUserPostProviderAp // 首次查询时返回总数 Long total = null; if (reqDTO.isFirstPage()) { - total = userPostMapper.selectCount(new LambdaQueryWrapper<>()); + // ⚠️ 只统计 userSource = 2 的用户的岗位关系 + total = userPostMapper.countWithUserSource(reqDTO.getTenantId()); } return success(CursorPageResult.of( @@ -121,8 +107,8 @@ public class DatabusUserPostProviderApiImpl implements DatabusUserPostProviderAp @Override public CommonResult count(Long tenantId) { - // 注意:UserPostDO 没有租户字段,返回全量总数 - return success(userPostMapper.selectCount(new LambdaQueryWrapper<>())); + // ⚠️ 只统计 userSource = 2 的用户的岗位关系 + return success(userPostMapper.countWithUserSource(tenantId)); } /** diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserProviderApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserProviderApiImpl.java index 286b9984..f6b9050a 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserProviderApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserProviderApiImpl.java @@ -54,6 +54,9 @@ public class DatabusUserProviderApiImpl implements DatabusUserProviderApi { // 构建游标查询条件 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + // ⚠️ 只同步 userSource = 2 的用户 + queryWrapper.eq(AdminUserDO::getUserSource, 2); + // 游标条件:create_time > cursorTime OR (create_time = cursorTime AND id > cursorId) if (!reqDTO.isFirstPage()) { queryWrapper.and(w -> w @@ -100,6 +103,8 @@ public class DatabusUserProviderApiImpl implements DatabusUserProviderApi { Long total = null; if (reqDTO.isFirstPage()) { LambdaQueryWrapper countWrapper = new LambdaQueryWrapper<>(); + // ⚠️ 只统计 userSource = 2 的用户 + countWrapper.eq(AdminUserDO::getUserSource, 2); if (reqDTO.getTenantId() != null) { countWrapper.eq(AdminUserDO::getTenantId, reqDTO.getTenantId()); } @@ -143,6 +148,8 @@ public class DatabusUserProviderApiImpl implements DatabusUserProviderApi { @Override public CommonResult count(Long tenantId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + // ⚠️ 只统计 userSource = 2 的用户 + queryWrapper.eq(AdminUserDO::getUserSource, 2); if (tenantId != null) { queryWrapper.eq(AdminUserDO::getTenantId, tenantId); } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/UserPostMapper.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/UserPostMapper.java index fa9bd6aa..2df5c891 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/UserPostMapper.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/UserPostMapper.java @@ -5,7 +5,10 @@ import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX; import com.zt.plat.module.system.dal.dataobject.dept.UserPostDO; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import java.time.LocalDateTime; import java.util.Collection; import java.util.List; @@ -29,4 +32,44 @@ public interface UserPostMapper extends BaseMapperX { default void deleteByUserId(Long userId) { delete(Wrappers.lambdaUpdate(UserPostDO.class).eq(UserPostDO::getUserId, userId)); } + + /** + * 游标分页查询用户-岗位关系(只查询 userSource = 2 的用户) + * @param cursorTime 游标时间 + * @param cursorId 游标ID + * @param tenantId 租户ID(可选) + * @param limit 限制数量 + * @return 用户岗位关系列表 + */ + @Select("") + List selectPageByCursorWithUserSource(@Param("cursorTime") LocalDateTime cursorTime, + @Param("cursorId") Long cursorId, + @Param("tenantId") Long tenantId, + @Param("limit") Integer limit); + + /** + * 统计用户-岗位关系数量(只统计 userSource = 2 的用户) + * @param tenantId 租户ID(可选) + * @return 数量 + */ + @Select("") + Long countWithUserSource(@Param("tenantId") Long tenantId); } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/userdept/UserDeptMapper.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/userdept/UserDeptMapper.java index b9aad69a..bf21f41d 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/userdept/UserDeptMapper.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/userdept/UserDeptMapper.java @@ -4,7 +4,10 @@ import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX; import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX; import com.zt.plat.module.system.dal.dataobject.userdept.UserDeptDO; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import java.time.LocalDateTime; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -45,4 +48,44 @@ public interface UserDeptMapper extends BaseMapperX { ); } + /** + * 游标分页查询用户-部门关系(只查询 userSource = 2 的用户) + * @param cursorTime 游标时间 + * @param cursorId 游标ID + * @param tenantId 租户ID(可选) + * @param limit 限制数量 + * @return 用户部门关系列表 + */ + @Select("") + List selectPageByCursorWithUserSource(@Param("cursorTime") LocalDateTime cursorTime, + @Param("cursorId") Long cursorId, + @Param("tenantId") Long tenantId, + @Param("limit") Integer limit); + + /** + * 统计用户-部门关系数量(只统计 userSource = 2 的用户) + * @param tenantId 租户ID(可选) + * @return 数量 + */ + @Select("") + Long countWithUserSource(@Param("tenantId") Long tenantId); + } \ No newline at end of file