From db13036ceac6c097cd1279ae570d7704c3757faf Mon Sep 17 00:00:00 2001
From: hewencai <2357300448@qq.com>
Date: Mon, 1 Dec 2025 23:44:32 +0800
Subject: [PATCH] =?UTF-8?q?feat(databus):=20=E5=AE=8C=E6=88=90=E9=98=B6?=
=?UTF-8?q?=E6=AE=B5=E5=9B=9B-DataBus=20Server=E5=AE=8C=E6=95=B4=E5=8A=9F?=
=?UTF-8?q?=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 补充缺失的 API 类(DatabusMessage、DatabusBatchMessage、DatabusEventType)
- 新增变更消息消费者(3个:部门、用户、岗位)
- 新增数据提供者(3个:部门、用户、岗位)
- 确认分发器服务(核心定向推送逻辑)
- 确认全量同步与消息推送组件
- 确认管理后台 API(5个 Controller)
- 确认 Service ��(4个核心服务)
- 确认 DAL 层(7个 DO + Mapper)
- 添加 databus-server starter 依赖到 pom.xml
- 编译验证通过
Ref: docs/databus/implementation-checklist.md 任务 39-70
---
.../pom.xml | 71 ++++
.../DatabusSyncClientAutoConfiguration.java | 23 ++
.../config/DatabusSyncClientProperties.java | 113 ++++++
.../controller/SyncMessageController.java | 43 +++
.../core/idempotent/IdempotentStore.java | 19 +
.../core/idempotent/RedisIdempotentStore.java | 30 ++
.../listener/DatabusConsumerRegistry.java | 148 ++++++++
.../client/core/message/SyncMessage.java | 54 +++
.../core/processor/MessageProcessor.java | 236 +++++++++++++
.../client/handler/BatchSyncEventHandler.java | 51 +++
.../client/handler/SyncEventHandler.java | 57 +++
.../client/handler/post/PostSyncService.java | 108 ++++++
.../handler/post/SystemPostFullHandler.java | 71 ++++
.../main/resources/META-INF/spring.factories | 2 +
...ot.autoconfigure.AutoConfiguration.imports | 1 +
.../pom.xml | 73 ++++
.../config/DatabusMessagingConfiguration.java | 27 ++
.../DatabusServerAutoConfiguration.java | 24 ++
.../config/DatabusServerProperties.java | 60 ++++
.../DatabusSyncServerAutoConfiguration.java | 45 +++
.../config/DatabusSyncServerProperties.java | 61 ++++
.../admin/DatabusSyncClientController.java | 92 +++++
.../DatabusSyncDeadLetterController.java | 76 ++++
.../admin/DatabusSyncEventController.java | 92 +++++
.../admin/DatabusSyncFullTaskController.java | 102 ++++++
.../admin/DatabusSyncPushLogController.java | 69 ++++
.../DatabusSyncSubscriptionController.java | 100 ++++++
.../vo/client/DatabusSyncClientPageReqVO.java | 27 ++
.../vo/client/DatabusSyncClientRespVO.java | 63 ++++
.../vo/client/DatabusSyncClientSaveReqVO.java | 55 +++
.../DatabusSyncDeadLetterPageReqVO.java | 43 +++
.../DatabusSyncDeadLetterRespVO.java | 63 ++++
.../vo/event/DatabusSyncEventPageReqVO.java | 24 ++
.../vo/event/DatabusSyncEventRespVO.java | 54 +++
.../vo/event/DatabusSyncEventSaveReqVO.java | 45 +++
.../DatabusSyncFullTaskCreateReqVO.java | 18 +
.../DatabusSyncFullTaskPageReqVO.java | 30 ++
.../fulltask/DatabusSyncFullTaskRespVO.java | 88 +++++
.../pushlog/DatabusSyncPushLogPageReqVO.java | 46 +++
.../vo/pushlog/DatabusSyncPushLogRespVO.java | 72 ++++
.../DatabusSyncSubscriptionPageReqVO.java | 24 ++
.../DatabusSyncSubscriptionRespVO.java | 78 +++++
.../DatabusSyncSubscriptionSaveReqVO.java | 39 +++
.../convert/DatabusSyncClientConvert.java | 25 ++
.../convert/DatabusSyncDeadLetterConvert.java | 22 ++
.../convert/DatabusSyncEventConvert.java | 25 ++
.../convert/DatabusSyncFullTaskConvert.java | 22 ++
.../convert/DatabusSyncPushLogConvert.java | 22 ++
.../DatabusSyncSubscriptionConvert.java | 25 ++
.../server/core/event/DatabusEvent.java | 71 ++++
.../server/core/message/BatchSyncMessage.java | 121 +++++++
.../server/core/message/SyncMessage.java | 54 +++
.../server/core/provider/DataProvider.java | 120 +++++++
.../core/provider/DataProviderRegistry.java | 62 ++++
.../core/publisher/DatabusEventPublisher.java | 28 ++
.../publisher/DatabusEventPublisherImpl.java | 60 ++++
.../server/core/pusher/MessagePusher.java | 50 +++
.../server/core/pusher/MessagePusherImpl.java | 103 ++++++
.../core/sync/DatabusFullSyncService.java | 51 +++
.../sync/DatabusIncrementalSyncService.java | 27 ++
.../DatabusIncrementalSyncServiceImpl.java | 246 +++++++++++++
.../server/core/sync/DatabusSyncService.java | 24 ++
.../core/sync/DatabusSyncServiceImpl.java | 237 +++++++++++++
.../dal/dataobject/DatabusSyncClientDO.java | 84 +++++
.../dataobject/DatabusSyncDeadLetterDO.java | 106 ++++++
.../dal/dataobject/DatabusSyncEventDO.java | 76 ++++
.../dataobject/DatabusSyncEventRecordDO.java | 87 +++++
.../dal/dataobject/DatabusSyncFullTaskDO.java | 126 +++++++
.../dal/dataobject/DatabusSyncLogDO.java | 126 +++++++
.../dataobject/DatabusSyncSubscriptionDO.java | 91 +++++
.../dal/mapper/DatabusSyncClientMapper.java | 38 ++
.../mapper/DatabusSyncDeadLetterMapper.java | 29 ++
.../dal/mapper/DatabusSyncEventMapper.java | 37 ++
.../mapper/DatabusSyncEventRecordMapper.java | 15 +
.../dal/mapper/DatabusSyncFullTaskMapper.java | 62 ++++
.../dal/mapper/DatabusSyncLogMapper.java | 30 ++
.../mapper/DatabusSyncSubscriptionMapper.java | 41 +++
.../server/enums/DataProviderTypeEnum.java | 36 ++
.../server/enums/DeadLetterStatusEnum.java | 51 +++
.../server/enums/ErrorCodeConstants.java | 30 ++
.../server/enums/FullTaskStatusEnum.java | 75 ++++
.../databus/server/enums/SyncModeEnum.java | 46 +++
.../databus/server/enums/SyncStatusEnum.java | 56 +++
.../databus/server/enums/TimelinessEnum.java | 51 +++
.../server/enums/TransportTypeEnum.java | 46 +++
.../producer/DatabusMessageProducer.java | 195 +++++++++++
.../service/DatabusSyncClientService.java | 70 ++++
.../service/DatabusSyncDeadLetterService.java | 54 +++
.../service/DatabusSyncEventService.java | 70 ++++
.../server/service/DatabusSyncLogService.java | 37 ++
.../DatabusSyncSubscriptionService.java | 75 ++++
.../impl/DatabusFullSyncServiceImpl.java | 328 ++++++++++++++++++
.../impl/DatabusSyncClientServiceImpl.java | 115 ++++++
.../DatabusSyncDeadLetterServiceImpl.java | 99 ++++++
.../impl/DatabusSyncEventServiceImpl.java | 115 ++++++
.../impl/DatabusSyncLogServiceImpl.java | 50 +++
.../DatabusSyncSubscriptionServiceImpl.java | 129 +++++++
.../main/resources/META-INF/spring.factories | 2 +
...ot.autoconfigure.AutoConfiguration.imports | 2 +
.../api/message/DatabusBatchMessage.java | 106 ++++++
.../databus/api/message/DatabusMessage.java | 73 ++++
.../databus/enums/DatabusEventType.java | 306 ++++++++++++++++
.../zt-module-databus-server/pom.xml | 7 +
.../consumer/DatabusDeptChangeConsumer.java | 90 +++++
.../consumer/DatabusPostChangeConsumer.java | 73 ++++
.../consumer/DatabusUserChangeConsumer.java | 79 +++++
.../provider/DeptDataFeignProvider.java | 85 +++++
.../provider/PostDataFeignProvider.java | 81 +++++
.../provider/UserDataFeignProvider.java | 81 +++++
109 files changed, 7673 insertions(+)
create mode 100644 zt-framework/zt-spring-boot-starter-databus-client/pom.xml
create mode 100644 zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/config/DatabusSyncClientAutoConfiguration.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/config/DatabusSyncClientProperties.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/controller/SyncMessageController.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/idempotent/IdempotentStore.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/idempotent/RedisIdempotentStore.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/listener/DatabusConsumerRegistry.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/message/SyncMessage.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/processor/MessageProcessor.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/BatchSyncEventHandler.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/SyncEventHandler.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/post/PostSyncService.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/post/SystemPostFullHandler.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-client/src/main/resources/META-INF/spring.factories
create mode 100644 zt-framework/zt-spring-boot-starter-databus-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/pom.xml
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusMessagingConfiguration.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusServerAutoConfiguration.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusServerProperties.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusSyncServerAutoConfiguration.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusSyncServerProperties.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncClientController.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncDeadLetterController.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncEventController.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncFullTaskController.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncPushLogController.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncSubscriptionController.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/client/DatabusSyncClientPageReqVO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/client/DatabusSyncClientRespVO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/client/DatabusSyncClientSaveReqVO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/deadletter/DatabusSyncDeadLetterPageReqVO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/deadletter/DatabusSyncDeadLetterRespVO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/event/DatabusSyncEventPageReqVO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/event/DatabusSyncEventRespVO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/event/DatabusSyncEventSaveReqVO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/fulltask/DatabusSyncFullTaskCreateReqVO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/fulltask/DatabusSyncFullTaskPageReqVO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/fulltask/DatabusSyncFullTaskRespVO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/pushlog/DatabusSyncPushLogPageReqVO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/pushlog/DatabusSyncPushLogRespVO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/subscription/DatabusSyncSubscriptionPageReqVO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/subscription/DatabusSyncSubscriptionRespVO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/subscription/DatabusSyncSubscriptionSaveReqVO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncClientConvert.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncDeadLetterConvert.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncEventConvert.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncFullTaskConvert.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncPushLogConvert.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncSubscriptionConvert.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/event/DatabusEvent.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/message/BatchSyncMessage.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/message/SyncMessage.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/provider/DataProvider.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/provider/DataProviderRegistry.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/publisher/DatabusEventPublisher.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/publisher/DatabusEventPublisherImpl.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/pusher/MessagePusher.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/pusher/MessagePusherImpl.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusFullSyncService.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusIncrementalSyncService.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusIncrementalSyncServiceImpl.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusSyncService.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusSyncServiceImpl.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncClientDO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncDeadLetterDO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncEventDO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncEventRecordDO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncFullTaskDO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncLogDO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncSubscriptionDO.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncClientMapper.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncDeadLetterMapper.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncEventMapper.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncEventRecordMapper.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncFullTaskMapper.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncLogMapper.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncSubscriptionMapper.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/DataProviderTypeEnum.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/DeadLetterStatusEnum.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/ErrorCodeConstants.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/FullTaskStatusEnum.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/SyncModeEnum.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/SyncStatusEnum.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/TimelinessEnum.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/TransportTypeEnum.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/producer/DatabusMessageProducer.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncClientService.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncDeadLetterService.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncEventService.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncLogService.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncSubscriptionService.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusFullSyncServiceImpl.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncClientServiceImpl.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncDeadLetterServiceImpl.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncEventServiceImpl.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncLogServiceImpl.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncSubscriptionServiceImpl.java
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/resources/META-INF/spring.factories
create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
create mode 100644 zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/message/DatabusBatchMessage.java
create mode 100644 zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/message/DatabusMessage.java
create mode 100644 zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/enums/DatabusEventType.java
create mode 100644 zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/mq/consumer/DatabusDeptChangeConsumer.java
create mode 100644 zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/mq/consumer/DatabusPostChangeConsumer.java
create mode 100644 zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/mq/consumer/DatabusUserChangeConsumer.java
create mode 100644 zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/provider/DeptDataFeignProvider.java
create mode 100644 zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/provider/PostDataFeignProvider.java
create mode 100644 zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/provider/UserDataFeignProvider.java
diff --git a/zt-framework/zt-spring-boot-starter-databus-client/pom.xml b/zt-framework/zt-spring-boot-starter-databus-client/pom.xml
new file mode 100644
index 00000000..08e8dcc8
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-client/pom.xml
@@ -0,0 +1,71 @@
+
+
+
+ com.zt.plat
+ zt-framework
+ ${revision}
+
+ 4.0.0
+ zt-spring-boot-starter-databus-client
+ jar
+
+ ${project.artifactId}
+ DataBus 客户端组件,负责接收数据变更并同步
+ https://github.com/YunaiV/ruoyi-vue-pro
+
+
+
+ com.zt.plat
+ zt-common
+
+
+
+
+ com.zt.plat
+ zt-module-databus-api
+ ${revision}
+
+
+
+
+ com.zt.plat
+ zt-module-system-api
+ ${revision}
+ true
+
+
+
+ cn.hutool
+ hutool-all
+
+
+
+
+ com.zt.plat
+ zt-spring-boot-starter-mq
+
+
+
+
+ com.zt.plat
+ zt-spring-boot-starter-redis
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ true
+
+
+
+
+ com.zt.plat
+ zt-spring-boot-starter-test
+ test
+
+
+
+
diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/config/DatabusSyncClientAutoConfiguration.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/config/DatabusSyncClientAutoConfiguration.java
new file mode 100644
index 00000000..afa72c43
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/config/DatabusSyncClientAutoConfiguration.java
@@ -0,0 +1,23 @@
+package com.zt.plat.framework.databus.client.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.ComponentScan;
+
+/**
+ * Databus 同步客户端自动配置
+ *
+ * @author ZT
+ */
+@Slf4j
+@AutoConfiguration
+@EnableConfigurationProperties(DatabusSyncClientProperties.class)
+@ComponentScan(basePackages = "com.zt.plat.framework.databus.client")
+public class DatabusSyncClientAutoConfiguration {
+
+ public DatabusSyncClientAutoConfiguration() {
+ log.info("[Databus] 数据同步客户端模块已加载");
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/config/DatabusSyncClientProperties.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/config/DatabusSyncClientProperties.java
new file mode 100644
index 00000000..f79478ef
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/config/DatabusSyncClientProperties.java
@@ -0,0 +1,113 @@
+package com.zt.plat.framework.databus.client.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * Databus 数据同步客户端配置属性
+ *
+ * @author ZT
+ */
+@Data
+@ConfigurationProperties(prefix = "zt.databus.sync.client")
+public class DatabusSyncClientProperties {
+
+ /**
+ * 是否启用
+ */
+ private Boolean enabled = true;
+ /**
+ * RocketMQ NameServer 地址
+ */
+ private String nameServer;
+
+ /**
+ * 客户端编码(必填,用于订阅专属Topic)
+ * Topic格式: databus-sync-{eventType}-{clientCode}
+ */
+ private String clientCode;
+
+ /**
+ * MQ配置
+ */
+ private Mq mq = new Mq();
+
+ /**
+ * HTTP配置
+ */
+ private Http http = new Http();
+
+ /**
+ * 幂等配置
+ */
+ private Idempotent idempotent = new Idempotent();
+
+ @Data
+ public static class Mq {
+ /**
+ * 是否启用MQ消费
+ */
+ private Boolean enabled = true;
+ /**
+ * RocketMQ NameServer 地址
+ */
+ private String nameServer;
+
+ /**
+ * Topic基础名称
+ */
+ private String topicBase = "databus-sync";
+
+ /**
+ * 消费者组前缀,完整格式: {consumerGroupPrefix}-{eventType}
+ * 默认: databus-client-{clientCode}
+ */
+ private String consumerGroupPrefix;
+
+ /**
+ * 消费线程数
+ */
+ private Integer consumeThreadMin = 1;
+
+ /**
+ * 消费线程数
+ */
+ private Integer consumeThreadMax = 5;
+
+ /**
+ * 最大重试次数
+ */
+ private Integer maxReconsumeTimes = 3;
+ }
+
+ @Data
+ public static class Http {
+ /**
+ * 是否启用HTTP推送接收
+ */
+ private Boolean enabled = false;
+
+ /**
+ * 接收端点路径
+ */
+ private String endpoint = "/databus/sync/receive";
+ }
+
+ @Data
+ public static class Idempotent {
+ /**
+ * 是否启用幂等检查
+ */
+ private Boolean enabled = true;
+ /**
+ * RocketMQ NameServer 地址
+ */
+ private String nameServer;
+
+ /**
+ * 幂等记录过期时间(秒)
+ */
+ private Integer expireSeconds = 86400; // 24小时
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/controller/SyncMessageController.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/controller/SyncMessageController.java
new file mode 100644
index 00000000..1d5ace2b
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/controller/SyncMessageController.java
@@ -0,0 +1,43 @@
+package com.zt.plat.framework.databus.client.core.controller;
+
+import com.zt.plat.framework.databus.client.core.processor.MessageProcessor;
+import com.zt.plat.module.databus.enums.DatabusEventType;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 同步消息HTTP接收控制器
+ *
+ * @author ZT
+ */
+@Slf4j
+@RestController
+@RequestMapping("${zt.databus.sync.client.http.endpoint:/databus/sync/receive}")
+@RequiredArgsConstructor
+@ConditionalOnProperty(prefix = "zt.databus.sync.client.http", name = "enabled", havingValue = "true")
+public class SyncMessageController {
+
+ private final MessageProcessor messageProcessor;
+
+ /**
+ * 接收同步消息
+ *
+ * @param eventType 事件类型
+ * @param message 消息体
+ */
+ @PostMapping("/{eventType}")
+ public void receive(@PathVariable("eventType") String eventType, @RequestBody String message) {
+ log.debug("[Databus Client] 接收到HTTP消息, eventType={}", eventType);
+
+ DatabusEventType type = DatabusEventType.valueOf(eventType);
+ if (type == null) {
+ log.warn("[Databus Client] 未知的事件类型: {}", eventType);
+ return;
+ }
+
+ messageProcessor.process(message, type);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/idempotent/IdempotentStore.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/idempotent/IdempotentStore.java
new file mode 100644
index 00000000..14f99600
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/idempotent/IdempotentStore.java
@@ -0,0 +1,19 @@
+package com.zt.plat.framework.databus.client.core.idempotent;
+
+/**
+ * 幂等存储接口
+ *
+ * @author ZT
+ */
+public interface IdempotentStore {
+
+ /**
+ * 检查并记录消息是否已处理
+ *
+ * @param syncId 同步ID
+ * @param expireSeconds 过期时间(秒)
+ * @return true-未处理(可以处理), false-已处理(应该跳过)
+ */
+ boolean checkAndMark(String syncId, int expireSeconds);
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/idempotent/RedisIdempotentStore.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/idempotent/RedisIdempotentStore.java
new file mode 100644
index 00000000..edae4ce7
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/idempotent/RedisIdempotentStore.java
@@ -0,0 +1,30 @@
+package com.zt.plat.framework.databus.client.core.idempotent;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 基于 Redis 的幂等存储实现
+ *
+ * @author ZT
+ */
+@Component
+@RequiredArgsConstructor
+public class RedisIdempotentStore implements IdempotentStore {
+
+ private static final String KEY_PREFIX = "databus:sync:idempotent:";
+
+ private final StringRedisTemplate stringRedisTemplate;
+
+ @Override
+ public boolean checkAndMark(String syncId, int expireSeconds) {
+ String key = KEY_PREFIX + syncId;
+ Boolean success = stringRedisTemplate.opsForValue()
+ .setIfAbsent(key, "1", expireSeconds, TimeUnit.SECONDS);
+ return Boolean.TRUE.equals(success);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/listener/DatabusConsumerRegistry.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/listener/DatabusConsumerRegistry.java
new file mode 100644
index 00000000..bf1ba313
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/listener/DatabusConsumerRegistry.java
@@ -0,0 +1,148 @@
+package com.zt.plat.framework.databus.client.core.listener;
+
+import com.zt.plat.framework.databus.client.config.DatabusSyncClientProperties;
+import com.zt.plat.framework.databus.client.core.processor.MessageProcessor;
+import com.zt.plat.module.databus.enums.DatabusEventType;
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.PreDestroy;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Component;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Databus Consumer 注册器
+ *
+ * 根据 DatabusEventType 枚举自动为所有事件类型创建消费者
+ * Topic格式: {topicBase}-{module}-{entity}-{action}-{clientCode}
+ * 例如: databus-sync-system-user-create-company-a
+ *
+ * @author ZT
+ */
+@Slf4j
+@Component
+@ConditionalOnProperty(prefix = "zt.databus.sync.client.mq", name = "enabled", havingValue = "true", matchIfMissing = true)
+public class DatabusConsumerRegistry {
+
+ private final MessageProcessor messageProcessor;
+ private final DatabusSyncClientProperties properties;
+
+
+ /**
+ * 管理的消费者列表
+ */
+ private final List consumers = new ArrayList<>();
+
+ public DatabusConsumerRegistry(MessageProcessor messageProcessor, DatabusSyncClientProperties properties) {
+ this.messageProcessor = messageProcessor;
+ this.properties = properties;
+ }
+
+ @PostConstruct
+ public void init() {
+ if (!Boolean.TRUE.equals(properties.getEnabled())) {
+ log.info("[Databus Client] 客户端未启用,跳过初始化");
+ return;
+ }
+
+ String nameServer = properties.getMq().getNameServer();
+ if (nameServer == null || nameServer.isEmpty()) {
+ log.warn("[Databus Client] RocketMQ nameServer未配置,跳过MQ消费者初始化");
+ return;
+ }
+
+ String clientCode = properties.getClientCode();
+ if (clientCode == null || clientCode.isEmpty()) {
+ log.error("[Databus Client] clientCode未配置,无法订阅Topic");
+ return;
+ }
+
+ String topicBase = properties.getMq().getTopicBase();
+ String consumerGroupPrefix = properties.getMq().getConsumerGroupPrefix();
+ if (consumerGroupPrefix == null || consumerGroupPrefix.isEmpty()) {
+ consumerGroupPrefix = "databus-client-" + clientCode;
+ }
+
+ // 为每个事件类型创建独立的消费者
+ for (DatabusEventType eventType : DatabusEventType.values()) {
+ try {
+ createConsumer(eventType, topicBase, clientCode, consumerGroupPrefix, nameServer);
+ } catch (Exception e) {
+ log.error("[Databus Client] 创建消费者失败, eventType={}", eventType.name(), e);
+ }
+ }
+
+ log.info("[Databus Client] 消费者注册完成,共创建 {} 个消费者", consumers.size());
+ }
+
+ /**
+ * 为指定事件类型创建消费者
+ */
+ private void createConsumer(DatabusEventType eventType, String topicBase, String clientCode, String consumerGroupPrefix, String nameServer) throws MQClientException {
+ // Topic: databus-sync-system-user-create-company-a
+ String topic = eventType.getTopic(topicBase, clientCode);
+ // ConsumerGroup: databus-client-company-a-system-user-create
+ String consumerGroup = String.format("%s-%s", consumerGroupPrefix, eventType.getTopicSuffix());
+
+ DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(consumerGroup);
+ consumer.setNamesrvAddr(nameServer);
+ consumer.setConsumeThreadMin(properties.getMq().getConsumeThreadMin());
+ consumer.setConsumeThreadMax(properties.getMq().getConsumeThreadMax());
+ consumer.setMaxReconsumeTimes(properties.getMq().getMaxReconsumeTimes());
+
+ // 订阅Topic
+ consumer.subscribe(topic, "*");
+
+ // 设置消息监听器
+ consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
+ for (MessageExt msg : msgs) {
+ try {
+ String messageBody = new String(msg.getBody(), StandardCharsets.UTF_8);
+ log.debug("[Databus Client] 收到消息, topic={}, msgId={}, eventType={}",
+ msg.getTopic(), msg.getMsgId(), eventType.name());
+
+ messageProcessor.process(messageBody, eventType);
+
+ } catch (Exception e) {
+ log.error("[Databus Client] 消息处理失败, topic={}, msgId={}, reconsumeTimes={}",
+ msg.getTopic(), msg.getMsgId(), msg.getReconsumeTimes(), e);
+
+ if (msg.getReconsumeTimes() >= properties.getMq().getMaxReconsumeTimes()) {
+ log.error("[Databus Client] 重试次数已达上限,放弃处理, msgId={}", msg.getMsgId());
+ return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
+ }
+ return ConsumeConcurrentlyStatus.RECONSUME_LATER;
+ }
+ }
+ return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
+ });
+
+ consumer.start();
+ consumers.add(consumer);
+
+ log.info("[Databus Client] 消费者启动成功, topic={}, consumerGroup={}, event={}",
+ topic, consumerGroup, eventType.getName());
+ }
+
+ @PreDestroy
+ public void destroy() {
+ for (DefaultMQPushConsumer consumer : consumers) {
+ try {
+ consumer.shutdown();
+ } catch (Exception e) {
+ log.error("[Databus Client] 关闭消费者失败", e);
+ }
+ }
+ consumers.clear();
+ log.info("[Databus Client] 所有消费者已关闭");
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/message/SyncMessage.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/message/SyncMessage.java
new file mode 100644
index 00000000..00d00ce0
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/message/SyncMessage.java
@@ -0,0 +1,54 @@
+package com.zt.plat.framework.databus.client.core.message;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 数据同步消息(服务端推送格式)
+ *
+ * @author ZT
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SyncMessage {
+
+ /**
+ * 同步ID(唯一标识)
+ */
+ private String syncId;
+
+ /**
+ * 事件记录ID
+ */
+ private Long eventRecordId;
+
+ /**
+ * 事件类型
+ */
+ private String eventType;
+
+ /**
+ * 事件动作
+ */
+ private String eventAction;
+
+ /**
+ * 业务数据快照(JSON字符串)
+ */
+ private String dataSnapshot;
+
+ /**
+ * 数据版本
+ */
+ private Integer dataVersion;
+
+ /**
+ * 时间戳
+ */
+ private Long timestamp;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/processor/MessageProcessor.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/processor/MessageProcessor.java
new file mode 100644
index 00000000..8f67e409
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/processor/MessageProcessor.java
@@ -0,0 +1,236 @@
+package com.zt.plat.framework.databus.client.core.processor;
+
+import cn.hutool.json.JSONUtil;
+import com.zt.plat.framework.databus.client.config.DatabusSyncClientProperties;
+import com.zt.plat.framework.databus.client.core.idempotent.IdempotentStore;
+import com.zt.plat.framework.databus.client.core.message.SyncMessage;
+import com.zt.plat.framework.databus.client.handler.BatchSyncEventHandler;
+import com.zt.plat.framework.databus.client.handler.SyncEventHandler;
+import com.zt.plat.module.databus.api.message.DatabusBatchMessage;
+import com.zt.plat.module.databus.api.message.DatabusMessage;
+import com.zt.plat.module.databus.enums.DatabusEventType;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * 消息处理器
+ *
+ * 负责消息的幂等检查和路由到具体的Handler
+ *
+ * @author ZT
+ */
+@Slf4j
+@Component
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class MessageProcessor {
+
+ private final IdempotentStore idempotentStore;
+ private final DatabusSyncClientProperties properties;
+
+ /**
+ * 增量同步处理器列表
+ */
+ private List handlers = new ArrayList<>();
+
+ /**
+ * 全量同步处理器列表
+ */
+ private List batchHandlers = new ArrayList<>();
+
+ private Map handlerMap;
+ private Map batchHandlerMap;
+
+ public MessageProcessor(IdempotentStore idempotentStore, DatabusSyncClientProperties properties) {
+ this.idempotentStore = idempotentStore;
+ this.properties = properties;
+ }
+
+ @Autowired(required = false)
+ public void setHandlers(List handlers) {
+ if (handlers != null) {
+ this.handlers = handlers;
+ }
+ }
+
+ @Autowired(required = false)
+ public void setBatchHandlers(List batchHandlers) {
+ if (batchHandlers != null) {
+ this.batchHandlers = batchHandlers;
+ }
+ }
+
+ /**
+ * 处理同步消息
+ *
+ * @param messageJson 消息JSON字符串
+ * @param eventType 事件类型枚举
+ */
+ public void process(String messageJson, DatabusEventType eventType) {
+ try {
+ if (eventType.isFullSync()) {
+ processBatchMessage(messageJson, eventType);
+ } else {
+ processIncrementalMessage(messageJson, eventType);
+ }
+ } catch (Exception e) {
+ log.error("[Databus Client] 消息处理失败, eventType={}, message={}", eventType.name(), messageJson, e);
+ throw new RuntimeException("消息处理失败", e);
+ }
+ }
+
+ /**
+ * 处理增量同步消息
+ */
+ private void processIncrementalMessage(String messageJson, DatabusEventType eventType) {
+ // 先解析为服务端推送的 SyncMessage 格式
+ SyncMessage syncMessage = JSONUtil.toBean(messageJson, SyncMessage.class);
+
+ // 幂等检查
+ if (properties.getIdempotent().getEnabled()) {
+ boolean canProcess = idempotentStore.checkAndMark(
+ syncMessage.getSyncId(),
+ properties.getIdempotent().getExpireSeconds()
+ );
+ if (!canProcess) {
+ log.info("[Databus Client] 消息已处理,跳过, syncId={}", syncMessage.getSyncId());
+ return;
+ }
+ }
+
+ // 路由到对应的Handler
+ SyncEventHandler handler = getHandler(eventType);
+ if (handler == null) {
+ log.warn("[Databus Client] 未找到事件处理器, eventType={}", eventType.name());
+ return;
+ }
+
+ // 获取 Handler 期望的数据类型,并转换消息
+ Class> dataType = handler.getDataType();
+ DatabusMessage message = convertToDatabusMessage(syncMessage, eventType, dataType);
+ handler.handle(message);
+ log.info("[Databus Client] 增量消息处理成功, syncId={}, eventType={}",
+ syncMessage.getSyncId(), eventType.name());
+ }
+
+ /**
+ * 将 SyncMessage 转换为 DatabusMessage
+ *
+ * @param syncMessage 服务端推送的同步消息
+ * @param eventType 事件类型
+ * @param dataType Handler 期望的数据类型
+ * @return DatabusMessage
+ */
+ private DatabusMessage convertToDatabusMessage(SyncMessage syncMessage, DatabusEventType eventType, Class> dataType) {
+ DatabusMessage message = new DatabusMessage();
+ message.setMessageId(syncMessage.getSyncId());
+ message.setEventType(eventType);
+
+ // 从 dataSnapshot JSON 字符串解析业务数据对象
+ if (syncMessage.getDataSnapshot() != null && !syncMessage.getDataSnapshot().isEmpty()) {
+ // 使用 Handler 提供的类型进行反序列化
+ Object data = JSONUtil.toBean(syncMessage.getDataSnapshot(), dataType);
+ message.setData(data);
+ }
+
+ // 设置时间戳
+ if (syncMessage.getTimestamp() != null) {
+ message.setTimestamp(java.time.LocalDateTime.ofInstant(
+ java.time.Instant.ofEpochMilli(syncMessage.getTimestamp()),
+ java.time.ZoneId.systemDefault()
+ ));
+ }
+
+ return message;
+ }
+
+ /**
+ * 处理全量同步批量消息
+ */
+ private void processBatchMessage(String messageJson, DatabusEventType eventType) {
+ DatabusBatchMessage message = JSONUtil.toBean(messageJson, DatabusBatchMessage.class);
+
+ // 幂等检查
+ if (properties.getIdempotent().getEnabled()) {
+ boolean canProcess = idempotentStore.checkAndMark(
+ message.getMessageId(),
+ properties.getIdempotent().getExpireSeconds()
+ );
+ if (!canProcess) {
+ log.info("[Databus Client] 批量消息已处理,跳过, messageId={}", message.getMessageId());
+ return;
+ }
+ }
+
+ // 路由到对应的BatchHandler
+ BatchSyncEventHandler handler = getBatchHandler(eventType);
+ if (handler == null) {
+ log.warn("[Databus Client] 未找到批量事件处理器, eventType={}", eventType.name());
+ return;
+ }
+
+ // 全量同步开始回调(第一批)
+ if (message.getBatchNo() != null && message.getBatchNo() == 1) {
+ handler.onFullSyncStart(message);
+ log.info("[Databus Client] 全量同步开始, taskId={}, eventType={}, totalCount={}",
+ message.getTaskId(), eventType.name(), message.getTotalCount());
+ }
+
+ // 执行批量处理
+ handler.handleBatch(message);
+ log.info("[Databus Client] 批量消息处理成功, messageId={}, eventType={}, batchNo={}/{}, count={}",
+ message.getMessageId(), eventType.name(),
+ message.getBatchNo(), message.getTotalBatch(), message.getCount());
+
+ // 全量同步完成回调(最后一批)
+ if (Boolean.TRUE.equals(message.getIsLastBatch())) {
+ handler.onFullSyncComplete(message);
+ log.info("[Databus Client] 全量同步完成, taskId={}, eventType={}, totalCount={}",
+ message.getTaskId(), eventType.name(), message.getTotalCount());
+ }
+ }
+
+ /**
+ * 获取增量同步事件处理器
+ */
+ private SyncEventHandler getHandler(DatabusEventType eventType) {
+ if (handlerMap == null) {
+ if (handlers == null || handlers.isEmpty()) {
+ handlerMap = Collections.emptyMap();
+ } else {
+ handlerMap = handlers.stream()
+ .collect(Collectors.toMap(
+ SyncEventHandler::getSupportedEventType,
+ Function.identity()
+ ));
+ }
+ }
+ return handlerMap.get(eventType);
+ }
+
+ /**
+ * 获取全量同步批量事件处理器
+ */
+ private BatchSyncEventHandler getBatchHandler(DatabusEventType eventType) {
+ if (batchHandlerMap == null) {
+ if (batchHandlers == null || batchHandlers.isEmpty()) {
+ batchHandlerMap = Collections.emptyMap();
+ } else {
+ batchHandlerMap = batchHandlers.stream()
+ .collect(Collectors.toMap(
+ BatchSyncEventHandler::getSupportedEventType,
+ Function.identity()
+ ));
+ }
+ }
+ return batchHandlerMap.get(eventType);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/BatchSyncEventHandler.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/BatchSyncEventHandler.java
new file mode 100644
index 00000000..4ab5a573
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/BatchSyncEventHandler.java
@@ -0,0 +1,51 @@
+package com.zt.plat.framework.databus.client.handler;
+
+import com.zt.plat.module.databus.api.message.DatabusBatchMessage;
+import com.zt.plat.module.databus.enums.DatabusEventType;
+
+/**
+ * 批量同步事件处理器接口
+ *
+ * 业务系统需要实现此接口来处理全量同步的批量数据
+ *
+ * @author ZT
+ */
+public interface BatchSyncEventHandler {
+
+ /**
+ * 获取支持的事件类型
+ *
+ * @return 事件类型枚举
+ */
+ DatabusEventType getSupportedEventType();
+
+ /**
+ * 处理批量同步消息
+ *
+ * @param message 批量同步消息
+ */
+ void handleBatch(DatabusBatchMessage message);
+
+ /**
+ * 全量同步开始回调(可选实现)
+ *
+ * 当收到第一批数据(batchNo=1)时调用
+ *
+ * @param message 批量同步消息
+ */
+ default void onFullSyncStart(DatabusBatchMessage message) {
+ // 默认空实现,子类可覆盖
+ }
+
+ /**
+ * 全量同步完成回调(可选实现)
+ *
+ * 当收到最后一批数据(isLastBatch=true)时调用
+ *
+ * @param message 批量同步消息
+ */
+ default void onFullSyncComplete(DatabusBatchMessage message) {
+ // 默认空实现,子类可覆盖
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/SyncEventHandler.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/SyncEventHandler.java
new file mode 100644
index 00000000..f89906d0
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/SyncEventHandler.java
@@ -0,0 +1,57 @@
+package com.zt.plat.framework.databus.client.handler;
+
+import com.zt.plat.module.databus.api.message.DatabusMessage;
+import com.zt.plat.module.databus.enums.DatabusEventType;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+/**
+ * 同步事件处理器接口
+ *
+ * 业务系统需要实现此接口来处理增量数据同步
+ *
+ * @author ZT
+ */
+public interface SyncEventHandler {
+
+ /**
+ * 获取支持的事件类型
+ *
+ * @return 事件类型枚举
+ */
+ DatabusEventType getSupportedEventType();
+
+ /**
+ * 处理同步消息
+ *
+ * @param message 同步消息
+ */
+ void handle(DatabusMessage message);
+
+ /**
+ * 获取数据类型
+ *
+ * 默认通过反射获取泛型类型参数,子类可以覆盖此方法提供具体类型
+ *
+ * @return 数据类型的 Class 对象
+ */
+ @SuppressWarnings("unchecked")
+ default Class getDataType() {
+ Type[] genericInterfaces = this.getClass().getGenericInterfaces();
+ for (Type genericInterface : genericInterfaces) {
+ if (genericInterface instanceof ParameterizedType) {
+ ParameterizedType parameterizedType = (ParameterizedType) genericInterface;
+ if (parameterizedType.getRawType().equals(SyncEventHandler.class)) {
+ Type[] typeArguments = parameterizedType.getActualTypeArguments();
+ if (typeArguments.length > 0 && typeArguments[0] instanceof Class) {
+ return (Class) typeArguments[0];
+ }
+ }
+ }
+ }
+ // 如果无法获取泛型类型,返回 Object.class
+ return (Class) Object.class;
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/post/PostSyncService.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/post/PostSyncService.java
new file mode 100644
index 00000000..f42330a9
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/post/PostSyncService.java
@@ -0,0 +1,108 @@
+package com.zt.plat.framework.databus.client.handler.post;
+
+import com.zt.plat.module.databus.api.data.PostData;
+import com.zt.plat.module.system.api.dept.PostApi;
+import com.zt.plat.module.system.api.dept.dto.PostSaveReqDTO;
+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;
+
+/**
+ * 岗位同步业务逻辑
+ *
+ * 被各个 PostHandler 共享使用
+ *
+ * @author ZT
+ */
+@Slf4j
+@Service
+@ConditionalOnProperty(prefix = "zt.databus.sync.client", name = "enabled", havingValue = "true")
+@ConditionalOnClass(name = "com.zt.plat.module.system.api.dept.PostApi")
+public class PostSyncService {
+
+ @Autowired(required = false)
+ private PostApi postApi;
+
+ /**
+ * 创建岗位
+ */
+ public void create(PostData data) {
+ if (postApi == null) {
+ log.warn("[PostSync] PostApi未注入,跳过创建岗位操作, postId={}", data.getId());
+ return;
+ }
+ PostSaveReqDTO dto = buildPostDTO(data);
+ postApi.createPost(dto).checkError();
+ log.info("[PostSync] 创建岗位成功, postId={}, postName={}", dto.getId(), dto.getName());
+ }
+
+ /**
+ * 更新岗位
+ */
+ public void update(PostData data) {
+ if (postApi == null) {
+ log.warn("[PostSync] PostApi未注入,跳过更新岗位操作, postId={}", data.getId());
+ return;
+ }
+ PostSaveReqDTO dto = buildPostDTO(data);
+ postApi.updatePost(dto).checkError();
+ log.info("[PostSync] 更新岗位成功, postId={}, postName={}", dto.getId(), dto.getName());
+ }
+
+ /**
+ * 删除岗位
+ */
+ public void delete(PostData data) {
+ if (postApi == null) {
+ log.warn("[PostSync] PostApi未注入,跳过删除岗位操作, postId={}", data.getId());
+ return;
+ }
+ Long postId = data.getId();
+ if (postId != null) {
+ postApi.deletePost(postId).checkError();
+ log.info("[PostSync] 删除岗位成功, postId={}", postId);
+ }
+ }
+
+ /**
+ * 全量同步单条数据(存在则更新,不存在则创建)
+ */
+ public void fullSync(PostData data) {
+ if (postApi == null) {
+ log.warn("[PostSync] PostApi未注入,跳过全量同步岗位操作, postId={}", data.getId());
+ return;
+ }
+ PostSaveReqDTO dto = buildPostDTO(data);
+ try {
+ if (dto.getId() != null) {
+ var existing = postApi.getPost(dto.getId());
+ if (existing.isSuccess() && existing.getData() != null) {
+ postApi.updatePost(dto).checkError();
+ } else {
+ postApi.createPost(dto).checkError();
+ }
+ } else {
+ postApi.createPost(dto).checkError();
+ }
+ } catch (Exception e) {
+ postApi.createPost(dto).checkError();
+ }
+ }
+
+ /**
+ * 构建岗位DTO
+ */
+ private PostSaveReqDTO buildPostDTO(PostData data) {
+ PostSaveReqDTO dto = new PostSaveReqDTO();
+ dto.setId(data.getId());
+ dto.setCode(data.getCode());
+ dto.setName(data.getName());
+ dto.setSort(data.getSort());
+ dto.setStatus(data.getStatus());
+ 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/post/SystemPostFullHandler.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/post/SystemPostFullHandler.java
new file mode 100644
index 00000000..50727a74
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/post/SystemPostFullHandler.java
@@ -0,0 +1,71 @@
+package com.zt.plat.framework.databus.client.handler.post;
+
+import com.zt.plat.framework.databus.client.handler.BatchSyncEventHandler;
+import com.zt.plat.module.databus.api.data.PostData;
+import com.zt.plat.module.databus.api.message.DatabusBatchMessage;
+import com.zt.plat.module.databus.enums.DatabusEventType;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Component;
+
+/**
+ * 岗位全量同步事件处理器
+ *
+ * @author ZT
+ */
+@Slf4j
+@Component
+@ConditionalOnProperty(prefix = "zt.databus.sync.client", name = "enabled", havingValue = "true")
+@ConditionalOnBean(PostSyncService.class)
+public class SystemPostFullHandler implements BatchSyncEventHandler {
+
+ @Resource
+ private PostSyncService postSyncService;
+
+ @Override
+ public DatabusEventType getSupportedEventType() {
+ return DatabusEventType.SYSTEM_POST_FULL;
+ }
+
+ @Override
+ public void onFullSyncStart(DatabusBatchMessage message) {
+ log.info("[PostSync] 全量同步开始, taskId={}, totalCount={}, totalBatch={}",
+ message.getTaskId(), message.getTotalCount(), message.getTotalBatch());
+ }
+
+ @Override
+ public void handleBatch(DatabusBatchMessage message) {
+ log.info("[PostSync] 处理批次, batchNo={}/{}, count={}",
+ message.getBatchNo(), message.getTotalBatch(), message.getCount());
+
+ if (message.getDataList() == null || message.getDataList().isEmpty()) {
+ log.warn("[PostSync] 数据列表为空, batchNo={}", message.getBatchNo());
+ return;
+ }
+
+ int successCount = 0;
+ int failCount = 0;
+
+ for (PostData data : message.getDataList()) {
+ try {
+ postSyncService.fullSync(data);
+ successCount++;
+ } catch (Exception e) {
+ failCount++;
+ log.error("[PostSync] 处理数据项失败, postId={}", data.getId(), e);
+ }
+ }
+
+ log.info("[PostSync] 批次处理完成, batchNo={}, success={}, fail={}",
+ message.getBatchNo(), successCount, failCount);
+ }
+
+ @Override
+ public void onFullSyncComplete(DatabusBatchMessage message) {
+ log.info("[PostSync] 全量同步完成, taskId={}, totalCount={}",
+ message.getTaskId(), message.getTotalCount());
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/resources/META-INF/spring.factories b/zt-framework/zt-spring-boot-starter-databus-client/src/main/resources/META-INF/spring.factories
new file mode 100644
index 00000000..9b570f2a
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+ com.zt.plat.framework.databus.client.config.DatabusSyncClientAutoConfiguration
diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/zt-framework/zt-spring-boot-starter-databus-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 00000000..50f5c6d4
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+com.zt.plat.framework.databus.client.config.DatabusSyncClientAutoConfiguration
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/pom.xml b/zt-framework/zt-spring-boot-starter-databus-server/pom.xml
new file mode 100644
index 00000000..59150712
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/pom.xml
@@ -0,0 +1,73 @@
+
+
+
+ com.zt.plat
+ zt-framework
+ ${revision}
+
+ 4.0.0
+ zt-spring-boot-starter-databus-server
+ jar
+
+ ${project.artifactId}
+ DataBus 服务端组件,负责发送数据变更消息到各客户端
+
+
+
+ com.zt.plat
+ zt-common
+
+
+
+
+ com.zt.plat
+ zt-module-databus-api
+ ${revision}
+
+
+
+ cn.hutool
+ hutool-all
+
+
+
+
+ com.zt.plat
+ zt-spring-boot-starter-mq
+
+
+
+
+ com.zt.plat
+ zt-spring-boot-starter-mybatis
+
+
+
+
+ com.zt.plat
+ zt-spring-boot-starter-web
+
+
+
+
+ com.zt.plat
+ zt-spring-boot-starter-security
+
+
+
+
+ com.zt.plat
+ zt-spring-boot-starter-biz-tenant
+
+
+
+
+ com.zt.plat
+ zt-spring-boot-starter-test
+ test
+
+
+
+
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusMessagingConfiguration.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusMessagingConfiguration.java
new file mode 100644
index 00000000..48e7d0cb
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusMessagingConfiguration.java
@@ -0,0 +1,27 @@
+package com.zt.plat.framework.databus.server.config;
+
+import com.zt.plat.framework.databus.server.core.pusher.MessagePusher;
+import com.zt.plat.framework.databus.server.core.pusher.MessagePusherImpl;
+import org.apache.rocketmq.spring.core.RocketMQTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Databus 消息配置类
+ *
+ * @author ZT
+ */
+@Configuration
+public class DatabusMessagingConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ public MessagePusher messagePusher(@Autowired(required = false) RocketMQTemplate rocketMQTemplate) {
+ MessagePusherImpl pusher = new MessagePusherImpl();
+ pusher.setRocketMQTemplate(rocketMQTemplate);
+ return pusher;
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusServerAutoConfiguration.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusServerAutoConfiguration.java
new file mode 100644
index 00000000..7444745e
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusServerAutoConfiguration.java
@@ -0,0 +1,24 @@
+package com.zt.plat.framework.databus.server.config;
+
+import com.zt.plat.framework.databus.server.producer.DatabusMessageProducer;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Databus 服务端自动配置
+ *
+ * @author ZT
+ */
+@Configuration
+@EnableConfigurationProperties(DatabusServerProperties.class)
+@ConditionalOnProperty(prefix = "zt.databus.sync.server", name = "enabled", havingValue = "true")
+public class DatabusServerAutoConfiguration {
+
+ @Bean
+ public DatabusMessageProducer databusMessageProducer(DatabusServerProperties properties) {
+ return new DatabusMessageProducer(properties);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusServerProperties.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusServerProperties.java
new file mode 100644
index 00000000..22836f48
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusServerProperties.java
@@ -0,0 +1,60 @@
+package com.zt.plat.framework.databus.server.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.List;
+
+/**
+ * Databus 服务端配置属性
+ *
+ * @author ZT
+ */
+@Data
+@ConfigurationProperties(prefix = "zt.databus.sync.server")
+public class DatabusServerProperties {
+
+ /**
+ * 是否启用
+ */
+ private boolean enabled = false;
+
+ /**
+ * MQ 配置
+ */
+ private MqConfig mq = new MqConfig();
+
+ /**
+ * 订阅的客户端列表
+ */
+ private List clients;
+
+ @Data
+ public static class MqConfig {
+ /**
+ * 是否启用 MQ 发送
+ */
+ private boolean enabled = true;
+
+ /**
+ * RocketMQ NameServer 地址
+ */
+ private String nameServer;
+
+ /**
+ * Topic 基础名称
+ */
+ private String topicBase = "databus-sync";
+
+ /**
+ * 生产者组名称
+ */
+ private String producerGroup = "databus-server-producer";
+ /**
+ * 发送超时时间(毫秒)
+ */
+ private int sendMsgTimeout = 10000; // 默认 10 秒
+
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusSyncServerAutoConfiguration.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusSyncServerAutoConfiguration.java
new file mode 100644
index 00000000..1c929812
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusSyncServerAutoConfiguration.java
@@ -0,0 +1,45 @@
+package com.zt.plat.framework.databus.server.config;
+
+import com.zt.plat.framework.databus.server.core.pusher.MessagePusher;
+import com.zt.plat.framework.databus.server.core.pusher.MessagePusherImpl;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.spring.core.RocketMQTemplate;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+/**
+ * Databus 同步服务端自动配置
+ *
+ * @author ZT
+ */
+@Slf4j
+@AutoConfiguration
+@EnableAsync
+@EnableConfigurationProperties(DatabusSyncServerProperties.class)
+@ComponentScan(basePackages = "com.zt.plat.framework.databus.server")
+@MapperScan("com.zt.plat.framework.databus.server.dal.mapper")
+public class DatabusSyncServerAutoConfiguration {
+
+ public DatabusSyncServerAutoConfiguration() {
+ log.info("[Databus] 数据同步服务端模块已加载");
+ }
+
+ /**
+ * 注册消息推送器 Bean
+ */
+ @Bean
+ @ConditionalOnBean(RocketMQTemplate.class)
+ public MessagePusher messagePusher(RocketMQTemplate rocketMQTemplate) {
+ MessagePusherImpl pusher = new MessagePusherImpl();
+ pusher.setRocketMQTemplate(rocketMQTemplate);
+ log.info("[Databus] MessagePusher Bean 已注册");
+ return pusher;
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusSyncServerProperties.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusSyncServerProperties.java
new file mode 100644
index 00000000..f1cba915
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/config/DatabusSyncServerProperties.java
@@ -0,0 +1,61 @@
+package com.zt.plat.framework.databus.server.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * Databus 数据同步服务端配置属性
+ *
+ * @author ZT
+ */
+@Data
+@ConfigurationProperties(prefix = "zt.databus.sync.server")
+public class DatabusSyncServerProperties {
+
+ /**
+ * 是否启用
+ */
+ private Boolean enabled = true;
+
+ /**
+ * 重试配置
+ */
+ private Retry retry = new Retry();
+
+ /**
+ * 批量推送配置
+ */
+ private Batch batch = new Batch();
+
+ @Data
+ public static class Retry {
+ /**
+ * 最大重试次数
+ */
+ private Integer maxAttempts = 5;
+
+ /**
+ * 初始重试延迟(秒)
+ */
+ private Integer initialDelay = 1;
+
+ /**
+ * 重试延迟倍数
+ */
+ private Integer multiplier = 2;
+ }
+
+ @Data
+ public static class Batch {
+ /**
+ * 默认批量大小
+ */
+ private Integer defaultSize = 500;
+
+ /**
+ * 批量推送间隔(秒)
+ */
+ private Integer interval = 5;
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncClientController.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncClientController.java
new file mode 100644
index 00000000..e758be19
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncClientController.java
@@ -0,0 +1,92 @@
+package com.zt.plat.framework.databus.server.controller.admin;
+
+import com.zt.plat.framework.common.pojo.CommonResult;
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.client.DatabusSyncClientPageReqVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.client.DatabusSyncClientRespVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.client.DatabusSyncClientSaveReqVO;
+import com.zt.plat.framework.databus.server.convert.DatabusSyncClientConvert;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncClientDO;
+import com.zt.plat.framework.databus.server.service.DatabusSyncClientService;
+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.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static com.zt.plat.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 数据同步客户端")
+@RestController
+@RequestMapping("/databus/sync/client")
+@Validated
+public class DatabusSyncClientController {
+
+ @Resource
+ private DatabusSyncClientService clientService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建数据同步客户端")
+ @PreAuthorize("@ss.hasPermission('databus:sync:client:create')")
+ public CommonResult createClient(@Valid @RequestBody DatabusSyncClientSaveReqVO createReqVO) {
+ return success(clientService.createClient(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新数据同步客户端")
+ @PreAuthorize("@ss.hasPermission('databus:sync:client:update')")
+ public CommonResult updateClient(@Valid @RequestBody DatabusSyncClientSaveReqVO updateReqVO) {
+ clientService.updateClient(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除数据同步客户端")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('databus:sync:client:delete')")
+ public CommonResult deleteClient(@RequestParam("id") Long id) {
+ clientService.deleteClient(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得数据同步客户端")
+ @Parameter(name = "id", description = "编号", required = true, example = "1")
+ @PreAuthorize("@ss.hasPermission('databus:sync:client:query')")
+ public CommonResult getClient(@RequestParam("id") Long id) {
+ DatabusSyncClientDO client = clientService.getClient(id);
+ return success(DatabusSyncClientConvert.INSTANCE.convert(client));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得数据同步客户端分页")
+ @PreAuthorize("@ss.hasPermission('databus:sync:client:query')")
+ public CommonResult> getClientPage(@Valid DatabusSyncClientPageReqVO pageReqVO) {
+ PageResult pageResult = clientService.getClientPage(pageReqVO);
+ return success(DatabusSyncClientConvert.INSTANCE.convertPage(pageResult));
+ }
+
+ @GetMapping("/list")
+ @Operation(summary = "获得数据同步客户端列表")
+ @PreAuthorize("@ss.hasPermission('databus:sync:client:query')")
+ public CommonResult> getClientList() {
+ List list = clientService.getClientList();
+ return success(DatabusSyncClientConvert.INSTANCE.convertList(list));
+ }
+
+ @PutMapping("/update-status")
+ @Operation(summary = "修改客户端启用状态")
+ @PreAuthorize("@ss.hasPermission('databus:sync:client:update')")
+ public CommonResult updateClientStatus(
+ @RequestParam("id") Long id,
+ @RequestParam("enabled") Integer enabled) {
+ clientService.updateClientStatus(id, enabled);
+ return success(true);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncDeadLetterController.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncDeadLetterController.java
new file mode 100644
index 00000000..7a89b128
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncDeadLetterController.java
@@ -0,0 +1,76 @@
+package com.zt.plat.framework.databus.server.controller.admin;
+
+import com.zt.plat.framework.common.pojo.CommonResult;
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.deadletter.DatabusSyncDeadLetterPageReqVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.deadletter.DatabusSyncDeadLetterRespVO;
+import com.zt.plat.framework.databus.server.convert.DatabusSyncDeadLetterConvert;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncDeadLetterDO;
+import com.zt.plat.framework.databus.server.service.DatabusSyncDeadLetterService;
+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.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static com.zt.plat.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 数据同步死信队列")
+@RestController
+@RequestMapping("/databus/sync/dead-letter")
+@Validated
+public class DatabusSyncDeadLetterController {
+
+ @Resource
+ private DatabusSyncDeadLetterService deadLetterService;
+
+ @GetMapping("/get")
+ @Operation(summary = "获得数据同步死信队列")
+ @Parameter(name = "id", description = "编号", required = true, example = "1")
+ @PreAuthorize("@ss.hasPermission('databus:sync:dead-letter:query')")
+ public CommonResult getDeadLetter(@RequestParam("id") Long id) {
+ DatabusSyncDeadLetterDO deadLetter = deadLetterService.getDeadLetter(id);
+ return success(DatabusSyncDeadLetterConvert.INSTANCE.convert(deadLetter));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得数据同步死信队列分页")
+ @PreAuthorize("@ss.hasPermission('databus:sync:dead-letter:query')")
+ public CommonResult> getDeadLetterPage(@Valid DatabusSyncDeadLetterPageReqVO pageReqVO) {
+ PageResult pageResult = deadLetterService.getDeadLetterPage(pageReqVO);
+ return success(DatabusSyncDeadLetterConvert.INSTANCE.convertPage(pageResult));
+ }
+
+ @PostMapping("/reprocess")
+ @Operation(summary = "重新投递死信消息")
+ @Parameter(name = "id", description = "死信ID", required = true)
+ @PreAuthorize("@ss.hasPermission('databus:sync:dead-letter:reprocess')")
+ public CommonResult reprocessDeadLetter(@RequestParam("id") Long id) {
+ deadLetterService.reprocessDeadLetter(id);
+ return success(true);
+ }
+
+ @PostMapping("/batch-reprocess")
+ @Operation(summary = "批量重新投递死信消息")
+ @PreAuthorize("@ss.hasPermission('databus:sync:dead-letter:reprocess')")
+ public CommonResult batchReprocessDeadLetter(@RequestBody List ids) {
+ deadLetterService.batchReprocessDeadLetter(ids);
+ return success(true);
+ }
+
+ @PutMapping("/mark-handled")
+ @Operation(summary = "标记为已处理")
+ @PreAuthorize("@ss.hasPermission('databus:sync:dead-letter:update')")
+ public CommonResult markHandled(
+ @RequestParam("id") Long id,
+ @RequestParam(value = "remark", required = false) String remark) {
+ deadLetterService.markHandled(id, remark);
+ return success(true);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncEventController.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncEventController.java
new file mode 100644
index 00000000..c74227d2
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncEventController.java
@@ -0,0 +1,92 @@
+package com.zt.plat.framework.databus.server.controller.admin;
+
+import com.zt.plat.framework.common.pojo.CommonResult;
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.event.DatabusSyncEventPageReqVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.event.DatabusSyncEventRespVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.event.DatabusSyncEventSaveReqVO;
+import com.zt.plat.framework.databus.server.convert.DatabusSyncEventConvert;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncEventDO;
+import com.zt.plat.framework.databus.server.service.DatabusSyncEventService;
+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.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static com.zt.plat.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 数据同步事件")
+@RestController
+@RequestMapping("/databus/sync/event")
+@Validated
+public class DatabusSyncEventController {
+
+ @Resource
+ private DatabusSyncEventService eventService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建数据同步事件")
+ @PreAuthorize("@ss.hasPermission('databus:sync:event:create')")
+ public CommonResult createEvent(@Valid @RequestBody DatabusSyncEventSaveReqVO createReqVO) {
+ return success(eventService.createEvent(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新数据同步事件")
+ @PreAuthorize("@ss.hasPermission('databus:sync:event:update')")
+ public CommonResult updateEvent(@Valid @RequestBody DatabusSyncEventSaveReqVO updateReqVO) {
+ eventService.updateEvent(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除数据同步事件")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('databus:sync:event:delete')")
+ public CommonResult deleteEvent(@RequestParam("id") Long id) {
+ eventService.deleteEvent(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得数据同步事件")
+ @Parameter(name = "id", description = "编号", required = true, example = "1")
+ @PreAuthorize("@ss.hasPermission('databus:sync:event:query')")
+ public CommonResult getEvent(@RequestParam("id") Long id) {
+ DatabusSyncEventDO event = eventService.getEvent(id);
+ return success(DatabusSyncEventConvert.INSTANCE.convert(event));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得数据同步事件分页")
+ @PreAuthorize("@ss.hasPermission('databus:sync:event:query')")
+ public CommonResult> getEventPage(@Valid DatabusSyncEventPageReqVO pageReqVO) {
+ PageResult pageResult = eventService.getEventPage(pageReqVO);
+ return success(DatabusSyncEventConvert.INSTANCE.convertPage(pageResult));
+ }
+
+ @GetMapping("/list")
+ @Operation(summary = "获得数据同步事件列表")
+ @PreAuthorize("@ss.hasPermission('databus:sync:event:query')")
+ public CommonResult> getEventList() {
+ List list = eventService.getEventList();
+ return success(DatabusSyncEventConvert.INSTANCE.convertList(list));
+ }
+
+ @PutMapping("/update-status")
+ @Operation(summary = "修改事件启用状态")
+ @PreAuthorize("@ss.hasPermission('databus:sync:event:update')")
+ public CommonResult updateEventStatus(
+ @RequestParam("id") Long id,
+ @RequestParam("enabled") Integer enabled) {
+ eventService.updateEventStatus(id, enabled);
+ return success(true);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncFullTaskController.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncFullTaskController.java
new file mode 100644
index 00000000..cca415c9
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncFullTaskController.java
@@ -0,0 +1,102 @@
+package com.zt.plat.framework.databus.server.controller.admin;
+
+import com.zt.plat.framework.common.pojo.CommonResult;
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.fulltask.DatabusSyncFullTaskCreateReqVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.fulltask.DatabusSyncFullTaskPageReqVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.fulltask.DatabusSyncFullTaskRespVO;
+import com.zt.plat.framework.databus.server.convert.DatabusSyncFullTaskConvert;
+import com.zt.plat.framework.databus.server.core.sync.DatabusFullSyncService;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncFullTaskDO;
+import com.zt.plat.framework.databus.server.dal.mapper.DatabusSyncFullTaskMapper;
+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.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import static com.zt.plat.framework.common.pojo.CommonResult.success;
+
+/**
+ * 管理后台 - 数据全量同步任务
+ *
+ * @author ZT
+ */
+@Tag(name = "管理后台 - 全量同步任务")
+@RestController
+@RequestMapping("/databus/sync/full-task")
+@Validated
+public class DatabusSyncFullTaskController {
+
+ @Resource
+ private DatabusFullSyncService fullSyncService;
+
+ @Resource
+ private DatabusSyncFullTaskMapper fullTaskMapper;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建全量同步任务")
+ @PreAuthorize("@ss.hasPermission('databus:sync:full-task:create')")
+ public CommonResult createFullTask(@Valid @RequestBody DatabusSyncFullTaskCreateReqVO createReqVO) {
+ Long taskId = fullSyncService.createFullSyncTask(createReqVO.getSubscriptionId(), createReqVO.getRemark());
+ return success(taskId);
+ }
+
+ @PostMapping("/execute")
+ @Operation(summary = "执行全量同步任务")
+ @Parameter(name = "id", description = "任务ID", required = true)
+ @PreAuthorize("@ss.hasPermission('databus:sync:full-task:execute')")
+ public CommonResult executeFullTask(@RequestParam("id") Long id) {
+ fullSyncService.executeFullSyncTask(id);
+ return success(true);
+ }
+
+ @PostMapping("/create-and-execute")
+ @Operation(summary = "创建并执行全量同步任务")
+ @PreAuthorize("@ss.hasPermission('databus:sync:full-task:create')")
+ public CommonResult createAndExecuteFullTask(@Valid @RequestBody DatabusSyncFullTaskCreateReqVO createReqVO) {
+ Long taskId = fullSyncService.createFullSyncTask(createReqVO.getSubscriptionId(), createReqVO.getRemark());
+ // 异步执行任务
+ fullSyncService.executeFullSyncTask(taskId);
+ return success(taskId);
+ }
+
+ @PostMapping("/cancel")
+ @Operation(summary = "取消全量同步任务")
+ @Parameter(name = "id", description = "任务ID", required = true)
+ @PreAuthorize("@ss.hasPermission('databus:sync:full-task:cancel')")
+ public CommonResult cancelFullTask(@RequestParam("id") Long id) {
+ fullSyncService.cancelFullSyncTask(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得全量同步任务详情")
+ @Parameter(name = "id", description = "任务ID", required = true, example = "1")
+ @PreAuthorize("@ss.hasPermission('databus:sync:full-task:query')")
+ public CommonResult getFullTask(@RequestParam("id") Long id) {
+ DatabusSyncFullTaskDO task = fullSyncService.getTaskById(id);
+ return success(DatabusSyncFullTaskConvert.INSTANCE.convert(task));
+ }
+
+ @GetMapping("/get-by-task-no")
+ @Operation(summary = "根据任务编号获得全量同步任务详情")
+ @Parameter(name = "taskNo", description = "任务编号", required = true, example = "abc123")
+ @PreAuthorize("@ss.hasPermission('databus:sync:full-task:query')")
+ public CommonResult getFullTaskByTaskNo(@RequestParam("taskNo") String taskNo) {
+ DatabusSyncFullTaskDO task = fullSyncService.getTaskByTaskNo(taskNo);
+ return success(DatabusSyncFullTaskConvert.INSTANCE.convert(task));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得全量同步任务分页")
+ @PreAuthorize("@ss.hasPermission('databus:sync:full-task:query')")
+ public CommonResult> getFullTaskPage(@Valid DatabusSyncFullTaskPageReqVO pageReqVO) {
+ PageResult pageResult = fullTaskMapper.selectPage(pageReqVO);
+ return success(DatabusSyncFullTaskConvert.INSTANCE.convertPage(pageResult));
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncPushLogController.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncPushLogController.java
new file mode 100644
index 00000000..52b10746
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncPushLogController.java
@@ -0,0 +1,69 @@
+package com.zt.plat.framework.databus.server.controller.admin;
+
+import com.zt.plat.framework.common.pojo.CommonResult;
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.pushlog.DatabusSyncPushLogPageReqVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.pushlog.DatabusSyncPushLogRespVO;
+import com.zt.plat.framework.databus.server.convert.DatabusSyncPushLogConvert;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncEventRecordDO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncLogDO;
+import com.zt.plat.framework.databus.server.dal.mapper.DatabusSyncEventRecordMapper;
+import com.zt.plat.framework.databus.server.service.DatabusSyncLogService;
+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.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import static com.zt.plat.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 数据同步推送日志")
+@RestController
+@RequestMapping("/databus/sync/push-log")
+@Validated
+public class DatabusSyncPushLogController {
+
+ @Resource
+ private DatabusSyncLogService pushLogService;
+
+ @Resource
+ private DatabusSyncEventRecordMapper eventRecordMapper;
+
+ @GetMapping("/get")
+ @Operation(summary = "获得数据同步推送日志")
+ @Parameter(name = "id", description = "编号", required = true, example = "1")
+ @PreAuthorize("@ss.hasPermission('databus:sync:push-log:query')")
+ public CommonResult getPushLog(@RequestParam("id") Long id) {
+ DatabusSyncLogDO pushLog = pushLogService.getPushLog(id);
+ DatabusSyncPushLogRespVO respVO = DatabusSyncPushLogConvert.INSTANCE.convert(pushLog);
+ // 关联查询事件记录,获取消息内容
+ if (pushLog != null && pushLog.getEventRecordId() != null) {
+ DatabusSyncEventRecordDO eventRecord = eventRecordMapper.selectById(pushLog.getEventRecordId());
+ if (eventRecord != null) {
+ respVO.setDataSnapshot(eventRecord.getDataSnapshot());
+ }
+ }
+ return success(respVO);
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得数据同步推送日志分页")
+ @PreAuthorize("@ss.hasPermission('databus:sync:push-log:query')")
+ public CommonResult> getPushLogPage(@Valid DatabusSyncPushLogPageReqVO pageReqVO) {
+ PageResult pageResult = pushLogService.getPushLogPage(pageReqVO);
+ return success(DatabusSyncPushLogConvert.INSTANCE.convertPage(pageResult));
+ }
+
+ @PostMapping("/retry")
+ @Operation(summary = "重试推送")
+ @Parameter(name = "id", description = "日志ID", required = true)
+ @PreAuthorize("@ss.hasPermission('databus:sync:push-log:retry')")
+ public CommonResult retryPush(@RequestParam("id") Long id) {
+ pushLogService.retryPush(id);
+ return success(true);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncSubscriptionController.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncSubscriptionController.java
new file mode 100644
index 00000000..737f138f
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/DatabusSyncSubscriptionController.java
@@ -0,0 +1,100 @@
+package com.zt.plat.framework.databus.server.controller.admin;
+
+import com.zt.plat.framework.common.pojo.CommonResult;
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.subscription.DatabusSyncSubscriptionPageReqVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.subscription.DatabusSyncSubscriptionRespVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.subscription.DatabusSyncSubscriptionSaveReqVO;
+import com.zt.plat.framework.databus.server.convert.DatabusSyncSubscriptionConvert;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncSubscriptionDO;
+import com.zt.plat.framework.databus.server.service.DatabusSyncSubscriptionService;
+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.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import static com.zt.plat.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 数据同步订阅")
+@RestController
+@RequestMapping("/databus/sync/subscription")
+@Validated
+public class DatabusSyncSubscriptionController {
+
+ @Resource
+ private DatabusSyncSubscriptionService subscriptionService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建数据同步订阅")
+ @PreAuthorize("@ss.hasPermission('databus:sync:subscription:create')")
+ public CommonResult createSubscription(@Valid @RequestBody DatabusSyncSubscriptionSaveReqVO createReqVO) {
+ return success(subscriptionService.createSubscription(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新数据同步订阅")
+ @PreAuthorize("@ss.hasPermission('databus:sync:subscription:update')")
+ public CommonResult updateSubscription(@Valid @RequestBody DatabusSyncSubscriptionSaveReqVO updateReqVO) {
+ subscriptionService.updateSubscription(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除数据同步订阅")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('databus:sync:subscription:delete')")
+ public CommonResult deleteSubscription(@RequestParam("id") Long id) {
+ subscriptionService.deleteSubscription(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得数据同步订阅")
+ @Parameter(name = "id", description = "编号", required = true, example = "1")
+ @PreAuthorize("@ss.hasPermission('databus:sync:subscription:query')")
+ public CommonResult getSubscription(@RequestParam("id") Long id) {
+ DatabusSyncSubscriptionDO subscription = subscriptionService.getSubscription(id);
+ return success(DatabusSyncSubscriptionConvert.INSTANCE.convert(subscription));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得数据同步订阅分页")
+ @PreAuthorize("@ss.hasPermission('databus:sync:subscription:query')")
+ public CommonResult> getSubscriptionPage(@Valid DatabusSyncSubscriptionPageReqVO pageReqVO) {
+ PageResult pageResult = subscriptionService.getSubscriptionPage(pageReqVO);
+ return success(DatabusSyncSubscriptionConvert.INSTANCE.convertPage(pageResult));
+ }
+
+ @PutMapping("/update-status")
+ @Operation(summary = "修改订阅启用状态")
+ @PreAuthorize("@ss.hasPermission('databus:sync:subscription:update')")
+ public CommonResult updateSubscriptionStatus(
+ @RequestParam("id") Long id,
+ @RequestParam("enabled") Integer enabled) {
+ subscriptionService.updateSubscriptionStatus(id, enabled);
+ return success(true);
+ }
+
+ @PutMapping("/reset-checkpoint")
+ @Operation(summary = "重置订阅断点")
+ @Parameter(name = "id", description = "订阅ID", required = true)
+ @PreAuthorize("@ss.hasPermission('databus:sync:subscription:update')")
+ public CommonResult resetCheckpoint(@RequestParam("id") Long id) {
+ subscriptionService.resetCheckpoint(id);
+ return success(true);
+ }
+
+ @PostMapping("/trigger-sync")
+ @Operation(summary = "手动触发同步")
+ @Parameter(name = "id", description = "订阅ID", required = true)
+ @PreAuthorize("@ss.hasPermission('databus:sync:subscription:trigger')")
+ public CommonResult triggerSync(@RequestParam("id") Long id) {
+ subscriptionService.triggerSync(id);
+ return success(true);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/client/DatabusSyncClientPageReqVO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/client/DatabusSyncClientPageReqVO.java
new file mode 100644
index 00000000..896bf61e
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/client/DatabusSyncClientPageReqVO.java
@@ -0,0 +1,27 @@
+package com.zt.plat.framework.databus.server.controller.admin.vo.client;
+
+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;
+
+@Schema(description = "管理后台 - 数据同步客户端分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DatabusSyncClientPageReqVO extends PageParam {
+
+ @Schema(description = "客户端编码", example = "company-a")
+ private String clientCode;
+
+ @Schema(description = "客户端名称", example = "A分公司")
+ private String clientName;
+
+ @Schema(description = "启用状态(0-禁用 1-启用)", example = "1")
+ private Integer enabled;
+
+ @Schema(description = "通信方式(MQ_FIRST-MQ优先 HTTP_ONLY-仅HTTP)", example = "MQ_FIRST")
+ private String transportType;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/client/DatabusSyncClientRespVO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/client/DatabusSyncClientRespVO.java
new file mode 100644
index 00000000..fcf35f7c
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/client/DatabusSyncClientRespVO.java
@@ -0,0 +1,63 @@
+package com.zt.plat.framework.databus.server.controller.admin.vo.client;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 数据同步客户端 Response VO")
+@Data
+public class DatabusSyncClientRespVO {
+
+ @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long id;
+
+ @Schema(description = "租户ID", example = "1")
+ private Long tenantId;
+
+ @Schema(description = "客户端编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "company-a")
+ private String clientCode;
+
+ @Schema(description = "客户端名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "A分公司")
+ private String clientName;
+
+ @Schema(description = "启用状态(0-禁用 1-启用)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Integer enabled;
+
+ @Schema(description = "通信方式(MQ_FIRST-MQ优先 HTTP_ONLY-仅HTTP)", requiredMode = Schema.RequiredMode.REQUIRED, example = "MQ_FIRST")
+ private String transportType;
+
+ @Schema(description = "MQ是否启用(0-否 1-是)", example = "1")
+ private Integer mqEnabled;
+
+ @Schema(description = "MQ NameServer地址", example = "localhost:9876")
+ private String mqNamesrvAddr;
+
+ @Schema(description = "MQ Topic基础名称", example = "databus-sync")
+ private String mqTopicBase;
+
+ @Schema(description = "HTTP是否启用(0-否 1-是)", example = "1")
+ private Integer httpEnabled;
+
+ @Schema(description = "HTTP推送端点", example = "http://example.com/databus/sync/receive")
+ private String httpEndpoint;
+
+ @Schema(description = "应用Key", example = "app-key-001")
+ private String appKey;
+
+ @Schema(description = "应用Secret", example = "***")
+ private String appSecret;
+
+ @Schema(description = "创建者", example = "admin")
+ private String creator;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+ @Schema(description = "更新者", example = "admin")
+ private String updater;
+
+ @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime updateTime;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/client/DatabusSyncClientSaveReqVO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/client/DatabusSyncClientSaveReqVO.java
new file mode 100644
index 00000000..475c9f7b
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/client/DatabusSyncClientSaveReqVO.java
@@ -0,0 +1,55 @@
+package com.zt.plat.framework.databus.server.controller.admin.vo.client;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Pattern;
+
+@Schema(description = "管理后台 - 数据同步客户端创建/修改 Request VO")
+@Data
+public class DatabusSyncClientSaveReqVO {
+
+ @Schema(description = "主键ID", example = "1")
+ private Long id;
+
+ @Schema(description = "客户端编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "company-a")
+ @NotBlank(message = "客户端编码不能为空")
+ @Pattern(regexp = "^[a-z0-9-]+$", message = "客户端编码只能包含小写字母、数字和短横线")
+ private String clientCode;
+
+ @Schema(description = "客户端名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "A分公司")
+ @NotBlank(message = "客户端名称不能为空")
+ private String clientName;
+
+ @Schema(description = "启用状态(0-禁用 1-启用)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "启用状态不能为空")
+ private Integer enabled;
+
+ @Schema(description = "通信方式(MQ_FIRST-MQ优先 HTTP_ONLY-仅HTTP)", requiredMode = Schema.RequiredMode.REQUIRED, example = "MQ_FIRST")
+ @NotBlank(message = "通信方式不能为空")
+ private String transportType;
+
+ @Schema(description = "MQ是否启用(0-否 1-是)", example = "1")
+ private Integer mqEnabled;
+
+ @Schema(description = "MQ NameServer地址", example = "localhost:9876")
+ private String mqNamesrvAddr;
+
+ @Schema(description = "MQ Topic基础名称", example = "databus-sync")
+ private String mqTopicBase;
+
+ @Schema(description = "HTTP是否启用(0-否 1-是)", example = "1")
+ private Integer httpEnabled;
+
+ @Schema(description = "HTTP推送端点", example = "http://example.com/databus/sync/receive")
+ private String httpEndpoint;
+
+ @Schema(description = "应用Key", example = "app-key-001")
+ private String appKey;
+
+ @Schema(description = "应用Secret(加密存储)", example = "secret")
+ private String appSecret;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/deadletter/DatabusSyncDeadLetterPageReqVO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/deadletter/DatabusSyncDeadLetterPageReqVO.java
new file mode 100644
index 00000000..d07889cc
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/deadletter/DatabusSyncDeadLetterPageReqVO.java
@@ -0,0 +1,43 @@
+package com.zt.plat.framework.databus.server.controller.admin.vo.deadletter;
+
+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;
+
+@Schema(description = "管理后台 - 数据同步死信队列分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DatabusSyncDeadLetterPageReqVO extends PageParam {
+
+ @Schema(description = "同步ID", example = "sync-20231124-001")
+ private String syncId;
+
+ @Schema(description = "客户端编码", example = "company-a")
+ private String clientCode;
+
+ @Schema(description = "事件类型", example = "user-changed")
+ private String eventType;
+
+ @Schema(description = "状态(PENDING-待处理 REDELIVERED-已重新投递 IGNORED-已忽略)", example = "PENDING")
+ private String status;
+
+ @Schema(description = "是否已处理(0-否 1-是)", example = "0")
+ private Integer handled;
+
+ @Schema(description = "创建时间开始", example = "2023-11-24 00:00:00")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime createTimeStart;
+
+ @Schema(description = "创建时间结束", example = "2023-11-24 23:59:59")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime createTimeEnd;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/deadletter/DatabusSyncDeadLetterRespVO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/deadletter/DatabusSyncDeadLetterRespVO.java
new file mode 100644
index 00000000..39f29bfb
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/deadletter/DatabusSyncDeadLetterRespVO.java
@@ -0,0 +1,63 @@
+package com.zt.plat.framework.databus.server.controller.admin.vo.deadletter;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 数据同步死信队列 Response VO")
+@Data
+public class DatabusSyncDeadLetterRespVO {
+
+ @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long id;
+
+ @Schema(description = "同步ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "sync-20231124-001")
+ private String syncId;
+
+ @Schema(description = "同步日志ID", example = "10001")
+ private Long syncLogId;
+
+ @Schema(description = "客户端编码", example = "company-a")
+ private String clientCode;
+
+ @Schema(description = "事件类型", example = "user-changed")
+ private String eventType;
+
+ @Schema(description = "消息体(JSON)", example = "{\"userId\":1001,\"userName\":\"张三\"}")
+ private String messageBody;
+
+ @Schema(description = "状态(PENDING-待处理 REDELIVERED-已重新投递 IGNORED-已忽略)", example = "PENDING")
+ private String status;
+
+ @Schema(description = "失败原因", example = "连接超时")
+ private String lastErrorMessage;
+
+ @Schema(description = "失败时间")
+ private LocalDateTime lastErrorTime;
+
+ @Schema(description = "重试次数", example = "5")
+ private Integer retryCount;
+
+ @Schema(description = "是否已处理(0-否 1-是)", example = "0")
+ private Integer handled;
+
+ @Schema(description = "处理时间")
+ private LocalDateTime handleTime;
+
+ @Schema(description = "处理人", example = "admin")
+ private String handler;
+
+ @Schema(description = "处理备注", example = "已通知开发人员修复")
+ private String handleRemark;
+
+ @Schema(description = "租户ID", example = "1")
+ private Long tenantId;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+ @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime updateTime;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/event/DatabusSyncEventPageReqVO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/event/DatabusSyncEventPageReqVO.java
new file mode 100644
index 00000000..708bb89a
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/event/DatabusSyncEventPageReqVO.java
@@ -0,0 +1,24 @@
+package com.zt.plat.framework.databus.server.controller.admin.vo.event;
+
+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;
+
+@Schema(description = "管理后台 - 数据同步事件分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DatabusSyncEventPageReqVO extends PageParam {
+
+ @Schema(description = "事件类型编码", example = "user-changed")
+ private String eventType;
+
+ @Schema(description = "事件名称", example = "用户信息变更")
+ private String eventName;
+
+ @Schema(description = "启用状态(0-禁用 1-启用)", example = "1")
+ private Integer enabled;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/event/DatabusSyncEventRespVO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/event/DatabusSyncEventRespVO.java
new file mode 100644
index 00000000..6dfd2d9e
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/event/DatabusSyncEventRespVO.java
@@ -0,0 +1,54 @@
+package com.zt.plat.framework.databus.server.controller.admin.vo.event;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 数据同步事件 Response VO")
+@Data
+public class DatabusSyncEventRespVO {
+
+ @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long id;
+
+ @Schema(description = "租户ID", example = "1")
+ private Long tenantId;
+
+ @Schema(description = "事件类型编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "system-user-full")
+ private String eventType;
+
+ @Schema(description = "事件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "用户信息变更")
+ private String eventName;
+
+ @Schema(description = "事件描述", example = "用户基本信息变更事件")
+ private String eventDesc;
+
+ @Schema(description = "启用状态(0-禁用 1-启用)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Integer enabled;
+
+ @Schema(description = "是否支持全量同步(0-否 1-是)", example = "1")
+ private Integer supportFullSync;
+
+ @Schema(description = "是否支持增量同步(0-否 1-是)", example = "1")
+ private Integer supportIncrementalSync;
+
+ @Schema(description = "数据结构版本", example = "1")
+ private Integer dataVersion;
+
+ @Schema(description = "数据提供者类型(全量同步使用)", example = "ORG")
+ private String dataProviderMethod;
+
+ @Schema(description = "创建者", example = "admin")
+ private String creator;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+ @Schema(description = "更新者", example = "admin")
+ private String updater;
+
+ @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime updateTime;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/event/DatabusSyncEventSaveReqVO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/event/DatabusSyncEventSaveReqVO.java
new file mode 100644
index 00000000..578854d8
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/event/DatabusSyncEventSaveReqVO.java
@@ -0,0 +1,45 @@
+package com.zt.plat.framework.databus.server.controller.admin.vo.event;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Pattern;
+
+@Schema(description = "管理后台 - 数据同步事件创建/修改 Request VO")
+@Data
+public class DatabusSyncEventSaveReqVO {
+
+ @Schema(description = "主键ID", example = "1")
+ private Long id;
+
+ @Schema(description = "事件类型编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "system-user-full")
+ @NotBlank(message = "事件类型编码不能为空")
+ @Pattern(regexp = "^[a-z0-9-]+$", message = "事件类型编码只能包含小写字母、数字和短横线")
+ private String eventType;
+
+ @Schema(description = "事件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "用户信息变更")
+ @NotBlank(message = "事件名称不能为空")
+ private String eventName;
+
+ @Schema(description = "事件描述", example = "用户基本信息变更事件")
+ private String eventDesc;
+
+ @Schema(description = "启用状态(0-禁用 1-启用)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "启用状态不能为空")
+ private Integer enabled;
+
+ @Schema(description = "数据提供者类型(全量同步使用)", example = "ORG")
+ private String dataProviderMethod;
+
+ @Schema(description = "是否支持全量同步(0-否 1-是)", example = "1")
+ private Integer supportFullSync;
+
+ @Schema(description = "是否支持增量同步(0-否 1-是)", example = "1")
+ private Integer supportIncrementalSync;
+
+ @Schema(description = "数据结构版本", example = "1")
+ private Integer dataVersion;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/fulltask/DatabusSyncFullTaskCreateReqVO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/fulltask/DatabusSyncFullTaskCreateReqVO.java
new file mode 100644
index 00000000..27d35719
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/fulltask/DatabusSyncFullTaskCreateReqVO.java
@@ -0,0 +1,18 @@
+package com.zt.plat.framework.databus.server.controller.admin.vo.fulltask;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 全量同步任务创建 Request VO")
+@Data
+public class DatabusSyncFullTaskCreateReqVO {
+
+ @Schema(description = "订阅关系ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "订阅关系ID不能为空")
+ private Long subscriptionId;
+
+ @Schema(description = "备注", example = "手动触发全量同步")
+ private String remark;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/fulltask/DatabusSyncFullTaskPageReqVO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/fulltask/DatabusSyncFullTaskPageReqVO.java
new file mode 100644
index 00000000..08ac6423
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/fulltask/DatabusSyncFullTaskPageReqVO.java
@@ -0,0 +1,30 @@
+package com.zt.plat.framework.databus.server.controller.admin.vo.fulltask;
+
+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;
+
+@Schema(description = "管理后台 - 全量同步任务分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DatabusSyncFullTaskPageReqVO extends PageParam {
+
+ @Schema(description = "任务编号", example = "abc123")
+ private String taskNo;
+
+ @Schema(description = "订阅关系ID", example = "1")
+ private Long subscriptionId;
+
+ @Schema(description = "客户端编码", example = "client-01")
+ private String clientCode;
+
+ @Schema(description = "事件类型", example = "ORG_SYNC")
+ private String eventType;
+
+ @Schema(description = "任务状态(0-待执行 1-执行中 2-已完成 3-失败 4-已取消)", example = "2")
+ private Integer status;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/fulltask/DatabusSyncFullTaskRespVO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/fulltask/DatabusSyncFullTaskRespVO.java
new file mode 100644
index 00000000..de43a6d7
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/fulltask/DatabusSyncFullTaskRespVO.java
@@ -0,0 +1,88 @@
+package com.zt.plat.framework.databus.server.controller.admin.vo.fulltask;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 全量同步任务 Response VO")
+@Data
+public class DatabusSyncFullTaskRespVO {
+
+ @Schema(description = "主键ID", example = "1")
+ private Long id;
+
+ @Schema(description = "任务编号", example = "abc123")
+ private String taskNo;
+
+ @Schema(description = "订阅关系ID", example = "1")
+ private Long subscriptionId;
+
+ @Schema(description = "客户端编码", example = "client-01")
+ private String clientCode;
+
+ @Schema(description = "事件类型", example = "ORG_SYNC")
+ private String eventType;
+
+ @Schema(description = "任务状态(0-待执行 1-执行中 2-已完成 3-失败 4-已取消)", example = "2")
+ private Integer status;
+
+ @Schema(description = "总数据量", example = "1000")
+ private Long totalCount;
+
+ @Schema(description = "已处理数据量", example = "500")
+ private Long processedCount;
+
+ @Schema(description = "成功数据量", example = "480")
+ private Long successCount;
+
+ @Schema(description = "失败数据量", example = "20")
+ private Long failCount;
+
+ @Schema(description = "总批次数", example = "10")
+ private Integer totalBatch;
+
+ @Schema(description = "当前批次号", example = "5")
+ private Integer currentBatch;
+
+ @Schema(description = "批量大小", example = "100")
+ private Integer batchSize;
+
+ @Schema(description = "任务开始时间")
+ private LocalDateTime startTime;
+
+ @Schema(description = "任务结束时间")
+ private LocalDateTime endTime;
+
+ @Schema(description = "最后一次错误信息", example = "网络超时")
+ private String lastErrorMessage;
+
+ @Schema(description = "租户ID", example = "1")
+ private Long tenantId;
+
+ @Schema(description = "备注", example = "手动触发全量同步")
+ private String remark;
+
+ @Schema(description = "创建时间")
+ private LocalDateTime createTime;
+
+ @Schema(description = "更新时间")
+ private LocalDateTime updateTime;
+
+ @Schema(description = "进度百分比", example = "50.0")
+ private Double progressPercent;
+
+ /**
+ * 计算进度百分比
+ */
+ public Double getProgressPercent() {
+ if (totalCount == null || totalCount == 0) {
+ return 0.0;
+ }
+ if (processedCount == null) {
+ return 0.0;
+ }
+ return Math.round(processedCount * 10000.0 / totalCount) / 100.0;
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/pushlog/DatabusSyncPushLogPageReqVO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/pushlog/DatabusSyncPushLogPageReqVO.java
new file mode 100644
index 00000000..eb481034
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/pushlog/DatabusSyncPushLogPageReqVO.java
@@ -0,0 +1,46 @@
+package com.zt.plat.framework.databus.server.controller.admin.vo.pushlog;
+
+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;
+
+@Schema(description = "管理后台 - 数据同步推送日志分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DatabusSyncPushLogPageReqVO extends PageParam {
+
+ @Schema(description = "同步ID", example = "sync-20231124-001")
+ private String syncId;
+
+ @Schema(description = "订阅关系ID", example = "1")
+ private Long subscriptionId;
+
+ @Schema(description = "客户端编码", example = "company-a")
+ private String clientCode;
+
+ @Schema(description = "事件类型", example = "user-changed")
+ private String eventType;
+
+ @Schema(description = "状态(PENDING-待处理 SUCCESS-成功 FAILED-失败 RETRYING-重试中)", example = "SUCCESS")
+ private String status;
+
+ @Schema(description = "传输方式(MQ/HTTP)", example = "MQ")
+ private String transportType;
+
+ @Schema(description = "创建时间开始", example = "2023-11-24 00:00:00")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime createTimeStart;
+
+ @Schema(description = "创建时间结束", example = "2023-11-24 23:59:59")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime createTimeEnd;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/pushlog/DatabusSyncPushLogRespVO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/pushlog/DatabusSyncPushLogRespVO.java
new file mode 100644
index 00000000..8d1e7cdf
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/pushlog/DatabusSyncPushLogRespVO.java
@@ -0,0 +1,72 @@
+package com.zt.plat.framework.databus.server.controller.admin.vo.pushlog;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 数据同步推送日志 Response VO")
+@Data
+public class DatabusSyncPushLogRespVO {
+
+ @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long id;
+
+ @Schema(description = "同步ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "sync-20231124-001")
+ private String syncId;
+
+ @Schema(description = "事件记录ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "10001")
+ private Long eventRecordId;
+
+ @Schema(description = "订阅关系ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long subscriptionId;
+
+ @Schema(description = "客户端编码", example = "company-a")
+ private String clientCode;
+
+ @Schema(description = "事件类型", example = "user-changed")
+ private String eventType;
+
+ @Schema(description = "同步模式(FULL-全量 INCREMENTAL-增量)", example = "INCREMENTAL")
+ private String syncMode;
+
+ @Schema(description = "传输方式(MQ/HTTP)", requiredMode = Schema.RequiredMode.REQUIRED, example = "MQ")
+ private String transportType;
+
+ @Schema(description = "MQ Topic", example = "databus-sync-user-changed-company-a")
+ private String mqTopic;
+
+ @Schema(description = "MQ消息ID", example = "C0A8012300002A9F0000000000000001")
+ private String mqMsgId;
+
+ @Schema(description = "状态(PENDING-待处理 SUCCESS-成功 FAILED-失败 RETRYING-重试中)", requiredMode = Schema.RequiredMode.REQUIRED, example = "SUCCESS")
+ private String status;
+
+ @Schema(description = "重试次数", example = "0")
+ private Integer retryCount;
+
+ @Schema(description = "错误信息", example = "连接超时")
+ private String errorMessage;
+
+ @Schema(description = "开始时间")
+ private LocalDateTime startTime;
+
+ @Schema(description = "结束时间")
+ private LocalDateTime endTime;
+
+ @Schema(description = "耗时(毫秒)", example = "150")
+ private Integer duration;
+
+ @Schema(description = "租户ID", example = "1")
+ private Long tenantId;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+ @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime updateTime;
+
+ @Schema(description = "推送消息内容(JSON)", example = "{\"id\":1,\"name\":\"张三\"}")
+ private String dataSnapshot;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/subscription/DatabusSyncSubscriptionPageReqVO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/subscription/DatabusSyncSubscriptionPageReqVO.java
new file mode 100644
index 00000000..6a057825
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/subscription/DatabusSyncSubscriptionPageReqVO.java
@@ -0,0 +1,24 @@
+package com.zt.plat.framework.databus.server.controller.admin.vo.subscription;
+
+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;
+
+@Schema(description = "管理后台 - 数据同步订阅分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DatabusSyncSubscriptionPageReqVO extends PageParam {
+
+ @Schema(description = "客户端ID", example = "1")
+ private Long clientId;
+
+ @Schema(description = "事件ID", example = "1")
+ private Long eventId;
+
+ @Schema(description = "启用状态(0-禁用 1-启用)", example = "1")
+ private Integer enabled;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/subscription/DatabusSyncSubscriptionRespVO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/subscription/DatabusSyncSubscriptionRespVO.java
new file mode 100644
index 00000000..50a8500b
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/subscription/DatabusSyncSubscriptionRespVO.java
@@ -0,0 +1,78 @@
+package com.zt.plat.framework.databus.server.controller.admin.vo.subscription;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 数据同步订阅 Response VO")
+@Data
+public class DatabusSyncSubscriptionRespVO {
+
+ @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long id;
+
+ @Schema(description = "租户ID", example = "1")
+ private Long tenantId;
+
+ @Schema(description = "客户端ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long clientId;
+
+ @Schema(description = "客户端编码(关联查询)", example = "company-a")
+ private String clientCode;
+
+ @Schema(description = "客户端名称(关联查询)", example = "A分公司")
+ private String clientName;
+
+ @Schema(description = "事件ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long eventId;
+
+ @Schema(description = "事件类型(关联查询)", example = "user-changed")
+ private String eventType;
+
+ @Schema(description = "事件名称(关联查询)", example = "用户信息变更")
+ private String eventName;
+
+ @Schema(description = "启用状态(0-禁用 1-启用)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Integer enabled;
+
+ @Schema(description = "同步模式(FULL-全量 INCREMENTAL-增量)", example = "INCREMENTAL")
+ private String syncMode;
+
+ @Schema(description = "时效性(REALTIME-实时 NEAR_REALTIME-准实时 BATCH-批量)", example = "NEAR_REALTIME")
+ private String timeliness;
+
+ @Schema(description = "时效值(秒)", example = "60")
+ private Integer timelinessValue;
+
+ @Schema(description = "批量大小", example = "500")
+ private Integer batchSize;
+
+ @Schema(description = "最后同步的事件记录ID", example = "10001")
+ private Long lastSyncEventId;
+
+ @Schema(description = "最后同步时间")
+ private LocalDateTime lastSyncTime;
+
+ @Schema(description = "总同步次数", example = "100")
+ private Long totalSyncCount;
+
+ @Schema(description = "成功次数", example = "95")
+ private Long totalSuccessCount;
+
+ @Schema(description = "失败次数", example = "5")
+ private Long totalFailCount;
+
+ @Schema(description = "创建者", example = "admin")
+ private String creator;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+ @Schema(description = "更新者", example = "admin")
+ private String updater;
+
+ @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime updateTime;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/subscription/DatabusSyncSubscriptionSaveReqVO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/subscription/DatabusSyncSubscriptionSaveReqVO.java
new file mode 100644
index 00000000..83caeba4
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/controller/admin/vo/subscription/DatabusSyncSubscriptionSaveReqVO.java
@@ -0,0 +1,39 @@
+package com.zt.plat.framework.databus.server.controller.admin.vo.subscription;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import jakarta.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 数据同步订阅创建/修改 Request VO")
+@Data
+public class DatabusSyncSubscriptionSaveReqVO {
+
+ @Schema(description = "主键ID", example = "1")
+ private Long id;
+
+ @Schema(description = "客户端ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "客户端ID不能为空")
+ private Long clientId;
+
+ @Schema(description = "事件ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "事件ID不能为空")
+ private Long eventId;
+
+ @Schema(description = "启用状态(0-禁用 1-启用)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "启用状态不能为空")
+ private Integer enabled;
+
+ @Schema(description = "同步模式(FULL-全量 INCREMENTAL-增量)", example = "INCREMENTAL")
+ private String syncMode;
+
+ @Schema(description = "时效性(REALTIME-实时 NEAR_REALTIME-准实时 BATCH-批量)", example = "NEAR_REALTIME")
+ private String timeliness;
+
+ @Schema(description = "时效值(秒)", example = "60")
+ private Integer timelinessValue;
+
+ @Schema(description = "批量大小", example = "500")
+ private Integer batchSize;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncClientConvert.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncClientConvert.java
new file mode 100644
index 00000000..0ec678c2
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncClientConvert.java
@@ -0,0 +1,25 @@
+package com.zt.plat.framework.databus.server.convert;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.client.DatabusSyncClientRespVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.client.DatabusSyncClientSaveReqVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncClientDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+@Mapper
+public interface DatabusSyncClientConvert {
+
+ DatabusSyncClientConvert INSTANCE = Mappers.getMapper(DatabusSyncClientConvert.class);
+
+ DatabusSyncClientDO convert(DatabusSyncClientSaveReqVO bean);
+
+ DatabusSyncClientRespVO convert(DatabusSyncClientDO bean);
+
+ List convertList(List list);
+
+ PageResult convertPage(PageResult page);
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncDeadLetterConvert.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncDeadLetterConvert.java
new file mode 100644
index 00000000..c8c87784
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncDeadLetterConvert.java
@@ -0,0 +1,22 @@
+package com.zt.plat.framework.databus.server.convert;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.deadletter.DatabusSyncDeadLetterRespVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncDeadLetterDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+@Mapper
+public interface DatabusSyncDeadLetterConvert {
+
+ DatabusSyncDeadLetterConvert INSTANCE = Mappers.getMapper(DatabusSyncDeadLetterConvert.class);
+
+ DatabusSyncDeadLetterRespVO convert(DatabusSyncDeadLetterDO bean);
+
+ List convertList(List list);
+
+ PageResult convertPage(PageResult page);
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncEventConvert.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncEventConvert.java
new file mode 100644
index 00000000..24ea52cd
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncEventConvert.java
@@ -0,0 +1,25 @@
+package com.zt.plat.framework.databus.server.convert;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.event.DatabusSyncEventRespVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.event.DatabusSyncEventSaveReqVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncEventDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+@Mapper
+public interface DatabusSyncEventConvert {
+
+ DatabusSyncEventConvert INSTANCE = Mappers.getMapper(DatabusSyncEventConvert.class);
+
+ DatabusSyncEventDO convert(DatabusSyncEventSaveReqVO bean);
+
+ DatabusSyncEventRespVO convert(DatabusSyncEventDO bean);
+
+ List convertList(List list);
+
+ PageResult convertPage(PageResult page);
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncFullTaskConvert.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncFullTaskConvert.java
new file mode 100644
index 00000000..931aab0b
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncFullTaskConvert.java
@@ -0,0 +1,22 @@
+package com.zt.plat.framework.databus.server.convert;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.fulltask.DatabusSyncFullTaskRespVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncFullTaskDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+@Mapper
+public interface DatabusSyncFullTaskConvert {
+
+ DatabusSyncFullTaskConvert INSTANCE = Mappers.getMapper(DatabusSyncFullTaskConvert.class);
+
+ DatabusSyncFullTaskRespVO convert(DatabusSyncFullTaskDO bean);
+
+ List convertList(List list);
+
+ PageResult convertPage(PageResult page);
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncPushLogConvert.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncPushLogConvert.java
new file mode 100644
index 00000000..7a1ddc30
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncPushLogConvert.java
@@ -0,0 +1,22 @@
+package com.zt.plat.framework.databus.server.convert;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.pushlog.DatabusSyncPushLogRespVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncLogDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+@Mapper
+public interface DatabusSyncPushLogConvert {
+
+ DatabusSyncPushLogConvert INSTANCE = Mappers.getMapper(DatabusSyncPushLogConvert.class);
+
+ DatabusSyncPushLogRespVO convert(DatabusSyncLogDO bean);
+
+ List convertList(List list);
+
+ PageResult convertPage(PageResult page);
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncSubscriptionConvert.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncSubscriptionConvert.java
new file mode 100644
index 00000000..fe9f4b61
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/convert/DatabusSyncSubscriptionConvert.java
@@ -0,0 +1,25 @@
+package com.zt.plat.framework.databus.server.convert;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.subscription.DatabusSyncSubscriptionRespVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.subscription.DatabusSyncSubscriptionSaveReqVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncSubscriptionDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+@Mapper
+public interface DatabusSyncSubscriptionConvert {
+
+ DatabusSyncSubscriptionConvert INSTANCE = Mappers.getMapper(DatabusSyncSubscriptionConvert.class);
+
+ DatabusSyncSubscriptionDO convert(DatabusSyncSubscriptionSaveReqVO bean);
+
+ DatabusSyncSubscriptionRespVO convert(DatabusSyncSubscriptionDO bean);
+
+ List convertList(List list);
+
+ PageResult convertPage(PageResult page);
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/event/DatabusEvent.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/event/DatabusEvent.java
new file mode 100644
index 00000000..5f209157
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/event/DatabusEvent.java
@@ -0,0 +1,71 @@
+package com.zt.plat.framework.databus.server.core.event;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+/**
+ * Databus 事件对象
+ *
+ * @author ZT
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DatabusEvent {
+
+ /**
+ * 事件类型编码
+ */
+ private String eventType;
+
+ /**
+ * 事件动作(create-创建 update-更新 delete-删除)
+ */
+ private String eventAction;
+
+ /**
+ * 完整业务数据快照(JSON格式)
+ */
+ private String dataSnapshot;
+
+ /**
+ * 数据版本号
+ */
+ private Integer dataVersion;
+
+ /**
+ * 来源服务名
+ */
+ private String sourceService;
+
+ /**
+ * 来源MQ Topic
+ */
+ private String sourceTopic;
+
+ /**
+ * 来源MQ消息ID
+ */
+ private String sourceMsgId;
+
+ /**
+ * 租户ID
+ */
+ private Long tenantId;
+
+ /**
+ * 操作人
+ */
+ private String operator;
+
+ /**
+ * 事件发生时间
+ */
+ private LocalDateTime eventTime;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/message/BatchSyncMessage.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/message/BatchSyncMessage.java
new file mode 100644
index 00000000..6b4abd37
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/message/BatchSyncMessage.java
@@ -0,0 +1,121 @@
+package com.zt.plat.framework.databus.server.core.message;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * 批量数据同步消息
+ *
+ * 用于全量同步和批量增量同步,一条消息包含多条数据
+ *
+ * @author ZT
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class BatchSyncMessage {
+
+ /**
+ * 消息ID(唯一标识)
+ */
+ private String messageId;
+
+ /**
+ * 请求ID(用于追踪)
+ */
+ private String requestId;
+
+ /**
+ * 事件类型
+ */
+ private String eventType;
+
+ /**
+ * 同步模式(1-全量 2-增量)
+ */
+ private Integer syncMode;
+
+ /**
+ * 数据结构版本
+ */
+ private Integer dataVersion;
+
+ /**
+ * 消息时间戳
+ */
+ private Long timestamp;
+
+ /**
+ * 租户ID
+ */
+ private Long tenantId;
+
+ /**
+ * 数据列表
+ */
+ private List dataList;
+
+ /**
+ * 本批次数据条数
+ */
+ private Integer count;
+
+ // ========== 全量同步相关字段 ==========
+
+ /**
+ * 全量任务ID
+ */
+ private Long fullTaskId;
+
+ /**
+ * 当前批次号
+ */
+ private Integer batchNo;
+
+ /**
+ * 总批次数
+ */
+ private Integer totalBatch;
+
+ /**
+ * 是否最后一批
+ */
+ private Boolean isLastBatch;
+
+ /**
+ * 总数据量
+ */
+ private Long totalCount;
+
+ /**
+ * 同步数据项
+ */
+ @Data
+ @Builder
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class SyncDataItem {
+
+ /**
+ * 操作类型:CREATE/UPDATE/DELETE
+ */
+ private String action;
+
+ /**
+ * 业务数据ID
+ */
+ private Long uid;
+
+ /**
+ * 业务数据快照(JSON)
+ */
+ private String data;
+
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/message/SyncMessage.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/message/SyncMessage.java
new file mode 100644
index 00000000..4a1b0db8
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/message/SyncMessage.java
@@ -0,0 +1,54 @@
+package com.zt.plat.framework.databus.server.core.message;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 数据同步消息
+ *
+ * @author ZT
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SyncMessage {
+
+ /**
+ * 同步ID(唯一标识)
+ */
+ private String syncId;
+
+ /**
+ * 事件记录ID
+ */
+ private Long eventRecordId;
+
+ /**
+ * 事件类型
+ */
+ private String eventType;
+
+ /**
+ * 事件动作
+ */
+ private String eventAction;
+
+ /**
+ * 业务数据快照(JSON)
+ */
+ private String dataSnapshot;
+
+ /**
+ * 数据版本
+ */
+ private Integer dataVersion;
+
+ /**
+ * 时间戳
+ */
+ private Long timestamp;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/provider/DataProvider.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/provider/DataProvider.java
new file mode 100644
index 00000000..faf6ea34
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/provider/DataProvider.java
@@ -0,0 +1,120 @@
+package com.zt.plat.framework.databus.server.core.provider;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 数据提供者接口
+ *
+ * 用于全量同步时获取数据,由业务模块实现具体的数据获取逻辑
+ *
+ * @author ZT
+ */
+public interface DataProvider {
+
+ /**
+ * 获取数据提供者类型标识
+ *
+ * @return 类型标识,如 "ORG"、"USER"
+ */
+ String getProviderType();
+
+ /**
+ * 游标分页获取数据
+ *
+ * @param cursorTime 游标时间(首次查询传 null)
+ * @param cursorId 游标ID(首次查询传 null)
+ * @param batchSize 批量大小
+ * @param tenantId 租户ID
+ * @return 分页结果
+ */
+ CursorPageData getPageByCursor(LocalDateTime cursorTime, Long cursorId, int batchSize, Long tenantId);
+
+ /**
+ * 统计总数
+ *
+ * @param tenantId 租户ID
+ * @return 总数量
+ */
+ long count(Long tenantId);
+
+ /**
+ * 从数据对象中提取 UID
+ *
+ * @param data 数据对象
+ * @return UID
+ */
+ Long extractUid(T data);
+
+ /**
+ * 游标分页数据结果
+ */
+ class CursorPageData {
+ private List list;
+ private LocalDateTime nextCursorTime;
+ private Long nextCursorId;
+ private int count;
+ private boolean hasMore;
+ private long total;
+
+ public List getList() {
+ return list;
+ }
+
+ public void setList(List list) {
+ this.list = list;
+ }
+
+ public LocalDateTime getNextCursorTime() {
+ return nextCursorTime;
+ }
+
+ public void setNextCursorTime(LocalDateTime nextCursorTime) {
+ this.nextCursorTime = nextCursorTime;
+ }
+
+ public Long getNextCursorId() {
+ return nextCursorId;
+ }
+
+ public void setNextCursorId(Long nextCursorId) {
+ this.nextCursorId = nextCursorId;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public boolean isHasMore() {
+ return hasMore;
+ }
+
+ public void setHasMore(boolean hasMore) {
+ this.hasMore = hasMore;
+ }
+
+ public long getTotal() {
+ return total;
+ }
+
+ public void setTotal(long total) {
+ this.total = total;
+ }
+
+ public static CursorPageData of(List list, LocalDateTime nextCursorTime, Long nextCursorId,
+ int count, boolean hasMore, long total) {
+ CursorPageData data = new CursorPageData<>();
+ data.setList(list);
+ data.setNextCursorTime(nextCursorTime);
+ data.setNextCursorId(nextCursorId);
+ data.setCount(count);
+ data.setHasMore(hasMore);
+ data.setTotal(total);
+ return data;
+ }
+ }
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/provider/DataProviderRegistry.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/provider/DataProviderRegistry.java
new file mode 100644
index 00000000..36ccf227
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/provider/DataProviderRegistry.java
@@ -0,0 +1,62 @@
+package com.zt.plat.framework.databus.server.core.provider;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 数据提供者注册中心
+ *
+ * 管理所有注册的数据提供者,根据类型获取对应的提供者
+ *
+ * @author ZT
+ */
+@Slf4j
+@Component
+public class DataProviderRegistry {
+
+ private final Map> providers = new ConcurrentHashMap<>();
+
+ /**
+ * 注册数据提供者
+ *
+ * @param provider 数据提供者
+ */
+ public void register(DataProvider> provider) {
+ String type = provider.getProviderType();
+ providers.put(type, provider);
+ log.info("[Databus] 数据提供者已注册: type={}", type);
+ }
+
+ /**
+ * 获取数据提供者
+ *
+ * @param type 类型标识
+ * @return 数据提供者,不存在则返回 null
+ */
+ @SuppressWarnings("unchecked")
+ public DataProvider getProvider(String type) {
+ return (DataProvider) providers.get(type);
+ }
+
+ /**
+ * 检查是否存在指定类型的提供者
+ *
+ * @param type 类型标识
+ * @return 是否存在
+ */
+ public boolean hasProvider(String type) {
+ return providers.containsKey(type);
+ }
+
+ /**
+ * 获取所有已注册的提供者类型
+ *
+ * @return 类型列表
+ */
+ public java.util.Set getRegisteredTypes() {
+ return providers.keySet();
+ }
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/publisher/DatabusEventPublisher.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/publisher/DatabusEventPublisher.java
new file mode 100644
index 00000000..b151f88c
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/publisher/DatabusEventPublisher.java
@@ -0,0 +1,28 @@
+package com.zt.plat.framework.databus.server.core.publisher;
+
+import com.zt.plat.framework.databus.server.core.event.DatabusEvent;
+
+/**
+ * Databus 事件发布器接口
+ * 用于发布业务数据变更事件到同步流水表
+ *
+ * @author ZT
+ */
+public interface DatabusEventPublisher {
+
+ /**
+ * 发布事件(异步)
+ *
+ * @param event 事件对象
+ */
+ void publish(DatabusEvent event);
+
+ /**
+ * 发布事件(同步,等待入库完成)
+ *
+ * @param event 事件对象
+ * @return 事件记录ID
+ */
+ Long publishSync(DatabusEvent event);
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/publisher/DatabusEventPublisherImpl.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/publisher/DatabusEventPublisherImpl.java
new file mode 100644
index 00000000..2ac2c33e
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/publisher/DatabusEventPublisherImpl.java
@@ -0,0 +1,60 @@
+package com.zt.plat.framework.databus.server.core.publisher;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.zt.plat.framework.databus.server.core.event.DatabusEvent;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncEventRecordDO;
+import com.zt.plat.framework.databus.server.dal.mapper.DatabusSyncEventRecordMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Databus 事件发布器实现
+ *
+ * @author ZT
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class DatabusEventPublisherImpl implements DatabusEventPublisher {
+
+ private final DatabusSyncEventRecordMapper eventRecordMapper;
+
+ @Async
+ @Override
+ public void publish(DatabusEvent event) {
+ try {
+ saveEventRecord(event);
+ } catch (Exception e) {
+ log.error("[Databus] 发布事件失败, eventType={}, eventAction={}",
+ event.getEventType(), event.getEventAction(), e);
+ }
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Long publishSync(DatabusEvent event) {
+ return saveEventRecord(event);
+ }
+
+ /**
+ * 保存事件记录到流水表
+ */
+ private Long saveEventRecord(DatabusEvent event) {
+ // 查询事件定义ID(这里简化处理,实际应该注入EventMapper查询)
+ // TODO: 根据 eventType 查询 event_id
+
+ DatabusSyncEventRecordDO record = new DatabusSyncEventRecordDO();
+ BeanUtil.copyProperties(event, record);
+
+ eventRecordMapper.insert(record);
+
+ log.info("[Databus] 事件记录已保存, id={}, eventType={}, eventAction={}",
+ record.getId(), event.getEventType(), event.getEventAction());
+
+ return record.getId();
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/pusher/MessagePusher.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/pusher/MessagePusher.java
new file mode 100644
index 00000000..101dd4b8
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/pusher/MessagePusher.java
@@ -0,0 +1,50 @@
+package com.zt.plat.framework.databus.server.core.pusher;
+
+import com.zt.plat.framework.databus.server.core.message.BatchSyncMessage;
+import com.zt.plat.framework.databus.server.core.message.SyncMessage;
+
+/**
+ * 消息推送器接口
+ * 支持 MQ 和 HTTP 两种推送方式
+ *
+ * @author ZT
+ */
+public interface MessagePusher {
+
+ /**
+ * 通过 MQ 推送消息
+ *
+ * @param topic Topic
+ * @param message 消息内容
+ * @return 消息ID
+ */
+ String pushByMQ(String topic, SyncMessage message);
+
+ /**
+ * 通过 HTTP 推送消息
+ *
+ * @param endpoint HTTP端点
+ * @param message 消息内容
+ * @return 是否成功
+ */
+ boolean pushByHttp(String endpoint, SyncMessage message);
+
+ /**
+ * 通过 MQ 推送批量消息
+ *
+ * @param topic Topic
+ * @param message 批量消息内容
+ * @return 消息ID
+ */
+ String pushBatchByMQ(String topic, BatchSyncMessage message);
+
+ /**
+ * 通过 HTTP 推送批量消息
+ *
+ * @param endpoint HTTP端点
+ * @param message 批量消息内容
+ * @return 是否成功
+ */
+ boolean pushBatchByHttp(String endpoint, BatchSyncMessage message);
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/pusher/MessagePusherImpl.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/pusher/MessagePusherImpl.java
new file mode 100644
index 00000000..39955102
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/pusher/MessagePusherImpl.java
@@ -0,0 +1,103 @@
+package com.zt.plat.framework.databus.server.core.pusher;
+
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONUtil;
+import com.zt.plat.framework.databus.server.core.message.BatchSyncMessage;
+import com.zt.plat.framework.databus.server.core.message.SyncMessage;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.client.producer.SendStatus;
+import org.apache.rocketmq.spring.core.RocketMQTemplate;
+
+/**
+ * 消息推送器实现
+ *
+ * @author ZT
+ */
+@Slf4j
+public class MessagePusherImpl implements MessagePusher {
+
+ private RocketMQTemplate rocketMQTemplate;
+
+ public void setRocketMQTemplate(RocketMQTemplate rocketMQTemplate) {
+ this.rocketMQTemplate = rocketMQTemplate;
+ }
+
+ @Override
+ public String pushByMQ(String topic, SyncMessage message) {
+ if (rocketMQTemplate == null) {
+ log.warn("[Databus] RocketMQTemplate未配置,无法推送MQ消息");
+ throw new RuntimeException("RocketMQTemplate未配置");
+ }
+
+ try {
+ // 使用 RocketMQ 发送消息
+ SendResult sendResult = rocketMQTemplate.syncSend(topic, message);
+ if (sendResult.getSendStatus() != SendStatus.SEND_OK) {
+ log.error("[Databus] MQ推送失败, topic={}, syncId={}, status={}, msgId={}",
+ topic, message.getSyncId(), sendResult.getSendStatus(), sendResult.getMsgId());
+ throw new RuntimeException("MQ推送失败: " + sendResult.getSendStatus());
+ }
+ log.info("[Databus] MQ推送成功, topic={}, syncId={}, msgId={}",
+ topic, message.getSyncId(), sendResult.getMsgId());
+ return message.getSyncId();
+ } catch (Exception e) {
+ log.error("[Databus] MQ推送失败, topic={}, syncId={}", topic, message.getSyncId(), e);
+ throw new RuntimeException("MQ推送失败", e);
+ }
+ }
+
+ @Override
+ public boolean pushByHttp(String endpoint, SyncMessage message) {
+ try {
+ String jsonBody = JSONUtil.toJsonStr(message);
+ String response = HttpUtil.post(endpoint, jsonBody);
+ log.info("[Databus] HTTP推送成功, endpoint={}, syncId={}", endpoint, message.getSyncId());
+ return true;
+ } catch (Exception e) {
+ log.error("[Databus] HTTP推送失败, endpoint={}, syncId={}", endpoint, message.getSyncId(), e);
+ return false;
+ }
+ }
+
+ @Override
+ public String pushBatchByMQ(String topic, BatchSyncMessage message) {
+ if (rocketMQTemplate == null) {
+ log.warn("[Databus] RocketMQTemplate未配置,无法推送MQ消息");
+ throw new RuntimeException("RocketMQTemplate未配置");
+ }
+
+ try {
+ // 使用 RocketMQ 发送批量消息
+ SendResult sendResult = rocketMQTemplate.syncSend(topic, message);
+ if (sendResult.getSendStatus() != SendStatus.SEND_OK) {
+ log.error("[Databus] 批量MQ推送失败, topic={}, messageId={}, status={}, mqMsgId={}",
+ topic, message.getMessageId(), sendResult.getSendStatus(), sendResult.getMsgId());
+ throw new RuntimeException("批量MQ推送失败: " + sendResult.getSendStatus());
+ }
+ log.info("[Databus] 批量MQ推送成功, topic={}, messageId={}, count={}, mqMsgId={}",
+ topic, message.getMessageId(), message.getCount(), sendResult.getMsgId());
+ return message.getMessageId();
+ } catch (Exception e) {
+ log.error("[Databus] 批量MQ推送失败, topic={}, messageId={}",
+ topic, message.getMessageId(), e);
+ throw new RuntimeException("批量MQ推送失败", e);
+ }
+ }
+
+ @Override
+ public boolean pushBatchByHttp(String endpoint, BatchSyncMessage message) {
+ try {
+ String jsonBody = JSONUtil.toJsonStr(message);
+ String response = HttpUtil.post(endpoint, jsonBody);
+ log.info("[Databus] 批量HTTP推送成功, endpoint={}, messageId={}, count={}",
+ endpoint, message.getMessageId(), message.getCount());
+ return true;
+ } catch (Exception e) {
+ log.error("[Databus] 批量HTTP推送失败, endpoint={}, messageId={}",
+ endpoint, message.getMessageId(), e);
+ return false;
+ }
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusFullSyncService.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusFullSyncService.java
new file mode 100644
index 00000000..62d00b16
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusFullSyncService.java
@@ -0,0 +1,51 @@
+package com.zt.plat.framework.databus.server.core.sync;
+
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncFullTaskDO;
+
+/**
+ * Databus 全量同步服务接口
+ *
+ * @author ZT
+ */
+public interface DatabusFullSyncService {
+
+ /**
+ * 创建全量同步任务
+ *
+ * @param subscriptionId 订阅关系ID
+ * @param remark 备注
+ * @return 任务ID
+ */
+ Long createFullSyncTask(Long subscriptionId, String remark);
+
+ /**
+ * 执行全量同步任务
+ *
+ * @param taskId 任务ID
+ */
+ void executeFullSyncTask(Long taskId);
+
+ /**
+ * 取消全量同步任务
+ *
+ * @param taskId 任务ID
+ */
+ void cancelFullSyncTask(Long taskId);
+
+ /**
+ * 获取任务详情
+ *
+ * @param taskId 任务ID
+ * @return 任务详情
+ */
+ DatabusSyncFullTaskDO getTaskById(Long taskId);
+
+ /**
+ * 根据任务编号获取任务详情
+ *
+ * @param taskNo 任务编号
+ * @return 任务详情
+ */
+ DatabusSyncFullTaskDO getTaskByTaskNo(String taskNo);
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusIncrementalSyncService.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusIncrementalSyncService.java
new file mode 100644
index 00000000..5baeb472
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusIncrementalSyncService.java
@@ -0,0 +1,27 @@
+package com.zt.plat.framework.databus.server.core.sync;
+
+import com.zt.plat.framework.databus.server.core.event.DatabusEvent;
+
+/**
+ * Databus 增量同步服务接口
+ * 用于实时处理业务MQ消息,进行三态判断、记录流水、推送到客户端Topic
+ *
+ * @author ZT
+ */
+public interface DatabusIncrementalSyncService {
+
+ /**
+ * 处理增量同步事件
+ *
+ * 核心流程:
+ * 1. 根据 eventType 查询事件定义,判断是否启用
+ * 2. 查询所有启用的订阅关系
+ * 3. 对每个订阅进行三态判断(事件/客户端/订阅是否启用)
+ * 4. 记录到 databus_sync_event_record 流水表
+ * 5. 推送到客户端专属 Topic(databus-sync-{eventType}-{clientCode})
+ *
+ * @param event 业务变更事件
+ */
+ void processEvent(DatabusEvent event);
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusIncrementalSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusIncrementalSyncServiceImpl.java
new file mode 100644
index 00000000..99766a04
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusIncrementalSyncServiceImpl.java
@@ -0,0 +1,246 @@
+package com.zt.plat.framework.databus.server.core.sync;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.IdUtil;
+import com.zt.plat.framework.databus.server.core.event.DatabusEvent;
+import com.zt.plat.framework.databus.server.core.message.SyncMessage;
+import com.zt.plat.framework.databus.server.core.pusher.MessagePusher;
+import com.zt.plat.framework.databus.server.dal.dataobject.*;
+import com.zt.plat.framework.databus.server.dal.mapper.*;
+import com.zt.plat.framework.databus.server.enums.SyncStatusEnum;
+import com.zt.plat.framework.databus.server.enums.TransportTypeEnum;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.List;
+
+/**
+ * Databus 增量同步服务实现
+ *
+ * 核心流程:
+ * 1. 根据 eventType 查询事件定义,判断是否启用
+ * 2. 记录到 event_record 流水表
+ * 3. 查询所有启用的订阅关系
+ * 4. 对每个订阅进行三态判断(事件/客户端/订阅是否启用)
+ * 5. 推送到客户端专属 Topic(databus-sync-{eventType}-{clientCode})
+ *
+ * @author ZT
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class DatabusIncrementalSyncServiceImpl implements DatabusIncrementalSyncService {
+
+ private final DatabusSyncEventMapper eventMapper;
+ private final DatabusSyncEventRecordMapper eventRecordMapper;
+ private final DatabusSyncSubscriptionMapper subscriptionMapper;
+ private final DatabusSyncClientMapper clientMapper;
+ private final DatabusSyncLogMapper syncLogMapper;
+ private final MessagePusher messagePusher;
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void processEvent(DatabusEvent event) {
+ log.info("[Databus增量同步] 开始处理事件, eventType={}, eventAction={}",
+ event.getEventType(), event.getEventAction());
+
+ // 1. 查询事件定义
+ DatabusSyncEventDO eventDef = eventMapper.selectByEventType(event.getEventType());
+ if (eventDef == null) {
+ log.warn("[Databus增量同步] 事件类型未定义, eventType={}", event.getEventType());
+ return;
+ }
+
+ // 2. 判断事件是否启用(三态判断之一)
+ if (eventDef.getEnabled() != 1) {
+ log.debug("[Databus增量同步] 事件未启用, eventType={}", event.getEventType());
+ return;
+ }
+
+ // 3. 判断事件是否支持增量同步
+ if (eventDef.getSupportIncrementalSync() != 1) {
+ log.debug("[Databus增量同步] 事件不支持增量同步, eventType={}", event.getEventType());
+ return;
+ }
+
+ // 4. 记录到 event_record 流水表
+ DatabusSyncEventRecordDO eventRecord = saveEventRecord(event, eventDef);
+
+ // 5. 查询所有启用的订阅关系
+ List subscriptions = subscriptionMapper.selectEnabledByEventId(eventDef.getId());
+ if (subscriptions.isEmpty()) {
+ log.debug("[Databus增量同步] 无启用的订阅, eventType={}", event.getEventType());
+ return;
+ }
+
+ log.info("[Databus增量同步] 找到{}个订阅需要推送, eventType={}",
+ subscriptions.size(), event.getEventType());
+
+ // 6. 对每个订阅进行推送
+ for (DatabusSyncSubscriptionDO subscription : subscriptions) {
+ try {
+ pushToSubscriber(subscription, eventDef, eventRecord);
+ } catch (Exception e) {
+ log.error("[Databus增量同步] 推送到订阅者失败, subscriptionId={}, eventType={}",
+ subscription.getId(), event.getEventType(), e);
+ }
+ }
+
+ log.info("[Databus增量同步] 事件处理完成, eventType={}, eventAction={}, recordId={}",
+ event.getEventType(), event.getEventAction(), eventRecord.getId());
+ }
+
+ /**
+ * 保存事件记录到流水表
+ */
+ private DatabusSyncEventRecordDO saveEventRecord(DatabusEvent event, DatabusSyncEventDO eventDef) {
+ DatabusSyncEventRecordDO record = new DatabusSyncEventRecordDO();
+ BeanUtil.copyProperties(event, record);
+ record.setEventId(eventDef.getId());
+
+ eventRecordMapper.insert(record);
+
+ log.info("[Databus增量同步] 事件记录已保存, recordId={}, eventType={}, eventAction={}",
+ record.getId(), event.getEventType(), event.getEventAction());
+
+ return record;
+ }
+
+ /**
+ * 推送到单个订阅者
+ */
+ private void pushToSubscriber(DatabusSyncSubscriptionDO subscription,
+ DatabusSyncEventDO eventDef,
+ DatabusSyncEventRecordDO eventRecord) {
+ // 查询客户端信息
+ DatabusSyncClientDO client = clientMapper.selectById(subscription.getClientId());
+ if (client == null) {
+ log.warn("[Databus增量同步] 客户端不存在, clientId={}", subscription.getClientId());
+ return;
+ }
+
+ // 三态判断之二:客户端是否启用
+ if (client.getEnabled() != 1) {
+ log.debug("[Databus增量同步] 客户端未启用, clientCode={}", client.getClientCode());
+ return;
+ }
+
+ // 三态判断之三:订阅是否启用(已在查询时过滤,这里再确认一次)
+ if (subscription.getEnabled() != 1) {
+ log.debug("[Databus增量同步] 订阅未启用, subscriptionId={}", subscription.getId());
+ return;
+ }
+
+ String syncId = IdUtil.fastSimpleUUID();
+ LocalDateTime startTime = LocalDateTime.now();
+
+ // 构建同步消息
+ SyncMessage message = SyncMessage.builder()
+ .syncId(syncId)
+ .eventRecordId(eventRecord.getId())
+ .eventType(eventRecord.getEventType())
+ .eventAction(eventRecord.getEventAction())
+ .dataSnapshot(eventRecord.getDataSnapshot())
+ .dataVersion(eventRecord.getDataVersion())
+ .timestamp(System.currentTimeMillis())
+ .build();
+
+ // 构建同步日志
+ DatabusSyncLogDO syncLog = DatabusSyncLogDO.builder()
+ .syncId(syncId)
+ .eventRecordId(eventRecord.getId())
+ .subscriptionId(subscription.getId())
+ .clientCode(client.getClientCode())
+ .eventType(eventRecord.getEventType())
+ .syncMode(2) // 增量同步
+ .startTime(startTime)
+ .status(SyncStatusEnum.PENDING.getStatus())
+ .retryCount(0)
+ .dataCount(1)
+ .tenantId(client.getTenantId())
+ .build();
+
+ try {
+ // 根据客户端配置选择推送方式
+ if (TransportTypeEnum.isMqFirst(client.getTransportType()) && client.getMqEnabled() == 1) {
+ // MQ 推送:Topic格式 = databus-sync-{eventType}-{clientCode}
+ String topic = buildClientTopic(client.getMqTopicBase(), eventDef.getEventType(), client.getClientCode());
+ String mqMsgId = messagePusher.pushByMQ(topic, message);
+
+ syncLog.setTransportType(TransportTypeEnum.MQ_FIRST.getType());
+ syncLog.setMqTopic(topic);
+ syncLog.setMqMsgId(mqMsgId);
+
+ log.info("[Databus增量同步] MQ推送成功, topic={}, syncId={}", topic, syncId);
+
+ } else if (client.getHttpEnabled() == 1) {
+ // HTTP 推送
+ boolean success = messagePusher.pushByHttp(client.getHttpEndpoint(), message);
+ if (!success) {
+ throw new RuntimeException("HTTP推送失败");
+ }
+
+ syncLog.setTransportType(TransportTypeEnum.HTTP_ONLY.getType());
+
+ log.info("[Databus增量同步] HTTP推送成功, endpoint={}, syncId={}",
+ client.getHttpEndpoint(), syncId);
+
+ } else {
+ throw new RuntimeException("无可用的推送方式");
+ }
+
+ // 更新日志状态为成功
+ syncLog.setStatus(SyncStatusEnum.SUCCESS.getStatus());
+ syncLog.setEndTime(LocalDateTime.now());
+ syncLog.setDuration((int) (System.currentTimeMillis() -
+ startTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()));
+
+ // 更新订阅断点
+ updateSubscriptionCheckpoint(subscription, eventRecord.getId());
+
+ } catch (Exception e) {
+ log.error("[Databus增量同步] 推送失败, syncId={}, clientCode={}", syncId, client.getClientCode(), e);
+
+ syncLog.setStatus(SyncStatusEnum.FAILED.getStatus());
+ syncLog.setErrorMessage(e.getMessage());
+ syncLog.setEndTime(LocalDateTime.now());
+ }
+
+ // 保存同步日志
+ syncLogMapper.insert(syncLog);
+ }
+
+ /**
+ * 构建客户端专属Topic
+ * 格式: {topicBase}-{module}-{entity}-{action}-{clientCode}
+ * 示例: databus-sync-system-org-create-company-a
+ *
+ * @param topicBase 基础Topic名称(如 databus-sync)
+ * @param eventType 事件类型(格式: system-org-create)
+ * @param clientCode 客户端编码
+ */
+ private String buildClientTopic(String topicBase, String eventType, String clientCode) {
+ // 默认topicBase为 databus-sync
+ if (topicBase == null || topicBase.isEmpty()) {
+ topicBase = "databus-sync";
+ }
+ // eventType 格式已经是 system-org-create,直接拼接
+ return String.format("%s-%s-%s", topicBase, eventType.toLowerCase(), clientCode);
+ }
+
+ /**
+ * 更新订阅断点
+ */
+ private void updateSubscriptionCheckpoint(DatabusSyncSubscriptionDO subscription, Long eventRecordId) {
+ subscription.setLastSyncEventId(eventRecordId);
+ subscription.setLastSyncTime(LocalDateTime.now());
+ subscription.setTotalSyncCount((subscription.getTotalSyncCount() == null ? 0 : subscription.getTotalSyncCount()) + 1);
+ subscription.setTotalSuccessCount((subscription.getTotalSuccessCount() == null ? 0 : subscription.getTotalSuccessCount()) + 1);
+ subscriptionMapper.updateById(subscription);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusSyncService.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusSyncService.java
new file mode 100644
index 00000000..00fd9b78
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusSyncService.java
@@ -0,0 +1,24 @@
+package com.zt.plat.framework.databus.server.core.sync;
+
+/**
+ * Databus 同步服务接口
+ * 负责扫描事件记录并推送到客户端
+ *
+ * @author ZT
+ */
+public interface DatabusSyncService {
+
+ /**
+ * 执行同步任务
+ * 扫描所有启用的订阅关系,推送新事件到客户端
+ */
+ void executeSyncTask();
+
+ /**
+ * 手动触发指定订阅的同步
+ *
+ * @param subscriptionId 订阅关系ID
+ */
+ void triggerSync(Long subscriptionId);
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusSyncServiceImpl.java
new file mode 100644
index 00000000..72c50892
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/core/sync/DatabusSyncServiceImpl.java
@@ -0,0 +1,237 @@
+package com.zt.plat.framework.databus.server.core.sync;
+
+import cn.hutool.core.util.IdUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.zt.plat.framework.databus.server.config.DatabusSyncServerProperties;
+import com.zt.plat.framework.databus.server.core.message.SyncMessage;
+import com.zt.plat.framework.databus.server.core.pusher.MessagePusher;
+import com.zt.plat.framework.databus.server.dal.dataobject.*;
+import com.zt.plat.framework.databus.server.dal.mapper.*;
+import com.zt.plat.framework.databus.server.enums.DeadLetterStatusEnum;
+import com.zt.plat.framework.databus.server.enums.SyncStatusEnum;
+import com.zt.plat.framework.databus.server.enums.TransportTypeEnum;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * Databus 同步服务实现
+ *
+ * @author ZT
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class DatabusSyncServiceImpl implements DatabusSyncService {
+
+ private final DatabusSyncSubscriptionMapper subscriptionMapper;
+ private final DatabusSyncEventRecordMapper eventRecordMapper;
+ private final DatabusSyncClientMapper clientMapper;
+ private final DatabusSyncEventMapper eventMapper;
+ private final DatabusSyncLogMapper syncLogMapper;
+ private final DatabusSyncDeadLetterMapper deadLetterMapper;
+ private final MessagePusher messagePusher;
+ private final DatabusSyncServerProperties properties;
+
+ @Override
+ public void executeSyncTask() {
+ log.info("[Databus] 开始执行同步任务");
+
+ // 查询所有启用的订阅关系
+ List subscriptions = subscriptionMapper.selectList(
+ new LambdaQueryWrapper()
+ .eq(DatabusSyncSubscriptionDO::getEnabled, 1)
+ );
+
+ for (DatabusSyncSubscriptionDO subscription : subscriptions) {
+ try {
+ processSubscription(subscription);
+ } catch (Exception e) {
+ log.error("[Databus] 处理订阅失败, subscriptionId={}", subscription.getId(), e);
+ }
+ }
+
+ log.info("[Databus] 同步任务执行完成, 处理订阅数={}", subscriptions.size());
+ }
+
+ @Override
+ public void triggerSync(Long subscriptionId) {
+ DatabusSyncSubscriptionDO subscription = subscriptionMapper.selectById(subscriptionId);
+ if (subscription == null) {
+ log.warn("[Databus] 订阅不存在, subscriptionId={}", subscriptionId);
+ return;
+ }
+
+ processSubscription(subscription);
+ }
+
+ /**
+ * 处理单个订阅
+ */
+ @Transactional(rollbackFor = Exception.class)
+ protected void processSubscription(DatabusSyncSubscriptionDO subscription) {
+ // 三状态启用检查
+ DatabusSyncClientDO client = clientMapper.selectById(subscription.getClientId());
+ if (client == null || client.getEnabled() != 1) {
+ log.debug("[Databus] 客户端未启用, clientId={}", subscription.getClientId());
+ return;
+ }
+
+ DatabusSyncEventDO event = eventMapper.selectById(subscription.getEventId());
+ if (event == null || event.getEnabled() != 1) {
+ log.debug("[Databus] 事件未启用, eventId={}", subscription.getEventId());
+ return;
+ }
+
+ // 查询新事件记录(断点续传)
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper()
+ .eq(DatabusSyncEventRecordDO::getEventId, subscription.getEventId())
+ .orderByAsc(DatabusSyncEventRecordDO::getId);
+
+ if (subscription.getLastSyncEventId() != null) {
+ queryWrapper.gt(DatabusSyncEventRecordDO::getId, subscription.getLastSyncEventId());
+ }
+
+ // 批量查询 - 使用 Page 分页,兼容达梦等数据库
+ Page page = new Page<>(1, subscription.getBatchSize(), false);
+ List records = eventRecordMapper.selectPage(page, queryWrapper).getRecords();
+
+ if (records.isEmpty()) {
+ log.debug("[Databus] 无新事件, subscriptionId={}", subscription.getId());
+ return;
+ }
+
+ log.info("[Databus] 开始同步, subscriptionId={}, eventCount={}", subscription.getId(), records.size());
+
+ // 推送事件
+ for (DatabusSyncEventRecordDO record : records) {
+ boolean success = pushEvent(subscription, client, record);
+ if (success) {
+ // 更新断点
+ subscription.setLastSyncEventId(record.getId());
+ subscription.setLastSyncTime(LocalDateTime.now());
+ subscription.setTotalSyncCount(subscription.getTotalSyncCount() + 1);
+ subscription.setTotalSuccessCount(subscription.getTotalSuccessCount() + 1);
+ } else {
+ subscription.setTotalFailCount(subscription.getTotalFailCount() + 1);
+ break; // 失败则停止当前批次
+ }
+ }
+
+ // 更新订阅统计
+ subscriptionMapper.updateById(subscription);
+ }
+
+ /**
+ * 推送单个事件
+ */
+ private boolean pushEvent(DatabusSyncSubscriptionDO subscription,
+ DatabusSyncClientDO client,
+ DatabusSyncEventRecordDO record) {
+ String syncId = IdUtil.fastSimpleUUID();
+ LocalDateTime startTime = LocalDateTime.now();
+
+ // 构建消息
+ SyncMessage message = SyncMessage.builder()
+ .syncId(syncId)
+ .eventRecordId(record.getId())
+ .eventType(record.getEventType())
+ .eventAction(record.getEventAction())
+ .dataSnapshot(record.getDataSnapshot())
+ .dataVersion(record.getDataVersion())
+ .timestamp(System.currentTimeMillis())
+ .build();
+
+ // 记录日志
+ DatabusSyncLogDO syncLog = DatabusSyncLogDO.builder()
+ .syncId(syncId)
+ .eventRecordId(record.getId())
+ .subscriptionId(subscription.getId())
+ .clientCode(client.getClientCode())
+ .eventType(record.getEventType())
+ .syncMode(subscription.getSyncMode())
+ .startTime(startTime)
+ .status(SyncStatusEnum.PENDING.getStatus())
+ .retryCount(0)
+ .tenantId(client.getTenantId())
+ .build();
+
+ try {
+ // 推送消息
+ if (TransportTypeEnum.isMqFirst(client.getTransportType()) && client.getMqEnabled() == 1) {
+ // MQ 推送
+ String topic = String.format("%s-%s-%s",
+ client.getMqTopicBase(), record.getEventType(), client.getClientCode());
+ String mqMsgId = messagePusher.pushByMQ(topic, message);
+
+ syncLog.setTransportType(TransportTypeEnum.MQ_FIRST.getType());
+ syncLog.setMqTopic(topic);
+ syncLog.setMqMsgId(mqMsgId);
+ } else if (client.getHttpEnabled() == 1) {
+ // HTTP 推送
+ boolean success = messagePusher.pushByHttp(client.getHttpEndpoint(), message);
+ if (!success) {
+ throw new RuntimeException("HTTP推送失败");
+ }
+
+ syncLog.setTransportType(TransportTypeEnum.HTTP_ONLY.getType());
+ } else {
+ throw new RuntimeException("无可用的推送方式");
+ }
+
+ // 更新日志状态
+ syncLog.setStatus(SyncStatusEnum.SUCCESS.getStatus());
+ syncLog.setEndTime(LocalDateTime.now());
+ syncLog.setDuration((int) (System.currentTimeMillis() - startTime.atZone(java.time.ZoneId.systemDefault()).toInstant().toEpochMilli()));
+ syncLogMapper.insert(syncLog);
+
+ return true;
+
+ } catch (Exception e) {
+ log.error("[Databus] 推送失败, syncId={}, eventRecordId={}", syncId, record.getId(), e);
+
+ // 更新日志状态
+ syncLog.setStatus(SyncStatusEnum.FAILED.getStatus());
+ syncLog.setErrorMessage(e.getMessage());
+ syncLog.setEndTime(LocalDateTime.now());
+ syncLogMapper.insert(syncLog);
+
+ // 检查重试次数,超过限制则进入死信队列
+ if (syncLog.getRetryCount() >= properties.getRetry().getMaxAttempts()) {
+ saveToDeadLetter(syncLog, message);
+ }
+
+ return false;
+ }
+ }
+
+ /**
+ * 保存到死信队列
+ */
+ private void saveToDeadLetter(DatabusSyncLogDO syncLog, SyncMessage message) {
+ DatabusSyncDeadLetterDO deadLetter = DatabusSyncDeadLetterDO.builder()
+ .syncLogId(syncLog.getId())
+ .syncId(syncLog.getSyncId())
+ .clientCode(syncLog.getClientCode())
+ .eventType(syncLog.getEventType())
+ .eventRecordId(syncLog.getEventRecordId())
+ .retryCount(syncLog.getRetryCount())
+ .lastErrorMessage(syncLog.getErrorMessage())
+ .lastErrorTime(LocalDateTime.now())
+ .messageBody(cn.hutool.json.JSONUtil.toJsonStr(message))
+ .status(DeadLetterStatusEnum.PENDING.getStatus())
+ .handled(0)
+ .tenantId(syncLog.getTenantId())
+ .build();
+
+ deadLetterMapper.insert(deadLetter);
+
+ log.warn("[Databus] 消息已进入死信队列, syncId={}", syncLog.getSyncId());
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncClientDO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncClientDO.java
new file mode 100644
index 00000000..68a3f867
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncClientDO.java
@@ -0,0 +1,84 @@
+package com.zt.plat.framework.databus.server.dal.dataobject;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.zt.plat.framework.tenant.core.db.TenantBaseDO;
+import lombok.*;
+
+/**
+ * 数据同步客户端配置 DO
+ *
+ * @author ZT
+ */
+@TableName("databus_sync_client")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DatabusSyncClientDO extends TenantBaseDO {
+
+ /**
+ * 主键ID
+ */
+ @TableId(type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * 客户端编码
+ */
+ private String clientCode;
+
+ /**
+ * 客户端名称
+ */
+ private String clientName;
+
+ /**
+ * 启用状态(0-禁用 1-启用)
+ */
+ private Integer enabled;
+
+ /**
+ * 通信方式(1-MQ优先 2-仅HTTP)
+ */
+ private Integer transportType;
+
+ /**
+ * MQ是否启用(0-否 1-是)
+ */
+ private Integer mqEnabled;
+
+ /**
+ * MQ NameServer地址
+ */
+ private String mqNamesrvAddr;
+
+ /**
+ * MQ Topic基础名称
+ */
+ private String mqTopicBase;
+
+ /**
+ * HTTP是否启用(0-否 1-是)
+ */
+ private Integer httpEnabled;
+
+ /**
+ * HTTP推送端点
+ */
+ private String httpEndpoint;
+
+ /**
+ * 应用Key
+ */
+ private String appKey;
+
+ /**
+ * 应用Secret(加密存储)
+ */
+ private String appSecret;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncDeadLetterDO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncDeadLetterDO.java
new file mode 100644
index 00000000..f8067841
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncDeadLetterDO.java
@@ -0,0 +1,106 @@
+package com.zt.plat.framework.databus.server.dal.dataobject;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.zt.plat.framework.mybatis.core.dataobject.BaseDO;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+/**
+ * 数据同步死信队列 DO
+ *
+ * @author ZT
+ */
+@TableName("databus_sync_dead_letter")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DatabusSyncDeadLetterDO extends BaseDO {
+
+ /**
+ * 主键ID
+ */
+ @TableId(type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * 同步日志ID
+ */
+ private Long syncLogId;
+
+ /**
+ * 同步ID
+ */
+ private String syncId;
+
+ /**
+ * 客户端编码
+ */
+ private String clientCode;
+
+ /**
+ * 事件类型
+ */
+ private String eventType;
+
+ /**
+ * 事件记录ID
+ */
+ private Long eventRecordId;
+
+ /**
+ * 已重试次数
+ */
+ private Integer retryCount;
+
+ /**
+ * 最后错误信息
+ */
+ private String lastErrorMessage;
+
+ /**
+ * 最后错误时间
+ */
+ private LocalDateTime lastErrorTime;
+
+ /**
+ * 消息内容(JSON格式)
+ */
+ private String messageBody;
+
+ /**
+ * 状态(0-待处理 1-已重新投递 2-已忽略)
+ */
+ private Integer status;
+
+ /**
+ * 是否已处理(0-否 1-是)
+ */
+ private Integer handled;
+
+ /**
+ * 处理时间
+ */
+ private LocalDateTime handleTime;
+
+ /**
+ * 处理人
+ */
+ private String handler;
+
+ /**
+ * 处理备注
+ */
+ private String handleRemark;
+
+ /**
+ * 租户ID
+ */
+ private Long tenantId;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncEventDO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncEventDO.java
new file mode 100644
index 00000000..7887c4ef
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncEventDO.java
@@ -0,0 +1,76 @@
+package com.zt.plat.framework.databus.server.dal.dataobject;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.zt.plat.framework.tenant.core.db.TenantBaseDO;
+import lombok.*;
+
+/**
+ * 数据同步事件定义 DO
+ *
+ * @author ZT
+ */
+@TableName("databus_sync_event")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DatabusSyncEventDO extends TenantBaseDO {
+
+ /**
+ * 主键ID
+ */
+ @TableId(type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * 事件类型编码
+ */
+ private String eventType;
+
+ /**
+ * 事件名称
+ */
+ private String eventName;
+
+ /**
+ * 事件描述
+ */
+ private String eventDesc;
+
+ /**
+ * 启用状态(0-禁用 1-启用)
+ */
+ private Integer enabled;
+
+ /**
+ * 是否支持全量同步(0-否 1-是)
+ */
+ private Integer supportFullSync;
+
+ /**
+ * 是否支持增量同步(0-否 1-是)
+ */
+ private Integer supportIncrementalSync;
+
+ /**
+ * 数据结构版本
+ */
+ private Integer dataVersion;
+
+ /**
+ * 数据提供者服务名(Feign服务名)
+ * 用于全量同步时调用对应服务获取数据
+ */
+ private String dataProviderService;
+
+ /**
+ * 数据提供者方法标识
+ * 如: ORG(组织)、USER(用户)
+ */
+ private String dataProviderMethod;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncEventRecordDO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncEventRecordDO.java
new file mode 100644
index 00000000..a2239361
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncEventRecordDO.java
@@ -0,0 +1,87 @@
+package com.zt.plat.framework.databus.server.dal.dataobject;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.zt.plat.framework.mybatis.core.dataobject.BaseDO;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+/**
+ * 数据同步事件流水 DO
+ * 用于断点续传
+ *
+ * @author ZT
+ */
+@TableName("databus_sync_event_record")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DatabusSyncEventRecordDO extends BaseDO {
+
+ /**
+ * 主键ID(雪花算法,全局唯一递增)
+ */
+ @TableId(type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * 事件定义ID
+ */
+ private Long eventId;
+
+ /**
+ * 事件类型编码
+ */
+ private String eventType;
+
+ /**
+ * 事件动作(create-创建 update-更新 delete-删除)
+ */
+ private String eventAction;
+
+ /**
+ * 完整业务数据快照(JSON格式)
+ */
+ private String dataSnapshot;
+
+ /**
+ * 数据版本号
+ */
+ private Integer dataVersion;
+
+ /**
+ * 来源服务名
+ */
+ private String sourceService;
+
+ /**
+ * 来源MQ Topic
+ */
+ private String sourceTopic;
+
+ /**
+ * 来源MQ消息ID
+ */
+ private String sourceMsgId;
+
+ /**
+ * 租户ID
+ */
+ private Long tenantId;
+
+ /**
+ * 操作人
+ */
+ private String operator;
+
+ /**
+ * 事件发生时间
+ */
+ private LocalDateTime eventTime;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncFullTaskDO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncFullTaskDO.java
new file mode 100644
index 00000000..6709a80d
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncFullTaskDO.java
@@ -0,0 +1,126 @@
+package com.zt.plat.framework.databus.server.dal.dataobject;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.zt.plat.framework.mybatis.core.dataobject.BaseDO;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+/**
+ * 数据全量同步任务 DO
+ *
+ * @author ZT
+ */
+@TableName("databus_sync_full_task")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DatabusSyncFullTaskDO extends BaseDO {
+
+ /**
+ * 主键ID
+ */
+ @TableId(type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * 任务编号(唯一标识)
+ */
+ private String taskNo;
+
+ /**
+ * 订阅关系ID
+ */
+ private Long subscriptionId;
+
+ /**
+ * 客户端编码
+ */
+ private String clientCode;
+
+ /**
+ * 事件类型
+ */
+ private String eventType;
+
+ /**
+ * 任务状态(0-待执行 1-执行中 2-已完成 3-失败 4-已取消)
+ */
+ private Integer status;
+
+ /**
+ * 总数据量
+ */
+ private Long totalCount;
+
+ /**
+ * 已处理数据量
+ */
+ private Long processedCount;
+
+ /**
+ * 成功数据量
+ */
+ private Long successCount;
+
+ /**
+ * 失败数据量
+ */
+ private Long failCount;
+
+ /**
+ * 总批次数
+ */
+ private Integer totalBatch;
+
+ /**
+ * 当前批次号
+ */
+ private Integer currentBatch;
+
+ /**
+ * 批量大小
+ */
+ private Integer batchSize;
+
+ /**
+ * 游标时间(断点续传)
+ */
+ private LocalDateTime cursorTime;
+
+ /**
+ * 游标ID(断点续传)
+ */
+ private Long cursorId;
+
+ /**
+ * 任务开始时间
+ */
+ private LocalDateTime startTime;
+
+ /**
+ * 任务结束时间
+ */
+ private LocalDateTime endTime;
+
+ /**
+ * 最后一次错误信息
+ */
+ private String lastErrorMessage;
+
+ /**
+ * 租户ID
+ */
+ private Long tenantId;
+
+ /**
+ * 备注
+ */
+ private String remark;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncLogDO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncLogDO.java
new file mode 100644
index 00000000..51ff7534
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncLogDO.java
@@ -0,0 +1,126 @@
+package com.zt.plat.framework.databus.server.dal.dataobject;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.zt.plat.framework.mybatis.core.dataobject.BaseDO;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+/**
+ * 数据同步日志 DO
+ *
+ * @author ZT
+ */
+@TableName("databus_sync_log")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DatabusSyncLogDO extends BaseDO {
+
+ /**
+ * 主键ID
+ */
+ @TableId(type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * 同步ID(唯一标识)
+ */
+ private String syncId;
+
+ /**
+ * 事件记录ID
+ */
+ private Long eventRecordId;
+
+ /**
+ * 订阅关系ID
+ */
+ private Long subscriptionId;
+
+ /**
+ * 客户端编码
+ */
+ private String clientCode;
+
+ /**
+ * 事件类型
+ */
+ private String eventType;
+
+ /**
+ * 同步模式(1-全量 2-增量)
+ */
+ private Integer syncMode;
+
+ /**
+ * 传输方式(1-MQ优先 2-仅HTTP)
+ */
+ private Integer transportType;
+
+ /**
+ * MQ Topic
+ */
+ private String mqTopic;
+
+ /**
+ * MQ消息ID
+ */
+ private String mqMsgId;
+
+ /**
+ * 状态(0-待处理 1-成功 2-失败 3-重试中)
+ */
+ private Integer status;
+
+ /**
+ * 重试次数
+ */
+ private Integer retryCount;
+
+ /**
+ * 错误信息
+ */
+ private String errorMessage;
+
+ /**
+ * 开始时间
+ */
+ private LocalDateTime startTime;
+
+ /**
+ * 结束时间
+ */
+ private LocalDateTime endTime;
+
+ /**
+ * 耗时(毫秒)
+ */
+ private Integer duration;
+
+ /**
+ * 租户ID
+ */
+ private Long tenantId;
+
+ /**
+ * 本批次数据条数
+ */
+ private Integer dataCount;
+
+ /**
+ * 批次号(全量同步时使用)
+ */
+ private Integer batchNo;
+
+ /**
+ * 全量任务ID(全量同步时关联)
+ */
+ private Long fullTaskId;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncSubscriptionDO.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncSubscriptionDO.java
new file mode 100644
index 00000000..a11aa085
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/dataobject/DatabusSyncSubscriptionDO.java
@@ -0,0 +1,91 @@
+package com.zt.plat.framework.databus.server.dal.dataobject;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.zt.plat.framework.tenant.core.db.TenantBaseDO;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+/**
+ * 数据同步订阅关系 DO
+ *
+ * @author ZT
+ */
+@TableName("databus_sync_subscription")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DatabusSyncSubscriptionDO extends TenantBaseDO {
+
+ /**
+ * 主键ID
+ */
+ @TableId(type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * 客户端ID
+ */
+ private Long clientId;
+
+ /**
+ * 事件ID
+ */
+ private Long eventId;
+
+ /**
+ * 订阅启用状态(0-禁用 1-启用)
+ */
+ private Integer enabled;
+
+ /**
+ * 同步模式(1-全量 2-增量)
+ */
+ private Integer syncMode;
+
+ /**
+ * 时效性(1-实时 2-准实时 3-批量)
+ */
+ private Integer timeliness;
+
+ /**
+ * 时效值(秒)
+ */
+ private Integer timelinessValue;
+
+ /**
+ * 批量大小
+ */
+ private Integer batchSize;
+
+ /**
+ * 最后同步的事件记录ID(断点续传)
+ */
+ private Long lastSyncEventId;
+
+ /**
+ * 最后同步时间
+ */
+ private LocalDateTime lastSyncTime;
+
+ /**
+ * 总同步次数
+ */
+ private Long totalSyncCount;
+
+ /**
+ * 成功次数
+ */
+ private Long totalSuccessCount;
+
+ /**
+ * 失败次数
+ */
+ private Long totalFailCount;
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncClientMapper.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncClientMapper.java
new file mode 100644
index 00000000..da34a1c5
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncClientMapper.java
@@ -0,0 +1,38 @@
+package com.zt.plat.framework.databus.server.dal.mapper;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.client.DatabusSyncClientPageReqVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncClientDO;
+import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
+import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 数据同步客户端 Mapper
+ *
+ * @author ZT
+ */
+@Mapper
+public interface DatabusSyncClientMapper extends BaseMapperX {
+
+ default DatabusSyncClientDO selectByClientCode(String clientCode) {
+ return selectOne(DatabusSyncClientDO::getClientCode, clientCode);
+ }
+
+ default PageResult selectPage(DatabusSyncClientPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX()
+ .likeIfPresent(DatabusSyncClientDO::getClientCode, reqVO.getClientCode())
+ .likeIfPresent(DatabusSyncClientDO::getClientName, reqVO.getClientName())
+ .eqIfPresent(DatabusSyncClientDO::getEnabled, reqVO.getEnabled())
+ .eqIfPresent(DatabusSyncClientDO::getTransportType, reqVO.getTransportType())
+ .orderByDesc(DatabusSyncClientDO::getId));
+ }
+
+ default List selectList() {
+ return selectList(new LambdaQueryWrapperX()
+ .orderByDesc(DatabusSyncClientDO::getId));
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncDeadLetterMapper.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncDeadLetterMapper.java
new file mode 100644
index 00000000..69ce53d3
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncDeadLetterMapper.java
@@ -0,0 +1,29 @@
+package com.zt.plat.framework.databus.server.dal.mapper;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.deadletter.DatabusSyncDeadLetterPageReqVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncDeadLetterDO;
+import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
+import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 数据同步死信队列 Mapper
+ *
+ * @author ZT
+ */
+@Mapper
+public interface DatabusSyncDeadLetterMapper extends BaseMapperX {
+
+ default PageResult selectPage(DatabusSyncDeadLetterPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX()
+ .eqIfPresent(DatabusSyncDeadLetterDO::getSyncId, reqVO.getSyncId())
+ .likeIfPresent(DatabusSyncDeadLetterDO::getClientCode, reqVO.getClientCode())
+ .likeIfPresent(DatabusSyncDeadLetterDO::getEventType, reqVO.getEventType())
+ .eqIfPresent(DatabusSyncDeadLetterDO::getStatus, reqVO.getStatus())
+ .eqIfPresent(DatabusSyncDeadLetterDO::getHandled, reqVO.getHandled())
+ .betweenIfPresent(DatabusSyncDeadLetterDO::getCreateTime, reqVO.getCreateTimeStart(), reqVO.getCreateTimeEnd())
+ .orderByDesc(DatabusSyncDeadLetterDO::getId));
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncEventMapper.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncEventMapper.java
new file mode 100644
index 00000000..a7a9880f
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncEventMapper.java
@@ -0,0 +1,37 @@
+package com.zt.plat.framework.databus.server.dal.mapper;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.event.DatabusSyncEventPageReqVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncEventDO;
+import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
+import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 数据同步事件定义 Mapper
+ *
+ * @author ZT
+ */
+@Mapper
+public interface DatabusSyncEventMapper extends BaseMapperX {
+
+ default DatabusSyncEventDO selectByEventType(String eventType) {
+ return selectOne(DatabusSyncEventDO::getEventType, eventType);
+ }
+
+ default PageResult selectPage(DatabusSyncEventPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX()
+ .likeIfPresent(DatabusSyncEventDO::getEventType, reqVO.getEventType())
+ .likeIfPresent(DatabusSyncEventDO::getEventName, reqVO.getEventName())
+ .eqIfPresent(DatabusSyncEventDO::getEnabled, reqVO.getEnabled())
+ .orderByDesc(DatabusSyncEventDO::getId));
+ }
+
+ default List selectList() {
+ return selectList(new LambdaQueryWrapperX()
+ .orderByDesc(DatabusSyncEventDO::getId));
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncEventRecordMapper.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncEventRecordMapper.java
new file mode 100644
index 00000000..7f26d3d9
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncEventRecordMapper.java
@@ -0,0 +1,15 @@
+package com.zt.plat.framework.databus.server.dal.mapper;
+
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncEventRecordDO;
+import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 数据同步事件流水 Mapper
+ *
+ * @author ZT
+ */
+@Mapper
+public interface DatabusSyncEventRecordMapper extends BaseMapperX {
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncFullTaskMapper.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncFullTaskMapper.java
new file mode 100644
index 00000000..5f3d6e70
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncFullTaskMapper.java
@@ -0,0 +1,62 @@
+package com.zt.plat.framework.databus.server.dal.mapper;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.fulltask.DatabusSyncFullTaskPageReqVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncFullTaskDO;
+import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
+import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 数据全量同步任务 Mapper
+ *
+ * @author ZT
+ */
+@Mapper
+public interface DatabusSyncFullTaskMapper extends BaseMapperX {
+
+ /**
+ * 根据任务编号查询
+ */
+ default DatabusSyncFullTaskDO selectByTaskNo(String taskNo) {
+ return selectOne(DatabusSyncFullTaskDO::getTaskNo, taskNo);
+ }
+
+ /**
+ * 查询指定订阅的进行中任务
+ */
+ default DatabusSyncFullTaskDO selectRunningBySubscriptionId(Long subscriptionId) {
+ return selectOne(new LambdaQueryWrapperX()
+ .eq(DatabusSyncFullTaskDO::getSubscriptionId, subscriptionId)
+ .in(DatabusSyncFullTaskDO::getStatus, 0, 1)); // 待执行或执行中
+ }
+
+ /**
+ * 查询待执行的任务列表
+ * 使用 MyBatis-Plus 分页机制,兼容达梦等数据库
+ */
+ default List selectPendingTasks(int limit) {
+ // 使用 Page 分页而不是 LIMIT 语法,以兼容达梦数据库
+ Page page = new Page<>(1, limit, false);
+ return selectPage(page, new LambdaQueryWrapperX()
+ .eq(DatabusSyncFullTaskDO::getStatus, 0)
+ .orderByAsc(DatabusSyncFullTaskDO::getCreateTime)).getRecords();
+ }
+
+ /**
+ * 分页查询
+ */
+ default PageResult selectPage(DatabusSyncFullTaskPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX()
+ .likeIfPresent(DatabusSyncFullTaskDO::getTaskNo, reqVO.getTaskNo())
+ .eqIfPresent(DatabusSyncFullTaskDO::getSubscriptionId, reqVO.getSubscriptionId())
+ .eqIfPresent(DatabusSyncFullTaskDO::getClientCode, reqVO.getClientCode())
+ .eqIfPresent(DatabusSyncFullTaskDO::getEventType, reqVO.getEventType())
+ .eqIfPresent(DatabusSyncFullTaskDO::getStatus, reqVO.getStatus())
+ .orderByDesc(DatabusSyncFullTaskDO::getId));
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncLogMapper.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncLogMapper.java
new file mode 100644
index 00000000..2fd52caa
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncLogMapper.java
@@ -0,0 +1,30 @@
+package com.zt.plat.framework.databus.server.dal.mapper;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.pushlog.DatabusSyncPushLogPageReqVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncLogDO;
+import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
+import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 数据同步日志 Mapper
+ *
+ * @author ZT
+ */
+@Mapper
+public interface DatabusSyncLogMapper extends BaseMapperX {
+
+ default PageResult selectPage(DatabusSyncPushLogPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX()
+ .eqIfPresent(DatabusSyncLogDO::getSyncId, reqVO.getSyncId())
+ .eqIfPresent(DatabusSyncLogDO::getSubscriptionId, reqVO.getSubscriptionId())
+ .likeIfPresent(DatabusSyncLogDO::getClientCode, reqVO.getClientCode())
+ .likeIfPresent(DatabusSyncLogDO::getEventType, reqVO.getEventType())
+ .eqIfPresent(DatabusSyncLogDO::getStatus, reqVO.getStatus())
+ .eqIfPresent(DatabusSyncLogDO::getTransportType, reqVO.getTransportType())
+ .betweenIfPresent(DatabusSyncLogDO::getCreateTime, reqVO.getCreateTimeStart(), reqVO.getCreateTimeEnd())
+ .orderByDesc(DatabusSyncLogDO::getId));
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncSubscriptionMapper.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncSubscriptionMapper.java
new file mode 100644
index 00000000..4d30f98a
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/dal/mapper/DatabusSyncSubscriptionMapper.java
@@ -0,0 +1,41 @@
+package com.zt.plat.framework.databus.server.dal.mapper;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.subscription.DatabusSyncSubscriptionPageReqVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncSubscriptionDO;
+import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
+import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 数据同步订阅关系 Mapper
+ *
+ * @author ZT
+ */
+@Mapper
+public interface DatabusSyncSubscriptionMapper extends BaseMapperX {
+
+ default DatabusSyncSubscriptionDO selectByClientIdAndEventId(Long clientId, Long eventId) {
+ return selectOne(new LambdaQueryWrapperX()
+ .eq(DatabusSyncSubscriptionDO::getClientId, clientId)
+ .eq(DatabusSyncSubscriptionDO::getEventId, eventId));
+ }
+
+ default PageResult selectPage(DatabusSyncSubscriptionPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX()
+ .eqIfPresent(DatabusSyncSubscriptionDO::getClientId, reqVO.getClientId())
+ .eqIfPresent(DatabusSyncSubscriptionDO::getEventId, reqVO.getEventId())
+ .eqIfPresent(DatabusSyncSubscriptionDO::getEnabled, reqVO.getEnabled())
+ .orderByDesc(DatabusSyncSubscriptionDO::getId));
+ }
+
+ /**
+ * 根据事件ID查询所有启用的订阅
+ */
+ default java.util.List selectEnabledByEventId(Long eventId) {
+ return selectList(new LambdaQueryWrapperX()
+ .eq(DatabusSyncSubscriptionDO::getEventId, eventId)
+ .eq(DatabusSyncSubscriptionDO::getEnabled, 1));
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/DataProviderTypeEnum.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/DataProviderTypeEnum.java
new file mode 100644
index 00000000..00ad24b6
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/DataProviderTypeEnum.java
@@ -0,0 +1,36 @@
+package com.zt.plat.framework.databus.server.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 数据提供者类型枚举
+ *
+ * @author ZT
+ */
+@Getter
+@AllArgsConstructor
+public enum DataProviderTypeEnum {
+
+ ORG("ORG", "组织机构"),
+ USER("USER", "用户");
+
+ /**
+ * 类型编码
+ */
+ private final String code;
+ /**
+ * 类型名称
+ */
+ private final String name;
+
+ public static DataProviderTypeEnum getByCode(String code) {
+ for (DataProviderTypeEnum value : values()) {
+ if (value.getCode().equals(code)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/DeadLetterStatusEnum.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/DeadLetterStatusEnum.java
new file mode 100644
index 00000000..1a3e8ecf
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/DeadLetterStatusEnum.java
@@ -0,0 +1,51 @@
+package com.zt.plat.framework.databus.server.enums;
+
+import cn.hutool.core.util.ObjUtil;
+import com.zt.plat.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 死信队列状态枚举
+ *
+ * @author ZT
+ */
+@Getter
+@AllArgsConstructor
+public enum DeadLetterStatusEnum implements ArrayValuable {
+
+ PENDING(0, "待处理"),
+ REDELIVERED(1, "已重新投递"),
+ IGNORED(2, "已忽略");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(DeadLetterStatusEnum::getStatus).toArray(Integer[]::new);
+
+ /**
+ * 状态值
+ */
+ private final Integer status;
+ /**
+ * 状态名
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ public static boolean isPending(Integer status) {
+ return ObjUtil.equal(PENDING.status, status);
+ }
+
+ public static boolean isRedelivered(Integer status) {
+ return ObjUtil.equal(REDELIVERED.status, status);
+ }
+
+ public static boolean isIgnored(Integer status) {
+ return ObjUtil.equal(IGNORED.status, status);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/ErrorCodeConstants.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/ErrorCodeConstants.java
new file mode 100644
index 00000000..893312d4
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/ErrorCodeConstants.java
@@ -0,0 +1,30 @@
+package com.zt.plat.framework.databus.server.enums;
+
+import com.zt.plat.framework.common.exception.ErrorCode;
+
+/**
+ * Databus 同步服务错误码枚举类
+ *
+ * databus 系统,使用 1-010-000-000 段
+ */
+public interface ErrorCodeConstants {
+
+ // ========== 数据同步事件 1-010-001-000 ==========
+ ErrorCode EVENT_NOT_EXISTS = new ErrorCode(1_010_001_000, "数据同步事件不存在");
+ ErrorCode EVENT_TYPE_DUPLICATE = new ErrorCode(1_010_001_001, "事件类型编码已存在");
+
+ // ========== 数据同步客户端 1-010-002-000 ==========
+ ErrorCode CLIENT_NOT_EXISTS = new ErrorCode(1_010_002_000, "数据同步客户端不存在");
+ ErrorCode CLIENT_CODE_DUPLICATE = new ErrorCode(1_010_002_001, "客户端编码已存在");
+
+ // ========== 数据同步订阅 1-010-003-000 ==========
+ ErrorCode SUBSCRIPTION_NOT_EXISTS = new ErrorCode(1_010_003_000, "数据同步订阅不存在");
+ ErrorCode SUBSCRIPTION_DUPLICATE = new ErrorCode(1_010_003_001, "该客户端已订阅该事件,不能重复订阅");
+
+ // ========== 数据同步推送日志 1-010-004-000 ==========
+ ErrorCode PUSH_LOG_NOT_EXISTS = new ErrorCode(1_010_004_000, "数据同步推送日志不存在");
+
+ // ========== 数据同步死信队列 1-010-005-000 ==========
+ ErrorCode DEAD_LETTER_NOT_EXISTS = new ErrorCode(1_010_005_000, "数据同步死信队列记录不存在");
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/FullTaskStatusEnum.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/FullTaskStatusEnum.java
new file mode 100644
index 00000000..a8aa2d4c
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/FullTaskStatusEnum.java
@@ -0,0 +1,75 @@
+package com.zt.plat.framework.databus.server.enums;
+
+import cn.hutool.core.util.ObjUtil;
+import com.zt.plat.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 全量任务状态枚举
+ *
+ * @author ZT
+ */
+@Getter
+@AllArgsConstructor
+public enum FullTaskStatusEnum implements ArrayValuable {
+
+ PENDING(0, "待执行"),
+ RUNNING(1, "执行中"),
+ COMPLETED(2, "已完成"),
+ FAILED(3, "失败"),
+ CANCELLED(4, "已取消");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(FullTaskStatusEnum::getStatus).toArray(Integer[]::new);
+
+ /**
+ * 状态值
+ */
+ private final Integer status;
+ /**
+ * 状态名
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ public static boolean isPending(Integer status) {
+ return ObjUtil.equal(PENDING.status, status);
+ }
+
+ public static boolean isRunning(Integer status) {
+ return ObjUtil.equal(RUNNING.status, status);
+ }
+
+ public static boolean isCompleted(Integer status) {
+ return ObjUtil.equal(COMPLETED.status, status);
+ }
+
+ public static boolean isFailed(Integer status) {
+ return ObjUtil.equal(FAILED.status, status);
+ }
+
+ public static boolean isCancelled(Integer status) {
+ return ObjUtil.equal(CANCELLED.status, status);
+ }
+
+ /**
+ * 是否可以取消
+ */
+ public static boolean canCancel(Integer status) {
+ return isPending(status) || isRunning(status);
+ }
+
+ /**
+ * 是否已终止(完成/失败/取消)
+ */
+ public static boolean isTerminated(Integer status) {
+ return isCompleted(status) || isFailed(status) || isCancelled(status);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/SyncModeEnum.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/SyncModeEnum.java
new file mode 100644
index 00000000..100c7daf
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/SyncModeEnum.java
@@ -0,0 +1,46 @@
+package com.zt.plat.framework.databus.server.enums;
+
+import cn.hutool.core.util.ObjUtil;
+import com.zt.plat.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 同步模式枚举
+ *
+ * @author ZT
+ */
+@Getter
+@AllArgsConstructor
+public enum SyncModeEnum implements ArrayValuable {
+
+ FULL(1, "全量同步"),
+ INCREMENTAL(2, "增量同步");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(SyncModeEnum::getMode).toArray(Integer[]::new);
+
+ /**
+ * 模式值
+ */
+ private final Integer mode;
+ /**
+ * 模式名
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ public static boolean isFull(Integer mode) {
+ return ObjUtil.equal(FULL.mode, mode);
+ }
+
+ public static boolean isIncremental(Integer mode) {
+ return ObjUtil.equal(INCREMENTAL.mode, mode);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/SyncStatusEnum.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/SyncStatusEnum.java
new file mode 100644
index 00000000..0bacda69
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/SyncStatusEnum.java
@@ -0,0 +1,56 @@
+package com.zt.plat.framework.databus.server.enums;
+
+import cn.hutool.core.util.ObjUtil;
+import com.zt.plat.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 同步状态枚举
+ *
+ * @author ZT
+ */
+@Getter
+@AllArgsConstructor
+public enum SyncStatusEnum implements ArrayValuable {
+
+ PENDING(0, "待处理"),
+ SUCCESS(1, "成功"),
+ FAILED(2, "失败"),
+ RETRYING(3, "重试中");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(SyncStatusEnum::getStatus).toArray(Integer[]::new);
+
+ /**
+ * 状态值
+ */
+ private final Integer status;
+ /**
+ * 状态名
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ public static boolean isPending(Integer status) {
+ return ObjUtil.equal(PENDING.status, status);
+ }
+
+ public static boolean isSuccess(Integer status) {
+ return ObjUtil.equal(SUCCESS.status, status);
+ }
+
+ public static boolean isFailed(Integer status) {
+ return ObjUtil.equal(FAILED.status, status);
+ }
+
+ public static boolean isRetrying(Integer status) {
+ return ObjUtil.equal(RETRYING.status, status);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/TimelinessEnum.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/TimelinessEnum.java
new file mode 100644
index 00000000..67b96c39
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/TimelinessEnum.java
@@ -0,0 +1,51 @@
+package com.zt.plat.framework.databus.server.enums;
+
+import cn.hutool.core.util.ObjUtil;
+import com.zt.plat.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 时效性枚举
+ *
+ * @author ZT
+ */
+@Getter
+@AllArgsConstructor
+public enum TimelinessEnum implements ArrayValuable {
+
+ REALTIME(1, "实时"),
+ NEAR_REALTIME(2, "准实时"),
+ BATCH(3, "批量");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(TimelinessEnum::getType).toArray(Integer[]::new);
+
+ /**
+ * 类型值
+ */
+ private final Integer type;
+ /**
+ * 类型名
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ public static boolean isRealtime(Integer type) {
+ return ObjUtil.equal(REALTIME.type, type);
+ }
+
+ public static boolean isNearRealtime(Integer type) {
+ return ObjUtil.equal(NEAR_REALTIME.type, type);
+ }
+
+ public static boolean isBatch(Integer type) {
+ return ObjUtil.equal(BATCH.type, type);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/TransportTypeEnum.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/TransportTypeEnum.java
new file mode 100644
index 00000000..c0fbf707
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/enums/TransportTypeEnum.java
@@ -0,0 +1,46 @@
+package com.zt.plat.framework.databus.server.enums;
+
+import cn.hutool.core.util.ObjUtil;
+import com.zt.plat.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 传输方式枚举
+ *
+ * @author ZT
+ */
+@Getter
+@AllArgsConstructor
+public enum TransportTypeEnum implements ArrayValuable {
+
+ MQ_FIRST(1, "MQ优先"),
+ HTTP_ONLY(2, "仅HTTP");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(TransportTypeEnum::getType).toArray(Integer[]::new);
+
+ /**
+ * 类型值
+ */
+ private final Integer type;
+ /**
+ * 类型名
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ public static boolean isMqFirst(Integer type) {
+ return ObjUtil.equal(MQ_FIRST.type, type);
+ }
+
+ public static boolean isHttpOnly(Integer type) {
+ return ObjUtil.equal(HTTP_ONLY.type, type);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/producer/DatabusMessageProducer.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/producer/DatabusMessageProducer.java
new file mode 100644
index 00000000..16807566
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/producer/DatabusMessageProducer.java
@@ -0,0 +1,195 @@
+package com.zt.plat.framework.databus.server.producer;
+
+import cn.hutool.json.JSONUtil;
+import com.zt.plat.framework.databus.server.config.DatabusServerProperties;
+import com.zt.plat.module.databus.api.message.DatabusBatchMessage;
+import com.zt.plat.module.databus.api.message.DatabusMessage;
+import com.zt.plat.module.databus.enums.DatabusEventType;
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.PreDestroy;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.common.message.Message;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+/**
+ * Databus 消息生产者
+ *
+ * 负责将数据变更消息发送到各个客户端的 Topic
+ *
+ * @author ZT
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class DatabusMessageProducer {
+
+ private final DatabusServerProperties properties;
+
+ private DefaultMQProducer producer;
+
+ @PostConstruct
+ public void init() throws MQClientException {
+ if (!properties.isEnabled() || !properties.getMq().isEnabled()) {
+ log.info("[Databus Server] MQ 发送未启用");
+ return;
+ }
+
+ producer = new DefaultMQProducer(properties.getMq().getProducerGroup());
+ producer.setNamesrvAddr(properties.getMq().getNameServer());
+ producer.setSendMsgTimeout(properties.getMq().getSendMsgTimeout());
+ producer.start();
+
+ log.info("[Databus Server] 消息生产者启动成功, nameServer={}, producerGroup={}",
+ properties.getMq().getNameServer(), properties.getMq().getProducerGroup());
+ }
+
+ @PreDestroy
+ public void destroy() {
+ if (producer != null) {
+ producer.shutdown();
+ log.info("[Databus Server] 消息生产者已关闭");
+ }
+ }
+
+ /**
+ * 发送增量消息到所有客户端
+ *
+ * @param message 消息
+ * @param 数据类型
+ */
+ public void send(DatabusMessage message) {
+ if (producer == null) {
+ log.warn("[Databus Server] Producer 未初始化,无法发送消息");
+ return;
+ }
+
+ List clients = properties.getClients();
+ if (clients == null || clients.isEmpty()) {
+ log.warn("[Databus Server] 未配置客户端列表,无法发送消息");
+ return;
+ }
+
+ String messageJson = JSONUtil.toJsonStr(message);
+ DatabusEventType eventType = message.getEventType();
+
+ for (String clientCode : clients) {
+ try {
+ String topic = eventType.getTopic(properties.getMq().getTopicBase(), clientCode);
+ Message mqMessage = new Message(topic, messageJson.getBytes(StandardCharsets.UTF_8));
+ mqMessage.setKeys(message.getMessageId());
+
+ SendResult result = producer.send(mqMessage);
+ log.debug("[Databus Server] 消息发送成功, topic={}, messageId={}, result={}",
+ topic, message.getMessageId(), result.getMsgId());
+ } catch (Exception e) {
+ log.error("[Databus Server] 消息发送失败, clientCode={}, eventType={}, messageId={}",
+ clientCode, eventType.name(), message.getMessageId(), e);
+ }
+ }
+ }
+
+ /**
+ * 发送增量消息到指定客户端
+ *
+ * @param message 消息
+ * @param clientCode 客户端编码
+ * @param 数据类型
+ */
+ public void sendTo(DatabusMessage message, String clientCode) {
+ if (producer == null) {
+ log.warn("[Databus Server] Producer 未初始化,无法发送消息");
+ return;
+ }
+
+ String messageJson = JSONUtil.toJsonStr(message);
+ DatabusEventType eventType = message.getEventType();
+ String topic = eventType.getTopic(properties.getMq().getTopicBase(), clientCode);
+
+ try {
+ Message mqMessage = new Message(topic, messageJson.getBytes(StandardCharsets.UTF_8));
+ mqMessage.setKeys(message.getMessageId());
+
+ SendResult result = producer.send(mqMessage);
+ log.info("[Databus Server] 消息发送成功, topic={}, messageId={}, result={}",
+ topic, message.getMessageId(), result.getMsgId());
+ } catch (Exception e) {
+ log.error("[Databus Server] 消息发送失败, clientCode={}, eventType={}, messageId={}",
+ clientCode, eventType.name(), message.getMessageId(), e);
+ throw new RuntimeException("消息发送失败", e);
+ }
+ }
+
+ /**
+ * 发送批量消息到所有客户端
+ *
+ * @param message 批量消息
+ * @param 数据类型
+ */
+ public void sendBatch(DatabusBatchMessage message) {
+ if (producer == null) {
+ log.warn("[Databus Server] Producer 未初始化,无法发送消息");
+ return;
+ }
+
+ List clients = properties.getClients();
+ if (clients == null || clients.isEmpty()) {
+ log.warn("[Databus Server] 未配置客户端列表,无法发送消息");
+ return;
+ }
+
+ String messageJson = JSONUtil.toJsonStr(message);
+ DatabusEventType eventType = message.getEventType();
+
+ for (String clientCode : clients) {
+ try {
+ String topic = eventType.getTopic(properties.getMq().getTopicBase(), clientCode);
+ Message mqMessage = new Message(topic, messageJson.getBytes(StandardCharsets.UTF_8));
+ mqMessage.setKeys(message.getMessageId());
+
+ SendResult result = producer.send(mqMessage);
+ log.debug("[Databus Server] 批量消息发送成功, topic={}, batchNo={}/{}, result={}",
+ topic, message.getBatchNo(), message.getTotalBatch(), result.getMsgId());
+ } catch (Exception e) {
+ log.error("[Databus Server] 批量消息发送失败, clientCode={}, eventType={}, batchNo={}",
+ clientCode, eventType.name(), message.getBatchNo(), e);
+ }
+ }
+ }
+
+ /**
+ * 发送批量消息到指定客户端
+ *
+ * @param message 批量消息
+ * @param clientCode 客户端编码
+ * @param 数据类型
+ */
+ public void sendBatchTo(DatabusBatchMessage message, String clientCode) {
+ if (producer == null) {
+ log.warn("[Databus Server] Producer 未初始化,无法发送消息");
+ return;
+ }
+
+ String messageJson = JSONUtil.toJsonStr(message);
+ DatabusEventType eventType = message.getEventType();
+ String topic = eventType.getTopic(properties.getMq().getTopicBase(), clientCode);
+
+ try {
+ Message mqMessage = new Message(topic, messageJson.getBytes(StandardCharsets.UTF_8));
+ mqMessage.setKeys(message.getMessageId());
+
+ SendResult result = producer.send(mqMessage);
+ log.info("[Databus Server] 批量消息发送成功, topic={}, batchNo={}/{}, result={}",
+ topic, message.getBatchNo(), message.getTotalBatch(), result.getMsgId());
+ } catch (Exception e) {
+ log.error("[Databus Server] 批量消息发送失败, clientCode={}, eventType={}, batchNo={}",
+ clientCode, eventType.name(), message.getBatchNo(), e);
+ throw new RuntimeException("批量消息发送失败", e);
+ }
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncClientService.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncClientService.java
new file mode 100644
index 00000000..7e634a61
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncClientService.java
@@ -0,0 +1,70 @@
+package com.zt.plat.framework.databus.server.service;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.client.DatabusSyncClientPageReqVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.client.DatabusSyncClientSaveReqVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncClientDO;
+
+import java.util.List;
+
+/**
+ * 数据同步客户端 Service 接口
+ *
+ * @author ZT
+ */
+public interface DatabusSyncClientService {
+
+ /**
+ * 创建数据同步客户端
+ *
+ * @param createReqVO 创建信息
+ * @return 编号
+ */
+ Long createClient(DatabusSyncClientSaveReqVO createReqVO);
+
+ /**
+ * 更新数据同步客户端
+ *
+ * @param updateReqVO 更新信息
+ */
+ void updateClient(DatabusSyncClientSaveReqVO updateReqVO);
+
+ /**
+ * 删除数据同步客户端
+ *
+ * @param id 编号
+ */
+ void deleteClient(Long id);
+
+ /**
+ * 获得数据同步客户端
+ *
+ * @param id 编号
+ * @return 数据同步客户端
+ */
+ DatabusSyncClientDO getClient(Long id);
+
+ /**
+ * 获得数据同步客户端分页
+ *
+ * @param pageReqVO 分页查询
+ * @return 数据同步客户端分页
+ */
+ PageResult getClientPage(DatabusSyncClientPageReqVO pageReqVO);
+
+ /**
+ * 获得数据同步客户端列表
+ *
+ * @return 数据同步客户端列表
+ */
+ List getClientList();
+
+ /**
+ * 更新客户端启用状态
+ *
+ * @param id 编号
+ * @param enabled 启用状态
+ */
+ void updateClientStatus(Long id, Integer enabled);
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncDeadLetterService.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncDeadLetterService.java
new file mode 100644
index 00000000..e922a8ad
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncDeadLetterService.java
@@ -0,0 +1,54 @@
+package com.zt.plat.framework.databus.server.service;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.deadletter.DatabusSyncDeadLetterPageReqVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncDeadLetterDO;
+
+import java.util.List;
+
+/**
+ * 数据同步死信队列 Service 接口
+ *
+ * @author ZT
+ */
+public interface DatabusSyncDeadLetterService {
+
+ /**
+ * 获得数据同步死信队列
+ *
+ * @param id 编号
+ * @return 数据同步死信队列
+ */
+ DatabusSyncDeadLetterDO getDeadLetter(Long id);
+
+ /**
+ * 获得数据同步死信队列分页
+ *
+ * @param pageReqVO 分页查询
+ * @return 数据同步死信队列分页
+ */
+ PageResult getDeadLetterPage(DatabusSyncDeadLetterPageReqVO pageReqVO);
+
+ /**
+ * 重新投递死信消息
+ *
+ * @param id 死信ID
+ */
+ void reprocessDeadLetter(Long id);
+
+ /**
+ * 批量重新投递死信消息
+ *
+ * @param ids 死信ID列表
+ */
+ void batchReprocessDeadLetter(List ids);
+
+ /**
+ * 标记为已处理
+ *
+ * @param id 死信ID
+ * @param remark 处理备注
+ */
+ void markHandled(Long id, String remark);
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncEventService.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncEventService.java
new file mode 100644
index 00000000..fe7c2b3f
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncEventService.java
@@ -0,0 +1,70 @@
+package com.zt.plat.framework.databus.server.service;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.event.DatabusSyncEventPageReqVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.event.DatabusSyncEventSaveReqVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncEventDO;
+
+import java.util.List;
+
+/**
+ * 数据同步事件 Service 接口
+ *
+ * @author ZT
+ */
+public interface DatabusSyncEventService {
+
+ /**
+ * 创建数据同步事件
+ *
+ * @param createReqVO 创建信息
+ * @return 编号
+ */
+ Long createEvent(DatabusSyncEventSaveReqVO createReqVO);
+
+ /**
+ * 更新数据同步事件
+ *
+ * @param updateReqVO 更新信息
+ */
+ void updateEvent(DatabusSyncEventSaveReqVO updateReqVO);
+
+ /**
+ * 删除数据同步事件
+ *
+ * @param id 编号
+ */
+ void deleteEvent(Long id);
+
+ /**
+ * 获得数据同步事件
+ *
+ * @param id 编号
+ * @return 数据同步事件
+ */
+ DatabusSyncEventDO getEvent(Long id);
+
+ /**
+ * 获得数据同步事件分页
+ *
+ * @param pageReqVO 分页查询
+ * @return 数据同步事件分页
+ */
+ PageResult getEventPage(DatabusSyncEventPageReqVO pageReqVO);
+
+ /**
+ * 获得数据同步事件列表
+ *
+ * @return 数据同步事件列表
+ */
+ List getEventList();
+
+ /**
+ * 更新事件启用状态
+ *
+ * @param id 编号
+ * @param enabled 启用状态
+ */
+ void updateEventStatus(Long id, Integer enabled);
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncLogService.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncLogService.java
new file mode 100644
index 00000000..26cc97b5
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncLogService.java
@@ -0,0 +1,37 @@
+package com.zt.plat.framework.databus.server.service;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.pushlog.DatabusSyncPushLogPageReqVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncLogDO;
+
+/**
+ * 数据同步推送日志 Service 接口
+ *
+ * @author ZT
+ */
+public interface DatabusSyncLogService {
+
+ /**
+ * 获得数据同步推送日志
+ *
+ * @param id 编号
+ * @return 数据同步推送日志
+ */
+ DatabusSyncLogDO getPushLog(Long id);
+
+ /**
+ * 获得数据同步推送日志分页
+ *
+ * @param pageReqVO 分页查询
+ * @return 数据同步推送日志分页
+ */
+ PageResult getPushLogPage(DatabusSyncPushLogPageReqVO pageReqVO);
+
+ /**
+ * 重试推送
+ *
+ * @param id 日志ID
+ */
+ void retryPush(Long id);
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncSubscriptionService.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncSubscriptionService.java
new file mode 100644
index 00000000..88239aaf
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/DatabusSyncSubscriptionService.java
@@ -0,0 +1,75 @@
+package com.zt.plat.framework.databus.server.service;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.subscription.DatabusSyncSubscriptionPageReqVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.subscription.DatabusSyncSubscriptionSaveReqVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncSubscriptionDO;
+
+/**
+ * 数据同步订阅 Service 接口
+ *
+ * @author ZT
+ */
+public interface DatabusSyncSubscriptionService {
+
+ /**
+ * 创建数据同步订阅
+ *
+ * @param createReqVO 创建信息
+ * @return 编号
+ */
+ Long createSubscription(DatabusSyncSubscriptionSaveReqVO createReqVO);
+
+ /**
+ * 更新数据同步订阅
+ *
+ * @param updateReqVO 更新信息
+ */
+ void updateSubscription(DatabusSyncSubscriptionSaveReqVO updateReqVO);
+
+ /**
+ * 删除数据同步订阅
+ *
+ * @param id 编号
+ */
+ void deleteSubscription(Long id);
+
+ /**
+ * 获得数据同步订阅
+ *
+ * @param id 编号
+ * @return 数据同步订阅
+ */
+ DatabusSyncSubscriptionDO getSubscription(Long id);
+
+ /**
+ * 获得数据同步订阅分页
+ *
+ * @param pageReqVO 分页查询
+ * @return 数据同步订阅分页
+ */
+ PageResult getSubscriptionPage(DatabusSyncSubscriptionPageReqVO pageReqVO);
+
+ /**
+ * 更新订阅启用状态
+ *
+ * @param id 编号
+ * @param enabled 启用状态
+ */
+ void updateSubscriptionStatus(Long id, Integer enabled);
+
+ /**
+ * 重置订阅断点
+ *
+ * @param id 编号
+ */
+ void resetCheckpoint(Long id);
+
+ /**
+ * 手动触发同步
+ *
+ * @param id 编号
+ */
+ void triggerSync(Long id);
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusFullSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusFullSyncServiceImpl.java
new file mode 100644
index 00000000..d92f8800
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusFullSyncServiceImpl.java
@@ -0,0 +1,328 @@
+package com.zt.plat.framework.databus.server.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.json.JSONUtil;
+import com.zt.plat.framework.databus.server.config.DatabusSyncServerProperties;
+import com.zt.plat.framework.databus.server.core.message.BatchSyncMessage;
+import com.zt.plat.framework.databus.server.core.provider.DataProvider;
+import com.zt.plat.framework.databus.server.core.provider.DataProviderRegistry;
+import com.zt.plat.framework.databus.server.core.pusher.MessagePusher;
+import com.zt.plat.framework.databus.server.core.sync.DatabusFullSyncService;
+import com.zt.plat.framework.databus.server.dal.dataobject.*;
+import com.zt.plat.framework.databus.server.dal.mapper.*;
+import com.zt.plat.framework.databus.server.enums.*;
+import com.zt.plat.module.databus.enums.DatabusEventType;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Databus Full Sync Service Implementation
+ *
+ * @author ZT
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class DatabusFullSyncServiceImpl implements DatabusFullSyncService {
+
+ private final DatabusSyncFullTaskMapper fullTaskMapper;
+ private final DatabusSyncSubscriptionMapper subscriptionMapper;
+ private final DatabusSyncClientMapper clientMapper;
+ private final DatabusSyncEventMapper eventMapper;
+ private final DatabusSyncLogMapper syncLogMapper;
+ private final MessagePusher messagePusher;
+ private final DatabusSyncServerProperties properties;
+ private final DataProviderRegistry dataProviderRegistry;
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Long createFullSyncTask(Long subscriptionId, String remark) {
+ DatabusSyncSubscriptionDO subscription = subscriptionMapper.selectById(subscriptionId);
+ if (subscription == null) {
+ throw new RuntimeException("Subscription not found");
+ }
+
+ DatabusSyncFullTaskDO runningTask = fullTaskMapper.selectRunningBySubscriptionId(subscriptionId);
+ if (runningTask != null) {
+ throw new RuntimeException("Full sync task already running: " + runningTask.getTaskNo());
+ }
+
+ DatabusSyncClientDO client = clientMapper.selectById(subscription.getClientId());
+ DatabusSyncEventDO event = eventMapper.selectById(subscription.getEventId());
+
+ if (client == null || event == null) {
+ throw new RuntimeException("Client or event config not found");
+ }
+
+ if (event.getSupportFullSync() != 1) {
+ throw new RuntimeException("Event does not support full sync");
+ }
+
+ DatabusSyncFullTaskDO task = DatabusSyncFullTaskDO.builder()
+ .taskNo(IdUtil.fastSimpleUUID())
+ .subscriptionId(subscriptionId)
+ .clientCode(client.getClientCode())
+ .eventType(event.getEventType())
+ .status(FullTaskStatusEnum.PENDING.getStatus())
+ .totalCount(0L)
+ .processedCount(0L)
+ .successCount(0L)
+ .failCount(0L)
+ .totalBatch(0)
+ .currentBatch(0)
+ .batchSize(subscription.getBatchSize())
+ .tenantId(client.getTenantId())
+ .remark(remark)
+ .build();
+
+ fullTaskMapper.insert(task);
+ log.info("[Databus] Full sync task created, taskId={}, taskNo={}", task.getId(), task.getTaskNo());
+
+ return task.getId();
+ }
+
+ @Override
+ @Async
+ public void executeFullSyncTask(Long taskId) {
+ DatabusSyncFullTaskDO task = fullTaskMapper.selectById(taskId);
+ if (task == null) {
+ log.error("[Databus] Task not found, taskId={}", taskId);
+ return;
+ }
+ // 允许 PENDING、RUNNING、FAILED 状态执行(支持重试)
+ if (FullTaskStatusEnum.isCompleted(task.getStatus()) ||
+ FullTaskStatusEnum.isCancelled(task.getStatus())) {
+ log.warn("[Databus] Task status not allowed, taskId={}, status={}", taskId, task.getStatus());
+ return;
+ }
+
+ task.setStatus(FullTaskStatusEnum.RUNNING.getStatus());
+ task.setStartTime(LocalDateTime.now());
+ fullTaskMapper.updateById(task);
+
+ try {
+ DatabusSyncSubscriptionDO subscription = subscriptionMapper.selectById(task.getSubscriptionId());
+ DatabusSyncClientDO client = clientMapper.selectById(subscription.getClientId());
+ DatabusSyncEventDO event = eventMapper.selectById(subscription.getEventId());
+
+ String providerType = event.getDataProviderMethod();
+ if (providerType == null) {
+ throw new RuntimeException("Event data provider type not configured");
+ }
+
+ DataProvider> dataProvider = dataProviderRegistry.getProvider(providerType);
+ if (dataProvider == null) {
+ throw new RuntimeException("Data provider not found: " + providerType);
+ }
+
+ executeGenericFullSync(task, subscription, client, event, dataProvider);
+
+ task.setStatus(FullTaskStatusEnum.COMPLETED.getStatus());
+ task.setEndTime(LocalDateTime.now());
+ fullTaskMapper.updateById(task);
+
+ log.info("[Databus] Full sync task completed, taskId={}, totalCount={}, successCount={}",
+ taskId, task.getTotalCount(), task.getSuccessCount());
+
+ } catch (Exception e) {
+ log.error("[Databus] Full sync task failed, taskId={}", taskId, e);
+
+ task.setStatus(FullTaskStatusEnum.FAILED.getStatus());
+ task.setEndTime(LocalDateTime.now());
+ task.setLastErrorMessage(e.getMessage());
+ fullTaskMapper.updateById(task);
+ }
+ }
+
+ private void executeGenericFullSync(DatabusSyncFullTaskDO task,
+ DatabusSyncSubscriptionDO subscription,
+ DatabusSyncClientDO client,
+ DatabusSyncEventDO event,
+ DataProvider dataProvider) {
+ long totalCount = dataProvider.count(task.getTenantId());
+ int totalBatch = (int) Math.ceil((double) totalCount / task.getBatchSize());
+
+ task.setTotalCount(totalCount);
+ task.setTotalBatch(totalBatch);
+ fullTaskMapper.updateById(task);
+
+ LocalDateTime cursorTime = task.getCursorTime();
+ Long cursorId = task.getCursorId();
+ int batchNo = task.getCurrentBatch();
+
+ while (true) {
+ DatabusSyncFullTaskDO currentTask = fullTaskMapper.selectById(task.getId());
+ if (FullTaskStatusEnum.isCancelled(currentTask.getStatus())) {
+ log.info("[Databus] Task cancelled, taskId={}", task.getId());
+ return;
+ }
+
+ batchNo++;
+ DataProvider.CursorPageData page = dataProvider.getPageByCursor(
+ cursorTime, cursorId, task.getBatchSize(), task.getTenantId());
+
+ if (CollUtil.isEmpty(page.getList())) {
+ break;
+ }
+
+ boolean isLastBatch = !page.isHasMore();
+ BatchSyncMessage message = buildBatchMessage(
+ task, event, page.getList(), dataProvider, batchNo, totalBatch, isLastBatch, totalCount);
+
+ boolean success = pushBatchMessage(client, event.getEventType(), message);
+
+ recordSyncLog(task, subscription, client, event, message, success, batchNo);
+
+ task.setCurrentBatch(batchNo);
+ task.setCursorTime(page.getNextCursorTime());
+ task.setCursorId(page.getNextCursorId());
+ task.setProcessedCount(task.getProcessedCount() + page.getCount());
+ if (success) {
+ task.setSuccessCount(task.getSuccessCount() + page.getCount());
+ } else {
+ task.setFailCount(task.getFailCount() + page.getCount());
+ }
+ fullTaskMapper.updateById(task);
+
+ if (isLastBatch) {
+ break;
+ }
+ cursorTime = page.getNextCursorTime();
+ cursorId = page.getNextCursorId();
+ }
+ }
+
+ private BatchSyncMessage buildBatchMessage(DatabusSyncFullTaskDO task,
+ DatabusSyncEventDO event,
+ List dataList,
+ DataProvider dataProvider,
+ int batchNo,
+ int totalBatch,
+ boolean isLastBatch,
+ long totalCount) {
+ List items = new ArrayList<>();
+ for (T data : dataList) {
+ Long uid = dataProvider.extractUid(data);
+ items.add(BatchSyncMessage.SyncDataItem.builder()
+ .action("FULL")
+ .uid(uid)
+ .data(JSONUtil.toJsonStr(data))
+ .build());
+ }
+
+ return BatchSyncMessage.builder()
+ .messageId(IdUtil.fastSimpleUUID())
+ .requestId(task.getTaskNo())
+ .eventType(event.getEventType())
+ .syncMode(SyncModeEnum.FULL.getMode())
+ .dataVersion(event.getDataVersion())
+ .timestamp(System.currentTimeMillis())
+ .tenantId(task.getTenantId())
+ .dataList(items)
+ .count(items.size())
+ .fullTaskId(task.getId())
+ .batchNo(batchNo)
+ .totalBatch(totalBatch)
+ .isLastBatch(isLastBatch)
+ .totalCount(totalCount)
+ .build();
+ }
+
+ private boolean pushBatchMessage(DatabusSyncClientDO client, String eventType,
+ BatchSyncMessage message) {
+ try {
+ if (TransportTypeEnum.isMqFirst(client.getTransportType()) && client.getMqEnabled() == 1) {
+ // 使用 getByTopicSuffix 支持数据库存储的 topic 格式(如 system-post-full)
+ DatabusEventType databusEventType = DatabusEventType.getByTopicSuffix(eventType);
+ if (databusEventType == null) {
+ log.error("[Databus] Unknown event type: {}", eventType);
+ return false;
+ }
+ String topicBase = client.getMqTopicBase();
+ if (topicBase == null || topicBase.isEmpty()) {
+ topicBase = "databus-sync";
+ }
+ String topic = databusEventType.getTopic(topicBase, client.getClientCode());
+ log.info("[Databus] Pushing batch message, topic={}, eventType={}, clientCode={}, messageId={}",
+ topic, eventType, client.getClientCode(), message.getMessageId());
+ messagePusher.pushBatchByMQ(topic, message);
+ } else if (client.getHttpEnabled() == 1) {
+ return messagePusher.pushBatchByHttp(client.getHttpEndpoint(), message);
+ } else {
+ throw new RuntimeException("No available push method");
+ }
+ return true;
+ } catch (Exception e) {
+ log.error("[Databus] Push batch message failed, messageId={}", message.getMessageId(), e);
+ return false;
+ }
+ }
+
+ private void recordSyncLog(DatabusSyncFullTaskDO task,
+ DatabusSyncSubscriptionDO subscription,
+ DatabusSyncClientDO client,
+ DatabusSyncEventDO event,
+ BatchSyncMessage message,
+ boolean success,
+ int batchNo) {
+ DatabusSyncLogDO syncLog = DatabusSyncLogDO.builder()
+ .syncId(message.getMessageId())
+ .eventRecordId(0L)
+ .subscriptionId(subscription.getId())
+ .clientCode(client.getClientCode())
+ .eventType(event.getEventType())
+ .syncMode(SyncModeEnum.FULL.getMode())
+ .transportType(TransportTypeEnum.isMqFirst(client.getTransportType()) && client.getMqEnabled() == 1
+ ? TransportTypeEnum.MQ_FIRST.getType()
+ : TransportTypeEnum.HTTP_ONLY.getType())
+ .status(success ? SyncStatusEnum.SUCCESS.getStatus() : SyncStatusEnum.FAILED.getStatus())
+ .retryCount(0)
+ .startTime(LocalDateTime.now())
+ .endTime(LocalDateTime.now())
+ .tenantId(task.getTenantId())
+ .dataCount(message.getCount())
+ .batchNo(batchNo)
+ .fullTaskId(task.getId())
+ .build();
+
+ syncLogMapper.insert(syncLog);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void cancelFullSyncTask(Long taskId) {
+ DatabusSyncFullTaskDO task = fullTaskMapper.selectById(taskId);
+ if (task == null) {
+ throw new RuntimeException("Task not found");
+ }
+
+ if (!FullTaskStatusEnum.canCancel(task.getStatus())) {
+ throw new RuntimeException("Task status not allowed to cancel");
+ }
+
+ task.setStatus(FullTaskStatusEnum.CANCELLED.getStatus());
+ task.setEndTime(LocalDateTime.now());
+ fullTaskMapper.updateById(task);
+
+ log.info("[Databus] Full sync task cancelled, taskId={}", taskId);
+ }
+
+ @Override
+ public DatabusSyncFullTaskDO getTaskById(Long taskId) {
+ return fullTaskMapper.selectById(taskId);
+ }
+
+ @Override
+ public DatabusSyncFullTaskDO getTaskByTaskNo(String taskNo) {
+ return fullTaskMapper.selectByTaskNo(taskNo);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncClientServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncClientServiceImpl.java
new file mode 100644
index 00000000..496463c9
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncClientServiceImpl.java
@@ -0,0 +1,115 @@
+package com.zt.plat.framework.databus.server.service.impl;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.client.DatabusSyncClientPageReqVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.client.DatabusSyncClientSaveReqVO;
+import com.zt.plat.framework.databus.server.convert.DatabusSyncClientConvert;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncClientDO;
+import com.zt.plat.framework.databus.server.dal.mapper.DatabusSyncClientMapper;
+import com.zt.plat.framework.databus.server.service.DatabusSyncClientService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.List;
+
+import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static com.zt.plat.framework.databus.server.enums.ErrorCodeConstants.*;
+
+/**
+ * 数据同步客户端 Service 实现类
+ *
+ * @author ZT
+ */
+@Slf4j
+@Service
+@Validated
+public class DatabusSyncClientServiceImpl implements DatabusSyncClientService {
+
+ @Resource
+ private DatabusSyncClientMapper clientMapper;
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Long createClient(DatabusSyncClientSaveReqVO createReqVO) {
+ // 校验客户端编码唯一性
+ validateClientCodeUnique(null, createReqVO.getClientCode());
+
+ // 插入
+ DatabusSyncClientDO client = DatabusSyncClientConvert.INSTANCE.convert(createReqVO);
+ clientMapper.insert(client);
+ return client.getId();
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void updateClient(DatabusSyncClientSaveReqVO updateReqVO) {
+ // 校验存在
+ validateClientExists(updateReqVO.getId());
+ // 校验客户端编码唯一性
+ validateClientCodeUnique(updateReqVO.getId(), updateReqVO.getClientCode());
+
+ // 更新
+ DatabusSyncClientDO updateObj = DatabusSyncClientConvert.INSTANCE.convert(updateReqVO);
+ clientMapper.updateById(updateObj);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void deleteClient(Long id) {
+ // 校验存在
+ validateClientExists(id);
+ // 删除
+ clientMapper.deleteById(id);
+ }
+
+ private void validateClientExists(Long id) {
+ if (clientMapper.selectById(id) == null) {
+ throw exception(CLIENT_NOT_EXISTS);
+ }
+ }
+
+ private void validateClientCodeUnique(Long id, String clientCode) {
+ DatabusSyncClientDO client = clientMapper.selectByClientCode(clientCode);
+ if (client == null) {
+ return;
+ }
+ // 如果 id 为空,说明不用比较是否为相同 id 的客户端
+ if (id == null) {
+ throw exception(CLIENT_CODE_DUPLICATE);
+ }
+ if (!client.getId().equals(id)) {
+ throw exception(CLIENT_CODE_DUPLICATE);
+ }
+ }
+
+ @Override
+ public DatabusSyncClientDO getClient(Long id) {
+ return clientMapper.selectById(id);
+ }
+
+ @Override
+ public PageResult getClientPage(DatabusSyncClientPageReqVO pageReqVO) {
+ return clientMapper.selectPage(pageReqVO);
+ }
+
+ @Override
+ public List getClientList() {
+ return clientMapper.selectList();
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void updateClientStatus(Long id, Integer enabled) {
+ // 校验存在
+ validateClientExists(id);
+ // 更新状态
+ DatabusSyncClientDO updateObj = new DatabusSyncClientDO();
+ updateObj.setId(id);
+ updateObj.setEnabled(enabled);
+ clientMapper.updateById(updateObj);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncDeadLetterServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncDeadLetterServiceImpl.java
new file mode 100644
index 00000000..ee16880b
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncDeadLetterServiceImpl.java
@@ -0,0 +1,99 @@
+package com.zt.plat.framework.databus.server.service.impl;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.deadletter.DatabusSyncDeadLetterPageReqVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncDeadLetterDO;
+import com.zt.plat.framework.databus.server.dal.mapper.DatabusSyncDeadLetterMapper;
+import com.zt.plat.framework.databus.server.enums.DeadLetterStatusEnum;
+import com.zt.plat.framework.databus.server.service.DatabusSyncDeadLetterService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static com.zt.plat.framework.databus.server.enums.ErrorCodeConstants.DEAD_LETTER_NOT_EXISTS;
+
+/**
+ * 数据同步死信队列 Service 实现类
+ *
+ * @author ZT
+ */
+@Slf4j
+@Service
+@Validated
+public class DatabusSyncDeadLetterServiceImpl implements DatabusSyncDeadLetterService {
+
+ @Resource
+ private DatabusSyncDeadLetterMapper deadLetterMapper;
+
+ @Override
+ public DatabusSyncDeadLetterDO getDeadLetter(Long id) {
+ return deadLetterMapper.selectById(id);
+ }
+
+ @Override
+ public PageResult getDeadLetterPage(DatabusSyncDeadLetterPageReqVO pageReqVO) {
+ return deadLetterMapper.selectPage(pageReqVO);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void reprocessDeadLetter(Long id) {
+ // 校验存在
+ DatabusSyncDeadLetterDO deadLetter = deadLetterMapper.selectById(id);
+ if (deadLetter == null) {
+ throw exception(DEAD_LETTER_NOT_EXISTS);
+ }
+
+ // TODO: 实现重新投递逻辑,将消息重新发送到 MQ 或 HTTP
+ log.info("[reprocessDeadLetter] 重新投递死信消息,ID: {}, 同步ID: {}", id, deadLetter.getSyncId());
+
+ // 更新状态为已重新投递
+ DatabusSyncDeadLetterDO updateObj = new DatabusSyncDeadLetterDO();
+ updateObj.setId(id);
+ updateObj.setStatus(DeadLetterStatusEnum.REDELIVERED.getStatus());
+ updateObj.setHandled(1);
+ updateObj.setHandleTime(LocalDateTime.now());
+ deadLetterMapper.updateById(updateObj);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void batchReprocessDeadLetter(List ids) {
+ if (ids == null || ids.isEmpty()) {
+ return;
+ }
+ for (Long id : ids) {
+ try {
+ reprocessDeadLetter(id);
+ } catch (Exception e) {
+ log.error("[batchReprocessDeadLetter] 重新投递失败,ID: {}", id, e);
+ }
+ }
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void markHandled(Long id, String remark) {
+ // 校验存在
+ DatabusSyncDeadLetterDO deadLetter = deadLetterMapper.selectById(id);
+ if (deadLetter == null) {
+ throw exception(DEAD_LETTER_NOT_EXISTS);
+ }
+
+ // 标记为已处理(忽略)
+ DatabusSyncDeadLetterDO updateObj = new DatabusSyncDeadLetterDO();
+ updateObj.setId(id);
+ updateObj.setStatus(DeadLetterStatusEnum.IGNORED.getStatus());
+ updateObj.setHandled(1);
+ updateObj.setHandleTime(LocalDateTime.now());
+ updateObj.setHandleRemark(remark);
+ deadLetterMapper.updateById(updateObj);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncEventServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncEventServiceImpl.java
new file mode 100644
index 00000000..355c5f77
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncEventServiceImpl.java
@@ -0,0 +1,115 @@
+package com.zt.plat.framework.databus.server.service.impl;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.event.DatabusSyncEventPageReqVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.event.DatabusSyncEventSaveReqVO;
+import com.zt.plat.framework.databus.server.convert.DatabusSyncEventConvert;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncEventDO;
+import com.zt.plat.framework.databus.server.dal.mapper.DatabusSyncEventMapper;
+import com.zt.plat.framework.databus.server.service.DatabusSyncEventService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.List;
+
+import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static com.zt.plat.framework.databus.server.enums.ErrorCodeConstants.*;
+
+/**
+ * 数据同步事件 Service 实现类
+ *
+ * @author ZT
+ */
+@Slf4j
+@Service
+@Validated
+public class DatabusSyncEventServiceImpl implements DatabusSyncEventService {
+
+ @Resource
+ private DatabusSyncEventMapper eventMapper;
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Long createEvent(DatabusSyncEventSaveReqVO createReqVO) {
+ // 校验事件类型唯一性
+ validateEventTypeUnique(null, createReqVO.getEventType());
+
+ // 插入
+ DatabusSyncEventDO event = DatabusSyncEventConvert.INSTANCE.convert(createReqVO);
+ eventMapper.insert(event);
+ return event.getId();
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void updateEvent(DatabusSyncEventSaveReqVO updateReqVO) {
+ // 校验存在
+ validateEventExists(updateReqVO.getId());
+ // 校验事件类型唯一性
+ validateEventTypeUnique(updateReqVO.getId(), updateReqVO.getEventType());
+
+ // 更新
+ DatabusSyncEventDO updateObj = DatabusSyncEventConvert.INSTANCE.convert(updateReqVO);
+ eventMapper.updateById(updateObj);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void deleteEvent(Long id) {
+ // 校验存在
+ validateEventExists(id);
+ // 删除
+ eventMapper.deleteById(id);
+ }
+
+ private void validateEventExists(Long id) {
+ if (eventMapper.selectById(id) == null) {
+ throw exception(EVENT_NOT_EXISTS);
+ }
+ }
+
+ private void validateEventTypeUnique(Long id, String eventType) {
+ DatabusSyncEventDO event = eventMapper.selectByEventType(eventType);
+ if (event == null) {
+ return;
+ }
+ // 如果 id 为空,说明不用比较是否为相同 id 的事件
+ if (id == null) {
+ throw exception(EVENT_TYPE_DUPLICATE);
+ }
+ if (!event.getId().equals(id)) {
+ throw exception(EVENT_TYPE_DUPLICATE);
+ }
+ }
+
+ @Override
+ public DatabusSyncEventDO getEvent(Long id) {
+ return eventMapper.selectById(id);
+ }
+
+ @Override
+ public PageResult getEventPage(DatabusSyncEventPageReqVO pageReqVO) {
+ return eventMapper.selectPage(pageReqVO);
+ }
+
+ @Override
+ public List getEventList() {
+ return eventMapper.selectList();
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void updateEventStatus(Long id, Integer enabled) {
+ // 校验存在
+ validateEventExists(id);
+ // 更新状态
+ DatabusSyncEventDO updateObj = new DatabusSyncEventDO();
+ updateObj.setId(id);
+ updateObj.setEnabled(enabled);
+ eventMapper.updateById(updateObj);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncLogServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncLogServiceImpl.java
new file mode 100644
index 00000000..64910c9a
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncLogServiceImpl.java
@@ -0,0 +1,50 @@
+package com.zt.plat.framework.databus.server.service.impl;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.pushlog.DatabusSyncPushLogPageReqVO;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncLogDO;
+import com.zt.plat.framework.databus.server.dal.mapper.DatabusSyncLogMapper;
+import com.zt.plat.framework.databus.server.service.DatabusSyncLogService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static com.zt.plat.framework.databus.server.enums.ErrorCodeConstants.PUSH_LOG_NOT_EXISTS;
+
+/**
+ * 数据同步推送日志 Service 实现类
+ *
+ * @author ZT
+ */
+@Slf4j
+@Service
+@Validated
+public class DatabusSyncLogServiceImpl implements DatabusSyncLogService {
+
+ @Resource
+ private DatabusSyncLogMapper pushLogMapper;
+
+ @Override
+ public DatabusSyncLogDO getPushLog(Long id) {
+ return pushLogMapper.selectById(id);
+ }
+
+ @Override
+ public PageResult getPushLogPage(DatabusSyncPushLogPageReqVO pageReqVO) {
+ return pushLogMapper.selectPage(pageReqVO);
+ }
+
+ @Override
+ public void retryPush(Long id) {
+ // 校验存在
+ DatabusSyncLogDO pushLog = pushLogMapper.selectById(id);
+ if (pushLog == null) {
+ throw exception(PUSH_LOG_NOT_EXISTS);
+ }
+ // TODO: 实现重试逻辑,将日志重新入队或触发推送
+ log.info("[retryPush] 重试推送,日志ID: {}, 同步ID: {}", id, pushLog.getSyncId());
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncSubscriptionServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncSubscriptionServiceImpl.java
new file mode 100644
index 00000000..20952417
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/service/impl/DatabusSyncSubscriptionServiceImpl.java
@@ -0,0 +1,129 @@
+package com.zt.plat.framework.databus.server.service.impl;
+
+import com.zt.plat.framework.common.pojo.PageResult;
+import com.zt.plat.framework.databus.server.controller.admin.vo.subscription.DatabusSyncSubscriptionPageReqVO;
+import com.zt.plat.framework.databus.server.controller.admin.vo.subscription.DatabusSyncSubscriptionSaveReqVO;
+import com.zt.plat.framework.databus.server.convert.DatabusSyncSubscriptionConvert;
+import com.zt.plat.framework.databus.server.dal.dataobject.DatabusSyncSubscriptionDO;
+import com.zt.plat.framework.databus.server.dal.mapper.DatabusSyncSubscriptionMapper;
+import com.zt.plat.framework.databus.server.service.DatabusSyncSubscriptionService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static com.zt.plat.framework.databus.server.enums.ErrorCodeConstants.*;
+
+/**
+ * 数据同步订阅 Service 实现类
+ *
+ * @author ZT
+ */
+@Slf4j
+@Service
+@Validated
+public class DatabusSyncSubscriptionServiceImpl implements DatabusSyncSubscriptionService {
+
+ @Resource
+ private DatabusSyncSubscriptionMapper subscriptionMapper;
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Long createSubscription(DatabusSyncSubscriptionSaveReqVO createReqVO) {
+ // 校验订阅唯一性(同一个客户端不能重复订阅同一个事件)
+ validateSubscriptionUnique(null, createReqVO.getClientId(), createReqVO.getEventId());
+
+ // 插入
+ DatabusSyncSubscriptionDO subscription = DatabusSyncSubscriptionConvert.INSTANCE.convert(createReqVO);
+ subscriptionMapper.insert(subscription);
+ return subscription.getId();
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void updateSubscription(DatabusSyncSubscriptionSaveReqVO updateReqVO) {
+ // 校验存在
+ validateSubscriptionExists(updateReqVO.getId());
+ // 校验订阅唯一性
+ validateSubscriptionUnique(updateReqVO.getId(), updateReqVO.getClientId(), updateReqVO.getEventId());
+
+ // 更新
+ DatabusSyncSubscriptionDO updateObj = DatabusSyncSubscriptionConvert.INSTANCE.convert(updateReqVO);
+ subscriptionMapper.updateById(updateObj);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void deleteSubscription(Long id) {
+ // 校验存在
+ validateSubscriptionExists(id);
+ // 删除
+ subscriptionMapper.deleteById(id);
+ }
+
+ private void validateSubscriptionExists(Long id) {
+ if (subscriptionMapper.selectById(id) == null) {
+ throw exception(SUBSCRIPTION_NOT_EXISTS);
+ }
+ }
+
+ private void validateSubscriptionUnique(Long id, Long clientId, Long eventId) {
+ DatabusSyncSubscriptionDO subscription = subscriptionMapper.selectByClientIdAndEventId(clientId, eventId);
+ if (subscription == null) {
+ return;
+ }
+ // 如果 id 为空,说明不用比较是否为相同 id 的订阅
+ if (id == null) {
+ throw exception(SUBSCRIPTION_DUPLICATE);
+ }
+ if (!subscription.getId().equals(id)) {
+ throw exception(SUBSCRIPTION_DUPLICATE);
+ }
+ }
+
+ @Override
+ public DatabusSyncSubscriptionDO getSubscription(Long id) {
+ return subscriptionMapper.selectById(id);
+ }
+
+ @Override
+ public PageResult getSubscriptionPage(DatabusSyncSubscriptionPageReqVO pageReqVO) {
+ return subscriptionMapper.selectPage(pageReqVO);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void updateSubscriptionStatus(Long id, Integer enabled) {
+ // 校验存在
+ validateSubscriptionExists(id);
+ // 更新状态
+ DatabusSyncSubscriptionDO updateObj = new DatabusSyncSubscriptionDO();
+ updateObj.setId(id);
+ updateObj.setEnabled(enabled);
+ subscriptionMapper.updateById(updateObj);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void resetCheckpoint(Long id) {
+ // 校验存在
+ validateSubscriptionExists(id);
+ // 重置断点
+ DatabusSyncSubscriptionDO updateObj = new DatabusSyncSubscriptionDO();
+ updateObj.setId(id);
+ updateObj.setLastSyncEventId(null);
+ updateObj.setLastSyncTime(null);
+ subscriptionMapper.updateById(updateObj);
+ }
+
+ @Override
+ public void triggerSync(Long id) {
+ // 校验存在
+ validateSubscriptionExists(id);
+ // TODO: 发送消息到 MQ 或调用异步任务触发同步
+ log.info("[triggerSync] 手动触发同步,订阅ID: {}", id);
+ }
+
+}
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/resources/META-INF/spring.factories b/zt-framework/zt-spring-boot-starter-databus-server/src/main/resources/META-INF/spring.factories
new file mode 100644
index 00000000..0a736d5e
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+ com.zt.plat.framework.databus.server.config.DatabusSyncServerAutoConfiguration
diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/zt-framework/zt-spring-boot-starter-databus-server/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 00000000..46075a66
--- /dev/null
+++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1,2 @@
+com.zt.plat.framework.databus.server.config.DatabusServerAutoConfiguration
+com.zt.plat.framework.databus.server.config.DatabusSyncServerAutoConfiguration
diff --git a/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/message/DatabusBatchMessage.java b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/message/DatabusBatchMessage.java
new file mode 100644
index 00000000..3047ac10
--- /dev/null
+++ b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/message/DatabusBatchMessage.java
@@ -0,0 +1,106 @@
+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 全量同步批量消息
+ *
+ * 用于全量同步场景,支持分批传输
+ *
+ * @author ZT
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DatabusBatchMessage 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;
+
+ /**
+ * 数据列��
+ */
+ private List dataList;
+
+ /**
+ * 消息产生时间
+ */
+ private LocalDateTime timestamp;
+
+ /**
+ * 来源系统
+ */
+ private String source;
+
+ /**
+ * 租户ID
+ */
+ private Long tenantId;
+
+ /**
+ * 创建批量消息
+ */
+ public static DatabusBatchMessage of(DatabusEventType eventType, String taskId,
+ int batchNo, int totalBatch,
+ List dataList, int totalCount) {
+ DatabusBatchMessage 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;
+ }
+
+}
diff --git a/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/message/DatabusMessage.java b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/message/DatabusMessage.java
new file mode 100644
index 00000000..ccf5e4a0
--- /dev/null
+++ b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/message/DatabusMessage.java
@@ -0,0 +1,73 @@
+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 增量同步消息
+ *
+ * 业务推送、服务端消费、服务端转发、客户端消费统一使用此消息体
+ *
+ * @author ZT
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DatabusMessage 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 DatabusMessage of(DatabusEventType eventType, Long dataId, T data) {
+ DatabusMessage 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;
+ }
+
+}
diff --git a/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/enums/DatabusEventType.java b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/enums/DatabusEventType.java
new file mode 100644
index 00000000..da726cd3
--- /dev/null
+++ b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/enums/DatabusEventType.java
@@ -0,0 +1,306 @@
+package com.zt.plat.module.databus.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * Databus 事件类型枚举
+ *
+ * 三级结构: 模块_数据类型_操作
+ *
+ * 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_DEPT_CREATE("system", "dept", "create", "部门创建"),
+
+ /**
+ * 部门-更新
+ */
+ SYSTEM_DEPT_UPDATE("system", "dept", "update", "部门更新"),
+
+ /**
+ * 部门-删除
+ */
+ SYSTEM_DEPT_DELETE("system", "dept", "delete", "部门删除"),
+
+ /**
+ * 部门-全量同步
+ */
+ SYSTEM_DEPT_FULL("system", "dept", "full", "部门全量同步"),
+
+ /**
+ * 组织机构-创建(兼容老代码,保留但不推荐使用)
+ */
+ @Deprecated
+ SYSTEM_ORG_CREATE("system", "org", "create", "组织机构创建"),
+
+ /**
+ * 组织机构-更新(兼容老代码,保留但不推荐使用)
+ */
+ @Deprecated
+ SYSTEM_ORG_UPDATE("system", "org", "update", "组织机构更新"),
+
+ /**
+ * 组织机构-删除(兼容老代码,保留但不推荐使用)
+ */
+ @Deprecated
+ SYSTEM_ORG_DELETE("system", "org", "delete", "组织机构删除"),
+
+ /**
+ * 组织机构-全量同步(兼容老代码,保留但不推荐使用)
+ */
+ @Deprecated
+ SYSTEM_ORG_FULL("system", "org", "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_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名称(服务端转发用)
+ * 格式: {topicBase}-{module}-{entity}-{action}-{clientCode}
+ */
+ public String getTopic(String topicBase, String clientCode) {
+ return String.format("%s-%s-%s-%s-%s", topicBase, module, entity, action, 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;
+ }
+
+ /**
+ * 判断是否为全量同步事件
+ */
+ public boolean isFullSync() {
+ return "full".equalsIgnoreCase(this.action);
+ }
+
+ /**
+ * 判断是否为增量同步事件
+ */
+ public boolean isIncrementalSync() {
+ return !isFullSync();
+ }
+
+}
diff --git a/zt-module-databus/zt-module-databus-server/pom.xml b/zt-module-databus/zt-module-databus-server/pom.xml
index 008a387f..e94168ad 100644
--- a/zt-module-databus/zt-module-databus-server/pom.xml
+++ b/zt-module-databus/zt-module-databus-server/pom.xml
@@ -42,6 +42,13 @@
${revision}
+
+
+ com.zt.plat
+ zt-spring-boot-starter-databus-server
+ ${revision}
+
+
com.zt.plat
diff --git a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/mq/consumer/DatabusDeptChangeConsumer.java b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/mq/consumer/DatabusDeptChangeConsumer.java
new file mode 100644
index 00000000..e3794b25
--- /dev/null
+++ b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/mq/consumer/DatabusDeptChangeConsumer.java
@@ -0,0 +1,90 @@
+package com.zt.plat.module.databus.mq.consumer;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.zt.plat.framework.databus.server.core.event.DatabusEvent;
+import com.zt.plat.framework.databus.server.core.sync.DatabusIncrementalSyncService;
+import com.zt.plat.module.system.api.mq.DatabusDeptChangeMessage;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Databus 部门变更消息消费者
+ *
+ * 消费来自 system-server 的部门变更消息,通过增量同步服务进行:
+ * 1. 三态判断(事件/客户端/订阅是否启用)
+ * 2. 记录到 event_record 流水表
+ * 3. 推送到客户端专属 Topic(databus-sync-{clientCode})
+ *
+ * @author ZT
+ */
+@Slf4j
+@Component
+@RocketMQMessageListener(
+ topic = DatabusDeptChangeMessage.TOPIC,
+ consumerGroup = DatabusDeptChangeMessage.TOPIC + "_CONSUMER"
+)
+public class DatabusDeptChangeConsumer implements RocketMQListener {
+
+ private static final String SOURCE_SERVICE = "system-server";
+
+ @Resource
+ private DatabusIncrementalSyncService databusIncrementalSyncService;
+
+ @Resource
+ private ObjectMapper objectMapper;
+
+ @Override
+ public void onMessage(DatabusDeptChangeMessage message) {
+ log.info("[Databus] 收到部门变更消息, action={}, deptId={}", message.getAction(), message.getDeptId());
+
+ try {
+ // 构建完整的业务数据快照
+ Map dataMap = new HashMap<>();
+ dataMap.put("id", message.getDeptId());
+ dataMap.put("code", message.getDeptCode());
+ dataMap.put("name", message.getDeptName());
+ dataMap.put("shortName", message.getShortName());
+ dataMap.put("parentId", message.getParentId());
+ dataMap.put("sort", message.getSort());
+ dataMap.put("leaderUserId", message.getLeaderUserId());
+ dataMap.put("phone", message.getPhone());
+ dataMap.put("email", message.getStatus());
+ dataMap.put("isCompany", message.getIsCompany());
+ dataMap.put("isGroup", message.getIsGroup());
+ dataMap.put("deptSource", message.getDeptSource());
+ dataMap.put("tenantId", message.getTenantId());
+ dataMap.put("eventTime", message.getEventTime());
+
+ // 构建完整的事件类型: system-dept-{action}
+ String eventType = String.format("system-dept-%s", message.getAction().toLowerCase());
+
+ // 构建 Databus 事件
+ DatabusEvent databusEvent = DatabusEvent.builder()
+ .eventType(eventType)
+ .eventAction(message.getAction())
+ .dataSnapshot(objectMapper.writeValueAsString(dataMap))
+ .dataVersion(1)
+ .sourceService(SOURCE_SERVICE)
+ .sourceTopic(DatabusDeptChangeMessage.TOPIC)
+ .tenantId(message.getTenantId())
+ .eventTime(message.getEventTime())
+ .build();
+
+ // 调用增量同步服务处理(三态判断 + 记录流水 + 推送客户端Topic)
+ databusIncrementalSyncService.processEvent(databusEvent);
+
+ log.info("[Databus] 部门变更事件处理完成, eventType={}, deptId={}",
+ eventType, message.getDeptId());
+ } catch (Exception e) {
+ log.error("[Databus] 处理部门变更消息失败, action={}, deptId={}",
+ message.getAction(), message.getDeptId(), e);
+ throw new RuntimeException("处理部门变更消息失败", e);
+ }
+ }
+}
diff --git a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/mq/consumer/DatabusPostChangeConsumer.java b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/mq/consumer/DatabusPostChangeConsumer.java
new file mode 100644
index 00000000..c51bd5e3
--- /dev/null
+++ b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/mq/consumer/DatabusPostChangeConsumer.java
@@ -0,0 +1,73 @@
+package com.zt.plat.module.databus.mq.consumer;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.zt.plat.framework.databus.server.core.event.DatabusEvent;
+import com.zt.plat.framework.databus.server.core.sync.DatabusIncrementalSyncService;
+import com.zt.plat.module.system.api.mq.DatabusPostChangeMessage;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Databus 岗位变更消息消费者
+ */
+@Slf4j
+@Component
+@RocketMQMessageListener(
+ topic = DatabusPostChangeMessage.TOPIC,
+ consumerGroup = DatabusPostChangeMessage.TOPIC + "_CONSUMER"
+)
+public class DatabusPostChangeConsumer implements RocketMQListener {
+
+ private static final String SOURCE_SERVICE = "system-server";
+
+ @Resource
+ private DatabusIncrementalSyncService databusIncrementalSyncService;
+
+ @Resource
+ private ObjectMapper objectMapper;
+
+ @Override
+ public void onMessage(DatabusPostChangeMessage message) {
+ log.info("[Databus] 收到岗位变更消息, action={}, postId={}", message.getAction(), message.getPostId());
+
+ try {
+ Map dataMap = new HashMap<>();
+ dataMap.put("id", message.getPostId());
+ dataMap.put("code", message.getPostCode());
+ dataMap.put("name", message.getPostName());
+ dataMap.put("sort", message.getSort());
+ dataMap.put("status", message.getStatus());
+ dataMap.put("remark", message.getRemark());
+ dataMap.put("tenantId", message.getTenantId());
+ dataMap.put("eventTime", message.getEventTime());
+
+ String eventType = String.format("system-post-%s", message.getAction().toLowerCase());
+
+ DatabusEvent databusEvent = DatabusEvent.builder()
+ .eventType(eventType)
+ .eventAction(message.getAction())
+ .dataSnapshot(objectMapper.writeValueAsString(dataMap))
+ .dataVersion(1)
+ .sourceService(SOURCE_SERVICE)
+ .sourceTopic(DatabusPostChangeMessage.TOPIC)
+ .tenantId(message.getTenantId())
+ .eventTime(message.getEventTime())
+ .build();
+
+ databusIncrementalSyncService.processEvent(databusEvent);
+
+ log.info("[Databus] 岗位变更事件处理完成, eventType={}, postId={}",
+ eventType, message.getPostId());
+ } catch (Exception e) {
+ log.error("[Databus] 处理岗位变更消息失败, action={}, postId={}",
+ message.getAction(), message.getPostId(), e);
+ throw new RuntimeException("处理岗位变更消息失败", e);
+ }
+ }
+}
diff --git a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/mq/consumer/DatabusUserChangeConsumer.java b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/mq/consumer/DatabusUserChangeConsumer.java
new file mode 100644
index 00000000..f7af1838
--- /dev/null
+++ b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/mq/consumer/DatabusUserChangeConsumer.java
@@ -0,0 +1,79 @@
+package com.zt.plat.module.databus.mq.consumer;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.zt.plat.framework.databus.server.core.event.DatabusEvent;
+import com.zt.plat.framework.databus.server.core.sync.DatabusIncrementalSyncService;
+import com.zt.plat.module.system.api.mq.DatabusUserChangeMessage;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Databus 用户变更消息消费者
+ */
+@Slf4j
+@Component
+@RocketMQMessageListener(
+ topic = DatabusUserChangeMessage.TOPIC,
+ consumerGroup = DatabusUserChangeMessage.TOPIC + "_CONSUMER"
+)
+public class DatabusUserChangeConsumer implements RocketMQListener {
+
+ private static final String SOURCE_SERVICE = "system-server";
+
+ @Resource
+ private DatabusIncrementalSyncService databusIncrementalSyncService;
+
+ @Resource
+ private ObjectMapper objectMapper;
+
+ @Override
+ public void onMessage(DatabusUserChangeMessage message) {
+ log.info("[Databus] 收到用户变更消息, action={}, userId={}", message.getAction(), message.getUserId());
+
+ try {
+ Map dataMap = new HashMap<>();
+ dataMap.put("id", message.getUserId());
+ dataMap.put("username", message.getUsername());
+ dataMap.put("nickname", message.getNickname());
+ dataMap.put("remark", message.getRemark());
+ dataMap.put("deptIds", message.getDeptIds());
+ dataMap.put("postIds", message.getPostIds());
+ dataMap.put("email", message.getEmail());
+ dataMap.put("mobile", message.getMobile());
+ dataMap.put("sex", message.getSex());
+ dataMap.put("avatar", message.getAvatar());
+ dataMap.put("status", message.getStatus());
+ dataMap.put("userSource", message.getUserSource());
+ dataMap.put("tenantId", message.getTenantId());
+ dataMap.put("eventTime", message.getEventTime());
+
+ String eventType = String.format("system-user-%s", message.getAction().toLowerCase());
+
+ DatabusEvent databusEvent = DatabusEvent.builder()
+ .eventType(eventType)
+ .eventAction(message.getAction())
+ .dataSnapshot(objectMapper.writeValueAsString(dataMap))
+ .dataVersion(1)
+ .sourceService(SOURCE_SERVICE)
+ .sourceTopic(DatabusUserChangeMessage.TOPIC)
+ .tenantId(message.getTenantId())
+ .eventTime(message.getEventTime())
+ .build();
+
+ databusIncrementalSyncService.processEvent(databusEvent);
+
+ log.info("[Databus] 用户变更事件处理完成, eventType={}, userId={}",
+ eventType, message.getUserId());
+ } catch (Exception e) {
+ log.error("[Databus] 处理用户变更消息失败, action={}, userId={}",
+ message.getAction(), message.getUserId(), e);
+ throw new RuntimeException("处理用户变更消息失败", e);
+ }
+ }
+}
diff --git a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/provider/DeptDataFeignProvider.java b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/provider/DeptDataFeignProvider.java
new file mode 100644
index 00000000..1423be81
--- /dev/null
+++ b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/provider/DeptDataFeignProvider.java
@@ -0,0 +1,85 @@
+package com.zt.plat.module.databus.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.DatabusDeptData;
+import com.zt.plat.module.databus.api.provider.DatabusDeptProviderApi;
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+
+/**
+ * 部门数据提供者
+ *
+ * 通过 Feign 调用 system-server 获取部门数据
+ *
+ * @author ZT
+ */
+@Slf4j
+@Component
+public class DeptDataFeignProvider implements DataProvider {
+
+ public static final String PROVIDER_TYPE = "DEPT";
+
+ @Resource
+ private DatabusDeptProviderApi deptProviderApi;
+
+ @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 = deptProviderApi.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 = deptProviderApi.count(tenantId);
+ if (!result.isSuccess()) {
+ throw new RuntimeException("获取部门总数失败: " + result.getMsg());
+ }
+ return result.getData();
+ }
+
+ @Override
+ public Long extractUid(DatabusDeptData data) {
+ return data.getId();
+ }
+}
diff --git a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/provider/PostDataFeignProvider.java b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/provider/PostDataFeignProvider.java
new file mode 100644
index 00000000..cfb4d8e3
--- /dev/null
+++ b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/provider/PostDataFeignProvider.java
@@ -0,0 +1,81 @@
+package com.zt.plat.module.databus.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.DatabusPostData;
+import com.zt.plat.module.databus.api.provider.DatabusPostProviderApi;
+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 PostDataFeignProvider implements DataProvider {
+
+ public static final String PROVIDER_TYPE = "POST";
+
+ @Resource
+ private DatabusPostProviderApi postProviderApi;
+
+ @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 = postProviderApi.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 = postProviderApi.count(tenantId);
+ if (!result.isSuccess()) {
+ throw new RuntimeException("获取岗位总数失败: " + result.getMsg());
+ }
+ return result.getData();
+ }
+
+ @Override
+ public Long extractUid(DatabusPostData data) {
+ return data.getId();
+ }
+}
diff --git a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/provider/UserDataFeignProvider.java b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/provider/UserDataFeignProvider.java
new file mode 100644
index 00000000..b2c162e3
--- /dev/null
+++ b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/provider/UserDataFeignProvider.java
@@ -0,0 +1,81 @@
+package com.zt.plat.module.databus.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.DatabusAdminUserData;
+import com.zt.plat.module.databus.api.provider.DatabusUserProviderApi;
+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 UserDataFeignProvider implements DataProvider {
+
+ public static final String PROVIDER_TYPE = "USER";
+
+ @Resource
+ private DatabusUserProviderApi userProviderApi;
+
+ @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 = userProviderApi.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 = userProviderApi.count(tenantId);
+ if (!result.isSuccess()) {
+ throw new RuntimeException("获取用户总数失败: " + result.getMsg());
+ }
+ return result.getData();
+ }
+
+ @Override
+ public Long extractUid(DatabusAdminUserData data) {
+ return data.getId();
+ }
+}