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:
hewencai
2025-12-03 11:10:57 +08:00
parent adf3ec601a
commit 6ac4a356cd
37 changed files with 659 additions and 41 deletions

View File

@@ -235,7 +235,7 @@
<env.name>dev</env.name> <env.name>dev</env.name>
<!--Nacos 配置--> <!--Nacos 配置-->
<config.server-addr>172.16.46.63:30848</config.server-addr> <config.server-addr>172.16.46.63:30848</config.server-addr>
<config.namespace>dev</config.namespace> <config.namespace>hwc</config.namespace>
<config.group>DEFAULT_GROUP</config.group> <config.group>DEFAULT_GROUP</config.group>
<config.username>nacos</config.username> <config.username>nacos</config.username>
<config.password>P@ssword25</config.password> <config.password>P@ssword25</config.password>

View File

@@ -17,7 +17,8 @@
<module>zt-spring-boot-starter-web</module> <module>zt-spring-boot-starter-web</module>
<module>zt-spring-boot-starter-security</module> <module>zt-spring-boot-starter-security</module>
<module>zt-spring-boot-starter-websocket</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-monitor</module>
<module>zt-spring-boot-starter-protection</module> <module>zt-spring-boot-starter-protection</module>
<!-- <module>zt-spring-boot-starter-config</module>--> <!-- <module>zt-spring-boot-starter-config</module>-->

View File

@@ -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.api.message.DatabusBatchMessage;
import com.zt.plat.module.databus.enums.DatabusEventType; import com.zt.plat.module.databus.enums.DatabusEventType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/** /**
* 批量同步事件处理器接口 * 批量同步事件处理器接口
* <p> * <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;
}
} }

View File

@@ -27,6 +27,13 @@
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- System API (for consuming change messages) -->
<dependency>
<groupId>com.zt.plat</groupId>
<artifactId>zt-module-system-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency> <dependency>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>

View File

@@ -1,4 +1,4 @@
package com.zt.plat.module.databus.mq.consumer; package com.zt.plat.framework.databus.server.consumer;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.zt.plat.framework.databus.server.core.event.DatabusEvent; import com.zt.plat.framework.databus.server.core.event.DatabusEvent;
@@ -61,8 +61,8 @@ public class DatabusDeptChangeConsumer implements RocketMQListener<DatabusDeptCh
dataMap.put("tenantId", message.getTenantId()); dataMap.put("tenantId", message.getTenantId());
dataMap.put("eventTime", message.getEventTime()); dataMap.put("eventTime", message.getEventTime());
// 构建完整的事件类型: system-dept-{action} // 构建完整的事件类型: SYSTEM_DEPT_{ACTION}大写下划线格式与数据库存储一致
String eventType = String.format("system-dept-%s", message.getAction().toLowerCase()); String eventType = String.format("SYSTEM_DEPT_%s", message.getAction().toUpperCase());
// 构建 Databus 事件 // 构建 Databus 事件
DatabusEvent databusEvent = DatabusEvent.builder() DatabusEvent databusEvent = DatabusEvent.builder()

View File

@@ -1,4 +1,4 @@
package com.zt.plat.module.databus.mq.consumer; package com.zt.plat.framework.databus.server.consumer;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.zt.plat.framework.databus.server.core.event.DatabusEvent; import com.zt.plat.framework.databus.server.core.event.DatabusEvent;
@@ -47,7 +47,8 @@ public class DatabusPostChangeConsumer implements RocketMQListener<DatabusPostCh
dataMap.put("tenantId", message.getTenantId()); dataMap.put("tenantId", message.getTenantId());
dataMap.put("eventTime", message.getEventTime()); dataMap.put("eventTime", message.getEventTime());
String eventType = String.format("system-post-%s", message.getAction().toLowerCase()); // 构建完整的事件类型: SYSTEM_POST_{ACTION}大写下划线格式与数据库存储一致
String eventType = String.format("SYSTEM_POST_%s", message.getAction().toUpperCase());
DatabusEvent databusEvent = DatabusEvent.builder() DatabusEvent databusEvent = DatabusEvent.builder()
.eventType(eventType) .eventType(eventType)

View File

@@ -1,4 +1,4 @@
package com.zt.plat.module.databus.mq.consumer; package com.zt.plat.framework.databus.server.consumer;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.zt.plat.framework.databus.server.core.event.DatabusEvent; import com.zt.plat.framework.databus.server.core.event.DatabusEvent;
@@ -53,7 +53,8 @@ public class DatabusUserChangeConsumer implements RocketMQListener<DatabusUserCh
dataMap.put("tenantId", message.getTenantId()); dataMap.put("tenantId", message.getTenantId());
dataMap.put("eventTime", message.getEventTime()); dataMap.put("eventTime", message.getEventTime());
String eventType = String.format("system-user-%s", message.getAction().toLowerCase()); // 构建完整的事件类型: SYSTEM_USER_{ACTION}大写下划线格式与数据库存储一致
String eventType = String.format("SYSTEM_USER_%s", message.getAction().toUpperCase());
DatabusEvent databusEvent = DatabusEvent.builder() DatabusEvent databusEvent = DatabusEvent.builder()
.eventType(eventType) .eventType(eventType)

View File

@@ -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.CommonResult;
import com.zt.plat.framework.common.pojo.PageResult; 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.DatabusSyncClientPageReqVO;
import com.zt.plat.framework.databus.server.controller.admin.vo.client.DatabusSyncClientRespVO; 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.controller.admin.vo.client.DatabusSyncClientSaveReqVO;
@@ -89,4 +90,12 @@ public class DatabusSyncClientController {
return success(true); 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);
}
} }

View File

@@ -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.CommonResult;
import com.zt.plat.framework.common.pojo.PageResult; 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.DatabusSyncEventPageReqVO;
import com.zt.plat.framework.databus.server.controller.admin.vo.event.DatabusSyncEventRespVO; 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.controller.admin.vo.event.DatabusSyncEventSaveReqVO;
@@ -89,4 +90,12 @@ public class DatabusSyncEventController {
return success(true); 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);
}
} }

Some files were not shown because too many files have changed in this diff Show More