fix(databus): 修复客户端消息处理和防止消息循环
1. 修复消息格式不匹配问题 - 增量消息:兼容 SyncMessage 格式,从 dataSnapshot 字段反序列化数据 - 批量消息:添加 getDataType() 方法获取泛型类型,正确转换 JSONObject 2. 防止消息循环 - 添加 zt.databus.change.producer.enabled 配置项 - 客户端禁用变更消息发送,避免 客户端写入 → 发送变更 → 循环 3. 修复 Feign 客户端注入 - 在 RpcConfiguration 中添加 DeptApi、PostApi - 确保客户端能通过 Feign 调用本地 system-server API 相关文件: - DatabusClientConsumer.java: 修复消息解析逻辑 - BatchSyncEventHandler.java: 添加 getDataType() 方法 - DatabusChangeProducer.java: 添加 enabled 开关 - RpcConfiguration.java: 启用 DeptApi/PostApi Feign 客户端 Ref: 修复 ClassCastException 和消息循环问题
This commit is contained in:
@@ -17,7 +17,8 @@
|
||||
<module>zt-spring-boot-starter-web</module>
|
||||
<module>zt-spring-boot-starter-security</module>
|
||||
<module>zt-spring-boot-starter-websocket</module>
|
||||
|
||||
<module>zt-spring-boot-starter-databus-server</module>
|
||||
<module>zt-spring-boot-starter-databus-client</module>
|
||||
<module>zt-spring-boot-starter-monitor</module>
|
||||
<module>zt-spring-boot-starter-protection</module>
|
||||
<!-- <module>zt-spring-boot-starter-config</module>-->
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,9 @@ 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;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* 批量同步事件处理器接口
|
||||
* <p>
|
||||
@@ -48,4 +51,29 @@ public interface BatchSyncEventHandler<T> {
|
||||
// 默认空实现,子类可覆盖
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据类型
|
||||
* <p>
|
||||
* 默认通过反射获取泛型类型参数,子类可以覆盖此方法提供具体类型
|
||||
*
|
||||
* @return 数据类型的 Class 对象
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
default Class<T> getDataType() {
|
||||
Type[] genericInterfaces = this.getClass().getGenericInterfaces();
|
||||
for (Type genericInterface : genericInterfaces) {
|
||||
if (genericInterface instanceof ParameterizedType) {
|
||||
ParameterizedType parameterizedType = (ParameterizedType) genericInterface;
|
||||
if (parameterizedType.getRawType().equals(BatchSyncEventHandler.class)) {
|
||||
Type[] typeArguments = parameterizedType.getActualTypeArguments();
|
||||
if (typeArguments.length > 0 && typeArguments[0] instanceof Class) {
|
||||
return (Class<T>) typeArguments[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果无法获取泛型类型,返回 Object.class
|
||||
return (Class<T>) Object.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,6 +27,13 @@
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- System API (for consuming change messages) -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-module-system-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.zt.plat.framework.databus.server.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 部门变更消息消费者
|
||||
* <p>
|
||||
* 消费来自 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<DatabusDeptChangeMessage> {
|
||||
|
||||
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<String, Object> 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().toUpperCase());
|
||||
|
||||
// 构建 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.zt.plat.framework.databus.server.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<DatabusPostChangeMessage> {
|
||||
|
||||
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<String, Object> 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());
|
||||
|
||||
// 构建完整的事件类型: SYSTEM_POST_{ACTION}(大写下划线格式,与数据库存储一致)
|
||||
String eventType = String.format("SYSTEM_POST_%s", message.getAction().toUpperCase());
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.zt.plat.framework.databus.server.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<DatabusUserChangeMessage> {
|
||||
|
||||
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<String, Object> 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());
|
||||
|
||||
// 构建完整的事件类型: SYSTEM_USER_{ACTION}(大写下划线格式,与数据库存储一致)
|
||||
String eventType = String.format("SYSTEM_USER_%s", message.getAction().toUpperCase());
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ 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.DatabusSyncClientBatchStatusReqVO;
|
||||
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;
|
||||
@@ -89,4 +90,12 @@ public class DatabusSyncClientController {
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/batch-status")
|
||||
@Operation(summary = "批量修改客户端启用状态")
|
||||
@PreAuthorize("@ss.hasPermission('databus:sync:client:update')")
|
||||
public CommonResult<Boolean> batchUpdateClientStatus(@Valid @RequestBody DatabusSyncClientBatchStatusReqVO reqVO) {
|
||||
clientService.batchUpdateClientStatus(reqVO.getIds(), reqVO.getEnabled());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ 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.DatabusSyncEventBatchStatusReqVO;
|
||||
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;
|
||||
@@ -89,4 +90,12 @@ public class DatabusSyncEventController {
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/batch-status")
|
||||
@Operation(summary = "批量修改事件启用状态")
|
||||
@PreAuthorize("@ss.hasPermission('databus:sync:event:update')")
|
||||
public CommonResult<Boolean> batchUpdateEventStatus(@Valid @RequestBody DatabusSyncEventBatchStatusReqVO reqVO) {
|
||||
eventService.batchUpdateEventStatus(reqVO.getIds(), reqVO.getEnabled());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.zt.plat.framework.databus.server.controller.admin;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.databus.server.controller.admin.vo.statistics.DatabusSyncStatisticsRespVO;
|
||||
import com.zt.plat.framework.databus.server.service.DatabusSyncStatisticsService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* DataBus 同步统计 Controller
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@Tag(name = "管理后台 - DataBus 同步统计")
|
||||
@RestController
|
||||
@RequestMapping("/databus/sync")
|
||||
@Validated
|
||||
public class DatabusSyncStatisticsController {
|
||||
|
||||
@Resource
|
||||
private DatabusSyncStatisticsService statisticsService;
|
||||
|
||||
@GetMapping("/statistics")
|
||||
@Operation(summary = "获取同步统计数据")
|
||||
@PreAuthorize("@ss.hasPermission('databus:sync:query')")
|
||||
public CommonResult<DatabusSyncStatisticsRespVO> getStatistics() {
|
||||
DatabusSyncStatisticsRespVO statistics = statisticsService.getStatistics();
|
||||
return success(statistics);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user