架构设计
名尚智联采用 Maven 多模块分层架构,严格隔离 AGPLv3 代码。
一、总体架构
┌─────────────────────────────────────────────────────────────────┐
│ 客户端层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Web 后台 │ │ 移动端 │ │ 设备 │ │ 第三方 API│ │
│ │ Vue3+EP │ │ uni-app │ │ MQTT等 │ │ REST │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
┌────┴────┐
│ Nginx │ 反代 + Gzip + SPA 回退
└────┬────┘
│
┌────────────────────────┼────────────────────────────────────────┐
│ ms-admin(Spring Boot) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Web Layer │ │Service │ │Protocol │ │Plugins │ │
│ │ Controller│ │Business │ │Servers │ │PE Modules│ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ ms-common 公共层 │ │
│ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │
│ │ │ core │ │web │ │mybatis │ │security│ │tdengine│ │ │
│ │ └────────┘ └────────┘ └────────┘ └────────┘ └────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│ │ │ │
┌────┴────┐ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐
│ MySQL │ │ Redis │ │ EMQX │ │ TDengine│
│ 3307 │ │ 6380 │ │ 1884 │ │ 6042 │
│ 主库+tenant│ │ TSLV缓存 │ │ MQTT Broker│ │ 时序数据 │
└─────────┘ └─────────┘ └─────────┘ └─────────┘二、模块分层
backend/
├── pom.xml # 父 POM,dependencyManagement 统一版本
├── ms-common/ # 公共层(5 子模块)
│ ├── ms-common-core # 基础工具:Result、BizException、BeanUtils
│ ├── ms-common-web # Web 自动配置:GlobalException、Cors
│ ├── ms-common-mybatis # MyBatis-Plus 自动配置:分页、TenantInterceptor
│ ├── ms-common-security # Sa-Token 安全:LoginUser、SaTokenConfig
│ └── ms-common-tdengine # TDengine 客户端:连接池、SQL 模板
├── ms-server/ # 协议接入层(7 子模块)
│ ├── ms-netty-core # Netty 多协议框架:PipelineProvider SPI
│ ├── ms-server-mqtt # MQTT:EMQX Webhook 认证
│ ├── ms-server-tcp # TCP/UDP 私有协议:MS-PRIVATE v1
│ ├── ms-server-modbus # Modbus 主站:TCP/RTU 轮询
│ ├── ms-server-coap # CoAP Server:RFC 7252 精简子集(自研)
│ └── ms-server-http # HTTP Digest:RFC 7616 认证
├── ms-service/ # 业务层(8 子模块)
│ ├── ms-service-system # 用户/角色/菜单
│ ├── ms-service-device # 产品/设备/物模型
│ ├── ms-service-alert # 告警规则/日志
│ ├── ms-service-rule # LiteFlow 规则引擎封装
│ ├── ms-service-tenant # 多租户:动态数据源、tenant_* 库
│ ├── ms-service-billing # 套餐/计费(EE)
│ └── ms-service-ai # AI 助手(PE)
├── ms-plugins/ # 插件层(4 子模块)
│ ├── ms-plugins-connector # 通知通道:钉钉/企微/短信
│ ├── ms-plugins-notify-enterprise # 企业通知 REST
│ ├── ms-plugins-bridge # HTTP/MQTT/DB 三向桥接
│ └── ms-plugins-media # ZLMediaKit 集成(PE)
├── sql/ # 初始化 SQL
│ ├── ms-init.sql # 主库表结构(ms_ 前缀)
│ ├── ms-tenant.sql # 租户库模板
│ ├── ms-ai.sql # AI 相关表
│ └── ms-media.sql # 视频监控相关表
└── ms-admin/ # 启动模块(Spring Boot Application)
└── mingshang-admin.jar # 最终产物(finalName 自定义)三、技术栈
| 类别 | 技术 | 版本 |
|---|---|---|
| 语言 | Java | 21 LTS |
| 框架 | Spring Boot | 3.5.11 |
| ORM | MyBatis-Plus | 3.5.14 |
| 安全 | Sa-Token | 1.44.0 |
| 规则引擎 | LiteFlow | 2.15.0 |
| 数据库 | MySQL | 8.4 |
| 缓存 | Redis | 7 + Redisson 3.51 |
| MQTT | EMQX | 5.8(外置) |
| 时序库 | TDengine | 3.5 |
| 前端 | Vue 3 + Element Plus | 最新 |
| 网络 | Netty | 由 Spring Boot 管理 |
| JSON | FastJSON2 | 2.0.60 |
四、多租户设计
4.1 数据隔离策略
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 主库 │ │ tenant_1 │ │ tenant_99 │
│ mingshang │ │ 租户1库 │ │ 租户99库 │
├─────────────┤ ├─────────────┤ ├─────────────┤
│ ms_user │ │ 设备/产品 │ │ 设备/产品 │
│ ms_role │ │ 业务表 │ │ 业务表 │
│ ms_menu │ └─────────────┘ └─────────────┘
│ ms_product │ (结构与主库业务表同构)
│ 公共表... │
└─────────────┘- 主库:用户、角色、菜单、产品(跨租户共享)
- tenant_ 库*:设备、告警、规则等租户专属表
- TenantContext:
ThreadLocal<Long>自动注入 MyBatis 拦截器
4.2 动态数据源路由
java
// TenantInterceptor 自动设置
TenantContext.set(tenantId);
// → DynamicRoutingDataSource 切换到 tenant_{tenantId}
// → SQL 自动 WHERE tenant_id = {tenantId}
// TenantContext.clear() 在 finally 中清理五、设备认证全局检索
所有协议接入模块(TCP/CoAP/HTTP)共享同一模式:
java
// 1. 先查主库
Device device = deviceMapper.selectBySerial(serial);
// 2. 主库没找到 → 遍历 tenant_* 动态库
if (device == null) {
Map<String, DataSource> dsMap = dynamicDataSource.getDataSources();
// TreeMap 排序保证确定性
for (Map.Entry<String, DataSource> entry : dsMap.entrySet()) {
if (entry.getKey().startsWith("tenant_")) {
// 切换数据源 + TenantContext.set
device = deviceMapper.selectBySerialIgnoreTenant(...);
if (device != null) break;
}
}
}
// 3. authCode 明文比对
return device != null && device.getAuthCode().equals(authCode);六、数据流
6.1 属性上报
设备 → TCP/CoAP/HTTP/MQTT 协议模块
→ DeviceAuthenticator(全局检索 + authCode 校验)
→ DeviceSession(注册会话)
→ DeviceDataDispatcher.reportProperties(tenantId, productId, deviceId, serial, props)
→ Redis TSLV 写入(ms:tsl:{tenantId}:{deviceId})
→ TDengine 历史写入(CREATE TABLE 自动)
→ touchOnline(online=1 + lastOnlineTime 更新)6.2 规则触发
DeviceDataDispatcher
→ LiteFlow 规则匹配(productId + identifier)
→ 执行 Chain(条件块 + 动作块)
→ 告警 → NotifyService(钉钉/企微/短信并发)
→ 桥接 → BridgeService(HTTP/MQTT 出站)
→ 下发 → CommandDispatcher(EMQX 反向推送)七、AGPLv3 隔离策略
| 策略 | 实施 |
|---|---|
| 包名隔离 | 全部 com.mingshang,零 com.fastbee |
| 表名隔离 | 全部 ms_ 前缀,零 fb_ |
| 代码隔离 | 所有代码从零实现,不抄 FastBee 源码 |
| 协议栈自研 | Netty 接入框架、CoAP、Digest 认证全部自研 |
| 依赖隔离 | 仅依赖通用开源组件(Spring/MyBatis/EMQX) |
八、端口映射
| 服务 | 端口 | 配置文件 |
|---|---|---|
| Spring Boot | 8080 | server.port |
| MySQL | 3307 | spring.datasource.dynamic.datasource.master.url |
| Redis | 6380 | spring.data.redis.port |
| EMQX MQTT | 1884 | docker-compose 映射 |
| EMQX Dashboard | 18084 | docker-compose 映射 |
| TDengine REST | 6042 | ms.tdengine.port |
| TCP 私有协议 | 11000 | ms.netty.tcp.port |
| UDP 私有协议 | 11001 | ms.netty.udp.port |
| CoAP | 5683 | ms.coap.port |
| Modbus | 502(网关配置) | ms.modbus.gateways[].port |