集成必要性功能

This commit is contained in:
2026-03-12 16:25:24 +08:00
parent 5708f80091
commit f0649cb888
201 changed files with 303 additions and 19897 deletions

View File

@@ -1,4 +0,0 @@
/**
* 针对 infra 模块的 api 包
*/
package com.njcn.rdms.framework.common.biz.infra;

View File

@@ -1,6 +1,6 @@
package com.njcn.rdms.framework.common.biz.infra.logger;
package com.njcn.rdms.framework.common.biz.system.logger;
import com.njcn.rdms.framework.common.biz.infra.logger.dto.ApiAccessLogCreateReqDTO;
import com.njcn.rdms.framework.common.biz.system.logger.dto.ApiAccessLogCreateReqDTO;
import com.njcn.rdms.framework.common.enums.RpcConstants;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import io.swagger.v3.oas.annotations.Operation;
@@ -11,11 +11,11 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(name = RpcConstants.INFRA_NAME)
@FeignClient(name = RpcConstants.SYSTEM_NAME)
@Tag(name = "RPC 服务 - API 访问日志")
public interface ApiAccessLogCommonApi {
String PREFIX = RpcConstants.INFRA_PREFIX + "/api-access-log";
String PREFIX = RpcConstants.SYSTEM_PREFIX + "/api-access-log";
@PostMapping(PREFIX + "/create")
@Operation(summary = "创建 API 访问日志")

View File

@@ -1,6 +1,6 @@
package com.njcn.rdms.framework.common.biz.infra.logger;
package com.njcn.rdms.framework.common.biz.system.logger;
import com.njcn.rdms.framework.common.biz.infra.logger.dto.ApiErrorLogCreateReqDTO;
import com.njcn.rdms.framework.common.biz.system.logger.dto.ApiErrorLogCreateReqDTO;
import com.njcn.rdms.framework.common.enums.RpcConstants;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import io.swagger.v3.oas.annotations.Operation;
@@ -11,11 +11,11 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(name = RpcConstants.INFRA_NAME)
@FeignClient(name = RpcConstants.SYSTEM_NAME)
@Tag(name = "RPC 服务 - API 异常日志")
public interface ApiErrorLogCommonApi {
String PREFIX = RpcConstants.INFRA_PREFIX + "/api-error-log";
String PREFIX = RpcConstants.SYSTEM_PREFIX + "/api-error-log";
@PostMapping(PREFIX + "/create")
@Operation(summary = "创建 API 异常日志")

View File

@@ -1,4 +1,4 @@
package com.njcn.rdms.framework.common.biz.infra.logger.dto;
package com.njcn.rdms.framework.common.biz.system.logger.dto;
import jakarta.validation.constraints.NotNull;
import lombok.Data;

View File

@@ -1,4 +1,4 @@
package com.njcn.rdms.framework.common.biz.infra.logger.dto;
package com.njcn.rdms.framework.common.biz.system.logger.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;

View File

@@ -26,15 +26,5 @@ public interface RpcConstants {
*/
String SYSTEM_PREFIX = RPC_API_PREFIX + "/system";
/**
* infra 服务名
*
* 注意,需要保证和 spring.application.name 保持一致
*/
String INFRA_NAME = "rdms-infra-server";
/**
* infra 服务的前缀
*/
String INFRA_PREFIX = RPC_API_PREFIX + "/infra";
}

View File

@@ -1,4 +1,4 @@
# MQ 改造方案(评审稿)
# MQ 改造方案(评审稿)
## 1. 背景与目标
你当前的业务策略是:
@@ -26,16 +26,13 @@
当前 `rdms-spring-boot-starter-mq` 的真实情况:
1. Redis 能力最完整包含模板、监听器抽象、Stream 补偿与清理任务。
2. RabbitMQ 只有 `MessageConverter` 级别自动配置,未形成统一收发抽象。
3. RocketMQ、Kafka 在该 starter 中没有对应自动配置主链路,实际接入主要在 WebSocket 模块。
当前 `rdms-system` 默认配置:
1. `rdms.websocket.sender-type: local`,即默认并未走 MQ 分发链路。
## 3. 改造原则
1. 先配置统一,再接口统一,最后再清理非主路径。
2. 任何阶段都必须可回滚,且回滚只改配置不改代码。
3. 保持 Rabbit/Kafka 包路径存在,避免一次性大删导致历史分支合并困难。
4. 先让 WebSocket 场景打通可切换,再考虑扩展到业务 MQ。
## 4. 目标架构(落地后)
统一引入配置:
@@ -44,10 +41,8 @@
统一行为:
1. 单体环境配 `redis`
2. 微服务环境配 `rocketmq`
3. WebSocket `sender-type` 跟随 `rdms.mq.type`,避免双配置。
建议方式:
1. `rdms.websocket.sender-type: ${rdms.mq.type}`
## 4.1 配置矩阵(最小可运行)
@@ -56,8 +51,6 @@
rdms:
mq:
type: redis
websocket:
sender-type: ${rdms.mq.type}
spring:
data:
@@ -71,8 +64,6 @@ spring:
rdms:
mq:
type: rocketmq
websocket:
sender-type: ${rdms.mq.type}
rocketmq:
name-server: 127.0.0.1:9876
@@ -102,7 +93,6 @@ rocketmq:
实施项:
1. 新增配置项 `rdms.mq.type`,默认值 `redis`
2. 修改环境配置,使 `rdms.websocket.sender-type` 引用 `rdms.mq.type`
3. 本阶段不删除 Rabbit/Kafka 代码,不变更包结构。
收益:
@@ -110,7 +100,6 @@ rocketmq:
2. 不触碰核心业务逻辑,风险最低。
回滚:
1.`rdms.websocket.sender-type` 改回固定值即可。
## 阶段 B中风险接口统一
目标:抽象统一 MQ 发送接口,减少业务对具体中间件的耦合。
@@ -119,7 +108,6 @@ rocketmq:
1. 新增统一接口,例如 `UnifiedMqSender`
2. 提供 `RedisMqSender``RocketMqSender` 两个实现。
3.`@ConditionalOnProperty` 根据 `rdms.mq.type` 注入唯一实现。
4. 在 WebSocket 发送链路优先替换为统一接口调用。
5. 统一消息契约,至少包含标准消息头:
`msgId``bizKey``timestamp``producer``traceId``version`
@@ -149,7 +137,6 @@ rocketmq:
## 6. 影响面评估
主要影响模块:
1. `rdms-framework/rdms-spring-boot-starter-mq`
2. `rdms-framework/rdms-spring-boot-starter-websocket`
3. `rdms-system/rdms-system-boot` 配置文件
主要风险点:
@@ -182,7 +169,6 @@ rocketmq:
## 7. 验收清单(每阶段都要过)
1. 单体环境 `rdms.mq.type=redis` 可启动、可发送、可消费。
2. 微服务环境 `rdms.mq.type=rocketmq` 可启动、可发送、可消费。
3. WebSocket 在两种模式下都能完成跨实例消息投递。
4. 关键链路日志可定位发送端与消费端。
5. 切换只改配置,不改代码。
6. 回滚路径已验证。
@@ -224,7 +210,6 @@ rocketmq:
3. 关键业务出现重复消费副作用。
回滚动作:
1. 只回滚 `rdms.mq.type``rdms.websocket.sender-type` 配置。
2. 不回滚代码,确保恢复路径最短。
## 9. 当前建议

View File

@@ -52,7 +52,6 @@ Redis 相关能力分成两类:
### 6. 多 MQ 的真实边界
虽然模块描述写了支持 Redis / RocketMQ / RabbitMQ / Kafka
但本 starter 的自动配置主要是 Redis + Rabbit。
RocketMQ / Kafka 的业务化接入在 `rdms-spring-boot-starter-websocket` 里有更完整示例。
## 自动配置入口
`META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports`:
@@ -78,13 +77,6 @@ RocketMQ / Kafka 的业务化接入在 `rdms-spring-boot-starter-websocket` 里
2. 先按第 2 节使用 `Pub/Sub`(这是项目里最常见路径)。
3. 需要可恢复消费时,再按第 3 节接入 `Stream`
WebSocket 场景建议:
1. 多实例广播: `rdms.websocket.sender-type: redis`
2. 单机部署: 保持 `rdms.websocket.sender-type: local`
说明:
1. 只要存在 `AbstractRedisChannelMessageListener` Bean框架会自动注册 Redis 监听容器。
## 2. 使用 Redis Pub/Sub广播
适用场景: 通知广播、在线会话广播、对可靠性要求不高但强调实时性。
@@ -232,13 +224,6 @@ public class DemoRedisMessageInterceptor implements RedisMessageInterceptor {
1. Redis Stream 要求 Redis 版本 >= 5.0
2. 只有存在 Stream 监听器时,重投/清理定时任务才会生效
## 与 WebSocket 的关系
`rdms-spring-boot-starter-websocket` 直接复用本模块能力:
1. `sender-type=redis` 时使用 `RedisMQTemplate` + `AbstractRedisChannelMessageListener`
2. `sender-type=rabbitmq/rocketmq/kafka` 时切换到对应中间件实现
你可以参考 websocket 模块作为本模块的落地样板。
## 当前已知注意点
1. `AbstractRedisStreamMessageListener` 有一个 `(streamKey, group)` 构造器,内部把 `messageType` 置空;而消费反序列化仍依赖 `messageType`
建议优先使用无参构造路径(即泛型推断消息类型的默认方式)。

View File

@@ -519,7 +519,13 @@ public Long createUser(UserSaveReqVO reqVO) {
token 的签发和存储仍在系统服务等其他模块。
2. 当前跨服务透传的是 `login-user`,不是原始 token
所以下游服务能识别当前用户,不等于它一直拿着原始 `Authorization`
所以下游服务能识别当前用户,不等于它一直拿着原始 `Authorization`
3. 单体部署(不经过网关)建议在入口层剥离 `login-user` 请求头,避免外部伪造登录态
- Nginx 示例:
```nginx
# 去除客户端伪造的 login-user 头
proxy_set_header login-user "";
```
3. 不加 `@PreAuthorize` 不代表匿名可访问
默认仍然需要登录,只是不会进一步做权限点校验。

View File

@@ -2,7 +2,7 @@ package com.njcn.rdms.framework.apilog.config;
import com.njcn.rdms.framework.apilog.core.filter.ApiAccessLogFilter;
import com.njcn.rdms.framework.apilog.core.interceptor.ApiAccessLogInterceptor;
import com.njcn.rdms.framework.common.biz.infra.logger.ApiAccessLogCommonApi;
import com.njcn.rdms.framework.common.biz.system.logger.ApiAccessLogCommonApi;
import com.njcn.rdms.framework.common.enums.WebFilterOrderEnum;
import com.njcn.rdms.framework.web.config.RdmsWebAutoConfiguration;
import com.njcn.rdms.framework.web.config.WebProperties;

View File

@@ -1,7 +1,7 @@
package com.njcn.rdms.framework.apilog.config;
import com.njcn.rdms.framework.common.biz.infra.logger.ApiAccessLogCommonApi;
import com.njcn.rdms.framework.common.biz.infra.logger.ApiErrorLogCommonApi;
import com.njcn.rdms.framework.common.biz.system.logger.ApiAccessLogCommonApi;
import com.njcn.rdms.framework.common.biz.system.logger.ApiErrorLogCommonApi;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.cloud.openfeign.EnableFeignClients;

View File

@@ -10,8 +10,8 @@ import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.njcn.rdms.framework.apilog.core.annotation.ApiAccessLog;
import com.njcn.rdms.framework.apilog.core.enums.OperateTypeEnum;
import com.njcn.rdms.framework.common.biz.infra.logger.ApiAccessLogCommonApi;
import com.njcn.rdms.framework.common.biz.infra.logger.dto.ApiAccessLogCreateReqDTO;
import com.njcn.rdms.framework.common.biz.system.logger.ApiAccessLogCommonApi;
import com.njcn.rdms.framework.common.biz.system.logger.dto.ApiAccessLogCreateReqDTO;
import com.njcn.rdms.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.util.json.JsonUtils;

View File

@@ -2,7 +2,7 @@ package com.njcn.rdms.framework.web.config;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Maps;
import com.njcn.rdms.framework.common.biz.infra.logger.ApiErrorLogCommonApi;
import com.njcn.rdms.framework.common.biz.system.logger.ApiErrorLogCommonApi;
import com.njcn.rdms.framework.common.enums.WebFilterOrderEnum;
import com.njcn.rdms.framework.web.core.filter.CacheRequestBodyFilter;
import com.njcn.rdms.framework.web.core.handler.GlobalExceptionHandler;

View File

@@ -7,8 +7,8 @@ import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.google.common.util.concurrent.UncheckedExecutionException;
import com.njcn.rdms.framework.common.biz.infra.logger.ApiErrorLogCommonApi;
import com.njcn.rdms.framework.common.biz.infra.logger.dto.ApiErrorLogCreateReqDTO;
import com.njcn.rdms.framework.common.biz.system.logger.ApiErrorLogCommonApi;
import com.njcn.rdms.framework.common.biz.system.logger.dto.ApiErrorLogCreateReqDTO;
import com.njcn.rdms.framework.common.exception.ServiceException;
import com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil;
import com.njcn.rdms.framework.common.pojo.CommonResult;

View File

@@ -1,21 +1,21 @@
# rdms-spring-boot-starter-websocket
# rdms-spring-boot-starter-websocket
## 1. 模块定位
`rdms-spring-boot-starter-websocket` 是 WebSocket 基础设施模块,用于统一处理连接、会话管理、消息分发与消息发送,并支持多节点场景下的广播投递
`rdms-spring-boot-starter-websocket` 是 WebSocket 基础设施模块,用于统一处理连接、会话管理、消息分发与消息发送。
模块聚合的核心能力:
- WebSocket 自动装配与路径注册
- 登录用户绑定与会话管理
- JSON 消息协议与监听器分发
- 消息发送与多节点广播
- 消息发送
## 2. 设计思路
- 统一 JSON 消息协议(`type` + `content`),通过 `type` 分发到对应监听器,降低业务耦合。
- 通过 `WebSocketSessionManager` 统一管理会话,支持按用户类型/用户编号/会话 ID 进行推送。
- 通过可插拔 `sender-type` 支持单机与多节点广播local/redis/rocketmq/rabbitmq/kafka
- 通过本地发送器支持单机消息推送
- 与安全体系结合,在握手阶段写入 `LoginUser`,便于后续鉴权与定向发送。
## 3. 功能模块
@@ -28,7 +28,7 @@
- 注册握手拦截器(默认 `LoginUserHandshakeInterceptor`
- 注册 `WebSocketSessionManager`
- 放行 WebSocket 路径的安全校验
- 注册消息发送器(按 `sender-type`
- 注册消息发送器
### 3.2 JSON 消息协议
@@ -69,14 +69,7 @@
消息会被封装为统一的 `JsonWebSocketMessage` 后发送。
### 3.5 多节点广播
`sender-type` 支持以下类型:
- `local`:单机直连(默认)
- `redis` / `rocketmq` / `rabbitmq` / `kafka`:通过 MQ 广播到各实例,再由各实例推送到本机会话
### 3.6 登录用户绑定
### 3.5 登录用户绑定
握手阶段会读取当前登录用户并写入 WebSocket Session
@@ -102,13 +95,11 @@ rdms:
websocket:
enable: true
path: /ws
sender-type: local
```
说明:
- `path` 默认 `/ws`
- `sender-type` 默认 `local`
- `enable` 默认 `true`
### 4.3 连接方式
@@ -148,49 +139,4 @@ public void push(Long userId, NoticeDTO notice) {
}
```
### 4.6 多节点广播配置示例
Redis
```yaml
rdms:
websocket:
sender-type: redis
```
RocketMQ
```yaml
rdms:
websocket:
sender-type: rocketmq
sender-rocketmq:
topic: ws-topic
consumer-group: ws-group
```
Kafka
```yaml
rdms:
websocket:
sender-type: kafka
sender-kafka:
topic: ws-topic
consumer-group: ws-group
```
RabbitMQ
```yaml
rdms:
websocket:
sender-type: rabbitmq
sender-rabbitmq:
exchange: ws-exchange
queue: ws-queue
```
注意:
- 使用 MQ 模式时,请确保对应 MQ 客户端依赖与连接配置已就绪。

View File

@@ -39,28 +39,6 @@
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- 消息队列相关 -->
<dependency>
<groupId>com.njcn</groupId>
<artifactId>rdms-spring-boot-starter-mq</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
</project>