mirror of
https://gitee.com/san-bing/JChargePointProtocol
synced 2026-07-13 02:07:58 +08:00
wiki生成
This commit is contained in:
452
docs/核心模块详解/协议处理框架.md
Normal file
452
docs/核心模块详解/协议处理框架.md
Normal file
@@ -0,0 +1,452 @@
|
||||
# 协议处理框架
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java)
|
||||
- [ProtocolContext.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolContext.java)
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java)
|
||||
- [TcpListener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java)
|
||||
- [JCPPHeadTailFrameDecoder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/decoder/JCPPHeadTailFrameDecoder.java)
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java)
|
||||
- [ProtocolCfg.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/cfg/ProtocolCfg.java)
|
||||
- [MemoryForwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/MemoryForwarder.java)
|
||||
- [Listener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/Listener.java)
|
||||
- [TcpCfg.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/cfg/TcpCfg.java)
|
||||
- [ProtocolsConfigProvider.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/provider/ProtocolsConfigProvider.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [引言](#引言)
|
||||
2. [核心组件](#核心组件)
|
||||
3. [架构概述](#架构概述)
|
||||
4. [详细组件分析](#详细组件分析)
|
||||
5. [依赖分析](#依赖分析)
|
||||
6. [性能考虑](#性能考虑)
|
||||
7. [故障排除指南](#故障排除指南)
|
||||
8. [结论](#结论)
|
||||
|
||||
## 引言
|
||||
|
||||
JChargePointProtocol协议处理框架是一个高度可扩展的通信协议处理系统,专为处理充电桩与服务器之间的通信而设计。该框架采用模块化设计,支持多种通信协议(如绿能、云快充等),并提供了完整的生命周期管理、消息处理、路由和基础设施集成能力。本架构文档将深入分析框架的核心组件,包括协议生命周期管理、依赖注入容器、消息处理流程、TCP连接处理等关键方面。
|
||||
|
||||
## 核心组件
|
||||
|
||||
JChargePointProtocol框架的核心组件包括ProtocolBootstrap抽象类、ProtocolContext依赖注入容器、ProtocolMessageProcessor消息处理器、ProtocolCommandRouter命令路由器和TcpListener
|
||||
TCP监听器。这些组件协同工作,为各种充电桩通信协议提供统一的处理框架。ProtocolBootstrap定义了协议的初始化和销毁生命周期,ProtocolContext作为依赖注入容器整合了缓存、队列、gRPC客户端等基础设施组件,ProtocolMessageProcessor负责消息的处理流程,ProtocolCommandRouter实现上行和下行指令的路由,而TcpListener则处理TCP长连接和消息帧的解码。
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java)
|
||||
- [ProtocolContext.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolContext.java)
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java)
|
||||
- [TcpListener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java)
|
||||
|
||||
## 架构概述
|
||||
|
||||
JChargePointProtocol框架采用分层架构设计,各组件之间通过清晰的接口进行交互,实现了高内聚低耦合的设计目标。框架的核心是ProtocolBootstrap抽象类,它定义了协议的生命周期管理。ProtocolContext作为依赖注入容器,为整个框架提供所需的基础设施组件。消息处理流程由ProtocolMessageProcessor负责,通过ProtocolCommandRouter实现命令的路由。TCP通信由TcpListener处理,包括连接管理和消息帧解码。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "协议实现层"
|
||||
Lvneng[LvnengV340ProtocolBootstrap]
|
||||
Yunkuaichong[YunkuaichongV150ProtocolBootstrap]
|
||||
end
|
||||
subgraph "框架核心层"
|
||||
Bootstrap[ProtocolBootstrap]
|
||||
Context[ProtocolContext]
|
||||
MessageProcessor[ProtocolMessageProcessor]
|
||||
CommandRouter[ProtocolCommandRouter]
|
||||
Listener[TcpListener]
|
||||
Forwarder[Forwarder]
|
||||
end
|
||||
subgraph "基础设施层"
|
||||
Cache[缓存系统]
|
||||
Queue[消息队列]
|
||||
Stats[统计系统]
|
||||
ThreadPool[线程池]
|
||||
end
|
||||
Lvneng --> Bootstrap
|
||||
Yunkuaichong --> Bootstrap
|
||||
Bootstrap --> Context
|
||||
Bootstrap --> MessageProcessor
|
||||
Bootstrap --> Listener
|
||||
Bootstrap --> Forwarder
|
||||
MessageProcessor --> CommandRouter
|
||||
Listener --> MessageProcessor
|
||||
Context --> Cache
|
||||
Context --> Queue
|
||||
Context --> Stats
|
||||
Context --> ThreadPool
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java)
|
||||
- [ProtocolContext.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolContext.java)
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java)
|
||||
- [TcpListener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### ProtocolBootstrap 生命周期管理
|
||||
|
||||
ProtocolBootstrap是所有协议实现的抽象基类,采用模板方法模式定义了协议的初始化和销毁生命周期。该类通过Spring的@PostConstruct和@PreDestroy注解定义了init和destroy方法,实现了协议服务的标准化生命周期管理。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolBootstrap {
|
||||
+protocolContext : ProtocolContext
|
||||
+protocolCfg : ProtocolCfg
|
||||
+listener : Listener
|
||||
+forwarder : Forwarder
|
||||
+init() : void
|
||||
+destroy() : void
|
||||
+health() : Health
|
||||
+getProtocolName() : String
|
||||
+_init() : void
|
||||
+_destroy() : void
|
||||
+messageProcessor() : ProtocolMessageProcessor
|
||||
}
|
||||
class LvnengV340ProtocolBootstrap {
|
||||
+getProtocolName() : String
|
||||
+_init() : void
|
||||
+_destroy() : void
|
||||
+messageProcessor() : ProtocolMessageProcessor
|
||||
}
|
||||
ProtocolBootstrap <|-- LvnengV340ProtocolBootstrap
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java)
|
||||
|
||||
#### 模板方法模式应用
|
||||
|
||||
ProtocolBootstrap采用了模板方法设计模式,其中init和destroy方法为模板方法,定义了协议初始化和销毁的标准流程。这些方法调用抽象方法_getProtocolName、_
|
||||
init、_destroy和_messageProcessor,由具体的协议实现类提供具体实现。这种设计模式确保了所有协议实现都遵循相同的生命周期管理流程,同时允许各协议根据自身需求定制具体行为。
|
||||
|
||||
在init方法中,框架首先加载协议配置,然后根据配置创建相应的转发器(Forwarder),最后初始化监听器(Listener)。destroy方法则负责优雅地关闭监听器和转发器。health方法提供了健康检查功能,监控监听器和转发器的状态。
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java)
|
||||
|
||||
### ProtocolContext 依赖注入容器
|
||||
|
||||
ProtocolContext是框架的核心依赖注入容器,负责整合和管理各种基础设施组件。它通过构造函数注入的方式,将统计工厂、协议配置提供器、会话注册表提供器、服务信息提供器、分区提供器、队列工厂和分片线程池等组件注入到容器中。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolContext {
|
||||
-statsFactory : StatsFactory
|
||||
-protocolsConfigProvider : ProtocolsConfigProvider
|
||||
-protocolSessionRegistryProvider : ProtocolSessionRegistryProvider
|
||||
-serviceInfoProvider : ServiceInfoProvider
|
||||
-partitionProvider : PartitionProvider
|
||||
-appQueueFactory : AppQueueFactory
|
||||
-shardingThreadPool : ShardingThreadPool
|
||||
+init() : void
|
||||
}
|
||||
class StatsFactory {
|
||||
+createGauge() : Gauge
|
||||
+createMessagesStats() : MessagesStats
|
||||
+createTimer() : Timer
|
||||
}
|
||||
class ProtocolsConfigProvider {
|
||||
+loadConfig(protocol : String) : ProtocolCfg
|
||||
}
|
||||
class AppQueueFactory {
|
||||
+createProtocolUplinkMsgProducer() : QueueProducer
|
||||
+createProtocolUplinkMsgConsumer() : QueueConsumer
|
||||
}
|
||||
ProtocolContext --> StatsFactory : "使用"
|
||||
ProtocolContext --> ProtocolsConfigProvider : "使用"
|
||||
ProtocolContext --> AppQueueFactory : "使用"
|
||||
ProtocolContext --> ShardingThreadPool : "使用"
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [ProtocolContext.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolContext.java)
|
||||
|
||||
#### 基础设施组件整合
|
||||
|
||||
ProtocolContext整合了多个关键基础设施组件:
|
||||
|
||||
- **StatsFactory**:提供统计功能,用于监控消息处理、连接状态等指标
|
||||
- **ProtocolsConfigProvider**:提供协议配置加载功能,支持动态配置管理
|
||||
- **AppQueueFactory**:创建消息队列的生产者和消费者,支持Kafka和内存队列
|
||||
- **ShardingThreadPool**:提供分片线程池,确保消息处理的顺序性和性能
|
||||
- **ServiceInfoProvider**:提供服务发现和分区信息,支持分布式部署
|
||||
|
||||
这些组件通过ProtocolContext统一管理,为协议实现提供了丰富的基础设施支持,使协议开发者可以专注于业务逻辑的实现,而不必关心底层基础设施的细节。
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [ProtocolContext.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolContext.java)
|
||||
|
||||
### ProtocolMessageProcessor 消息处理流程
|
||||
|
||||
ProtocolMessageProcessor是框架的消息处理核心,负责处理上行和下行消息。它采用抽象类设计,定义了消息处理的基本流程和异常处理机制,具体的协议实现需要继承此类并实现具体的处理逻辑。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolMessageProcessor {
|
||||
-forwarder : Forwarder
|
||||
-protocolContext : ProtocolContext
|
||||
+uplinkHandleAsync(listenerToHandlerMsg : ListenerToHandlerMsg, uplinkMsgStats : MessagesStats) : void
|
||||
+downlinkHandle(sessionToHandlerMsg : SessionToHandlerMsg, downlinkMsgStats : MessagesStats) : void
|
||||
+ProtocolMessageProcessor(forwarder : Forwarder, protocolContext : ProtocolContext)
|
||||
#uplinkHandle(listenerToHandlerMsg : ListenerToHandlerMsg) : void
|
||||
#doDownlinkHandle(sessionToHandlerMsg : SessionToHandlerMsg) : void
|
||||
}
|
||||
class LvnengProtocolMessageProcessor {
|
||||
-uplinkRouter : ProtocolCommandRouter~LvnengUplinkCmdExe~
|
||||
-downlinkRouter : ProtocolCommandRouter~LvnengDownlinkCmdExe~
|
||||
-downlinkCmdConverter : DownlinkCmdConverter
|
||||
+uplinkHandle(listenerToHandlerMsg : ListenerToHandlerMsg) : void
|
||||
+doDownlinkHandle(sessionToHandlerMsg : SessionToHandlerMsg) : void
|
||||
+exeCmd(message : LvnengUplinkMessage, session : TcpSession) : void
|
||||
+exeCmd(message : LvnengDwonlinkMessage, session : TcpSession) : void
|
||||
}
|
||||
ProtocolMessageProcessor <|-- LvnengProtocolMessageProcessor
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java)
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java)
|
||||
|
||||
#### 上行消息处理流程
|
||||
|
||||
上行消息处理流程从TcpListener接收到原始字节数据开始,经过解码器处理后,由ProtocolMessageProcessor的uplinkHandleAsync方法异步处理。该方法使用分片线程池执行消息处理,确保同一会话的消息按顺序处理。
|
||||
|
||||
处理流程包括:
|
||||
|
||||
1. 从ListenerToHandlerMsg中提取会话、消息ID和原始数据
|
||||
2. 调用协议特定的uplinkHandle方法进行消息解析
|
||||
3. 通过ProtocolCommandRouter路由到相应的命令执行器
|
||||
4. 执行具体的业务逻辑
|
||||
5. 将处理结果通过Forwarder转发到消息队列
|
||||
|
||||
在LvnengProtocolMessageProcessor的具体实现中,上行消息处理还包括帧头解析、长度校验、校验和验证等步骤,确保消息的完整性和正确性。
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java)
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java)
|
||||
|
||||
#### 下行消息处理流程
|
||||
|
||||
下行消息处理流程由ProtocolMessageProcessor的downlinkHandle方法负责,该方法提供统一的异常处理和日志记录。具体的处理逻辑由doDownlinkHandle抽象方法定义,由协议实现类提供具体实现。
|
||||
|
||||
处理流程包括:
|
||||
|
||||
1. 从SessionToHandlerMsg中提取下行请求和会话信息
|
||||
2. 通过DownlinkCmdConverter将通用命令转换为协议特定的命令字
|
||||
3. 通过ProtocolCommandRouter路由到相应的命令执行器
|
||||
4. 执行具体的业务逻辑
|
||||
5. 将生成的协议消息发送到客户端
|
||||
|
||||
下行消息处理采用同步方式,确保调用方能够及时获取处理结果或异常信息。框架提供了完善的异常处理机制,捕获并记录处理过程中的任何异常,同时通过统计系统记录失败消息的数量。
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java)
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java)
|
||||
|
||||
### ProtocolCommandRouter 命令路由
|
||||
|
||||
ProtocolCommandRouter是框架的命令路由核心,负责将上行和下行指令路由到相应的命令执行器。它采用基于协议名和命令字的路由策略,支持多版本协议的共存。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolCommandRouter~T~ {
|
||||
-executorMap : Map~String, T~
|
||||
+ProtocolCommandRouter(scanBaseClass : Class~?~, executorFilter : Predicate~Class~?~~)
|
||||
+getExecutor(protocolName : String, cmd : int) : T
|
||||
#initializeRoutes(scanBaseClass : Class~?~, executorFilter : Predicate~Class~?~~) : void
|
||||
#registerExecutor(executorClass : Class~?~) : void
|
||||
#buildKey(protocolName : String, cmd : int) : String
|
||||
}
|
||||
class ProtocolCmd {
|
||||
+value() : int
|
||||
+protocolNames() : String[]
|
||||
}
|
||||
ProtocolCommandRouter --> ProtocolCmd : "使用"
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java)
|
||||
- [ProtocolCmd.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/annotation/ProtocolCmd.java)
|
||||
|
||||
#### 上行和下行指令路由
|
||||
|
||||
ProtocolCommandRouter通过扫描带有@ProtocolCmd注解的类来初始化路由表。每个命令执行器类都必须使用@ProtocolCmd注解,指定命令字值和支持的协议名列表。
|
||||
|
||||
在LvnengProtocolMessageProcessor中,创建了两个ProtocolCommandRouter实例:
|
||||
|
||||
- uplinkRouter:用于路由上行指令,扫描LvnengUplinkCmdExe类型的类
|
||||
- downlinkRouter:用于路由下行指令,扫描LvnengDownlinkCmdExe类型的类
|
||||
|
||||
当接收到消息时,框架根据协议名和命令字构建路由键(protocolName:
|
||||
cmd),在executorMap中查找对应的命令执行器。如果找到,则调用执行器的execute方法处理消息;如果未找到,则记录警告日志。
|
||||
|
||||
这种路由机制具有良好的扩展性,新增协议命令只需添加相应的命令执行器类并使用@ProtocolCmd注解即可,无需修改路由代码。
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java)
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java)
|
||||
|
||||
### TcpListener TCP连接处理
|
||||
|
||||
TcpListener负责处理TCP长连接和消息帧的解码,基于Netty框架实现高性能的网络通信。它管理服务器引导、事件循环组和通道初始化,确保稳定可靠的TCP连接。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class TcpListener {
|
||||
-serverChannel : Channel
|
||||
-bossGroup : EventLoopGroup
|
||||
-workerGroup : EventLoopGroup
|
||||
+TcpListener(protocolName : String, tcpCfg : TcpCfg, protocolMessageProcessor : ProtocolMessageProcessor, statsFactory : StatsFactory)
|
||||
+destroy() : void
|
||||
+health() : Health
|
||||
#tcpServerBootstrap(tcpCfg : TcpCfg) : void
|
||||
#tcpServerShutdown() : void
|
||||
}
|
||||
class Listener {
|
||||
-protocolName : String
|
||||
-protocolMessageProcessor : ProtocolMessageProcessor
|
||||
-connectionsGauge : AtomicInteger
|
||||
-uplinkMsgStats : MessagesStats
|
||||
-downlinkMsgStats : MessagesStats
|
||||
-downlinkTimer : Timer
|
||||
-parameter : ChannelHandlerParameter
|
||||
+health() : Health
|
||||
+destroy() : void
|
||||
}
|
||||
class JCPPHeadTailFrameDecoder {
|
||||
-headBytes : byte[]
|
||||
-tailBytes : byte[]
|
||||
+JCPPHeadTailFrameDecoder(head : String, tail : String)
|
||||
+decode(ctx : ChannelHandlerContext, in : ByteBuf, out : Object[]) : void
|
||||
}
|
||||
TcpListener --> Listener : "继承"
|
||||
TcpListener --> JCPPHeadTailFrameDecoder : "使用"
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [TcpListener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java)
|
||||
- [Listener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/Listener.java)
|
||||
- [JCPPHeadTailFrameDecoder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/decoder/JCPPHeadTailFrameDecoder.java)
|
||||
|
||||
#### 消息帧解码
|
||||
|
||||
JCPPHeadTailFrameDecoder是基于起始域和结束域的拆包解码器,负责将TCP流中的原始字节数据分割成完整的消息帧。解码器使用十六进制字符串配置的起始域和结束域来识别消息边界。
|
||||
|
||||
解码流程包括:
|
||||
|
||||
1. 检查可读字节长度是否足够(至少包含起始域和结束域)
|
||||
2. 读取前n个字节与起始域进行比较
|
||||
3. 如果不匹配,丢弃一个字节并继续
|
||||
4. 如果匹配,查找结束域的位置
|
||||
5. 提取起始域和结束域之间的完整消息帧
|
||||
|
||||
这种解码方式适用于基于特定起始和结束标记的协议,如绿能协议。解码器还提供了详细的日志记录,便于调试和问题排查。
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [JCPPHeadTailFrameDecoder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/decoder/JCPPHeadTailFrameDecoder.java)
|
||||
- [TcpListener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java)
|
||||
|
||||
## 依赖分析
|
||||
|
||||
JChargePointProtocol框架的组件之间存在清晰的依赖关系,体现了高内聚低耦合的设计原则。ProtocolBootstrap作为顶层组件,依赖于ProtocolContext、ProtocolMessageProcessor、Listener和Forwarder。ProtocolContext作为依赖注入容器,为其他组件提供基础设施服务。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
Bootstrap[ProtocolBootstrap] --> Context[ProtocolContext]
|
||||
Bootstrap --> MessageProcessor[ProtocolMessageProcessor]
|
||||
Bootstrap --> Listener[TcpListener]
|
||||
Bootstrap --> Forwarder[Forwarder]
|
||||
MessageProcessor --> CommandRouter[ProtocolCommandRouter]
|
||||
Listener --> MessageProcessor
|
||||
Context --> Cache[缓存系统]
|
||||
Context --> Queue[消息队列]
|
||||
Context --> Stats[统计系统]
|
||||
Context --> ThreadPool[线程池]
|
||||
MessageProcessor --> Context
|
||||
CommandRouter --> Annotation[ProtocolCmd]
|
||||
style Bootstrap fill:#f9f,stroke:#333
|
||||
style Context fill:#bbf,stroke:#333
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java)
|
||||
- [ProtocolContext.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolContext.java)
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java)
|
||||
- [TcpListener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java)
|
||||
|
||||
#### 新协议启动流程
|
||||
|
||||
当启动一个新的协议实现时,各组件的协同工作流程如下:
|
||||
|
||||
1. Spring容器创建ProtocolBootstrap的子类实例
|
||||
2. 调用@PostConstruct注解的init方法
|
||||
3. 从ProtocolContext获取协议配置
|
||||
4. 根据配置创建Forwarder实例(Kafka或内存)
|
||||
5. 创建TcpListener实例,启动TCP服务器
|
||||
6. 调用子类实现的_init方法进行协议特定的初始化
|
||||
7. 协议服务进入运行状态,开始处理消息
|
||||
|
||||
这个流程确保了所有协议实现都遵循相同的标准初始化过程,同时允许各协议根据需要进行定制化初始化。
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java)
|
||||
- [ProtocolContext.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolContext.java)
|
||||
|
||||
## 性能考虑
|
||||
|
||||
JChargePointProtocol框架在设计时充分考虑了性能因素,采用了多种优化策略:
|
||||
|
||||
- 使用Netty框架处理TCP通信,确保高并发下的性能表现
|
||||
- 采用分片线程池处理消息,既保证了消息处理的顺序性,又充分利用了多核CPU的处理能力
|
||||
- 通过ProtocolContext集中管理基础设施组件,减少资源重复创建和销毁的开销
|
||||
- 使用高效的序列化和反序列化机制,减少消息处理的CPU消耗
|
||||
- 提供详细的统计信息,便于性能监控和优化
|
||||
|
||||
框架还支持多种部署模式,包括单体部署和微服务部署,可以根据实际需求选择合适的部署方式以优化性能。
|
||||
|
||||
## 故障排除指南
|
||||
|
||||
当遇到协议处理框架的问题时,可以按照以下步骤进行排查:
|
||||
|
||||
1. 检查ProtocolBootstrap的健康状态,确认Listener和Forwarder是否正常
|
||||
2. 查看日志文件,特别是ERROR和WARN级别的日志
|
||||
3. 检查TCP连接状态,确认客户端是否能够正常连接
|
||||
4. 验证消息帧格式,确保起始域、结束域和校验和正确
|
||||
5. 检查命令路由,确认ProtocolCommandRouter是否能够正确找到命令执行器
|
||||
6. 监控统计指标,分析消息处理的成功率和延迟
|
||||
|
||||
对于常见的连接问题,应检查防火墙设置、端口占用情况和网络配置。对于消息处理问题,应重点关注解码器的日志输出和命令执行器的实现逻辑。
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java)
|
||||
- [TcpListener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java)
|
||||
|
||||
## 结论
|
||||
|
||||
JChargePointProtocol协议处理框架通过精心设计的架构和组件,为充电桩通信协议的实现提供了强大而灵活的基础。框架采用模板方法模式确保协议生命周期管理的一致性,通过ProtocolContext实现依赖注入和基础设施整合,利用ProtocolCommandRouter提供灵活的命令路由机制。这些设计优势使得框架具有良好的可扩展性和松耦合性,能够轻松支持多种通信协议的实现和共存。
|
||||
|
||||
框架的设计充分考虑了实际应用场景的需求,包括高性能、高可用性、易于维护和扩展等方面。通过标准化的接口和清晰的职责划分,降低了协议实现的复杂度,使开发者能够专注于业务逻辑的实现。未来,框架可以进一步增强配置管理、监控告警和自动化测试等方面的能力,以满足更复杂的应用场景需求。
|
||||
638
docs/核心模块详解/协议实现模块/云快充协议实现/上行消息处理.md
Normal file
638
docs/核心模块详解/协议实现模块/云快充协议实现/上行消息处理.md
Normal file
@@ -0,0 +1,638 @@
|
||||
# 上行消息处理
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java)
|
||||
- [ProtocolCmd.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/annotation/ProtocolCmd.java)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java)
|
||||
- [YunKuaiChongUplinkCmdExe.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongUplinkCmdExe.java)
|
||||
- [YunKuaiChongUplinkMessage.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongUplinkMessage.java)
|
||||
- [KafkaForwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/KafkaForwarder.java)
|
||||
- [YunKuaiChongV150HeartbeatULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150HeartbeatULCmd.java)
|
||||
- [YunKuaiChongV150LoginULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LoginULCmd.java)
|
||||
- [YunKuaiChongV150StartChargeULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150StartChargeULCmd.java)
|
||||
- [YunKuaiChongV150RealTimeDataULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150RealTimeDataULCmd.java)
|
||||
- [YunKuaiChongV150TransactionRecordULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150TransactionRecordULCmd.java)
|
||||
- [YunKuaiChongProtocolConstants.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolConstants.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [概述](#概述)
|
||||
2. [系统架构](#系统架构)
|
||||
3. [消息处理流程](#消息处理流程)
|
||||
4. [协议命令注解机制](#协议命令注解机制)
|
||||
5. [关键上行命令详解](#关键上行命令详解)
|
||||
6. [消息转发机制](#消息转发机制)
|
||||
7. [数据持久化与状态管理](#数据持久化与状态管理)
|
||||
8. [性能优化策略](#性能优化策略)
|
||||
9. [总结](#总结)
|
||||
|
||||
## 概述
|
||||
|
||||
云快充协议上行消息处理系统是一个高度模块化的分布式消息处理框架,负责接收、解析、分发和处理来自充电桩的各种上行消息。该系统采用事件驱动架构,通过反射机制和命令路由模式实现灵活的消息处理。
|
||||
|
||||
核心特性包括:
|
||||
|
||||
- **高性能TCP监听**:基于Netty的异步I/O处理
|
||||
- **智能协议解析**:支持多种协议版本的统一处理
|
||||
- **反射命令路由**:基于注解的自动化命令分发
|
||||
- **消息转发队列**:通过Kafka实现异步消息传递
|
||||
- **状态管理**:实时更新充电桩状态和属性
|
||||
|
||||
## 系统架构
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "网络层"
|
||||
TCP[TCP监听器]
|
||||
Session[TCP会话管理]
|
||||
end
|
||||
subgraph "协议处理层"
|
||||
Processor[云快充协议处理器]
|
||||
Router[命令路由器]
|
||||
Message[消息解析器]
|
||||
end
|
||||
subgraph "命令执行层"
|
||||
Heartbeat[心跳命令]
|
||||
Login[登录命令]
|
||||
Charge[充电命令]
|
||||
RealTime[实时数据]
|
||||
Transaction[交易记录]
|
||||
end
|
||||
subgraph "消息转发层"
|
||||
Forwarder[Kafka转发器]
|
||||
Queue[消息队列]
|
||||
end
|
||||
subgraph "应用服务层"
|
||||
App[jcpp-app服务]
|
||||
DB[数据库存储]
|
||||
end
|
||||
TCP --> Session
|
||||
Session --> Processor
|
||||
Processor --> Router
|
||||
Router --> Message
|
||||
Message --> Heartbeat
|
||||
Message --> Login
|
||||
Message --> Charge
|
||||
Message --> RealTime
|
||||
Message --> Transaction
|
||||
Heartbeat --> Forwarder
|
||||
Login --> Forwarder
|
||||
Charge --> Forwarder
|
||||
RealTime --> Forwarder
|
||||
Transaction --> Forwarder
|
||||
Forwarder --> Queue
|
||||
Queue --> App
|
||||
App --> DB
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L27-L61)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java#L25-L40)
|
||||
|
||||
## 消息处理流程
|
||||
|
||||
### TCP监听器接收数据
|
||||
|
||||
系统从TcpListener接收到原始数据包开始,首先进行基本的完整性检查:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([接收数据包]) --> CheckLength{数据包长度检查}
|
||||
CheckLength --> |长度不足| Reject[拒绝处理]
|
||||
CheckLength --> |长度足够| CheckHeader{头部标识检查}
|
||||
CheckHeader --> |头部无效| Reject
|
||||
CheckHeader --> |头部有效| ParseHeader[解析协议头]
|
||||
ParseHeader --> CheckBoundary{边界检查}
|
||||
CheckBoundary --> |边界无效| Reject
|
||||
CheckBoundary --> |边界有效| ParseFields[解析字段]
|
||||
ParseFields --> CheckCRC{校验和验证}
|
||||
CheckCRC --> |校验失败| Reject
|
||||
CheckCRC --> |校验成功| BuildMessage[构建消息对象]
|
||||
BuildMessage --> RouteCommand[路由命令]
|
||||
RouteCommand --> ExecuteCommand[执行命令]
|
||||
ExecuteCommand --> End([处理完成])
|
||||
Reject --> End
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L63-L154)
|
||||
|
||||
### 消息解析与验证
|
||||
|
||||
协议处理器执行严格的验证流程:
|
||||
|
||||
1. **长度验证**:确保数据包包含最小长度(8字节)
|
||||
2. **头部验证**:检查起始标识符(0x68)
|
||||
3. **边界检查**:验证数据长度字段的合理性
|
||||
4. **CRC校验**:双重校验和验证(小端和大端)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L63-L154)
|
||||
|
||||
### 命令路由与分发
|
||||
|
||||
解析完成后,消息通过命令路由器进行分发:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Processor as 协议处理器
|
||||
participant Router as 命令路由器
|
||||
participant Executor as 命令执行器
|
||||
participant Forwarder as 消息转发器
|
||||
Processor->>Router : 查找命令执行器
|
||||
Router->>Router : 构建路由键(protocol : cmd)
|
||||
Router->>Router : 查询执行器映射表
|
||||
Router-->>Processor : 返回执行器实例
|
||||
Processor->>Executor : 调用execute方法
|
||||
Executor->>Executor : 处理业务逻辑
|
||||
Executor->>Forwarder : 发送消息到队列
|
||||
Forwarder-->>Executor : 确认发送
|
||||
Executor-->>Processor : 返回处理结果
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L170-L184)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java#L85-L95)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L170-L184)
|
||||
|
||||
## 协议命令注解机制
|
||||
|
||||
### @ProtocolCmd注解设计
|
||||
|
||||
系统采用基于注解的命令映射机制,通过`@ProtocolCmd`注解实现声明式命令注册:
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolCmd {
|
||||
+int value()
|
||||
+String[] protocolNames()
|
||||
}
|
||||
class ProtocolCommandRouter {
|
||||
-Map~String,T~ executorMap
|
||||
+ProtocolCommandRouter(Class, Predicate)
|
||||
+getExecutor(String, int) T
|
||||
-initializeRoutes(Class, Predicate)
|
||||
-registerExecutor(Class)
|
||||
}
|
||||
class YunKuaiChongUplinkCmdExe {
|
||||
+execute(TcpSession, YunKuaiChongUplinkMessage, ProtocolContext)
|
||||
#uplinkMessageBuilder(String, TcpSession, YunKuaiChongUplinkMessage)
|
||||
}
|
||||
ProtocolCmd --> YunKuaiChongUplinkCmdExe : 注解标记
|
||||
ProtocolCommandRouter --> YunKuaiChongUplinkCmdExe : 管理实例
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [ProtocolCmd.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/annotation/ProtocolCmd.java#L20-L32)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java#L25-L40)
|
||||
|
||||
### 反射机制工作原理
|
||||
|
||||
命令路由器通过以下步骤实现反射机制:
|
||||
|
||||
1. **类扫描**:扫描指定包路径下带有`@ProtocolCmd`注解的类
|
||||
2. **注解解析**:提取命令字和协议名称数组
|
||||
3. **实例化**:动态创建命令执行器实例
|
||||
4. **路由注册**:构建`protocol:cmd`键值对存储到映射表
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java#L42-L85)
|
||||
|
||||
### 多版本协议支持
|
||||
|
||||
系统通过协议名称数组支持多个协议版本的统一处理:
|
||||
|
||||
| 命令类型 | 协议版本 | 命令字 | 功能描述 |
|
||||
|------|----------------|------|---------|
|
||||
| 心跳命令 | V150/V160/V170 | 0x03 | 充电桩状态报告 |
|
||||
| 登录命令 | V150/V160/V170 | 0x01 | 充电桩认证注册 |
|
||||
| 充电启动 | V150/V160/V170 | 0x31 | 主动充电请求 |
|
||||
| 实时数据 | V150/V160/V170 | 0x13 | 充电过程监控 |
|
||||
| 交易记录 | V150/V160 | 0x3B | 充电完成记录 |
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunKuaiChongProtocolConstants.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolConstants.java#L25-L40)
|
||||
|
||||
## 关键上行命令详解
|
||||
|
||||
### 心跳包处理
|
||||
|
||||
心跳命令(0x03)负责维持连接状态和报告充电桩状态:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Pile as 充电桩
|
||||
participant Processor as 协议处理器
|
||||
participant HeartbeatCmd as 心跳命令
|
||||
participant Session as 会话管理
|
||||
participant Forwarder as 消息转发器
|
||||
Pile->>Processor : 发送心跳数据
|
||||
Processor->>HeartbeatCmd : 路由到心跳处理器
|
||||
HeartbeatCmd->>HeartbeatCmd : 解析桩编号和枪状态
|
||||
HeartbeatCmd->>Session : 刷新会话激活状态
|
||||
HeartbeatCmd->>HeartbeatCmd : 构建心跳请求消息
|
||||
HeartbeatCmd->>Forwarder : 发送到Kafka队列
|
||||
HeartbeatCmd->>Pile : 发送心跳响应
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunKuaiChongV150HeartbeatULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150HeartbeatULCmd.java#L30-L84)
|
||||
|
||||
**业务逻辑特点**:
|
||||
|
||||
- **状态更新**:刷新会话激活时间
|
||||
- **响应机制**:自动回复心跳确认
|
||||
- **信息提取**:解析桩编号、枪号、状态等关键信息
|
||||
- **转发处理**:将心跳信息发送到后端服务
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunKuaiChongV150HeartbeatULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150HeartbeatULCmd.java#L30-L84)
|
||||
|
||||
### 登录请求处理
|
||||
|
||||
登录命令(0x01)负责充电桩的身份认证和会话建立:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
LoginReq[登录请求] --> ParseInfo[解析设备信息]
|
||||
ParseInfo --> ExtractPileCode[提取桩编号]
|
||||
ExtractPileCode --> ExtractType[提取桩类型]
|
||||
ExtractType --> ExtractGuns[提取枪数量]
|
||||
ExtractGuns --> ExtractVersion[提取软件版本]
|
||||
ExtractVersion --> ExtractSIM[提取SIM卡信息]
|
||||
ExtractSIM --> RegisterSession[注册会话]
|
||||
RegisterSession --> BuildLoginMsg[构建登录消息]
|
||||
BuildLoginMsg --> ForwardToBackend[转发到后端]
|
||||
ForwardToBackend --> Complete[处理完成]
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunKuaiChongV150LoginULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LoginULCmd.java#L30-L84)
|
||||
|
||||
**认证流程**:
|
||||
|
||||
1. **身份验证**:通过桩编号验证设备合法性
|
||||
2. **会话注册**:建立和维护设备会话状态
|
||||
3. **信息收集**:收集设备硬件和软件信息
|
||||
4. **后端通知**:通知应用服务新设备上线
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunKuaiChongV150LoginULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LoginULCmd.java#L30-L84)
|
||||
|
||||
### 启动充电处理
|
||||
|
||||
充电启动命令(0x31)处理充电桩主动发起的充电请求:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
StartCharge[充电启动请求] --> ParseBasic[解析基础信息]
|
||||
ParseBasic --> ParseCard[解析卡片信息]
|
||||
ParseCard --> ParseVIN[解析VIN码]
|
||||
ParseVIN --> ValidatePassword{需要密码?}
|
||||
ValidatePassword --> |是| HashPassword[密码哈希处理]
|
||||
ValidatePassword --> |否| SkipPassword[跳过密码处理]
|
||||
HashPassword --> ReverseVIN[反转VIN码]
|
||||
SkipPassword --> ReverseVIN
|
||||
ReverseVIN --> BuildRequest[构建启动请求]
|
||||
BuildRequest --> ForwardMessage[转发消息]
|
||||
ForwardMessage --> Complete[处理完成]
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunKuaiChongV150StartChargeULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150StartChargeULCmd.java#L35-L124)
|
||||
|
||||
**处理要点**:
|
||||
|
||||
- **卡片验证**:处理物理卡片号和密码验证
|
||||
- **VIN码处理**:特殊格式的VIN码反转处理
|
||||
- **启动方式**:支持多种启动方式(APP、卡片、离线卡等)
|
||||
- **安全机制**:密码MD5哈希处理
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunKuaiChongV150StartChargeULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150StartChargeULCmd.java#L35-L124)
|
||||
|
||||
### 实时数据处理
|
||||
|
||||
实时数据命令(0x13)负责传输充电过程中的监控数据:
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class RealTimeDataProcessor {
|
||||
+execute(TcpSession, YunKuaiChongUplinkMessage, ProtocolContext)
|
||||
-parseGunStatus(int, int, String) GunRunStatus
|
||||
-parseFaults(byte[]) boolean[]
|
||||
-getFaultDescriptions(boolean[]) String[]
|
||||
-reduceMagnification(long, int) BigDecimal
|
||||
}
|
||||
class FaultDescription {
|
||||
+急停按钮动作故障
|
||||
+无可用整流模块
|
||||
+出风口温度过高
|
||||
+交流防雷故障
|
||||
+交直流模块通信中断
|
||||
+绝缘检测模块通信中断
|
||||
+电度表通信中断
|
||||
+读卡器通信中断
|
||||
+RC10通信中断
|
||||
+风扇调速板故障
|
||||
+直流熔断器故障
|
||||
+高压接触器故障
|
||||
+门打开
|
||||
}
|
||||
RealTimeDataProcessor --> FaultDescription : 使用
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunKuaiChongV150RealTimeDataULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150RealTimeDataULCmd.java#L35-L239)
|
||||
|
||||
**数据处理能力**:
|
||||
|
||||
- **状态解析**:解析充电枪的各种运行状态
|
||||
- **故障检测**:14种硬件故障的bit位解析
|
||||
- **数值转换**:精密的数值放大倍率处理
|
||||
- **多消息转发**:同时发送状态和进度消息
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunKuaiChongV150RealTimeDataULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150RealTimeDataULCmd.java#L35-L239)
|
||||
|
||||
### 交易记录处理
|
||||
|
||||
交易记录命令(0x3B)处理充电完成后的结算信息:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
TransactionRecord[交易记录] --> ParseTradeNo[解析交易流水号]
|
||||
ParseTradeNo --> ParsePileGun[解析桩号和枪号]
|
||||
ParsePileGun --> ParseTimes[解析时间信息]
|
||||
ParseTimes --> ParseEnergy[解析电量数据]
|
||||
ParseEnergy --> ParseAmount[解析金额信息]
|
||||
ParseAmount --> ParseMeter[解析电表数据]
|
||||
ParseMeter --> ParseVIN[解析VIN码]
|
||||
ParseVIN --> ParseStartFlag[解析启动方式]
|
||||
ParseStartFlag --> ParseStopReason[解析停止原因]
|
||||
ParseStopReason --> ParseCard[解析卡片信息]
|
||||
ParseCard --> BuildTransaction[构建交易记录]
|
||||
BuildTransaction --> ForwardToBackend[转发到后端]
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunKuaiChongV150TransactionRecordULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150TransactionRecordULCmd.java#L35-L305)
|
||||
|
||||
**结算信息完整性**:
|
||||
|
||||
- **分时电价**:支持尖峰平谷四种电价模式
|
||||
- **电量统计**:精确到4位小数的电量计量
|
||||
- **费用明细**:详细的电费和服务费计算
|
||||
- **异常处理**:128种充电异常原因的完整映射
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunKuaiChongV150TransactionRecordULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150TransactionRecordULCmd.java#L35-L305)
|
||||
|
||||
## 消息转发机制
|
||||
|
||||
### Kafka转发器架构
|
||||
|
||||
系统采用Kafka作为消息中间件,实现异步消息传递:
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "消息生产者"
|
||||
Processor[协议处理器]
|
||||
CmdExe[命令执行器]
|
||||
end
|
||||
subgraph "Kafka集群"
|
||||
Broker1[Kafka Broker 1]
|
||||
Broker2[Kafka Broker 2]
|
||||
Broker3[Kafka Broker 3]
|
||||
end
|
||||
subgraph "消息消费者"
|
||||
Consumer1[jcpp-app服务1]
|
||||
Consumer2[jcpp-app服务2]
|
||||
Consumer3[jcpp-app服务3]
|
||||
end
|
||||
Processor --> CmdExe
|
||||
CmdExe --> KafkaForwarder[Kafka转发器]
|
||||
KafkaForwarder --> Broker1
|
||||
KafkaForwarder --> Broker2
|
||||
KafkaForwarder --> Broker3
|
||||
Broker1 --> Consumer1
|
||||
Broker2 --> Consumer2
|
||||
Broker3 --> Consumer3
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [KafkaForwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/KafkaForwarder.java#L40-L80)
|
||||
|
||||
### 消息序列化与传输
|
||||
|
||||
转发器支持多种消息格式和传输模式:
|
||||
|
||||
| 传输模式 | 格式类型 | 性能特点 | 使用场景 |
|
||||
|-----------|----------|------|-------|
|
||||
| Monolith | Protobuf | 高性能 | 单体部署 |
|
||||
| Partition | JSON | 易调试 | 分布式部署 |
|
||||
| Custom | 自定义 | 灵活扩展 | 特殊需求 |
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [KafkaForwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/KafkaForwarder.java#L120-L180)
|
||||
|
||||
### 消息路由策略
|
||||
|
||||
系统实现了智能的消息路由机制:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Message[上行消息] --> CheckMode{检查传输模式}
|
||||
CheckMode --> |Monolith| DirectSend[直接发送]
|
||||
CheckMode --> |Partition| PartitionSend[分区发送]
|
||||
CheckMode --> |Custom| CustomSend[自定义发送]
|
||||
DirectSend --> MonolithQueue[单体队列]
|
||||
PartitionSend --> PartitionKey[分区键]
|
||||
PartitionKey --> KafkaTopic[Kafka主题]
|
||||
CustomSend --> CustomLogic[自定义逻辑]
|
||||
MonolithQueue --> Consumer[jcpp-app消费者]
|
||||
KafkaTopic --> Consumer
|
||||
CustomLogic --> Consumer
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [KafkaForwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/KafkaForwarder.java#L120-L180)
|
||||
|
||||
## 数据持久化与状态管理
|
||||
|
||||
### 属性系统架构
|
||||
|
||||
系统采用属性(Attribute)系统进行数据持久化:
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
ENTITY {
|
||||
uuid id PK
|
||||
string entity_type
|
||||
timestamp created_at
|
||||
timestamp last_update_ts
|
||||
}
|
||||
ATTRIBUTE {
|
||||
uuid entity_id FK
|
||||
string attr_key
|
||||
string str_value
|
||||
double dbl_value
|
||||
bigint long_value
|
||||
boolean bool_value
|
||||
json json_value
|
||||
timestamp last_update_ts
|
||||
int version
|
||||
}
|
||||
ENTITY ||--o{ ATTRIBUTE : contains
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [DefaultAttributeRepository.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/attribute/DefaultAttributeRepository.java#L112-L142)
|
||||
|
||||
### 状态更新流程
|
||||
|
||||
系统实现了高效的状态更新机制:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Cmd as 命令处理器
|
||||
participant AttrSvc as 属性服务
|
||||
participant Repo as 属性仓库
|
||||
participant Queue as 批量队列
|
||||
participant DB as 数据库
|
||||
Cmd->>AttrSvc : 请求状态更新
|
||||
AttrSvc->>AttrSvc : 构建属性列表
|
||||
AttrSvc->>Repo : 添加到批量队列
|
||||
Repo->>Queue : 排队等待
|
||||
Queue->>DB : 批量插入/更新
|
||||
DB-->>Queue : 确认写入
|
||||
Queue-->>Repo : 返回版本号
|
||||
Repo-->>AttrSvc : 返回操作结果
|
||||
AttrSvc-->>Cmd : 返回更新状态
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [DefaultAttributeRepository.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/attribute/DefaultAttributeRepository.java#L71-L110)
|
||||
|
||||
### 批量处理优化
|
||||
|
||||
系统采用批量处理策略提升性能:
|
||||
|
||||
| 优化策略 | 实现方式 | 性能提升 |
|
||||
|------|------------------|-----------|
|
||||
| 批量队列 | SqlBlockingQueue | 减少数据库连接开销 |
|
||||
| 异步处理 | Future模式 | 提升并发处理能力 |
|
||||
| 版本控制 | 冲突检测 | 确保数据一致性 |
|
||||
| 缓存机制 | 多级缓存 | 减少重复查询 |
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [DefaultAttributeRepository.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/attribute/DefaultAttributeRepository.java#L71-L110)
|
||||
|
||||
## 性能优化策略
|
||||
|
||||
### 异步处理架构
|
||||
|
||||
系统采用完全异步的处理架构:
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph "网络层"
|
||||
Netty[Netty I/O线程]
|
||||
end
|
||||
subgraph "处理层"
|
||||
Processor[协议处理器]
|
||||
Router[命令路由器]
|
||||
Executor[命令执行器]
|
||||
end
|
||||
subgraph "异步层"
|
||||
AsyncPool[异步线程池]
|
||||
Future[Future模式]
|
||||
end
|
||||
subgraph "存储层"
|
||||
DB[数据库]
|
||||
Cache[缓存]
|
||||
end
|
||||
Netty --> Processor
|
||||
Processor --> Router
|
||||
Router --> Executor
|
||||
Executor --> AsyncPool
|
||||
AsyncPool --> Future
|
||||
Future --> DB
|
||||
Future --> Cache
|
||||
```
|
||||
|
||||
### 内存优化策略
|
||||
|
||||
系统实现了多层次的内存优化:
|
||||
|
||||
| 优化层级 | 策略 | 效果 |
|
||||
|------|---------------|---------|
|
||||
| 对象池 | ByteBuf复用 | 减少GC压力 |
|
||||
| 缓存 | Caffeine本地缓存 | 提升访问速度 |
|
||||
| 序列化 | Protobuf二进制格式 | 减少序列化开销 |
|
||||
| 批量 | 批量操作 | 减少网络往返 |
|
||||
|
||||
### 并发控制机制
|
||||
|
||||
系统采用多种并发控制策略:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Request[请求到达] --> Lock{获取锁}
|
||||
Lock --> |成功| Process[处理请求]
|
||||
Lock --> |失败| Queue[加入队列]
|
||||
Process --> Release[释放锁]
|
||||
Queue --> Wait[等待执行]
|
||||
Wait --> Process
|
||||
Release --> Complete[完成处理]
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
云快充协议上行消息处理系统是一个高度优化的分布式消息处理框架,具有以下核心优势:
|
||||
|
||||
### 技术亮点
|
||||
|
||||
1. **模块化设计**:通过注解驱动的命令路由实现高度可扩展的架构
|
||||
2. **高性能处理**:基于Netty的异步I/O和批量处理策略
|
||||
3. **强一致性**:通过事务性和批量操作保证数据一致性
|
||||
4. **可观测性**:完善的日志记录和监控指标体系
|
||||
|
||||
### 业务价值
|
||||
|
||||
1. **实时响应**:毫秒级的消息处理延迟
|
||||
2. **高可靠性**:多重校验和容错机制
|
||||
3. **可扩展性**:支持多种协议版本和未来扩展
|
||||
4. **运维友好**:清晰的日志和监控界面
|
||||
|
||||
### 应用场景
|
||||
|
||||
该系统适用于大规模充电桩管理平台,能够处理数万甚至数十万充电桩的并发消息处理需求,为电动车充电服务提供稳定可靠的技术支撑。
|
||||
475
docs/核心模块详解/协议实现模块/云快充协议实现/下行消息处理.md
Normal file
475
docs/核心模块详解/协议实现模块/云快充协议实现/下行消息处理.md
Normal file
@@ -0,0 +1,475 @@
|
||||
# 云快充协议下行消息处理链路
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [DownlinkController.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java)
|
||||
- [DownlinkGrpcService.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkGrpcService.java)
|
||||
- [YunKuaiChongDownlinkCmdExe.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongDownlinkCmdExe.java)
|
||||
- [YunKuaiChongDownlinkCmdConverter.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/mapping/YunKuaiChongDownlinkCmdConverter.java)
|
||||
- [YunKuaiChongV150RemoteStartDLCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150RemoteStartDLCmd.java)
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java)
|
||||
- [AbstractYunKuaiChongCmdExe.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/AbstractYunKuaiChongCmdExe.java)
|
||||
- [ProtocolSession.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/ProtocolSession.java)
|
||||
- [TcpChannelHandler.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpChannelHandler.java)
|
||||
- [DownlinkCmdEnum.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/DownlinkCmdEnum.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [概述](#概述)
|
||||
2. [系统架构](#系统架构)
|
||||
3. [外部接口层](#外部接口层)
|
||||
4. [协议处理层](#协议处理层)
|
||||
5. [命令转换层](#命令转换层)
|
||||
6. [消息构建层](#消息构建层)
|
||||
7. [传输层](#传输层)
|
||||
8. [错误处理与超时机制](#错误处理与超时机制)
|
||||
9. [完整时序图](#完整时序图)
|
||||
10. [总结](#总结)
|
||||
|
||||
## 概述
|
||||
|
||||
云快充协议下行消息处理链路是一个完整的从外部系统发起控制请求到最终发送到充电桩设备的处理流程。该系统支持两种主要的外部接口:REST
|
||||
API 和 gRPC 服务,通过统一的协议处理框架实现对云快充协议的下行指令处理。
|
||||
|
||||
## 系统架构
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "外部接口层"
|
||||
REST[REST API<br/>DownlinkController]
|
||||
GRPC[gRPC服务<br/>DownlinkGrpcService]
|
||||
end
|
||||
subgraph "协议处理层"
|
||||
PMM[协议消息处理器<br/>YunKuaiChongProtocolMessageProcessor]
|
||||
DCC[命令转换器<br/>YunKuaiChongDownlinkCmdConverter]
|
||||
DCE[命令执行器基类<br/>AbstractYunKuaiChongCmdExe]
|
||||
end
|
||||
subgraph "命令执行层"
|
||||
RS[远程启动命令<br/>YunKuaiChongV150RemoteStartDLCmd]
|
||||
SS[停止充电命令<br/>YunKuaiChongV150RemoteStopDLCmd]
|
||||
TS[时间同步命令<br/>YunKuaiChongV150TimeSyncDLCmd]
|
||||
end
|
||||
subgraph "传输层"
|
||||
PS[协议会话<br/>ProtocolSession]
|
||||
TC[TCP通道处理器<br/>TcpChannelHandler]
|
||||
CH[通道<br/>Channel]
|
||||
end
|
||||
REST --> PMM
|
||||
GRPC --> PMM
|
||||
PMM --> DCC
|
||||
PMM --> DCE
|
||||
DCE --> RS
|
||||
DCE --> SS
|
||||
DCE --> TS
|
||||
RS --> PS
|
||||
PS --> TC
|
||||
TC --> CH
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [DownlinkController.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java#L1-L76)
|
||||
- [DownlinkGrpcService.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkGrpcService.java#L1-L185)
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L1-L204)
|
||||
|
||||
## 外部接口层
|
||||
|
||||
### REST API 接口
|
||||
|
||||
REST API 提供了一个标准的 HTTP 接口,通过 `/api/onDownlink` 端点接收下行控制请求。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as 外部客户端
|
||||
participant Controller as DownlinkController
|
||||
participant Registry as SessionRegistry
|
||||
participant Session as ProtocolSession
|
||||
Client->>Controller : POST /api/onDownlink<br/>protobuf消息
|
||||
Controller->>Controller : 解析消息获取sessionId
|
||||
Controller->>Registry : 获取ProtocolSession
|
||||
Registry-->>Controller : 返回session或null
|
||||
alt session存在
|
||||
Controller->>Session : onDownlink(downlinkMsg)
|
||||
Session-->>Controller : 处理完成
|
||||
Controller-->>Client : 200 OK
|
||||
else session不存在
|
||||
Controller-->>Client : 404 Not Found
|
||||
end
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [DownlinkController.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java#L37-L75)
|
||||
|
||||
### gRPC 服务接口
|
||||
|
||||
gRPC 服务提供了高性能的双向流式通信接口,支持实时的下行控制请求处理。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as gRPC客户端
|
||||
participant Service as DownlinkGrpcService
|
||||
participant Registry as SessionRegistry
|
||||
participant Session as ProtocolSession
|
||||
Client->>Service : onDownlink(stream)<br/>连接请求
|
||||
Service->>Service : 建立连接状态
|
||||
Client->>Service : onDownlink(stream)<br/>下行请求
|
||||
Service->>Service : 解析消息获取sessionId
|
||||
Service->>Registry : 获取ProtocolSession
|
||||
Registry-->>Service : 返回session或null
|
||||
alt session存在
|
||||
Service->>Session : onDownlink(downlinkMsg)
|
||||
Session-->>Service : 处理完成
|
||||
Service-->>Client : 响应确认
|
||||
else session不存在
|
||||
Service-->>Client : 记录日志
|
||||
end
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [DownlinkGrpcService.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkGrpcService.java#L123-L184)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [DownlinkController.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java#L1-L76)
|
||||
- [DownlinkGrpcService.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkGrpcService.java#L1-L185)
|
||||
|
||||
## 协议处理层
|
||||
|
||||
### 协议消息处理器
|
||||
|
||||
协议消息处理器负责接收来自外部接口的下行请求,并将其转换为内部的消息格式进行处理。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([接收下行请求]) --> ParseMsg["解析DownlinkRequestMessage"]
|
||||
ParseMsg --> ConvertCmd["转换命令类型"]
|
||||
ConvertCmd --> CheckSupport{"命令是否支持?"}
|
||||
CheckSupport --> |否| LogWarn["记录警告日志"]
|
||||
CheckSupport --> |是| CreateMsg["创建YunKuaiChongDwonlinkMessage"]
|
||||
CreateMsg --> GetExecutor["获取命令执行器"]
|
||||
GetExecutor --> ExecutorExists{"执行器是否存在?"}
|
||||
ExecutorExists --> |否| LogInfo["记录未知指令日志"]
|
||||
ExecutorExists --> |是| ExecuteCmd["执行命令"]
|
||||
ExecuteCmd --> End([处理完成])
|
||||
LogWarn --> End
|
||||
LogInfo --> End
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L140-L202)
|
||||
|
||||
### 命令枚举定义
|
||||
|
||||
系统定义了完整的下行命令枚举,涵盖了所有支持的云快充协议指令。
|
||||
|
||||
| 命令类型 | 描述 | 协议支持 |
|
||||
|----------------------------|---------|-------|
|
||||
| LOGIN_ACK | 登录应答 | 全版本 |
|
||||
| HEARTBEAT_ACK | 心跳应答 | 全版本 |
|
||||
| SET_PRICING | 设置定价模型 | V1.5+ |
|
||||
| REMOTE_START_CHARGING | 远程启动充电 | V1.5+ |
|
||||
| REMOTE_STOP_CHARGING | 远程停止充电 | V1.5+ |
|
||||
| TRANSACTION_RECORD_ACK | 交易记录确认 | V1.5+ |
|
||||
| SYNC_TIME_REQUEST | 同步时间请求 | V1.5+ |
|
||||
| OFFLINE_CARD_QUERY_REQUEST | 离线卡查询请求 | V1.5+ |
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L1-L204)
|
||||
- [DownlinkCmdEnum.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/DownlinkCmdEnum.java#L1-L55)
|
||||
|
||||
## 命令转换层
|
||||
|
||||
### 命令转换器
|
||||
|
||||
命令转换器负责将通用的 `DownlinkCmdEnum` 转换为云快充协议特定的命令码。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class DownlinkCmdConverter {
|
||||
<<interface>>
|
||||
+convertToCmd(DownlinkCmdEnum) Integer
|
||||
+supports(DownlinkCmdEnum) boolean
|
||||
+getProtocolName() String
|
||||
}
|
||||
class YunKuaiChongDownlinkCmdConverter {
|
||||
-COMMAND_MAP Map~DownlinkCmdEnum,Integer~
|
||||
-INSTANCE YunKuaiChongDownlinkCmdConverter
|
||||
+getInstance() YunKuaiChongDownlinkCmdConverter
|
||||
+convertToCmd(DownlinkCmdEnum) Integer
|
||||
+getProtocolName() String
|
||||
}
|
||||
DownlinkCmdConverter <|-- YunKuaiChongDownlinkCmdConverter
|
||||
note for YunKuaiChongDownlinkCmdConverter "单例模式,使用ConcurrentHashMap存储转换关系\n提供O(1)查找性能"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunKuaiChongDownlinkCmdConverter.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/mapping/YunKuaiChongDownlinkCmdConverter.java#L1-L89)
|
||||
|
||||
### 转换映射表
|
||||
|
||||
以下是部分关键命令的转换映射:
|
||||
|
||||
| 通用命令 | 云快充协议命令码 | 功能描述 |
|
||||
|------------------------|----------|--------|
|
||||
| REMOTE_START_CHARGING | 0x34 | 远程启动充电 |
|
||||
| REMOTE_STOP_CHARGING | 0x36 | 远程停止充电 |
|
||||
| SET_PRICING | 0x58 | 设置定价模型 |
|
||||
| SYNC_TIME_REQUEST | 0x56 | 同步时间请求 |
|
||||
| TRANSACTION_RECORD_ACK | 0x40 | 交易记录确认 |
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunKuaiChongDownlinkCmdConverter.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/mapping/YunKuaiChongDownlinkCmdConverter.java#L1-L89)
|
||||
|
||||
## 消息构建层
|
||||
|
||||
### 命令执行器基类
|
||||
|
||||
抽象命令执行器基类提供了消息编码和发送的核心功能。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class AbstractYunKuaiChongCmdExe {
|
||||
-DOWNLINK_CMD_CONVERTER DownlinkCmdConverter
|
||||
+encode(int, int, int, ByteBuf) byte[]
|
||||
+encodeAndWriteFlush(int, int, int, ByteBuf, TcpSession) void
|
||||
+encodeAndWriteFlush(int, ByteBuf, TcpSession) void
|
||||
+encodeAndWriteFlush(DownlinkCmdEnum, int, int, ByteBuf, TcpSession) void
|
||||
+encodeAndWriteFlush(DownlinkCmdEnum, ByteBuf, TcpSession) void
|
||||
+encodePileCode(String) byte[]
|
||||
+encodeGunCode(String) byte[]
|
||||
+encodeTradeNo(String) byte[]
|
||||
+encodeLogicalCardNo(String) byte[]
|
||||
+encodePhysicalCardNo(String) long
|
||||
}
|
||||
class YunKuaiChongV150RemoteStartDLCmd {
|
||||
+execute(TcpSession, YunKuaiChongDwonlinkMessage, ProtocolContext) void
|
||||
}
|
||||
AbstractYunKuaiChongCmdExe <|-- YunKuaiChongV150RemoteStartDLCmd
|
||||
note for AbstractYunKuaiChongCmdExe "提供协议特定的消息编码功能\n包括BCD编码、CRC校验等"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [AbstractYunKuaiChongCmdExe.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/AbstractYunKuaiChongCmdExe.java#L1-L310)
|
||||
|
||||
### 远程启动命令实现
|
||||
|
||||
以远程启动充电命令为例,展示具体的命令处理流程。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Cmd as YunKuaiChongV150RemoteStartDLCmd
|
||||
participant Base as AbstractYunKuaiChongCmdExe
|
||||
participant Session as TcpSession
|
||||
participant Channel as Netty Channel
|
||||
Cmd->>Cmd : 解析请求参数
|
||||
Note over Cmd : pileCode, gunCode, tradeNo<br/>logicalCardNo, physicalCardNo<br/>limitYuan
|
||||
Cmd->>Cmd : 创建ByteBuf
|
||||
Cmd->>Cmd : 写入交易流水号(32字节BCD)
|
||||
Cmd->>Cmd : 写入桩编码(14字节BCD)
|
||||
Cmd->>Cmd : 写入枪号(2字节BCD)
|
||||
Cmd->>Cmd : 写入逻辑卡号(16字节BCD)
|
||||
Cmd->>Cmd : 写入物理卡号(8字节LE Long)
|
||||
Cmd->>Cmd : 写入账户余额(4字节LE Int)
|
||||
Cmd->>Base : encodeAndWriteFlush(cmd, msgBody, session)
|
||||
Base->>Base : encode(cmd, seqNo, flag, msgBody)
|
||||
Note over Base : 添加协议头、长度、序列号<br/>加密标志、命令字、数据域<br/>计算CRC校验和
|
||||
Base->>Session : writeAndFlush(encodedMessage)
|
||||
Session->>Channel : 发送到网络
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunKuaiChongV150RemoteStartDLCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150RemoteStartDLCmd.java#L1-L72)
|
||||
- [AbstractYunKuaiChongCmdExe.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/AbstractYunKuaiChongCmdExe.java#L180-L220)
|
||||
|
||||
### 协议消息格式
|
||||
|
||||
云快充协议的下行消息格式如下:
|
||||
|
||||
| 字段 | 长度 | 描述 |
|
||||
|------|-----|-----------------|
|
||||
| 帧头 | 1字节 | 固定值 0x68 |
|
||||
| 数据长度 | 1字节 | 包含后续所有字段的长度 |
|
||||
| 序列号 | 2字节 | LE格式,自动递增 |
|
||||
| 加密标志 | 1字节 | 0表示正常加密 |
|
||||
| 命令字 | 1字节 | 下行命令类型 |
|
||||
| 数据域 | 可变 | 具体命令的数据内容 |
|
||||
| 校验和 | 2字节 | CRC校验,多项式0x180D |
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [AbstractYunKuaiChongCmdExe.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/AbstractYunKuaiChongCmdExe.java#L1-L310)
|
||||
- [YunKuaiChongV150RemoteStartDLCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150RemoteStartDLCmd.java#L1-L72)
|
||||
|
||||
## 传输层
|
||||
|
||||
### 协议会话管理
|
||||
|
||||
协议会话负责维护与充电桩设备的连接状态和消息路由。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolSession {
|
||||
<<abstract>>
|
||||
#protocolName String
|
||||
#id UUID
|
||||
#lastActivityTime LocalDateTime
|
||||
#pileCodeSet Set~String~
|
||||
#requestCache Cache~String,Object~
|
||||
+onDownlink(DownlinkRequestMessage) void
|
||||
+close(SessionCloseReason) void
|
||||
+addPileCode(String) void
|
||||
+addSchedule(String, Function) void
|
||||
}
|
||||
class TcpSession {
|
||||
-sendDownlinkConsumer Consumer~DownlinkRequestMessage~
|
||||
-writeAndFlushConsumer Consumer~ByteBuf~
|
||||
-sequenceNumber AtomicInteger
|
||||
+nextSeqNo(SequenceNumberLength) int
|
||||
+writeAndFlush(ByteBuf) void
|
||||
+onDownlink(DownlinkRequestMessage) void
|
||||
}
|
||||
ProtocolSession <|-- TcpSession
|
||||
note for TcpSession "继承自ProtocolSession<br/>提供TCP连接的下行消息发送功能"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [ProtocolSession.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/ProtocolSession.java#L1-L124)
|
||||
- [TcpChannelHandler.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpChannelHandler.java#L30-L128)
|
||||
|
||||
### TCP通道处理器
|
||||
|
||||
TCP通道处理器负责实际的网络数据传输和消息发送。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([消息发送请求]) --> CheckSession{"会话是否有效?"}
|
||||
CheckSession --> |否| LogError["记录错误日志"]
|
||||
CheckSession --> |是| EncodeMsg["编码协议消息"]
|
||||
EncodeMsg --> WriteToChannel["写入Netty Channel"]
|
||||
WriteToChannel --> CheckResult{"发送是否成功?"}
|
||||
CheckResult --> |否| LogFailure["记录发送失败"]
|
||||
CheckResult --> |是| LogSuccess["记录发送成功"]
|
||||
LogError --> End([结束])
|
||||
LogFailure --> End
|
||||
LogSuccess --> End
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [TcpChannelHandler.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpChannelHandler.java#L175-L218)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [ProtocolSession.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/ProtocolSession.java#L1-L124)
|
||||
- [TcpChannelHandler.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpChannelHandler.java#L1-L218)
|
||||
|
||||
## 错误处理与超时机制
|
||||
|
||||
### 超时处理
|
||||
|
||||
系统在多个层面实现了超时处理机制:
|
||||
|
||||
1. **HTTP超时**: REST API 默认超时时间为3秒
|
||||
2. **gRPC超时**: 连接建立和消息处理都有超时保护
|
||||
3. **消息发送超时**: TCP通道处理器记录发送时间并监控结果
|
||||
|
||||
### 错误恢复策略
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Error([发生错误]) --> CheckType{"错误类型"}
|
||||
CheckType --> |网络错误| Retry["重试机制"]
|
||||
CheckType --> |协议错误| LogError["记录错误日志"]
|
||||
CheckType --> |超时错误| TimeoutAction["超时处理"]
|
||||
Retry --> RetryCount{"重试次数检查"}
|
||||
RetryCount --> |未超限| DelayRetry["延迟重试"]
|
||||
RetryCount --> |超限| FailFast["快速失败"]
|
||||
DelayRetry --> SendAgain["重新发送"]
|
||||
SendAgain --> Success{"发送成功?"}
|
||||
Success --> |是| LogSuccess["记录成功"]
|
||||
Success --> |否| LogError
|
||||
TimeoutAction --> LogTimeout["记录超时"]
|
||||
LogError --> Cleanup["清理资源"]
|
||||
FailFast --> Cleanup
|
||||
LogSuccess --> Cleanup
|
||||
LogTimeout --> Cleanup
|
||||
Cleanup --> End([结束])
|
||||
```
|
||||
|
||||
### 异常处理机制
|
||||
|
||||
系统提供了完善的异常处理机制,包括:
|
||||
|
||||
- **DownlinkException**: 下行消息处理异常
|
||||
- **IllegalArgumentException**: 参数验证异常
|
||||
- **RuntimeException**: 通用运行时异常处理
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [DownlinkController.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java#L37-L75)
|
||||
- [DownlinkGrpcService.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkGrpcService.java#L123-L184)
|
||||
|
||||
## 完整时序图
|
||||
|
||||
以下展示了从外部系统发起远程启动充电请求到设备响应的完整时序:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as 外部客户端
|
||||
participant Controller as DownlinkController
|
||||
participant PMM as 协议消息处理器
|
||||
participant Converter as 命令转换器
|
||||
participant Executor as 命令执行器
|
||||
participant Session as 协议会话
|
||||
participant Channel as TCP通道
|
||||
participant Device as 充电桩设备
|
||||
Note over Client,Device : 远程启动充电流程
|
||||
Client->>Controller : POST /api/onDownlink<br/>RemoteStartChargingRequest
|
||||
Controller->>Controller : 解析protobuf消息
|
||||
Controller->>Session : 获取ProtocolSession
|
||||
Session-->>Controller : 返回会话对象
|
||||
Controller->>PMM : downlinkHandle(sessionToHandlerMsg)
|
||||
PMM->>Converter : convertToCmd(REMOTE_START_CHARGING)
|
||||
Converter-->>PMM : 返回命令码 0x34
|
||||
PMM->>Executor : 获取YunKuaiChongV150RemoteStartDLCmd
|
||||
Executor->>Executor : 解析请求参数
|
||||
Executor->>Executor : 构建消息体
|
||||
Note over Executor : 交易流水号+桩编码+枪号<br/>卡号+余额等信息
|
||||
Executor->>Executor : encodeAndWriteFlush(0x34, msgBody, session)
|
||||
Executor->>Session : writeAndFlush(encodedMessage)
|
||||
Session->>Channel : 发送到网络
|
||||
Channel->>Device : 传输协议消息
|
||||
Device-->>Channel : 设备响应
|
||||
Channel-->>Session : 接收响应
|
||||
Session-->>PMM : 处理上行消息
|
||||
PMM-->>Controller : 处理完成
|
||||
Controller-->>Client : 返回成功响应
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [DownlinkController.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java#L37-L75)
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L140-L202)
|
||||
- [YunKuaiChongV150RemoteStartDLCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150RemoteStartDLCmd.java#L30-L71)
|
||||
|
||||
## 总结
|
||||
|
||||
云快充协议下行消息处理链路展现了现代工业物联网系统的典型架构特点:
|
||||
|
||||
1. **分层架构**: 清晰的分层设计使得系统具有良好的可维护性和扩展性
|
||||
2. **多接口支持**: 同时支持REST API和gRPC两种接口,满足不同场景需求
|
||||
3. **协议抽象**: 通过命令转换器实现协议无关的设计
|
||||
4. **高效传输**: 基于Netty的异步非阻塞IO,确保高并发处理能力
|
||||
5. **健壮性**: 完善的错误处理和超时机制保证系统稳定性
|
||||
|
||||
该系统为云快充平台提供了可靠、高效的下行指令处理能力,支撑着大规模充电桩的远程控制需求。通过模块化的架构设计和标准化的协议处理流程,系统能够快速适配新的协议版本和功能需求。
|
||||
490
docs/核心模块详解/协议实现模块/云快充协议实现/云快充协议实现.md
Normal file
490
docs/核心模块详解/协议实现模块/云快充协议实现/云快充协议实现.md
Normal file
@@ -0,0 +1,490 @@
|
||||
# 云快充协议实现
|
||||
|
||||
<cite>
|
||||
**本文档中引用的文件**
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java)
|
||||
- [YunkuaichongV160ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v160/YunkuaichongV160ProtocolBootstrap.java)
|
||||
- [YunkuaichongV170ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v170/YunkuaichongV170ProtocolBootstrap.java)
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java)
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java)
|
||||
- [ProtocolCmd.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/annotation/ProtocolCmd.java)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java)
|
||||
- [DownlinkController.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java)
|
||||
- [YunKuaiChongDownlinkCmdExe.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongDownlinkCmdExe.java)
|
||||
- [YunKuaiChongV150HeartbeatULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150HeartbeatULCmd.java)
|
||||
- [TcpChannelHandler.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpChannelHandler.java)
|
||||
- [YunKuaiChongProtocolConstants.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolConstants.java)
|
||||
- [DownlinkCmdEnum.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/DownlinkCmdEnum.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构概览](#架构概览)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [协议版本管理](#协议版本管理)
|
||||
7. [命令处理机制](#命令处理机制)
|
||||
8. [消息编解码流程](#消息编解码流程)
|
||||
9. [性能考虑](#性能考虑)
|
||||
10. [故障排除指南](#故障排除指南)
|
||||
11. [结论](#结论)
|
||||
|
||||
## 简介
|
||||
|
||||
云快充协议是一个专为电动汽车充电站设计的通信协议实现,采用模块化架构支持多个协议版本(v150、v160、v170),提供了完整的上行和下行消息处理能力。该协议实现了基于Netty的高性能TCP通信,支持心跳检测、远程控制、参数配置等核心功能。
|
||||
|
||||
## 项目结构
|
||||
|
||||
云快充协议的项目结构遵循分层架构设计,主要包含以下模块:
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "协议API层"
|
||||
API[Protocol API]
|
||||
Bootstrap[Protocol Bootstrap]
|
||||
MessageProcessor[Message Processor]
|
||||
end
|
||||
subgraph "云快充实现层"
|
||||
V150[Version 1.5.0]
|
||||
V160[Version 1.6.0]
|
||||
V170[Version 1.7.0]
|
||||
Constants[Protocol Constants]
|
||||
end
|
||||
subgraph "命令处理层"
|
||||
UplinkCmd[Uplink Commands]
|
||||
DownlinkCmd[Downlink Commands]
|
||||
Router[Command Router]
|
||||
end
|
||||
API --> Bootstrap
|
||||
Bootstrap --> MessageProcessor
|
||||
MessageProcessor --> V150
|
||||
MessageProcessor --> V160
|
||||
MessageProcessor --> V170
|
||||
V150 --> UplinkCmd
|
||||
V150 --> DownlinkCmd
|
||||
Router --> UplinkCmd
|
||||
Router --> DownlinkCmd
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L1-L127)
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java#L1-L48)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java#L1-L48)
|
||||
- [YunkuaichongV160ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v160/YunkuaichongV160ProtocolBootstrap.java#L1-L48)
|
||||
- [YunkuaichongV170ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v170/YunkuaichongV170ProtocolBootstrap.java#L1-L49)
|
||||
|
||||
## 核心组件
|
||||
|
||||
### YunkuaichongV150ProtocolBootstrap
|
||||
|
||||
`YunkuaichongV150ProtocolBootstrap` 是云快充协议的核心入口点,负责协议的初始化和配置。它继承自 `ProtocolBootstrap`
|
||||
,实现了协议的基本生命周期管理。
|
||||
|
||||
#### 主要特性:
|
||||
|
||||
- **协议标识**:使用 `@ProtocolComponent` 注解标记协议名称
|
||||
- **消息处理器**:创建并返回 `YunKuaiChongProtocolMessageProcessor` 实例
|
||||
- **版本支持**:支持 v150、v160、v170 三个版本
|
||||
|
||||
#### 初始化流程:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Bootstrap as YunkuaichongV150ProtocolBootstrap
|
||||
participant Parent as ProtocolBootstrap
|
||||
participant Processor as MessageProcessor
|
||||
participant Listener as TCP Listener
|
||||
Bootstrap->>Parent : init()
|
||||
Parent->>Parent : loadConfig(protocolName)
|
||||
Parent->>Parent : createForwarder()
|
||||
Parent->>Listener : new TcpListener()
|
||||
Bootstrap->>Processor : new YunKuaiChongProtocolMessageProcessor()
|
||||
Processor->>Processor : initializeRouters()
|
||||
Processor-->>Bootstrap : 返回处理器实例
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java#L30-L47)
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L40-L80)
|
||||
|
||||
### YunKuaiChongProtocolMessageProcessor
|
||||
|
||||
这是协议消息处理的核心组件,负责解析原始字节流并路由到具体的命令处理器。
|
||||
|
||||
#### 核心功能:
|
||||
|
||||
- **上行消息处理**:解析TCP接收到的原始字节流
|
||||
- **下行消息处理**:处理来自REST API的下行请求
|
||||
- **命令路由**:使用 `ProtocolCommandRouter` 进行命令分发
|
||||
- **校验和验证**:支持多种校验和算法
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java#L30-L47)
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L1-L204)
|
||||
|
||||
## 架构概览
|
||||
|
||||
云快充协议采用分层架构,从底层的网络通信到高层的业务逻辑处理:
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "应用层"
|
||||
REST[REST API Controller]
|
||||
GRPC[gRPC Service]
|
||||
end
|
||||
subgraph "协议层"
|
||||
Bootstrap[Protocol Bootstrap]
|
||||
MessageProcessor[Message Processor]
|
||||
Router[Command Router]
|
||||
end
|
||||
subgraph "传输层"
|
||||
TCP[TCP Listener]
|
||||
ChannelHandler[TCP Channel Handler]
|
||||
end
|
||||
subgraph "网络层"
|
||||
Netty[Netty Framework]
|
||||
Codec[Message Codec]
|
||||
end
|
||||
REST --> Bootstrap
|
||||
GRPC --> Bootstrap
|
||||
Bootstrap --> MessageProcessor
|
||||
MessageProcessor --> Router
|
||||
Router --> ChannelHandler
|
||||
ChannelHandler --> TCP
|
||||
TCP --> Netty
|
||||
Netty --> Codec
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [DownlinkController.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java#L1-L76)
|
||||
- [TcpChannelHandler.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpChannelHandler.java#L1-L234)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### 协议命令注解系统
|
||||
|
||||
`@ProtocolCmd` 注解是云快充协议命令映射的核心机制:
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolCmd {
|
||||
+int value()
|
||||
+String[] protocolNames()
|
||||
}
|
||||
class YunKuaiChongV150HeartbeatULCmd {
|
||||
+execute(TcpSession, YunKuaiChongUplinkMessage, ProtocolContext)
|
||||
}
|
||||
class ProtocolCommandRouter {
|
||||
-Map~String,T~ executorMap
|
||||
+getExecutor(String, int) T
|
||||
+registerExecutor(Class)
|
||||
}
|
||||
ProtocolCmd --> YunKuaiChongV150HeartbeatULCmd : "注解"
|
||||
ProtocolCommandRouter --> YunKuaiChongV150HeartbeatULCmd : "路由"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [ProtocolCmd.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/annotation/ProtocolCmd.java#L1-L33)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java#L1-L105)
|
||||
- [YunKuaiChongV150HeartbeatULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150HeartbeatULCmd.java#L1-L85)
|
||||
|
||||
#### 注解机制工作原理:
|
||||
|
||||
1. **扫描阶段**:`ProtocolCommandRouter` 使用反射扫描带有 `@ProtocolCmd` 注解的类
|
||||
2. **注册阶段**:将命令字与执行器类建立映射关系
|
||||
3. **路由阶段**:根据协议名称和命令字查找对应的执行器
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [ProtocolCmd.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/annotation/ProtocolCmd.java#L1-L33)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java#L40-L80)
|
||||
|
||||
### 上行命令处理流程
|
||||
|
||||
上行命令处理是协议的核心功能之一,负责解析设备发送的消息:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([接收TCP消息]) --> ValidateHeader["验证协议头<br/>0x68开头"]
|
||||
ValidateHeader --> ParseLength["解析数据长度字段"]
|
||||
ParseLength --> ValidateBounds["边界检查<br/>确保消息完整"]
|
||||
ValidateBounds --> ExtractFields["提取关键字段<br/>序列号、加密标志、帧类型"]
|
||||
ExtractFields --> ChecksumValidation["校验和验证<br/>支持LE和BE两种格式"]
|
||||
ChecksumValidation --> Success{"校验成功?"}
|
||||
Success --> |否| LogError["记录错误日志"]
|
||||
Success --> |是| ParseBody["解析消息体"]
|
||||
ParseBody --> RouteCommand["路由到命令处理器"]
|
||||
RouteCommand --> ExecuteCmd["执行具体命令"]
|
||||
ExecuteCmd --> End([处理完成])
|
||||
LogError --> End
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L50-L150)
|
||||
|
||||
### 下行命令处理流程
|
||||
|
||||
下行命令处理负责响应REST API请求,向设备发送控制指令:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Controller as DownlinkController
|
||||
participant Session as TcpSession
|
||||
participant Processor as MessageProcessor
|
||||
participant Router as CommandRouter
|
||||
participant Executor as CmdExecutor
|
||||
participant Channel as TCP Channel
|
||||
Controller->>Session : 查找会话
|
||||
Session->>Processor : onDownlink(downlinkMsg)
|
||||
Processor->>Processor : convertToCmd(downlinkCmd)
|
||||
Processor->>Router : getExecutor(protocolName, cmd)
|
||||
Router-->>Processor : 返回执行器
|
||||
Processor->>Executor : execute(session, message, context)
|
||||
Executor->>Executor : encodeAndWriteFlush()
|
||||
Executor->>Channel : 写入TCP缓冲区
|
||||
Channel-->>Controller : 返回响应
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [DownlinkController.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java#L40-L75)
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L150-L204)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [DownlinkController.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java#L40-L75)
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L150-L204)
|
||||
|
||||
## 协议版本管理
|
||||
|
||||
云快充协议支持多个版本,每个版本都有自己的 `ProtocolBootstrap` 实现:
|
||||
|
||||
### 版本差异对比
|
||||
|
||||
| 功能特性 | v150 | v160 | v170 |
|
||||
|------|----------|--------|--------|
|
||||
| 基础协议 | ✓ | ✓ | ✓ |
|
||||
| 并行启动 | ✗ | ✓ | ✓ |
|
||||
| 新增命令 | 心跳、登录、对时 | 并行启动命令 | 交易记录命令 |
|
||||
| 向后兼容 | ✓ | ✓ | ✓ |
|
||||
|
||||
### 版本兼容性策略
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph "版本兼容性"
|
||||
V150[v1.5.0]
|
||||
V160[v1.6.0]
|
||||
V170[v1.7.0]
|
||||
end
|
||||
subgraph "共享组件"
|
||||
Common[公共命令集]
|
||||
Router[统一路由]
|
||||
Processor[通用处理器]
|
||||
end
|
||||
V150 --> Common
|
||||
V160 --> Common
|
||||
V170 --> Common
|
||||
Common --> Router
|
||||
Router --> Processor
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java#L20-L25)
|
||||
- [YunkuaichongV160ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v160/YunkuaichongV160ProtocolBootstrap.java#L20-L25)
|
||||
- [YunkuaichongV170ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v170/YunkuaichongV170ProtocolBootstrap.java#L20-L25)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java#L20-L25)
|
||||
- [YunkuaichongV160ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v160/YunkuaichongV160ProtocolBootstrap.java#L20-L25)
|
||||
- [YunkuaichongV170ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v170/YunkuaichongV170ProtocolBootstrap.java#L20-L25)
|
||||
|
||||
## 命令处理机制
|
||||
|
||||
### 上行命令处理
|
||||
|
||||
以心跳命令为例,展示完整的命令处理流程:
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class YunKuaiChongV150HeartbeatULCmd {
|
||||
+execute(TcpSession, YunKuaiChongUplinkMessage, ProtocolContext)
|
||||
-pingAck(TcpSession, YunKuaiChongUplinkMessage, byte[], byte)
|
||||
}
|
||||
class YunKuaiChongUplinkCmdExe {
|
||||
<<abstract>>
|
||||
+execute(TcpSession, YunKuaiChongUplinkMessage, ProtocolContext)*
|
||||
+uplinkMessageBuilder(String, TcpSession, YunKuaiChongUplinkMessage)
|
||||
+encodeAndWriteFlush(DownlinkCmdEnum, int, int, ByteBuf, TcpSession)
|
||||
}
|
||||
class YunKuaiChongUplinkMessage {
|
||||
+int getCmd()
|
||||
+byte[] getMsgBody()
|
||||
+int getSequenceNumber()
|
||||
+int getEncryptionFlag()
|
||||
}
|
||||
YunKuaiChongUplinkCmdExe <|-- YunKuaiChongV150HeartbeatULCmd
|
||||
YunKuaiChongV150HeartbeatULCmd --> YunKuaiChongUplinkMessage : "使用"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunKuaiChongV150HeartbeatULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150HeartbeatULCmd.java#L25-L85)
|
||||
|
||||
### 下行命令处理
|
||||
|
||||
下行命令处理涉及REST API调用到设备响应的完整流程:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
RESTReq[REST请求] --> Controller[DownlinkController]
|
||||
Controller --> Session[查找TCP会话]
|
||||
Session --> MsgProc[MessageProcessor]
|
||||
MsgProc --> Converter[命令转换器]
|
||||
Converter --> Router[CommandRouter]
|
||||
Router --> Executor[命令执行器]
|
||||
Executor --> Encoder[消息编码]
|
||||
Encoder --> TCP[发送到设备]
|
||||
Controller --> Success[HTTP 200]
|
||||
Controller --> Timeout[HTTP 408]
|
||||
Controller --> NotFound[HTTP 404]
|
||||
Controller --> Error[HTTP 500]
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [DownlinkController.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java#L40-L75)
|
||||
- [YunKuaiChongDownlinkCmdExe.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongDownlinkCmdExe.java#L1-L19)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunKuaiChongV150HeartbeatULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150HeartbeatULCmd.java#L25-L85)
|
||||
- [DownlinkController.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java#L40-L75)
|
||||
|
||||
## 消息编解码流程
|
||||
|
||||
### TCP消息处理
|
||||
|
||||
`TcpChannelHandler` 负责Netty框架层面的消息处理:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Netty as Netty Channel
|
||||
participant Handler as TcpChannelHandler
|
||||
participant Processor as MessageProcessor
|
||||
participant Stats as Metrics
|
||||
Netty->>Handler : channelRead0(msg)
|
||||
Handler->>Handler : process(msg)
|
||||
Handler->>Processor : uplinkHandleAsync()
|
||||
Processor->>Stats : 记录统计信息
|
||||
Processor-->>Handler : 处理完成
|
||||
Handler->>Handler : writeAndFlush()
|
||||
Handler->>Netty : 写入响应
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [TcpChannelHandler.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpChannelHandler.java#L60-L120)
|
||||
|
||||
### 消息格式规范
|
||||
|
||||
云快充协议的消息格式采用固定长度头部加可变长度体的设计:
|
||||
|
||||
| 字段 | 长度 | 描述 |
|
||||
|------|-----|-----------|
|
||||
| 标识符 | 1字节 | 固定值 0x68 |
|
||||
| 数据长度 | 1字节 | 包含头部的总长度 |
|
||||
| 序列号 | 2字节 | 请求-响应配对 |
|
||||
| 加密标志 | 1字节 | 0=明文,1=加密 |
|
||||
| 帧类型 | 1字节 | 命令字 |
|
||||
| 消息体 | 可变 | 具体命令数据 |
|
||||
| 校验和 | 2字节 | CRC校验 |
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [TcpChannelHandler.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpChannelHandler.java#L60-L120)
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L50-L150)
|
||||
|
||||
## 性能考虑
|
||||
|
||||
### 异步处理机制
|
||||
|
||||
协议采用异步处理模式,避免阻塞主线程:
|
||||
|
||||
- **消息队列**:使用Netty的事件循环处理消息
|
||||
- **并发控制**:支持多线程并发处理
|
||||
- **内存优化**:使用ByteBuf进行零拷贝操作
|
||||
|
||||
### 缓存策略
|
||||
|
||||
- **命令路由缓存**:`ProtocolCommandRouter` 使用ConcurrentHashMap缓存命令映射
|
||||
- **会话管理**:TCP会话状态缓存
|
||||
- **统计信息**:实时监控指标缓存
|
||||
|
||||
### 错误处理
|
||||
|
||||
- **快速失败**:无效消息立即丢弃
|
||||
- **优雅降级**:部分功能不可用时保持核心功能
|
||||
- **日志记录**:详细的错误日志便于问题排查
|
||||
|
||||
## 故障排除指南
|
||||
|
||||
### 常见问题及解决方案
|
||||
|
||||
#### 1. 协议版本不匹配
|
||||
|
||||
**症状**:设备无法识别命令
|
||||
**解决方案**:检查协议版本配置,确保客户端和服务端版本一致
|
||||
|
||||
#### 2. 校验和错误
|
||||
|
||||
**症状**:日志显示校验失败
|
||||
**解决方案**:检查消息编码和传输过程中的数据完整性
|
||||
|
||||
#### 3. 命令路由失败
|
||||
|
||||
**症状**:未知命令错误日志
|
||||
**解决方案**:确认命令注解配置正确,检查命令处理器注册
|
||||
|
||||
#### 4. TCP连接问题
|
||||
|
||||
**症状**:连接频繁断开
|
||||
**解决方案**:检查网络稳定性,调整心跳间隔配置
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L100-L150)
|
||||
|
||||
## 结论
|
||||
|
||||
云快充协议实现展现了现代通信协议设计的最佳实践:
|
||||
|
||||
### 主要优势
|
||||
|
||||
1. **模块化设计**:清晰的分层架构便于维护和扩展
|
||||
2. **版本兼容性**:支持多版本并保持向后兼容
|
||||
3. **高性能**:基于Netty的异步处理机制
|
||||
4. **可扩展性**:灵活的命令路由机制支持新功能添加
|
||||
5. **可靠性**:完善的错误处理和监控机制
|
||||
|
||||
### 技术特色
|
||||
|
||||
- **注解驱动开发**:简化命令注册和映射
|
||||
- **统一消息处理**:标准化的消息编解码流程
|
||||
- **灵活的版本管理**:支持协议演进和向后兼容
|
||||
- **完善的监控体系**:实时性能监控和错误追踪
|
||||
|
||||
该协议为电动汽车充电站提供了稳定、高效的通信解决方案,具备良好的可维护性和扩展性,能够满足不同场景下的通信需求。
|
||||
444
docs/核心模块详解/协议实现模块/云快充协议实现/核心架构与初始化.md
Normal file
444
docs/核心模块详解/协议实现模块/云快充协议实现/核心架构与初始化.md
Normal file
@@ -0,0 +1,444 @@
|
||||
# 云快充协议核心架构与初始化
|
||||
|
||||
<cite>
|
||||
**本文档中引用的文件**
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java)
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java)
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java)
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java)
|
||||
- [ProtocolContext.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolContext.java)
|
||||
- [TcpListener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java)
|
||||
- [YunKuaiChongUplinkMessage.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongUplinkMessage.java)
|
||||
- [YunKuaiChongUplinkCmdExe.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongUplinkCmdExe.java)
|
||||
- [YunKuaiChongDownlinkCmdExe.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongDownlinkCmdExe.java)
|
||||
- [YunKuaiChongProtocolConstants.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolConstants.java)
|
||||
- [TcpCfg.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/cfg/TcpCfg.java)
|
||||
- [ProtocolCmd.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/annotation/ProtocolCmd.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [引言](#引言)
|
||||
2. [项目结构概览](#项目结构概览)
|
||||
3. [核心架构设计](#核心架构设计)
|
||||
4. [协议栈初始化流程](#协议栈初始化流程)
|
||||
5. [消息处理机制](#消息处理机制)
|
||||
6. [协议版本管理](#协议版本管理)
|
||||
7. [基础设施组件注入](#基础设施组件注入)
|
||||
8. [性能优化策略](#性能优化策略)
|
||||
9. [故障排除指南](#故障排除指南)
|
||||
10. [总结](#总结)
|
||||
|
||||
## 引言
|
||||
|
||||
云快充协议是JChargePointProtocol项目中的核心通信协议,负责电动汽车充电桩与中央管理系统之间的数据交换。本文档深入解析了云快充协议的核心架构设计,重点阐述了YunkuaichongV150ProtocolBootstrap如何继承ProtocolBootstrap并实现抽象方法,完成协议栈的初始化流程,包括TCP监听器的创建、端口配置、编解码器的注册以及会话管理器的设置。
|
||||
|
||||
## 项目结构概览
|
||||
|
||||
云快充协议采用模块化设计,主要包含以下核心模块:
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "协议层"
|
||||
Bootstrap[协议引导器]
|
||||
Processor[消息处理器]
|
||||
Constants[协议常量]
|
||||
end
|
||||
subgraph "版本管理"
|
||||
V150[V150协议]
|
||||
V160[V160协议]
|
||||
V170[V170协议]
|
||||
end
|
||||
subgraph "基础设施"
|
||||
Context[协议上下文]
|
||||
Router[命令路由器]
|
||||
Listener[TCP监听器]
|
||||
end
|
||||
Bootstrap --> Processor
|
||||
Bootstrap --> V150
|
||||
Bootstrap --> V160
|
||||
Bootstrap --> V170
|
||||
Processor --> Router
|
||||
Processor --> Context
|
||||
Bootstrap --> Listener
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java#L1-L48)
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L1-L50)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java#L1-L48)
|
||||
- [YunKuaiChongProtocolConstants.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolConstants.java#L1-L44)
|
||||
|
||||
## 核心架构设计
|
||||
|
||||
### 协议引导器层次结构
|
||||
|
||||
云快充协议采用了清晰的分层架构设计,通过继承和组合的方式实现了高度的可扩展性和可维护性:
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolBootstrap {
|
||||
<<abstract>>
|
||||
#ProtocolContext protocolContext
|
||||
#ProtocolCfg protocolCfg
|
||||
#Listener listener
|
||||
#Forwarder forwarder
|
||||
+init() void
|
||||
+destroy() void
|
||||
+health() Health
|
||||
#getProtocolName()* String
|
||||
#_init()* void
|
||||
#_destroy()* void
|
||||
#messageProcessor()* ProtocolMessageProcessor
|
||||
}
|
||||
class YunkuaichongV150ProtocolBootstrap {
|
||||
+String PROTOCOL_NAME
|
||||
+getProtocolName() String
|
||||
+_init() void
|
||||
+_destroy() void
|
||||
+messageProcessor() ProtocolMessageProcessor
|
||||
}
|
||||
class YunkuaichongV160ProtocolBootstrap {
|
||||
+String PROTOCOL_NAME
|
||||
+getProtocolName() String
|
||||
+_init() void
|
||||
+_destroy() void
|
||||
+messageProcessor() ProtocolMessageProcessor
|
||||
}
|
||||
class YunkuaichongV170ProtocolBootstrap {
|
||||
+String PROTOCOL_NAME
|
||||
+getProtocolName() String
|
||||
+_init() void
|
||||
+_destroy() void
|
||||
+messageProcessor() ProtocolMessageProcessor
|
||||
}
|
||||
class YunKuaiChongProtocolMessageProcessor {
|
||||
-ProtocolCommandRouter~YunKuaiChongUplinkCmdExe~ uplinkRouter
|
||||
-ProtocolCommandRouter~YunKuaiChongDownlinkCmdExe~ downlinkRouter
|
||||
-DownlinkCmdConverter downlinkCmdConverter
|
||||
+uplinkHandle(ListenerToHandlerMsg) void
|
||||
+doDownlinkHandle(SessionToHandlerMsg) void
|
||||
-exeCmd(YunKuaiChongUplinkMessage, TcpSession) void
|
||||
-exeCmd(YunKuaiChongDwonlinkMessage, TcpSession) void
|
||||
}
|
||||
ProtocolBootstrap <|-- YunkuaichongV150ProtocolBootstrap
|
||||
ProtocolBootstrap <|-- YunkuaichongV160ProtocolBootstrap
|
||||
ProtocolBootstrap <|-- YunkuaichongV170ProtocolBootstrap
|
||||
ProtocolBootstrap --> YunKuaiChongProtocolMessageProcessor
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L25-L127)
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java#L20-L48)
|
||||
|
||||
### 消息处理架构
|
||||
|
||||
协议的消息处理采用了事件驱动的设计模式,通过命令路由器实现消息的动态路由和处理:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as 客户端设备
|
||||
participant Listener as TCP监听器
|
||||
participant Processor as 消息处理器
|
||||
participant Router as 命令路由器
|
||||
participant Executor as 命令执行器
|
||||
Client->>Listener : 发送原始字节流
|
||||
Listener->>Processor : uplinkHandle(ListenerToHandlerMsg)
|
||||
Processor->>Processor : 解析协议头
|
||||
Processor->>Processor : 校验和验证
|
||||
Processor->>Processor : 构建YunKuaiChongUplinkMessage
|
||||
Processor->>Router : getExecutor(protocolName, cmd)
|
||||
Router->>Executor : 返回对应的命令执行器
|
||||
Executor->>Executor : execute(session, message, context)
|
||||
Executor-->>Processor : 处理结果
|
||||
Processor-->>Listener : 处理完成
|
||||
Listener-->>Client : 响应消息
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L63-L120)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java#L80-L104)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L27-L61)
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L40-L80)
|
||||
|
||||
## 协议栈初始化流程
|
||||
|
||||
### Bootstrap类的生命周期管理
|
||||
|
||||
YunkuaichongV150ProtocolBootstrap作为协议栈的入口点,继承自ProtocolBootstrap并实现了三个关键的抽象方法:
|
||||
|
||||
#### onInit方法实现
|
||||
|
||||
Bootstrap类的初始化过程遵循严格的生命周期管理原则:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([启动初始化]) --> GetProtocolName["获取协议名称<br/>getProtocolName()"]
|
||||
GetProtocolName --> LoadConfig["加载协议配置<br/>protocolContext.getProtocolsConfigProvider()"]
|
||||
LoadConfig --> CheckForwarder{"检查转发器类型"}
|
||||
CheckForwarder --> |内存模式| CreateMemoryForwarder["创建内存转发器<br/>MemoryForwarder"]
|
||||
CheckForwarder --> |Kafka模式| CreateKafkaForwarder["创建Kafka转发器<br/>KafkaForwarder"]
|
||||
CreateMemoryForwarder --> LoadTcpConfig["加载TCP配置<br/>protocolCfg.getListener().getTcp()"]
|
||||
CreateKafkaForwarder --> LoadTcpConfig
|
||||
LoadTcpConfig --> CreateTcpListener["创建TCP监听器<br/>TcpListener"]
|
||||
CreateTcpListener --> CallOnInit["_init()回调"]
|
||||
CallOnInit --> CreateMessageProcessor["创建消息处理器<br/>messageProcessor()"]
|
||||
CreateMessageProcessor --> Complete([初始化完成])
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L40-L80)
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java#L25-L47)
|
||||
|
||||
#### onDestroy方法实现
|
||||
|
||||
协议栈的销毁过程同样遵循优雅关闭的原则:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始销毁]) --> LogDestroy["记录销毁日志<br/>log.info('{} destroy...', getProtocolName())"]
|
||||
LogDestroy --> CheckListener{"监听器存在?"}
|
||||
CheckListener --> |是| DestroyListener["销毁TCP监听器<br/>listener.destroy()"]
|
||||
CheckListener --> |否| CheckForwarder{"转发器存在?"}
|
||||
DestroyListener --> CheckForwarder
|
||||
CheckForwarder --> |是| DestroyForwarder["销毁转发器<br/>forwarder.destroy()"]
|
||||
CheckForwarder --> |否| CallOnDestroy["_destroy()回调"]
|
||||
DestroyForwarder --> CallOnDestroy
|
||||
CallOnDestroy --> Complete([销毁完成])
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L82-L95)
|
||||
|
||||
### TCP监听器的创建与配置
|
||||
|
||||
TCP监听器是协议栈的核心组件,负责建立和维护客户端连接:
|
||||
|
||||
#### 监听器配置参数
|
||||
|
||||
| 配置项 | 类型 | 默认值 | 描述 |
|
||||
|------------------------|---------|-----------|---------------|
|
||||
| bindAddress | String | localhost | 绑定地址 |
|
||||
| bindPort | int | 8888 | 监听端口 |
|
||||
| bossGroupThreadCount | int | 1 | Boss线程池大小 |
|
||||
| workerGroupThreadCount | int | 4 | Worker线程池大小 |
|
||||
| soBacklog | int | 100 | 连接队列长度 |
|
||||
| soKeepAlive | boolean | true | TCP保活机制 |
|
||||
| nodelay | boolean | true | TCP_NODELAY选项 |
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [TcpListener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java#L40-L70)
|
||||
- [TcpCfg.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/cfg/TcpCfg.java#L15-L46)
|
||||
|
||||
## 消息处理机制
|
||||
|
||||
### 原始字节流解析流程
|
||||
|
||||
YunKuaiChongProtocolMessageProcessor的核心职责是将接收到的原始字节流解析为结构化的消息对象:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([接收原始字节流]) --> QuickFail["快速失败检查<br/>长度 & 起始标志"]
|
||||
QuickFail --> ParseHeader["解析协议头<br/>dataLength, seqNo, encryptFlag, frameType"]
|
||||
ParseHeader --> BoundaryCheck["边界检查<br/>dataLength & 可读字节数"]
|
||||
BoundaryCheck --> FieldParse["字段快速解析<br/>序列号、加密标志、帧类型"]
|
||||
FieldParse --> ChecksumCheck["校验和验证<br/>CRC LE & BE两种模式"]
|
||||
ChecksumCheck --> BuildMessage["构建消息对象<br/>YunKuaiChongUplinkMessage"]
|
||||
BuildMessage --> RouteMessage["消息路由<br/>ProtocolCommandRouter"]
|
||||
RouteMessage --> ExecuteCmd["执行命令<br/>命令执行器"]
|
||||
ExecuteCmd --> Complete([处理完成])
|
||||
QuickFail --> |失败| DropMessage["丢弃消息"]
|
||||
BoundaryCheck --> |失败| DropMessage
|
||||
ChecksumCheck --> |失败| DropMessage
|
||||
DropMessage --> Complete
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L63-L120)
|
||||
|
||||
### 消息头信息路由机制
|
||||
|
||||
协议通过消息头中的关键字段进行智能路由:
|
||||
|
||||
| 字段 | 用途 | 路由策略 |
|
||||
|-------------------|-----------|-----------|
|
||||
| 命令码(cmd) | 指定具体操作类型 | 命令路由器精确匹配 |
|
||||
| 序列号(seqNo) | 事务跟踪和响应关联 | 保持会话状态 |
|
||||
| 加密标志(encryptFlag) | 安全级别标识 | 决定后续处理流程 |
|
||||
| 数据长度(dataLength) | 消息完整性验证 | 边界检查和解析控制 |
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L85-L120)
|
||||
|
||||
## 协议版本管理
|
||||
|
||||
### 版本兼容性策略
|
||||
|
||||
云快充协议支持多个版本的并存和演进:
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph "协议版本"
|
||||
V150[V150<br/>基础功能]
|
||||
V160[V160<br/>并行启动]
|
||||
V170[V170<br/>交易记录增强]
|
||||
end
|
||||
subgraph "版本特性"
|
||||
V150Features[登录认证<br/>心跳检测<br/>充电控制]
|
||||
V160Features[远程并行启动<br/>批量操作]
|
||||
V170Features[增强交易记录<br/>详细状态上报]
|
||||
end
|
||||
V150 --> V150Features
|
||||
V160 --> V160Features
|
||||
V170 --> V170Features
|
||||
V150 -.-> V160
|
||||
V160 -.-> V170
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunKuaiChongProtocolConstants.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolConstants.java#L20-L35)
|
||||
|
||||
### 协议常量定义
|
||||
|
||||
每个协议版本都有明确的命名规范和常量定义:
|
||||
|
||||
| 版本 | 常量名 | 协议名称 |
|
||||
|--------|-------------------|------------------|
|
||||
| v1.5.0 | YUNKUAICHONG_V150 | yunkuaichongV150 |
|
||||
| v1.6.0 | YUNKUAICHONG_V160 | yunkuaichongV160 |
|
||||
| v1.7.0 | YUNKUAICHONG_V170 | yunkuaichongV170 |
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunKuaiChongProtocolConstants.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolConstants.java#L20-L40)
|
||||
|
||||
## 基础设施组件注入
|
||||
|
||||
### ProtocolContext的作用
|
||||
|
||||
ProtocolContext作为基础设施组件的容器,负责向协议栈注入必要的服务:
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolContext {
|
||||
-StatsFactory statsFactory
|
||||
-ProtocolsConfigProvider protocolsConfigProvider
|
||||
-ProtocolSessionRegistryProvider protocolSessionRegistryProvider
|
||||
-ServiceInfoProvider serviceInfoProvider
|
||||
-PartitionProvider partitionProvider
|
||||
-AppQueueFactory appQueueFactory
|
||||
-ShardingThreadPool shardingThreadPool
|
||||
+init() void
|
||||
}
|
||||
class StatsFactory {
|
||||
+createMessagesStats() MessagesStats
|
||||
}
|
||||
class ProtocolsConfigProvider {
|
||||
+loadConfig(protocolName) ProtocolCfg
|
||||
}
|
||||
class ShardingThreadPool {
|
||||
+execute(shardingKey, runnable) void
|
||||
}
|
||||
ProtocolContext --> StatsFactory
|
||||
ProtocolContext --> ProtocolsConfigProvider
|
||||
ProtocolContext --> ShardingThreadPool
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [ProtocolContext.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolContext.java#L25-L65)
|
||||
|
||||
### 组件依赖关系
|
||||
|
||||
ProtocolContext注入的各个组件在协议栈中发挥着关键作用:
|
||||
|
||||
| 组件 | 用途 | 关键功能 |
|
||||
|-------------------------|------|-------------|
|
||||
| StatsFactory | 性能监控 | 消息统计、健康检查 |
|
||||
| ProtocolsConfigProvider | 配置管理 | 协议配置加载 |
|
||||
| ShardingThreadPool | 并发处理 | 请求分片和线程池管理 |
|
||||
| AppQueueFactory | 消息队列 | 异步消息传递 |
|
||||
| ServiceInfoProvider | 服务发现 | 微服务环境下的服务定位 |
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [ProtocolContext.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolContext.java#L35-L65)
|
||||
|
||||
## 性能优化策略
|
||||
|
||||
### 消息处理优化
|
||||
|
||||
协议栈采用了多种性能优化技术:
|
||||
|
||||
1. **异步处理**: 使用线程池处理上行消息,避免阻塞网络线程
|
||||
2. **零拷贝**: Netty框架的ByteBuf提供了高效的内存管理
|
||||
3. **批量处理**: 支持批量消息处理以提高吞吐量
|
||||
4. **缓存机制**: 命令路由器使用ConcurrentHashMap实现快速查找
|
||||
|
||||
### 内存管理优化
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([消息到达]) --> FastPath["快速路径<br/>长度检查 & 起始标志"]
|
||||
FastPath --> SliceBuffer["切片缓冲区<br/>避免数据复制"]
|
||||
SliceBuffer --> PoolAllocation["池化分配<br/>减少GC压力"]
|
||||
PoolAllocation --> AsyncProcess["异步处理<br/>非阻塞"]
|
||||
AsyncProcess --> ReleaseBuffer["释放缓冲区<br/>及时回收"]
|
||||
ReleaseBuffer --> Complete([处理完成])
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L63-L120)
|
||||
|
||||
## 故障排除指南
|
||||
|
||||
### 常见问题诊断
|
||||
|
||||
1. **连接失败**: 检查TCP监听器配置和防火墙设置
|
||||
2. **消息解析错误**: 验证协议版本兼容性和消息格式
|
||||
3. **性能问题**: 监控线程池使用率和内存分配情况
|
||||
4. **路由失败**: 检查命令执行器的注册状态
|
||||
|
||||
### 日志分析要点
|
||||
|
||||
协议栈提供了详细的日志记录,便于问题诊断:
|
||||
|
||||
- **连接日志**: 记录客户端连接和断开事件
|
||||
- **消息日志**: 记录消息解析和处理过程
|
||||
- **错误日志**: 记录异常情况和失败原因
|
||||
- **性能日志**: 记录处理时间和资源使用情况
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L100-L120)
|
||||
|
||||
## 总结
|
||||
|
||||
云快充协议的核心架构设计体现了现代分布式系统的设计理念:
|
||||
|
||||
1. **模块化设计**: 清晰的分层架构和职责分离
|
||||
2. **可扩展性**: 支持多版本协议并存和演进
|
||||
3. **高性能**: 异步处理和零拷贝优化
|
||||
4. **可靠性**: 完善的错误处理和恢复机制
|
||||
5. **可观测性**: 全面的日志记录和监控指标
|
||||
|
||||
通过YunkuaichongV150ProtocolBootstrap的实现,我们看到了一个典型的协议引导器应该具备的功能:协议栈的初始化、资源管理和生命周期控制。而YunKuaiChongProtocolMessageProcessor则展示了如何高效地处理复杂的协议消息,通过智能路由和优化的解析算法实现高性能的消息处理。
|
||||
|
||||
这种设计不仅满足了当前的业务需求,也为未来的功能扩展和性能优化奠定了坚实的基础。
|
||||
289
docs/核心模块详解/协议实现模块/协议实现模块.md
Normal file
289
docs/核心模块详解/协议实现模块/协议实现模块.md
Normal file
@@ -0,0 +1,289 @@
|
||||
# 协议实现模块
|
||||
|
||||
<cite>
|
||||
**本文档中引用的文件**
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java)
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java)
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java)
|
||||
- [ProtocolCmd.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/annotation/ProtocolCmd.java)
|
||||
- [ProtocolSession.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/ProtocolSession.java)
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java)
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml)
|
||||
- [YunKuaiChongV150HeartbeatULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150HeartbeatULCmd.java)
|
||||
- [DefaultProtocolsConfigProvider.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/provider/impl/DefaultProtocolsConfigProvider.java)
|
||||
- [ProtocolContext.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolContext.java)
|
||||
- [DownlinkCmdEnum.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/DownlinkCmdEnum.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [引言](#引言)
|
||||
2. [协议引导类实现](#协议引导类实现)
|
||||
3. [上行命令处理器设计](#上行命令处理器设计)
|
||||
4. [下行指令生成与发送](#下行指令生成与发送)
|
||||
5. [新协议开发指南](#新协议开发指南)
|
||||
6. [协议版本管理策略](#协议版本管理策略)
|
||||
7. [配置文件详解](#配置文件详解)
|
||||
|
||||
## 引言
|
||||
|
||||
本文档旨在为协议实现模块提供详细的开发指南,重点介绍如何基于现有框架扩展新的协议处理功能。通过分析云快充(YunKuaiChong)和绿能(Lvneng)两个具体实现,本文将阐述协议引导类的继承与实现机制、上行命令处理器的设计模式、下行指令的生成与发送流程,并提供新协议开发的分步指南。此外,还将讨论协议版本管理的最佳实践。
|
||||
|
||||
## 协议引导类实现
|
||||
|
||||
本文档分析了云快充和绿能两种协议的引导类实现,它们都继承自`ProtocolBootstrap`抽象类。该基类提供了协议服务初始化、健康检查和资源销毁的通用框架。
|
||||
`YunkuaichongV150ProtocolBootstrap`和`LvnengV340ProtocolBootstrap`通过重写抽象方法,实现了特定于各自协议的初始化配置。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolBootstrap {
|
||||
<<abstract>>
|
||||
+ProtocolContext protocolContext
|
||||
+ProtocolCfg protocolCfg
|
||||
+Listener listener
|
||||
+Forwarder forwarder
|
||||
+init() void
|
||||
+destroy() void
|
||||
+health() Health
|
||||
+getProtocolName() String
|
||||
+_init() void
|
||||
+_destroy() void
|
||||
+messageProcessor() ProtocolMessageProcessor
|
||||
}
|
||||
class YunkuaichongV150ProtocolBootstrap {
|
||||
+PROTOCOL_NAME String
|
||||
+getProtocolName() String
|
||||
+_init() void
|
||||
+_destroy() void
|
||||
+messageProcessor() ProtocolMessageProcessor
|
||||
}
|
||||
class LvnengV340ProtocolBootstrap {
|
||||
+PROTOCOL_NAME String
|
||||
+getProtocolName() String
|
||||
+_init() void
|
||||
+_destroy() void
|
||||
+messageProcessor() ProtocolMessageProcessor
|
||||
}
|
||||
ProtocolBootstrap <|-- YunkuaichongV150ProtocolBootstrap
|
||||
ProtocolBootstrap <|-- LvnengV340ProtocolBootstrap
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java)
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java)
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L1-L126)
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java#L1-L47)
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java#L1-L41)
|
||||
|
||||
### 云快充V150协议引导类
|
||||
|
||||
`YunkuaichongV150ProtocolBootstrap`是云快充1.5.0版本协议的引导类。它通过`@ProtocolComponent`
|
||||
注解注册到Spring容器中,确保在服务启动时被正确加载。该类的核心是重写`messageProcessor()`方法,返回一个
|
||||
`YunKuaiChongProtocolMessageProcessor`实例,该实例负责处理所有与云快充协议相关的消息编解码和路由。
|
||||
|
||||
### 绿能V340协议引导类
|
||||
|
||||
`LvnengV340ProtocolBootstrap`是绿能3.4.0版本协议的引导类,其结构和实现方式与云快充引导类高度相似。它同样通过
|
||||
`@ProtocolComponent`注解进行注册,并在`messageProcessor()`方法中返回一个`LvnengProtocolMessageProcessor`实例,用于处理绿能协议的特定消息。
|
||||
|
||||
## 上行命令处理器设计
|
||||
|
||||
上行命令处理器的设计采用了基于注解的命令路由模式。核心是`@ProtocolCmd`注解,它将一个命令类与特定的命令字(value)和协议名称(protocolNames)关联起来。
|
||||
`ProtocolCommandRouter`负责在应用启动时扫描所有带有`@ProtocolCmd`注解的类,并构建一个从协议名+命令字到处理器实例的映射表。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant 设备 as 充电桩设备
|
||||
participant TcpListener as TcpListener
|
||||
participant ProtocolCommandRouter as ProtocolCommandRouter
|
||||
participant 处理器 as YunKuaiChongV150HeartbeatULCmd
|
||||
设备->>TcpListener : 发送心跳包 (0x03)
|
||||
TcpListener->>ProtocolCommandRouter : 根据协议名和命令字查找处理器
|
||||
ProtocolCommandRouter-->>TcpListener : 返回处理器实例
|
||||
TcpListener->>处理器 : 调用execute方法
|
||||
处理器->>处理器 : 解析消息体,提取桩编码、枪号等信息
|
||||
处理器->>处理器 : 刷新会话状态
|
||||
处理器->>Kafka : 将心跳数据转发到后端
|
||||
处理器->>设备 : 发送心跳响应
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [ProtocolCmd.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/annotation/ProtocolCmd.java)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java)
|
||||
- [YunKuaiChongV150HeartbeatULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150HeartbeatULCmd.java)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [ProtocolCmd.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/annotation/ProtocolCmd.java#L1-L32)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java#L1-L104)
|
||||
- [YunKuaiChongV150HeartbeatULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150HeartbeatULCmd.java#L1-L84)
|
||||
|
||||
### @ProtocolCmd注解详解
|
||||
|
||||
`@ProtocolCmd`注解是命令路由机制的核心。其`value`属性定义了命令的唯一标识(如0x03代表心跳),`protocolNames`
|
||||
属性则指定了该命令适用于哪些协议版本。例如,`YunKuaiChongV150HeartbeatULCmd`的`protocolNames`
|
||||
包含了V150、V160和V170,表明该处理器可以处理这三个版本的心跳包。
|
||||
|
||||
### 心跳包处理器示例
|
||||
|
||||
`YunKuaiChongV150HeartbeatULCmd`是一个典型的上行命令处理器。当设备发送心跳包时,`ProtocolCommandRouter`
|
||||
会根据协议名和命令字0x03找到该处理器。`execute`方法首先解析消息体,提取桩编码、枪号等信息,然后通过
|
||||
`ProtocolSessionRegistryProvider`激活会话,最后将心跳数据封装成Protobuf消息并发送到Kafka主题,同时向设备发送一个心跳响应。
|
||||
|
||||
## 下行指令生成与发送
|
||||
|
||||
下行指令的生成与发送流程始于一个REST API调用。当后端应用需要向充电桩发送指令(如远程启动充电)时,它会调用协议服务的REST接口。该请求最终由
|
||||
`DownlinkController`接收,并通过`ProtocolSession`下发到具体的TCP连接。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant 前端 as 前端应用
|
||||
participant DownlinkController as DownlinkController
|
||||
participant ProtocolSession as ProtocolSession
|
||||
participant TcpSession as TcpSession
|
||||
participant 设备 as 充电桩设备
|
||||
前端->>DownlinkController : POST /downlink (远程启动指令)
|
||||
DownlinkController->>ProtocolSession : onDownlink(DownlinkRequestMessage)
|
||||
ProtocolSession->>TcpSession : 获取对应的TCP会话
|
||||
TcpSession->>TcpSession : 根据指令类型查找编码器
|
||||
TcpSession->>TcpSession : 编码指令为二进制流
|
||||
TcpSession->>设备 : 通过TCP连接发送指令
|
||||
设备->>TcpSession : 返回响应
|
||||
TcpSession->>ProtocolSession : 处理响应
|
||||
ProtocolSession->>DownlinkController : 返回执行结果
|
||||
DownlinkController->>前端 : 返回API响应
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [DownlinkController.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java)
|
||||
- [ProtocolSession.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/ProtocolSession.java)
|
||||
- [TcpSession.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpSession.java)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [ProtocolSession.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/ProtocolSession.java#L1-L123)
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java#L1-L77)
|
||||
- [DownlinkCmdEnum.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/DownlinkCmdEnum.java#L1-L54)
|
||||
|
||||
### 流程详解
|
||||
|
||||
1. **API调用**:前端或后端服务通过HTTP POST请求调用`/downlink`接口,请求体包含指令类型(如`REMOTE_START_CHARGING`)和相关参数。
|
||||
2. **指令接收**:`DownlinkController`接收到请求,将其转换为`DownlinkRequestMessage`对象。
|
||||
3. **会话查找**:控制器通过`ProtocolSessionRegistryProvider`根据桩编码找到对应的`ProtocolSession`。
|
||||
4. **指令下发**:`ProtocolSession`的`onDownlink`方法被调用,它会将指令委托给底层的`TcpSession`。
|
||||
5. **消息编码**:`TcpSession`根据指令类型(由`DownlinkCmdEnum`定义)查找对应的编码器,将Protobuf消息编码为协议规定的二进制格式。
|
||||
6. **网络发送**:编码后的二进制流通过Netty的`Channel`发送到充电桩设备。
|
||||
7. **响应处理**:设备返回响应后,`TcpSession`会根据响应的命令字触发相应的上行处理器进行处理。
|
||||
|
||||
## 新协议开发指南
|
||||
|
||||
开发一个新协议的实现可以遵循以下分步指南:
|
||||
|
||||
### 第一步:创建Bootstrap类
|
||||
|
||||
1. 在`jcpp-protocol-<your-protocol-name>`模块中创建一个新的包,例如`v100`。
|
||||
2. 创建一个名为`YourProtocolV100Bootstrap`的类,继承`ProtocolBootstrap`。
|
||||
3. 使用`@ProtocolComponent`注解标记该类,并传入协议的唯一名称。
|
||||
4. 重写`getProtocolName()`方法,返回协议名称常量。
|
||||
5. 重写`messageProcessor()`方法,返回一个自定义的`ProtocolMessageProcessor`实现。
|
||||
|
||||
### 第二步:定义消息处理器
|
||||
|
||||
1. 创建一个`cmd`包来存放所有命令处理器。
|
||||
2. 为每个上行命令创建一个处理器类,例如`YourProtocolV100LoginULCmd`。
|
||||
3. 让处理器类继承`AbstractProtocolUplinkCmdExe`或类似基类。
|
||||
4. 使用`@ProtocolCmd`注解标记该类,指定命令字和适用的协议名称。
|
||||
5. 重写`execute`方法,实现消息解析、业务逻辑处理和响应生成。
|
||||
|
||||
### 第三步:配置文件
|
||||
|
||||
1. 在`protocol-service.yml`文件的`service.protocols`节点下,为新协议添加一个配置项。
|
||||
2. 配置`enabled`、`listener.tcp.bind-port`和`forwarder.type`等关键参数。
|
||||
3. 确保`bind-port`不与其他协议冲突。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始]) --> CreateBootstrap["创建Bootstrap类<br/>继承ProtocolBootstrap"]
|
||||
CreateBootstrap --> Annotate["使用@ProtocolComponent注解"]
|
||||
Annotate --> OverrideMethods["重写getProtocolName<br/>和messageProcessor方法"]
|
||||
OverrideMethods --> DefineCmd["定义上行命令处理器<br/>在cmd包中"]
|
||||
DefineCmd --> AnnotateCmd["使用@ProtocolCmd注解<br/>指定命令字和协议名"]
|
||||
AnnotateCmd --> ImplementExecute["实现execute方法<br/>处理业务逻辑"]
|
||||
ImplementExecute --> Configure["在protocol-service.yml中<br/>添加协议配置"]
|
||||
Configure --> Test["测试新协议功能"]
|
||||
Test --> End([完成])
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java)
|
||||
- [YunKuaiChongV150HeartbeatULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150HeartbeatULCmd.java)
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java#L1-L47)
|
||||
- [YunKuaiChongV150HeartbeatULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150HeartbeatULCmd.java#L1-L84)
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml#L1-L273)
|
||||
|
||||
## 协议版本管理策略
|
||||
|
||||
本框架通过模块化和配置化的方式支持多协议版本管理。每个协议版本都有独立的Bootstrap类和命令处理器,这使得不同版本的协议可以并行运行而互不干扰。
|
||||
|
||||
### 策略一:独立版本模块
|
||||
|
||||
如云快充协议所示,`v150`、`v160`和`v170`分别有独立的`YunkuaichongV150ProtocolBootstrap`、
|
||||
`YunkuaichongV160ProtocolBootstrap`和`YunkuaichongV170ProtocolBootstrap`。每个版本监听不同的TCP端口(38001, 38002,
|
||||
38003),从而实现了物理隔离。
|
||||
|
||||
### 策略二:共享处理器
|
||||
|
||||
对于功能兼容的版本,可以共享部分命令处理器。例如,`YunKuaiChongV150HeartbeatULCmd`的`@ProtocolCmd`注解中`protocolNames`
|
||||
包含了V150、V160和V170,这意味着同一个处理器可以处理这三个版本的心跳包,减少了代码重复。
|
||||
|
||||
### 策略三:配置驱动
|
||||
|
||||
协议的启用、端口、转发器类型等都通过`protocol-service.yml`文件中的配置项控制。通过环境变量(如
|
||||
`PROTOCOLS_YUNKUAICHONGV150_ENABLED`)可以动态地启用或禁用某个协议版本,无需重新编译代码。
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java)
|
||||
- [YunkuaichongV160ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v160/YunkuaichongV160ProtocolBootstrap.java)
|
||||
- [YunkuaichongV170ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v170/YunkuaichongV170ProtocolBootstrap.java)
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml)
|
||||
|
||||
## 配置文件详解
|
||||
|
||||
`protocol-service.yml`是协议服务的核心配置文件,它定义了所有协议的运行参数。
|
||||
|
||||
### 协议配置结构
|
||||
|
||||
每个协议的配置都位于`service.protocols`节点下,以协议名称(如`yunkuaichongV150`)作为键。其主要包含两个子节点:
|
||||
|
||||
- **listener.tcp**: 定义TCP监听器的配置,包括`bind-address`、`bind-port`、线程池大小和连接超时等。
|
||||
- **forwarder**: 定义消息转发器的配置,包括`type`(kafka或memory)和具体的转发目标(如Kafka主题)。
|
||||
|
||||
### 环境变量注入
|
||||
|
||||
配置文件大量使用了环境变量(如`${PROTOCOLS_YUNKUAICHONGV150_LISTENER_TCP_BIND_PORT:38001}`
|
||||
),这使得服务可以在不同环境中灵活部署。冒号后的值是默认值,当环境变量未设置时使用。
|
||||
|
||||
### 拆包器配置
|
||||
|
||||
`listener.tcp.handler.configuration`是一个关键配置,它定义了Netty的拆包器。例如,云快充协议使用
|
||||
`JCPPLengthFieldBasedFrameDecoder`,并指定了帧头、长度字段偏移量等参数,确保能正确解析设备发送的二进制流。
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml#L1-L273)
|
||||
- [DefaultProtocolsConfigProvider.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/provider/impl/DefaultProtocolsConfigProvider.java#L1-L38)
|
||||
- [ProtocolCfg.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/cfg/ProtocolCfg.java#L1-L26)
|
||||
338
docs/核心模块详解/协议实现模块/绿能协议实现/下行消息处理.md
Normal file
338
docs/核心模块详解/协议实现模块/绿能协议实现/下行消息处理.md
Normal file
@@ -0,0 +1,338 @@
|
||||
# 下行消息处理
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [LvnengDownlinkCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengDownlinkCmdExe.java)
|
||||
- [LvnengDownlinkCmdConverter.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/mapping/LvnengDownlinkCmdConverter.java)
|
||||
- [LvnengV340RemoteStopDLCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopDLCmd.java)
|
||||
- [LvnengV340SetPricingModelDLCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetPricingModelDLCmd.java)
|
||||
- [AbstractLvnengCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/AbstractLvnengCmdExe.java)
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java)
|
||||
- [DefaultPileProtocolService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java)
|
||||
- [TcpSession.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpSession.java)
|
||||
- [ProtocolSession.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/ProtocolSession.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [引言](#引言)
|
||||
2. [gRPC调用接收与下行指令生成](#grpc调用接收与下行指令生成)
|
||||
3. [协议命令转换机制](#协议命令转换机制)
|
||||
4. [具体下行命令实现](#具体下行命令实现)
|
||||
5. [消息序列化过程](#消息序列化过程)
|
||||
6. [指令重试与超时处理](#指令重试与超时处理)
|
||||
7. [完整时序图与报文格式示例](#完整时序图与报文格式示例)
|
||||
8. [结论](#结论)
|
||||
|
||||
## 引言
|
||||
|
||||
本文档系统阐述了绿能协议v3.40的下行消息处理流程。重点分析了从gRPC请求到设备响应的完整处理链路,包括LvnengDownlinkCmdExe如何接收gRPC调用并生成相应的下行指令,LvnengDownlinkCmdConverter如何将通用的协议命令转换为绿能协议特有的命令码,以及具体下行命令的实现细节。同时描述了消息序列化过程、指令重试机制和超时处理策略,并提供了完整的时序图和报文格式示例。
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [LvnengDownlinkCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengDownlinkCmdExe.java)
|
||||
- [LvnengDownlinkCmdConverter.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/mapping/LvnengDownlinkCmdConverter.java)
|
||||
- [LvnengV340RemoteStopDLCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopDLCmd.java)
|
||||
- [LvnengV340SetPricingModelDLCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetPricingModelDLCmd.java)
|
||||
- [AbstractLvnengCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/AbstractLvnengCmdExe.java)
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java)
|
||||
- [DefaultPileProtocolService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java)
|
||||
- [TcpSession.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpSession.java)
|
||||
- [ProtocolSession.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/ProtocolSession.java)
|
||||
|
||||
## gRPC调用接收与下行指令生成
|
||||
|
||||
绿能协议v3.40的下行消息处理流程始于gRPC调用的接收。系统通过`DownlinkGrpcService`接收来自客户端的gRPC请求,这些请求被封装为
|
||||
`DownlinkRequestMessage`对象。当gRPC服务接收到请求时,会通过`ProtocolSession`的`onDownlink`方法将消息传递给协议处理器。
|
||||
|
||||
`LvnengProtocolMessageProcessor`作为核心处理器,负责处理所有下行消息。它通过`doDownlinkHandle`方法接收
|
||||
`SessionToHandlerMsg`对象,该对象包含了`DownlinkRequestMessage`和`TcpSession`。处理器首先从`DownlinkRequestMessage`中提取
|
||||
`downlinkCmd`字段,并通过`DownlinkCmdEnum.valueOf()`将其转换为枚举类型。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as "客户端"
|
||||
participant GrpcService as "DownlinkGrpcService"
|
||||
participant ProtocolSession as "ProtocolSession"
|
||||
participant MessageProcessor as "LvnengProtocolMessageProcessor"
|
||||
Client->>GrpcService : 发送gRPC请求(DownlinkRequestMessage)
|
||||
GrpcService->>ProtocolSession : 调用onDownlink(DownlinkRequestMessage)
|
||||
ProtocolSession->>MessageProcessor : 传递SessionToHandlerMsg
|
||||
MessageProcessor->>MessageProcessor : 解析DownlinkCmdEnum
|
||||
MessageProcessor->>MessageProcessor : 转换为协议特定命令码
|
||||
MessageProcessor->>MessageProcessor : 执行具体命令处理器
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [DownlinkGrpcService.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkGrpcService.java#L123-L151)
|
||||
- [ProtocolSession.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/ProtocolSession.java#L0-L77)
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L0-L186)
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java)
|
||||
- [DownlinkGrpcService.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkGrpcService.java)
|
||||
- [ProtocolSession.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/ProtocolSession.java)
|
||||
|
||||
## 协议命令转换机制
|
||||
|
||||
绿能协议v3.40使用`LvnengDownlinkCmdConverter`类来实现通用协议命令到绿能协议特定命令码的转换。该类实现了
|
||||
`DownlinkCmdConverter`接口,采用单例模式确保全局唯一实例。
|
||||
|
||||
转换器内部使用`ConcurrentHashMap`存储命令映射关系,提供O(1)的查找性能。在静态初始化块中,预定义了绿能协议支持的所有命令映射:
|
||||
|
||||
```java
|
||||
static {
|
||||
COMMAND_MAP.put(DownlinkCmdEnum.LOGIN_ACK, 105);
|
||||
COMMAND_MAP.put(DownlinkCmdEnum.SYNC_TIME_REQUEST, 3);
|
||||
COMMAND_MAP.put(DownlinkCmdEnum.TRANSACTION_RECORD_ACK, 201);
|
||||
COMMAND_MAP.put(DownlinkCmdEnum.HEARTBEAT_ACK, 101);
|
||||
COMMAND_MAP.put(DownlinkCmdEnum.REAL_TIME_DATA_ACK, 103);
|
||||
COMMAND_MAP.put(DownlinkCmdEnum.SET_PRICING, 1103);
|
||||
COMMAND_MAP.put(DownlinkCmdEnum.REMOTE_STOP_CHARGING, 5);
|
||||
COMMAND_MAP.put(DownlinkCmdEnum.SET_QRCODE, 3);
|
||||
}
|
||||
```
|
||||
|
||||
当需要转换命令时,`convertToCmd`方法会根据传入的`DownlinkCmdEnum`
|
||||
返回对应的协议特定命令码。如果命令不被支持,则返回null。这种设计使得命令转换过程高效且易于维护,新增命令只需在静态块中添加映射关系即可。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class DownlinkCmdConverter {
|
||||
<<interface>>
|
||||
+convertToCmd(DownlinkCmdEnum) Integer
|
||||
+supports(DownlinkCmdEnum) boolean
|
||||
+getProtocolName() String
|
||||
}
|
||||
class LvnengDownlinkCmdConverter {
|
||||
-INSTANCE LvnengDownlinkCmdConverter
|
||||
-COMMAND_MAP Map~DownlinkCmdEnum, Integer~
|
||||
+getInstance() LvnengDownlinkCmdConverter
|
||||
+convertToCmd(DownlinkCmdEnum) Integer
|
||||
+getProtocolName() String
|
||||
}
|
||||
DownlinkCmdConverter <|.. LvnengDownlinkCmdConverter
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [LvnengDownlinkCmdConverter.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/mapping/LvnengDownlinkCmdConverter.java#L0-L75)
|
||||
- [DownlinkCmdConverter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/mapping/DownlinkCmdConverter.java#L0-L44)
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [LvnengDownlinkCmdConverter.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/mapping/LvnengDownlinkCmdConverter.java)
|
||||
|
||||
## 具体下行命令实现
|
||||
|
||||
### 远程停止充电指令实现
|
||||
|
||||
`LvnengV340RemoteStopDLCmd`类负责处理远程停止充电指令。该类继承自`LvnengDownlinkCmdExe`,并使用`@ProtocolCmd`
|
||||
注解标记其支持的命令码为5,协议版本为V340。
|
||||
|
||||
在`execute`方法中,首先从`LvnengDwonlinkMessage`中提取`RemoteStopChargingRequest`对象,获取充电桩编码和充电枪号。然后构建消息体
|
||||
`ByteBuf`,按照协议规范填充数据:
|
||||
|
||||
1. 写入2字节预留字段(值为0x00)
|
||||
2. 写入1字节充电枪口编号
|
||||
3. 写入4字节启始命令地址(值为2)
|
||||
4. 写入1字节命令个数(值为1)
|
||||
5. 写入2字节命令参数长度(值为4)
|
||||
6. 写入4字节命令参数(值为0x55)
|
||||
|
||||
最后调用`encodeAndWriteFlush`方法将指令发送到设备。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始]) --> ExtractData["提取RemoteStopChargingRequest数据"]
|
||||
ExtractData --> CreateBuffer["创建44字节的ByteBuf"]
|
||||
CreateBuffer --> WriteReserved["写入2字节预留字段(0x00)"]
|
||||
WriteReserved --> WriteGunCode["写入充电枪口编号"]
|
||||
WriteGunCode --> WriteStartAddr["写入启始命令地址(2)"]
|
||||
WriteStartAddr --> WriteCmdCount["写入命令个数(1)"]
|
||||
WriteCmdCount --> WriteParamLen["写入命令参数长度(4)"]
|
||||
WriteParamLen --> WriteParam["写入命令参数(0x55)"]
|
||||
WriteParam --> Send["调用encodeAndWriteFlush发送"]
|
||||
Send --> End([结束])
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [LvnengV340RemoteStopDLCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopDLCmd.java#L0-L67)
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [LvnengV340RemoteStopDLCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopDLCmd.java)
|
||||
|
||||
### 电价设置报文实现
|
||||
|
||||
`LvnengV340SetPricingModelDLCmd`类负责生成电价设置报文。该类同样继承自`LvnengDownlinkCmdExe`,并使用`@ProtocolCmd`
|
||||
注解标记其支持的命令码为1103,协议版本为V340。
|
||||
|
||||
在`execute`方法中,首先从`SetPricingRequest`中提取计费模型信息。对于时段计价模式,遍历所有时间段,将每个时间段的开始时间、结束时间、电费和服务费编码到消息体中:
|
||||
|
||||
1. 将开始时间解析为`LocalTime`对象,分别写入小时和分钟
|
||||
2. 将结束时间解析为`LocalTime`对象,分别写入小时和分钟
|
||||
3. 将电费价格乘以10000后转换为整数,写入4字节
|
||||
4. 将服务费价格乘以10000后转换为整数,写入4字节
|
||||
|
||||
价格转换通过`buildPrice`方法实现,使用`BigDecimal`进行精确计算,避免浮点数精度问题。在发送指令前,将计费ID存入会话的请求缓存中,用于后续的响应匹配。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始]) --> ExtractData["提取SetPricingRequest数据"]
|
||||
ExtractData --> CheckPricing["检查计费模式"]
|
||||
CheckPricing --> |时段计价| ProcessPeriods["处理每个时间段"]
|
||||
ProcessPeriods --> ParseStartTime["解析开始时间"]
|
||||
ParseStartTime --> WriteStartHour["写入开始小时"]
|
||||
WriteStartHour --> WriteStartMinute["写入开始分钟"]
|
||||
WriteStartMinute --> ParseEndTime["解析结束时间"]
|
||||
ParseEndTime --> WriteEndHour["写入结束小时"]
|
||||
WriteEndHour --> WriteEndMinute["写入结束分钟"]
|
||||
WriteEndMinute --> ConvertElecPrice["转换电费价格"]
|
||||
ConvertElecPrice --> WriteElecPrice["写入4字节电费"]
|
||||
WriteElecPrice --> ConvertServPrice["转换服务费价格"]
|
||||
ConvertServPrice --> WriteServPrice["写入4字节服务费"]
|
||||
WriteServPrice --> NextPeriod{"还有更多时间段?"}
|
||||
NextPeriod --> |是| ProcessPeriods
|
||||
NextPeriod --> |否| CachePricingId["缓存计费ID"]
|
||||
CachePricingId --> Send["调用encodeAndWriteFlush发送"]
|
||||
Send --> End([结束])
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [LvnengV340SetPricingModelDLCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetPricingModelDLCmd.java#L0-L98)
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [LvnengV340SetPricingModelDLCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetPricingModelDLCmd.java)
|
||||
|
||||
## 消息序列化过程
|
||||
|
||||
绿能协议v3.40的消息序列化过程由`AbstractLvnengCmdExe`类的`encode`
|
||||
方法实现。该方法按照协议规范构建完整的下行消息帧,格式为:帧头(2) + 长度(2) + 加密标识(1) + 序号(1) + 命令字(2) + 数据域(
|
||||
n) + 校验和(1)。
|
||||
|
||||
序列化过程分为以下几个步骤:
|
||||
|
||||
1. 计算总长度:数据域长度 + 9字节固定头尾
|
||||
2. 构建消息头和数据域:依次写入帧头、长度、加密标识、序号、命令字和数据域
|
||||
3. 准备校验和计算数据:命令字 + 数据域
|
||||
4. 计算并写入校验和:使用`ByteUtil.calculateSum`方法计算累加和
|
||||
5. 转换为字节数组:使用`ByteUtil.toBytes`方法将`ByteBuf`转换为字节数组
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始]) --> CalculateLength["计算总长度 = 数据域长度 + 9"]
|
||||
CalculateLength --> BuildHeader["构建消息头"]
|
||||
BuildHeader --> WriteHead["写入帧头(0xAAF5)"]
|
||||
WriteHead --> WriteLength["写入长度(小端序)"]
|
||||
WriteLength --> WriteEncryption["写入加密标识(0x10)"]
|
||||
WriteEncryption --> WriteSeqNo["写入序号"]
|
||||
WriteSeqNo --> WriteCmd["写入命令字(小端序)"]
|
||||
WriteCmd --> WriteData["写入数据域"]
|
||||
WriteData --> PrepareSum["准备校验和数据(命令字+数据域)"]
|
||||
PrepareSum --> CalculateSum["计算累加和(ByteUtil.calculateSum)"]
|
||||
CalculateSum --> WriteSum["写入校验和"]
|
||||
WriteSum --> ConvertBytes["转换为字节数组(ByteUtil.toBytes)"]
|
||||
ConvertBytes --> End([结束])
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [AbstractLvnengCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/AbstractLvnengCmdExe.java#L30-L60)
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [AbstractLvnengCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/AbstractLvnengCmdExe.java)
|
||||
|
||||
## 指令重试与超时处理
|
||||
|
||||
绿能协议v3.40的指令重试与超时处理机制主要通过会话层的请求缓存和定时任务实现。`ProtocolSession`类维护了一个`requestCache`
|
||||
,用于存储待确认的请求。该缓存使用Caffeine构建,具有以下特性:
|
||||
|
||||
- 初始容量:1000
|
||||
- 最大容量:1000
|
||||
- 过期策略:访问后1分钟过期
|
||||
|
||||
当发送下行指令时,相关的请求ID和业务数据会被存入缓存。如果在规定时间内未收到设备的响应,缓存项将自动过期,触发重试逻辑。
|
||||
`TcpSession`类维护了一个原子整数`sequenceNumber`,用于生成消息序号,确保每条消息的唯一性。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolSession {
|
||||
-requestCache Cache~String, Object~
|
||||
+onDownlink(DownlinkRequestMessage)
|
||||
+close(SessionCloseReason)
|
||||
}
|
||||
class TcpSession {
|
||||
-sequenceNumber AtomicInteger
|
||||
+nextSeqNo(SequenceNumberLength)
|
||||
+writeAndFlush(ByteBuf)
|
||||
}
|
||||
ProtocolSession "1" -- "1" TcpSession
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [ProtocolSession.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/ProtocolSession.java#L46-L77)
|
||||
- [TcpSession.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpSession.java#L41-L98)
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [ProtocolSession.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/ProtocolSession.java)
|
||||
- [TcpSession.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpSession.java)
|
||||
|
||||
## 完整时序图与报文格式示例
|
||||
|
||||
### 完整时序图
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as "客户端"
|
||||
participant AppService as "应用服务"
|
||||
participant ProtocolService as "协议服务"
|
||||
participant ProtocolProcessor as "协议处理器"
|
||||
participant Device as "设备"
|
||||
Client->>AppService : 调用setPricing(SetPricingDTO)
|
||||
AppService->>ProtocolService : 构建DownlinkRequestMessage
|
||||
ProtocolService->>ProtocolProcessor : 发送下行消息
|
||||
ProtocolProcessor->>ProtocolProcessor : 转换命令码
|
||||
ProtocolProcessor->>ProtocolProcessor : 构建消息体
|
||||
ProtocolProcessor->>ProtocolProcessor : 序列化消息
|
||||
ProtocolProcessor->>Device : 发送报文
|
||||
Device->>ProtocolProcessor : 返回响应
|
||||
ProtocolProcessor->>ProtocolService : 处理上行消息
|
||||
ProtocolService->>AppService : 通知结果
|
||||
AppService->>Client : 返回成功
|
||||
```
|
||||
|
||||
### 报文格式示例
|
||||
|
||||
以远程停止充电指令为例,完整的报文格式如下:
|
||||
|
||||
| 字段 | 长度(字节) | 值(十六进制) | 说明 |
|
||||
|------|--------|---------------------|----------------------|
|
||||
| 帧头 | 2 | AAF5 | 固定值 |
|
||||
| 长度 | 2 | 002C | 总长度44字节 |
|
||||
| 加密标识 | 1 | 10 | 固定值 |
|
||||
| 序号 | 1 | 01 | 消息序号 |
|
||||
| 命令字 | 2 | 0005 | REMOTE_STOP_CHARGING |
|
||||
| 数据域 | 44 | 0000010200010455... | 消息体 |
|
||||
| 校验和 | 1 | XX | 累加和校验 |
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java)
|
||||
- [AbstractLvnengCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/AbstractLvnengCmdExe.java)
|
||||
- [LvnengV340RemoteStopDLCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopDLCmd.java)
|
||||
|
||||
## 结论
|
||||
|
||||
本文档详细阐述了绿能协议v3.40的下行消息处理流程。系统通过gRPC接口接收外部请求,经由`LvnengProtocolMessageProcessor`
|
||||
进行命令解析和路由,使用`LvnengDownlinkCmdConverter`将通用命令转换为协议特定命令码,并通过具体的命令执行器(如
|
||||
`LvnengV340RemoteStopDLCmd`和`LvnengV340SetPricingModelDLCmd`
|
||||
)生成相应的下行指令。消息序列化过程严格遵循协议规范,包含帧头、长度、加密标识、序号、命令字、数据域和校验和等字段。指令重试与超时处理通过会话层的请求缓存机制实现,确保了通信的可靠性。整个流程设计合理,模块职责清晰,为充电桩远程控制提供了稳定可靠的基础。
|
||||
522
docs/核心模块详解/协议实现模块/绿能协议实现/核心架构.md
Normal file
522
docs/核心模块详解/协议实现模块/绿能协议实现/核心架构.md
Normal file
@@ -0,0 +1,522 @@
|
||||
# 绿能协议v3.40核心架构设计
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java)
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java)
|
||||
- [LvnengProtocolConstants.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolConstants.java)
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java)
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java)
|
||||
- [LvnengUplinkMessage.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengUplinkMessage.java)
|
||||
- [LvnengDwonlinkMessage.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengDwonlinkMessage.java)
|
||||
- [LvnengUplinkCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengUplinkCmdExe.java)
|
||||
- [LvnengDownlinkCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengDownlinkCmdExe.java)
|
||||
- [AbstractLvnengCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/AbstractLvnengCmdExe.java)
|
||||
- [LvnengV340LoginULCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340LoginULCmd.java)
|
||||
- [LvnengV340RemoteStopDLCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopDLCmd.java)
|
||||
- [TcpListener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [引言](#引言)
|
||||
2. [项目结构概览](#项目结构概览)
|
||||
3. [核心组件架构](#核心组件架构)
|
||||
4. [协议启动器设计](#协议启动器设计)
|
||||
5. [消息处理机制](#消息处理机制)
|
||||
6. [协议帧结构设计](#协议帧结构设计)
|
||||
7. [命令路由系统](#命令路由系统)
|
||||
8. [组件交互时序](#组件交互时序)
|
||||
9. [性能优化考虑](#性能优化考虑)
|
||||
10. [总结](#总结)
|
||||
|
||||
## 引言
|
||||
|
||||
绿能协议v3.40是JCPP(充电点协议平台)中的一个重要组成部分,专门用于处理绿能品牌的充电设备通信协议。该协议采用模块化设计,通过继承和组合模式实现了高度可扩展的架构。本文档将深入分析其核心架构设计,包括协议启动器、消息处理器、帧结构设计以及组件间的协作机制。
|
||||
|
||||
## 项目结构概览
|
||||
|
||||
绿能协议v3.40的项目结构遵循分层架构原则,主要分为以下几个层次:
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "应用层"
|
||||
Bootstrap[LvnengV340ProtocolBootstrap<br/>协议启动器]
|
||||
end
|
||||
subgraph "业务层"
|
||||
Processor[LvnengProtocolMessageProcessor<br/>消息处理器]
|
||||
Constants[LvnengProtocolConstants<br/>协议常量]
|
||||
end
|
||||
subgraph "命令层"
|
||||
UplinkCmd[LvnengUplinkCmdExe<br/>上行命令基类]
|
||||
DownlinkCmd[LvnengDownlinkCmdExe<br/>下行命令基类]
|
||||
AbstractCmd[AbstractLvnengCmdExe<br/>协议基础类]
|
||||
end
|
||||
subgraph "数据模型层"
|
||||
UplinkMsg[LvnengUplinkMessage<br/>上行消息模型]
|
||||
DownlinkMsg[LvnengDwonlinkMessage<br/>下行消息模型]
|
||||
end
|
||||
subgraph "基础设施层"
|
||||
BaseBootstrap[ProtocolBootstrap<br/>基础启动器]
|
||||
BaseProcessor[ProtocolMessageProcessor<br/>基础消息处理器]
|
||||
Router[ProtocolCommandRouter<br/>命令路由器]
|
||||
end
|
||||
Bootstrap --> Processor
|
||||
Processor --> UplinkCmd
|
||||
Processor --> DownlinkCmd
|
||||
UplinkCmd --> AbstractCmd
|
||||
DownlinkCmd --> AbstractCmd
|
||||
Processor --> UplinkMsg
|
||||
Processor --> DownlinkMsg
|
||||
Bootstrap --> BaseBootstrap
|
||||
Processor --> BaseProcessor
|
||||
Processor --> Router
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java#L1-L42)
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L1-L187)
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L1-L127)
|
||||
|
||||
## 核心组件架构
|
||||
|
||||
### 组件关系图
|
||||
|
||||
绿能协议v3.40的核心架构采用了经典的分层设计模式,各组件之间通过接口进行解耦:
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolBootstrap {
|
||||
<<abstract>>
|
||||
+ProtocolContext protocolContext
|
||||
+ProtocolCfg protocolCfg
|
||||
+Listener listener
|
||||
+Forwarder forwarder
|
||||
+init() void
|
||||
+destroy() void
|
||||
#getProtocolName()* String
|
||||
#_init()* void
|
||||
#_destroy()* void
|
||||
#messageProcessor()* ProtocolMessageProcessor
|
||||
}
|
||||
class LvnengV340ProtocolBootstrap {
|
||||
+String PROTOCOL_NAME
|
||||
+getProtocolName() String
|
||||
+_init() void
|
||||
+_destroy() void
|
||||
+messageProcessor() LvnengProtocolMessageProcessor
|
||||
}
|
||||
class ProtocolMessageProcessor {
|
||||
<<abstract>>
|
||||
+Forwarder forwarder
|
||||
+ProtocolContext protocolContext
|
||||
+uplinkHandleAsync() void
|
||||
+downlinkHandle() void
|
||||
#uplinkHandle()* void
|
||||
#doDownlinkHandle()* void
|
||||
}
|
||||
class LvnengProtocolMessageProcessor {
|
||||
-ProtocolCommandRouter~LvnengUplinkCmdExe~ uplinkRouter
|
||||
-ProtocolCommandRouter~LvnengDownlinkCmdExe~ downlinkRouter
|
||||
-DownlinkCmdConverter downlinkCmdConverter
|
||||
+uplinkHandle() void
|
||||
+doDownlinkHandle() void
|
||||
-exeCmd() void
|
||||
}
|
||||
class LvnengUplinkCmdExe {
|
||||
<<abstract>>
|
||||
+execute() void
|
||||
#uplinkMessageBuilder() Builder
|
||||
}
|
||||
class LvnengDownlinkCmdExe {
|
||||
<<abstract>>
|
||||
+execute() void
|
||||
}
|
||||
class AbstractLvnengCmdExe {
|
||||
#encode() byte[]
|
||||
#encodeAndWriteFlush() void
|
||||
}
|
||||
ProtocolBootstrap <|-- LvnengV340ProtocolBootstrap
|
||||
ProtocolMessageProcessor <|-- LvnengProtocolMessageProcessor
|
||||
LvnengUplinkCmdExe <|-- AbstractLvnengCmdExe
|
||||
LvnengDownlinkCmdExe <|-- AbstractLvnengCmdExe
|
||||
LvnengProtocolMessageProcessor --> LvnengUplinkCmdExe
|
||||
LvnengProtocolMessageProcessor --> LvnengDownlinkCmdExe
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L25-L127)
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java#L15-L42)
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java#L20-L78)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L1-L127)
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java#L1-L42)
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java#L1-L78)
|
||||
|
||||
## 协议启动器设计
|
||||
|
||||
### LvnengV340ProtocolBootstrap核心实现
|
||||
|
||||
LvnengV340ProtocolBootstrap作为绿能协议v3.40的主要入口点,继承自ProtocolBootstrap抽象类,并实现了协议特有的初始化和销毁逻辑。
|
||||
|
||||
#### 继承关系与方法实现
|
||||
|
||||
协议启动器通过以下方式实现核心功能:
|
||||
|
||||
1. **协议名称管理**:通过`getProtocolName()`方法返回协议标识
|
||||
2. **初始化逻辑**:重写了`_init()`方法,目前为空实现
|
||||
3. **资源清理**:重写了`_destroy()`方法,目前为空实现
|
||||
4. **消息处理器创建**:通过`messageProcessor()`方法创建具体的处理器实例
|
||||
|
||||
#### 启动流程时序图
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant App as 应用程序
|
||||
participant Bootstrap as LvnengV340ProtocolBootstrap
|
||||
participant Base as ProtocolBootstrap
|
||||
participant Listener as TcpListener
|
||||
participant Forwarder as Forwarder
|
||||
participant Processor as LvnengProtocolMessageProcessor
|
||||
App->>Bootstrap : 实例化启动器
|
||||
App->>Base : 调用init()
|
||||
Base->>Base : 加载协议配置
|
||||
Base->>Forwarder : 创建转发器
|
||||
Base->>Listener : 创建TCP监听器
|
||||
Base->>Bootstrap : 调用_init()
|
||||
Bootstrap-->>Base : 初始化完成
|
||||
Base-->>App : 启动成功
|
||||
Note over App,Processor : 协议运行阶段
|
||||
App->>Listener : 接收客户端连接
|
||||
Listener->>Processor : 处理上行消息
|
||||
Processor->>Processor : 解析协议帧
|
||||
Processor->>Processor : 路由命令处理
|
||||
Processor-->>App : 返回处理结果
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java#L25-L42)
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L45-L85)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java#L1-L42)
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L45-L85)
|
||||
|
||||
## 消息处理机制
|
||||
|
||||
### LvnengProtocolMessageProcessor核心功能
|
||||
|
||||
LvnengProtocolMessageProcessor是绿能协议的消息处理中心,负责处理上行和下行消息流。它继承自ProtocolMessageProcessor,并实现了协议特定的消息解析和路由逻辑。
|
||||
|
||||
#### 消息处理架构
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([接收原始消息]) --> ParseHeader[解析帧头信息]
|
||||
ParseHeader --> ValidateLength{验证消息长度}
|
||||
ValidateLength --> |长度异常| LogWarning[记录警告日志]
|
||||
ValidateLength --> |长度正常| ExtractBody[提取消息体]
|
||||
ExtractBody --> VerifyChecksum[验证校验和]
|
||||
VerifyChecksum --> ChecksumValid{校验和有效?}
|
||||
ChecksumValid --> |无效| LogError[记录错误日志]
|
||||
ChecksumValid --> |有效| BuildMessage[构建消息对象]
|
||||
BuildMessage --> RouteCommand[路由命令处理]
|
||||
RouteCommand --> ExecuteCmd[执行命令]
|
||||
ExecuteCmd --> SendResponse[发送响应]
|
||||
LogWarning --> End([处理结束])
|
||||
LogError --> End
|
||||
SendResponse --> End
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L55-L120)
|
||||
|
||||
#### 上行消息处理流程
|
||||
|
||||
上行消息处理包含以下关键步骤:
|
||||
|
||||
1. **帧头解析**:读取起始符、长度、加密标识、序列号和命令码
|
||||
2. **长度验证**:确保消息长度符合最小要求
|
||||
3. **消息体提取**:读取实际的数据内容
|
||||
4. **校验和验证**:使用CRC算法验证数据完整性
|
||||
5. **消息对象构建**:封装为LvnengUplinkMessage对象
|
||||
6. **命令路由**:根据命令类型路由到相应的处理器
|
||||
|
||||
#### 下行消息处理流程
|
||||
|
||||
下行消息处理采用统一的处理模式:
|
||||
|
||||
1. **命令转换**:将通用命令转换为协议特定命令
|
||||
2. **消息构建**:创建LvnengDwonlinkMessage对象
|
||||
3. **命令执行**:调用相应的命令处理器
|
||||
4. **响应发送**:将处理结果发送给客户端
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L55-L187)
|
||||
|
||||
## 协议帧结构设计
|
||||
|
||||
### 帧结构定义
|
||||
|
||||
绿能协议v3.40采用固定格式的帧结构,确保消息的可靠传输和解析:
|
||||
|
||||
| 字段 | 长度(字节) | 描述 |
|
||||
|------|--------|-------------------|
|
||||
| 起始符 | 2 | 固定值0xAAF5,标识帧开始 |
|
||||
| 长度 | 2 | 包含整个帧的总长度(小端序) |
|
||||
| 加密标识 | 1 | 0x10表示加密,0x00表示明文 |
|
||||
| 序列号 | 1 | 用于消息顺序控制 |
|
||||
| 命令码 | 2 | 指示消息类型(小端序) |
|
||||
| 数据域 | 变长 | 实际消息内容 |
|
||||
| 校验和 | 1 | CRC8校验值 |
|
||||
|
||||
#### 帧结构示例
|
||||
|
||||
```
|
||||
+------------------+------------------+------------------+------------------+
|
||||
| 起始符 | 长度 | 加密标识 | 序列号 | 命令码 |
|
||||
| (2字节) | (2字节) | (1字节) | (1字节) | (2字节) |
|
||||
+------------------+------------------+------------------+------------------+
|
||||
| |
|
||||
| 数据域 |
|
||||
| |
|
||||
+---------------------------------------------------------------+
|
||||
| 校验和 |
|
||||
| (1字节) |
|
||||
+--------------+
|
||||
```
|
||||
|
||||
### 校验和算法
|
||||
|
||||
协议采用CRC8算法进行数据完整性验证:
|
||||
|
||||
1. **校验和计算**:对命令码和数据域进行CRC8计算
|
||||
2. **校验和验证**:接收端重新计算并比较
|
||||
3. **错误处理**:校验失败时记录日志并丢弃消息
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L30-L35)
|
||||
- [AbstractLvnengCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/AbstractLvnengCmdExe.java#L50-L70)
|
||||
|
||||
## 命令路由系统
|
||||
|
||||
### ProtocolCommandRouter设计
|
||||
|
||||
ProtocolCommandRouter提供了基于协议名和命令字的智能路由功能,支持多版本协议的统一管理:
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolCommandRouter {
|
||||
-Map~String,T~ executorMap
|
||||
+ProtocolCommandRouter(scanBaseClass, executorFilter)
|
||||
+getExecutor(protocolName, cmd) T
|
||||
-initializeRoutes() void
|
||||
-registerExecutor() void
|
||||
-buildKey() String
|
||||
}
|
||||
class ProtocolCmd {
|
||||
<<annotation>>
|
||||
+int value()
|
||||
+String[] protocolNames()
|
||||
}
|
||||
class LvnengUplinkCmdExe {
|
||||
<<abstract>>
|
||||
+execute() void
|
||||
}
|
||||
class LvnengV340LoginULCmd {
|
||||
+execute() void
|
||||
}
|
||||
ProtocolCommandRouter --> LvnengUplinkCmdExe
|
||||
LvnengUplinkCmdExe --> ProtocolCmd
|
||||
LvnengV340LoginULCmd --|> LvnengUplinkCmdExe
|
||||
ProtocolCmd --> LvnengV340LoginULCmd
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java#L25-L105)
|
||||
- [LvnengUplinkCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengUplinkCmdExe.java#L19-L39)
|
||||
|
||||
### 命令执行器层次结构
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class AbstractLvnengCmdExe {
|
||||
#byte[] encode()
|
||||
#encodeAndWriteFlush()
|
||||
#DOWNLINK_CMD_CONVERTER
|
||||
#LVNENG_HEAD
|
||||
#LVNENG_ENCRYPTION_FLAG
|
||||
}
|
||||
class LvnengUplinkCmdExe {
|
||||
<<abstract>>
|
||||
+execute() void
|
||||
#uplinkMessageBuilder()
|
||||
}
|
||||
class LvnengDownlinkCmdExe {
|
||||
<<abstract>>
|
||||
+execute() void
|
||||
}
|
||||
class LvnengV340LoginULCmd {
|
||||
+execute() void
|
||||
}
|
||||
class LvnengV340RemoteStopDLCmd {
|
||||
+execute() void
|
||||
}
|
||||
AbstractLvnengCmdExe <|-- LvnengUplinkCmdExe
|
||||
AbstractLvnengCmdExe <|-- LvnengDownlinkCmdExe
|
||||
LvnengUplinkCmdExe <|-- LvnengV340LoginULCmd
|
||||
LvnengDownlinkCmdExe <|-- LvnengV340RemoteStopDLCmd
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [AbstractLvnengCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/AbstractLvnengCmdExe.java#L18-L120)
|
||||
- [LvnengUplinkCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengUplinkCmdExe.java#L19-L39)
|
||||
- [LvnengDownlinkCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengDownlinkCmdExe.java#L14-L18)
|
||||
|
||||
### 命令处理时序图
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Session as TcpSession
|
||||
participant Processor as LvnengProtocolMessageProcessor
|
||||
participant Router as ProtocolCommandRouter
|
||||
participant Executor as 命令执行器
|
||||
participant Forwarder as Forwarder
|
||||
Session->>Processor : uplinkHandleAsync()
|
||||
Processor->>Processor : 解析消息帧
|
||||
Processor->>Router : getExecutor(protocolName, cmd)
|
||||
Router-->>Processor : 返回命令执行器
|
||||
Processor->>Executor : execute(session, message, context)
|
||||
Executor->>Executor : 处理业务逻辑
|
||||
Executor->>Forwarder : 发送上行消息
|
||||
Forwarder-->>Session : 返回处理结果
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L150-L187)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java#L25-L105)
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L150-L187)
|
||||
|
||||
## 组件交互时序
|
||||
|
||||
### 协议初始化时序
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant App as 应用程序
|
||||
participant Bootstrap as LvnengV340ProtocolBootstrap
|
||||
participant Config as ProtocolContext
|
||||
participant Forwarder as Forwarder
|
||||
participant Listener as TcpListener
|
||||
participant Processor as LvnengProtocolMessageProcessor
|
||||
App->>Bootstrap : 实例化
|
||||
App->>Bootstrap : init()
|
||||
Bootstrap->>Config : loadConfig(protocolName)
|
||||
Config-->>Bootstrap : 返回配置信息
|
||||
Bootstrap->>Forwarder : 创建转发器
|
||||
Forwarder-->>Bootstrap : 转发器实例
|
||||
Bootstrap->>Listener : 创建TCP监听器
|
||||
Listener->>Processor : 创建消息处理器
|
||||
Processor->>Processor : 初始化命令路由器
|
||||
Processor-->>Listener : 处理器就绪
|
||||
Listener-->>Bootstrap : 监听器就绪
|
||||
Bootstrap->>Bootstrap : _init()
|
||||
Bootstrap-->>App : 初始化完成
|
||||
Note over App,Processor : 协议服务已启动
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java#L25-L42)
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L45-L85)
|
||||
|
||||
### 消息处理时序
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as 客户端
|
||||
participant Listener as TcpListener
|
||||
participant Processor as LvnengProtocolMessageProcessor
|
||||
participant Router as ProtocolCommandRouter
|
||||
participant CmdExe as 命令执行器
|
||||
participant Forwarder as Forwarder
|
||||
Client->>Listener : 发送原始消息
|
||||
Listener->>Processor : uplinkHandleAsync()
|
||||
Processor->>Processor : 解析协议帧
|
||||
Processor->>Processor : 验证校验和
|
||||
Processor->>Router : getExecutor(protocolName, cmd)
|
||||
Router-->>Processor : 返回执行器
|
||||
Processor->>CmdExe : execute(session, message, context)
|
||||
CmdExe->>CmdExe : 处理业务逻辑
|
||||
CmdExe->>Forwarder : sendMessage(uplinkQueueMessage)
|
||||
Forwarder-->>Client : 返回处理结果
|
||||
Note over Client,Forwarder : 异步处理流程
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L55-L120)
|
||||
- [TcpListener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java#L40-L70)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java#L25-L42)
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L55-L120)
|
||||
|
||||
## 性能优化考虑
|
||||
|
||||
### 异步处理机制
|
||||
|
||||
协议采用异步处理模式,通过线程池管理消息处理:
|
||||
|
||||
1. **线程池隔离**:使用分片线程池避免资源竞争
|
||||
2. **异步消息处理**:上行消息处理采用异步模式
|
||||
3. **内存管理**:及时释放ByteBuf资源
|
||||
|
||||
### 内存优化策略
|
||||
|
||||
1. **对象复用**:重用消息对象减少GC压力
|
||||
2. **缓冲区管理**:合理设置TCP缓冲区大小
|
||||
3. **序列号管理**:维护序列号状态避免重复
|
||||
|
||||
### 并发控制
|
||||
|
||||
1. **无锁设计**:使用ConcurrentHashMap实现线程安全
|
||||
2. **原子操作**:利用CAS操作提高并发性能
|
||||
3. **批量处理**:支持批量消息处理
|
||||
|
||||
## 总结
|
||||
|
||||
绿能协议v3.40的核心架构展现了优秀的软件设计原则:
|
||||
|
||||
### 设计亮点
|
||||
|
||||
1. **模块化设计**:清晰的分层架构,职责分离明确
|
||||
2. **可扩展性**:基于注解的命令路由系统,易于添加新命令
|
||||
3. **可靠性**:完善的错误处理和校验机制
|
||||
4. **性能优化**:异步处理和资源管理策略
|
||||
|
||||
### 架构优势
|
||||
|
||||
1. **高内聚低耦合**:各组件职责单一,依赖关系清晰
|
||||
2. **可测试性**:良好的接口设计便于单元测试
|
||||
3. **可维护性**:清晰的代码结构和文档
|
||||
4. **可监控性**:完整的健康检查和统计指标
|
||||
|
||||
该架构为绿能协议v3.40提供了稳定、高效、可扩展的通信基础,能够满足现代充电站系统的复杂需求。
|
||||
526
docs/核心模块详解/协议实现模块/绿能协议实现/绿能协议实现.md
Normal file
526
docs/核心模块详解/协议实现模块/绿能协议实现/绿能协议实现.md
Normal file
@@ -0,0 +1,526 @@
|
||||
# 绿能协议实现
|
||||
|
||||
<cite>
|
||||
**本文档中引用的文件**
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java)
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java)
|
||||
- [LvnengUplinkCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengUplinkCmdExe.java)
|
||||
- [LvnengDownlinkCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengDownlinkCmdExe.java)
|
||||
- [LvnengDownlinkCmdConverter.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/mapping/LvnengDownlinkCmdConverter.java)
|
||||
- [LvnengV340RealTimeDataULCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340RealTimeDataULCmd.java)
|
||||
- [LvnengUplinkMessage.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengUplinkMessage.java)
|
||||
- [LvnengDwonlinkMessage.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengDwonlinkMessage.java)
|
||||
- [LvnengProtocolConstants.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolConstants.java)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java)
|
||||
- [AbstractLvnengCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/AbstractLvnengCmdExe.java)
|
||||
- [LvnengV340SetPricingModelDLCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetPricingModelDLCmd.java)
|
||||
- [LvnengV340RemoteStopDLCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopDLCmd.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构概览](#架构概览)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [协议消息处理流程](#协议消息处理流程)
|
||||
7. [命令路由机制](#命令路由机制)
|
||||
8. [数据包格式与处理](#数据包格式与处理)
|
||||
9. [实际应用示例](#实际应用示例)
|
||||
10. [性能考虑](#性能考虑)
|
||||
11. [故障排除指南](#故障排除指南)
|
||||
12. [总结](#总结)
|
||||
|
||||
## 简介
|
||||
|
||||
绿能协议(v3.40)是一个专为电动汽车充电站设计的通信协议,实现了充电桩与服务器之间的可靠数据交换。该协议采用TCP传输层,具有严格的消息帧结构、校验和验证机制和完善的命令处理体系。
|
||||
|
||||
本文档深入分析了绿能协议v3.40的实现细节,重点关注LvnengV340ProtocolBootstrap的配置机制、消息帧结构的设计、以及LvnengProtocolMessageProcessor的处理逻辑。同时详细阐述了上行命令处理器和下行指令生成机制,展示了从gRPC调用到协议报文构建的完整流程。
|
||||
|
||||
## 项目结构
|
||||
|
||||
绿能协议模块采用分层架构设计,主要包含以下核心包结构:
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "协议核心模块"
|
||||
A[jcpp-protocol-lvneng]
|
||||
A --> B[v340 - 协议版本实现]
|
||||
A --> C[mapping - 命令映射]
|
||||
A --> D[enums - 枚举定义]
|
||||
A --> E[cmd - 命令处理器]
|
||||
end
|
||||
subgraph "基础框架"
|
||||
F[jcpp-protocol-api]
|
||||
G[jcpp-protocol-bootstrap]
|
||||
H[jcpp-protocol-yunkuaichong]
|
||||
end
|
||||
subgraph "基础设施"
|
||||
I[jcpp-infrastructure-util]
|
||||
J[jcpp-infrastructure-cache]
|
||||
K[jcpp-infrastructure-queue]
|
||||
end
|
||||
A --> F
|
||||
F --> I
|
||||
F --> J
|
||||
F --> K
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java#L1-L42)
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L1-L187)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java#L1-L42)
|
||||
- [LvnengProtocolConstants.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolConstants.java#L1-L38)
|
||||
|
||||
## 核心组件
|
||||
|
||||
绿能协议的核心组件包括协议引导器、消息处理器、命令执行器和命令转换器等关键模块。这些组件协同工作,实现了完整的协议栈功能。
|
||||
|
||||
### 协议引导器(LvnengV340ProtocolBootstrap)
|
||||
|
||||
协议引导器负责初始化和配置整个协议栈,它继承自基础的ProtocolBootstrap类,提供了协议特定的初始化逻辑。
|
||||
|
||||
### 消息处理器(LvnengProtocolMessageProcessor)
|
||||
|
||||
消息处理器是协议的核心,负责解析和处理所有上行和下行消息。它实现了严格的帧结构解析、校验和验证和命令路由功能。
|
||||
|
||||
### 命令执行器基类
|
||||
|
||||
系统提供了两个抽象基类:LvnengUplinkCmdExe用于处理上行命令,LvnengDownlinkCmdExe用于处理下行命令。它们都继承自AbstractLvnengCmdExe,提供了统一的编码和发送机制。
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java#L15-L42)
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L25-L50)
|
||||
|
||||
## 架构概览
|
||||
|
||||
绿能协议采用事件驱动的异步处理架构,通过Netty框架实现高效的网络通信。整个架构分为消息接收层、协议处理层、命令执行层和业务逻辑层。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "网络层"
|
||||
A[TCP连接] --> B[消息解码器]
|
||||
B --> C[帧解析器]
|
||||
end
|
||||
subgraph "协议处理层"
|
||||
C --> D[LvnengProtocolMessageProcessor]
|
||||
D --> E[上行命令路由]
|
||||
D --> F[下行命令路由]
|
||||
end
|
||||
subgraph "命令执行层"
|
||||
E --> G[LvnengUplinkCmdExe]
|
||||
F --> H[LvnengDownlinkCmdExe]
|
||||
G --> I[业务逻辑处理]
|
||||
H --> J[协议报文生成]
|
||||
end
|
||||
subgraph "数据转换层"
|
||||
K[LvnengDownlinkCmdConverter] --> H
|
||||
L[消息对象封装] --> G
|
||||
L --> H
|
||||
end
|
||||
subgraph "输出层"
|
||||
I --> M[UplinkQueueMessage]
|
||||
J --> N[编码后的字节数组]
|
||||
end
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L40-L80)
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java#L20-L60)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### LvnengV340ProtocolBootstrap配置机制
|
||||
|
||||
LvnengV340ProtocolBootstrap作为协议的入口点,负责建立TCP监听器和初始化协议上下文。它通过注解@ProtocolComponent标记协议名称,并重写父类方法提供具体的初始化逻辑。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class LvnengV340ProtocolBootstrap {
|
||||
+String PROTOCOL_NAME
|
||||
+getProtocolName() String
|
||||
+_init() void
|
||||
+_destroy() void
|
||||
+messageProcessor() ProtocolMessageProcessor
|
||||
}
|
||||
class ProtocolBootstrap {
|
||||
<<abstract>>
|
||||
+forwarder Forwarder
|
||||
+protocolContext ProtocolContext
|
||||
+messageProcessor() ProtocolMessageProcessor
|
||||
}
|
||||
class LvnengProtocolMessageProcessor {
|
||||
+uplinkRouter ProtocolCommandRouter
|
||||
+downlinkRouter ProtocolCommandRouter
|
||||
+downlinkCmdConverter DownlinkCmdConverter
|
||||
+uplinkHandle(ListenerToHandlerMsg) void
|
||||
+doDownlinkHandle(SessionToHandlerMsg) void
|
||||
}
|
||||
LvnengV340ProtocolBootstrap --|> ProtocolBootstrap
|
||||
LvnengV340ProtocolBootstrap --> LvnengProtocolMessageProcessor : creates
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java#L15-L42)
|
||||
|
||||
### 消息帧结构设计
|
||||
|
||||
绿能协议采用严格的帧结构设计,确保消息的可靠传输和完整性验证。帧结构包括起始标志、长度字段、加密标识、序列号、命令字和校验和等关键字段。
|
||||
|
||||
| 字段名称 | 长度(字节) | 描述 |
|
||||
|------|--------|-------------------|
|
||||
| 起始标志 | 2 | 固定值0xAAF5,标识帧开始 |
|
||||
| 数据长度 | 2 | 包含头部和校验和在内的总长度 |
|
||||
| 加密标识 | 1 | 0x10表示加密,0x00表示明文 |
|
||||
| 序列号 | 1 | 用于消息顺序控制 |
|
||||
| 命令字 | 2 | 标识具体命令类型 |
|
||||
| 数据域 | 可变 | 实际消息内容 |
|
||||
| 校验和 | 1 | 对命令字和数据域的校验 |
|
||||
|
||||
### LvnengProtocolMessageProcessor消息处理
|
||||
|
||||
消息处理器实现了复杂的消息解析逻辑,包括帧头解析、长度验证、校验和计算和命令路由等功能。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as 客户端
|
||||
participant Processor as LvnengProtocolMessageProcessor
|
||||
participant Router as 命令路由器
|
||||
participant Executor as 命令执行器
|
||||
participant Forwarder as 消息转发器
|
||||
Client->>Processor : 接收原始消息
|
||||
Processor->>Processor : 解析帧头信息
|
||||
Processor->>Processor : 验证消息长度
|
||||
Processor->>Processor : 读取消息体
|
||||
Processor->>Processor : 计算并验证校验和
|
||||
Processor->>Router : 查找命令执行器
|
||||
Router->>Executor : 返回匹配的执行器
|
||||
Executor->>Executor : 执行业务逻辑
|
||||
Executor->>Forwarder : 转发处理结果
|
||||
Forwarder->>Client : 发送响应消息
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L50-L120)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L25-L187)
|
||||
|
||||
## 协议消息处理流程
|
||||
|
||||
### 上行消息处理流程
|
||||
|
||||
上行消息处理涉及复杂的帧解析和命令执行过程。处理器首先验证消息格式,然后提取各个字段,最后通过命令路由机制找到对应的执行器。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([接收上行消息]) --> ParseHeader["解析帧头信息<br/>起始标志 + 长度 + 加密标识 + 序列号 + 命令字"]
|
||||
ParseHeader --> ValidateLength{"验证消息长度<br/>dataLength >= 9?"}
|
||||
ValidateLength --> |否| LogWarning["记录警告日志"]
|
||||
ValidateLength --> |是| ReadBody["读取消息体<br/>msgBodyLength = dataLength - 9"]
|
||||
ReadBody --> CalcChecksum["计算校验和<br/>sumData = 命令字 + 数据域"]
|
||||
CalcChecksum --> VerifyChecksum{"校验和验证"}
|
||||
VerifyChecksum --> |失败| LogError["记录错误日志"]
|
||||
VerifyChecksum --> |成功| BuildMessage["构建LvnengUplinkMessage对象"]
|
||||
BuildMessage --> RouteCommand["命令路由查找"]
|
||||
RouteCommand --> ExecuteCmd["执行命令处理器"]
|
||||
ExecuteCmd --> SendResponse["发送响应消息"]
|
||||
LogWarning --> End([处理结束])
|
||||
LogError --> End
|
||||
SendResponse --> End
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L50-L120)
|
||||
|
||||
### 下行消息处理流程
|
||||
|
||||
下行消息处理从gRPC调用开始,经过命令转换、消息构建和协议编码等步骤,最终生成符合绿能协议规范的报文。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([接收gRPC调用]) --> ConvertCmd["命令转换<br/>DownlinkCmdEnum -> 协议命令字"]
|
||||
ConvertCmd --> ValidateSupport{"验证命令支持"}
|
||||
ValidateSupport --> |不支持| LogUnsupported["记录不支持命令"]
|
||||
ValidateSupport --> |支持| BuildMessage["构建LvnengDwonlinkMessage"]
|
||||
BuildMessage --> ExtractData["提取请求数据"]
|
||||
ExtractData --> RouteCommand["命令路由查找"]
|
||||
RouteCommand --> ExecuteCmd["执行命令处理器"]
|
||||
ExecuteCmd --> EncodeMsg["编码协议消息<br/>帧头 + 长度 + 加密 + 序列号 + 命令字 + 数据域 + 校验和"]
|
||||
EncodeMsg --> SendMsg["发送到TCP会话"]
|
||||
LogUnsupported --> End([处理结束])
|
||||
SendMsg --> End
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L120-L187)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L50-L187)
|
||||
|
||||
## 命令路由机制
|
||||
|
||||
### ProtocolCommandRouter实现
|
||||
|
||||
ProtocolCommandRouter提供了基于协议名和命令字的智能路由功能,支持自动扫描和注册命令执行器,实现了松耦合的命令处理架构。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolCommandRouter~T~ {
|
||||
-Map~String,T~ executorMap
|
||||
+ProtocolCommandRouter(Class, Predicate)
|
||||
+getExecutor(String, int) T
|
||||
-initializeRoutes(Class, Predicate) void
|
||||
-registerExecutor(Class) void
|
||||
-buildKey(String, int) String
|
||||
}
|
||||
class LvnengUplinkCmdExe {
|
||||
<<abstract>>
|
||||
+execute(TcpSession, LvnengUplinkMessage, ProtocolContext) void
|
||||
#uplinkMessageBuilder(String, TcpSession, LvnengUplinkMessage) UplinkQueueMessage.Builder
|
||||
}
|
||||
class LvnengDownlinkCmdExe {
|
||||
<<abstract>>
|
||||
+execute(TcpSession, LvnengDwonlinkMessage, ProtocolContext) void
|
||||
}
|
||||
class LvnengV340RealTimeDataULCmd {
|
||||
+execute(TcpSession, LvnengUplinkMessage, ProtocolContext) void
|
||||
}
|
||||
class LvnengV340SetPricingModelDLCmd {
|
||||
+execute(TcpSession, LvnengDwonlinkMessage, ProtocolContext) void
|
||||
}
|
||||
ProtocolCommandRouter --> LvnengUplinkCmdExe : routes
|
||||
ProtocolCommandRouter --> LvnengDownlinkCmdExe : routes
|
||||
LvnengUplinkCmdExe <|-- LvnengV340RealTimeDataULCmd
|
||||
LvnengDownlinkCmdExe <|-- LvnengV340SetPricingModelDLCmd
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java#L20-L105)
|
||||
- [LvnengUplinkCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengUplinkCmdExe.java#L15-L40)
|
||||
|
||||
### 命令注册机制
|
||||
|
||||
系统通过@ProtocolCmd注解自动发现和注册命令执行器,每个执行器可以支持多个协议版本。这种设计使得协议升级更加灵活。
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [ProtocolCommandRouter.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/routing/ProtocolCommandRouter.java#L20-L105)
|
||||
- [LvnengUplinkCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengUplinkCmdExe.java#L15-L40)
|
||||
|
||||
## 数据包格式与处理
|
||||
|
||||
### 上行命令处理示例:实时数据上报
|
||||
|
||||
LvnengV340RealTimeDataULCmd展示了典型的上行命令处理流程,包括数据解析、状态更新和消息转发。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Pile as 充电桩
|
||||
participant Cmd as LvnengV340RealTimeDataULCmd
|
||||
participant Session as TCP会话
|
||||
participant Context as 协议上下文
|
||||
participant Forwarder as 消息转发器
|
||||
Pile->>Cmd : 接收实时数据上报
|
||||
Cmd->>Cmd : 解析消息体<br/>充电桩编码 + 枪口数量 + 枪口号
|
||||
Cmd->>Cmd : 提取状态信息<br/>工作状态 + SOC + 告警码
|
||||
Cmd->>Cmd : 解析电气参数<br/>电压、电流、电量
|
||||
Cmd->>Session : 更新会话信息
|
||||
Cmd->>Context : 注册会话
|
||||
Cmd->>Cmd : 构建状态消息<br/>GunRunStatusProto
|
||||
Cmd->>Forwarder : 转发状态信息
|
||||
Cmd->>Cmd : 构建充电进度消息<br/>ChargingProgressProto
|
||||
Cmd->>Forwarder : 转发充电进度
|
||||
Cmd->>Cmd : 发送应答消息<br/>REAL_TIME_DATA_ACK
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [LvnengV340RealTimeDataULCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340RealTimeDataULCmd.java#L35-L316)
|
||||
|
||||
### 下行命令处理示例:设置定价模型
|
||||
|
||||
LvnengV340SetPricingModelDLCmd演示了下行命令的处理流程,包括参数解析、数据转换和响应生成。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Server as 服务器
|
||||
participant Cmd as LvnengV340SetPricingModelDLCmd
|
||||
participant Session as TCP会话
|
||||
participant Cache as 请求缓存
|
||||
Server->>Cmd : 接收定价模型设置
|
||||
Cmd->>Cmd : 验证消息格式<br/>SetPricingRequest
|
||||
Cmd->>Cmd : 解析计费规则<br/>时段计价或阶梯计价
|
||||
Cmd->>Cmd : 构建响应数据<br/>48个时间段 * 12字节
|
||||
Cmd->>Cache : 存储请求ID
|
||||
Cmd->>Session : 发送应答消息<br/>SET_PRICING_ACK
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [LvnengV340SetPricingModelDLCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetPricingModelDLCmd.java#L35-L98)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [LvnengV340RealTimeDataULCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340RealTimeDataULCmd.java#L35-L316)
|
||||
- [LvnengV340SetPricingModelDLCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetPricingModelDLCmd.java#L35-L98)
|
||||
|
||||
## 实际应用示例
|
||||
|
||||
### 协议命令转换机制
|
||||
|
||||
LvnengDownlinkCmdConverter作为命令转换器,建立了通用命令与协议特定命令字之间的映射关系。这种设计确保了协议的可扩展性和向后兼容性。
|
||||
|
||||
| 通用命令 | 绿能协议命令字 | 描述 |
|
||||
|------------------------|---------|--------|
|
||||
| LOGIN_ACK | 105 | 登录应答 |
|
||||
| SYNC_TIME_REQUEST | 3 | 时间同步请求 |
|
||||
| TRANSACTION_RECORD_ACK | 201 | 交易记录应答 |
|
||||
| HEARTBEAT_ACK | 101 | 心跳应答 |
|
||||
| REAL_TIME_DATA_ACK | 103 | 实时数据应答 |
|
||||
| SET_PRICING | 1103 | 设置定价模型 |
|
||||
| REMOTE_STOP_CHARGING | 5 | 远程停止充电 |
|
||||
| SET_QRCODE | 3 | 设置二维码 |
|
||||
|
||||
### 消息对象结构
|
||||
|
||||
系统定义了专门的消息对象来封装协议数据,提供了类型安全的数据访问接口。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class LvnengUplinkMessage {
|
||||
-UUID id
|
||||
-int head
|
||||
-int dataLength
|
||||
-int sequenceNumber
|
||||
-int encryptionFlag
|
||||
-int cmd
|
||||
-byte[] msgBody
|
||||
-int checkSum
|
||||
-byte[] rawFrame
|
||||
+getId() UUID
|
||||
+getCmd() int
|
||||
+getMsgBody() byte[]
|
||||
+getRawFrame() byte[]
|
||||
}
|
||||
class LvnengDwonlinkMessage {
|
||||
-UUID id
|
||||
-UUID requestId
|
||||
-int cmd
|
||||
-DownlinkRequestMessage msg
|
||||
-LvnengUplinkMessage requestData
|
||||
+getId() UUID
|
||||
+getCmd() int
|
||||
+getRequestId() UUID
|
||||
+getMsg() DownlinkRequestMessage
|
||||
}
|
||||
class AbstractLvnengCmdExe {
|
||||
#encode(int, int, int, ByteBuf) byte[]
|
||||
#encodeAndWriteFlush(int, ByteBuf, TcpSession) void
|
||||
#encodeAndWriteFlush(DownlinkCmdEnum, ByteBuf, TcpSession) void
|
||||
}
|
||||
LvnengDwonlinkMessage --> LvnengUplinkMessage : requestData
|
||||
AbstractLvnengCmdExe --> LvnengUplinkMessage : processes
|
||||
AbstractLvnengCmdExe --> LvnengDwonlinkMessage : processes
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [LvnengUplinkMessage.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengUplinkMessage.java#L15-L54)
|
||||
- [LvnengDwonlinkMessage.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengDwonlinkMessage.java#L15-L42)
|
||||
- [AbstractLvnengCmdExe.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/AbstractLvnengCmdExe.java#L15-L120)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [LvnengDownlinkCmdConverter.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/mapping/LvnengDownlinkCmdConverter.java#L25-L75)
|
||||
- [LvnengUplinkMessage.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengUplinkMessage.java#L15-L54)
|
||||
- [LvnengDwonlinkMessage.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengDwonlinkMessage.java#L15-L42)
|
||||
|
||||
## 性能考虑
|
||||
|
||||
绿能协议在设计时充分考虑了性能优化,采用了多种技术手段来提高系统的响应速度和吞吐量。
|
||||
|
||||
### 异步处理机制
|
||||
|
||||
系统采用Netty框架实现异步I/O操作,避免了线程阻塞,提高了并发处理能力。消息处理完全基于事件驱动,能够高效处理大量并发连接。
|
||||
|
||||
### 内存管理优化
|
||||
|
||||
- 使用ByteBuf进行零拷贝操作,减少内存分配和垃圾回收压力
|
||||
- 采用对象池技术复用消息对象,降低GC频率
|
||||
- 合理设计消息结构,减少不必要的数据复制
|
||||
|
||||
### 缓存策略
|
||||
|
||||
- 命令路由表采用ConcurrentHashMap实现,提供O(1)的查找性能
|
||||
- 请求ID缓存机制避免重复处理相同请求
|
||||
- 会话状态信息本地化存储,减少数据库访问
|
||||
|
||||
## 故障排除指南
|
||||
|
||||
### 常见问题诊断
|
||||
|
||||
#### 消息解析失败
|
||||
|
||||
- 检查帧头是否为0xAAF5
|
||||
- 验证消息长度是否正确
|
||||
- 确认校验和计算是否准确
|
||||
|
||||
#### 命令路由失败
|
||||
|
||||
- 确认命令执行器是否正确注册
|
||||
- 检查@ProtocolCmd注解配置
|
||||
- 验证协议名称匹配
|
||||
|
||||
#### 连接异常
|
||||
|
||||
- 检查TCP连接状态
|
||||
- 验证网络防火墙设置
|
||||
- 确认端口监听状态
|
||||
|
||||
### 日志分析
|
||||
|
||||
系统提供了详细的日志记录,帮助快速定位问题:
|
||||
|
||||
- WARN级别:消息格式异常、校验和失败
|
||||
- ERROR级别:命令执行异常、系统内部错误
|
||||
- DEBUG级别:消息处理流程跟踪
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L70-L100)
|
||||
|
||||
## 总结
|
||||
|
||||
绿能协议v3.40实现了一个功能完整、性能优异的电动汽车充电站通信协议。通过模块化的架构设计、严格的帧结构规范和智能的命令路由机制,系统实现了高可靠性的消息传输和处理。
|
||||
|
||||
### 主要特性
|
||||
|
||||
1. **严格的协议规范**:采用标准的帧结构和校验机制,确保消息传输的可靠性
|
||||
2. **灵活的命令处理**:支持多种命令类型,具备良好的扩展性
|
||||
3. **高性能架构**:基于Netty的异步处理,支持高并发场景
|
||||
4. **完善的错误处理**:提供详细的日志记录和异常处理机制
|
||||
5. **类型安全设计**:使用强类型的消息对象,减少运行时错误
|
||||
|
||||
### 技术优势
|
||||
|
||||
- **模块化设计**:各组件职责明确,便于维护和扩展
|
||||
- **自动化注册**:通过注解机制自动发现和注册命令执行器
|
||||
- **性能优化**:采用多种优化技术,确保系统高效运行
|
||||
- **向后兼容**:支持协议版本升级,保证系统稳定性
|
||||
|
||||
该协议实现为电动汽车充电站提供了稳定可靠的通信基础,支撑了大规模充电网络的运营需求。通过持续的优化和改进,系统能够适应不断发展的行业需求和技术进步。
|
||||
214
docs/核心模块详解/核心模块详解.md
Normal file
214
docs/核心模块详解/核心模块详解.md
Normal file
@@ -0,0 +1,214 @@
|
||||
# 核心模块详解
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java)
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java)
|
||||
- [ProtocolContext.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolContext.java)
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java)
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java)
|
||||
- [LvnengV340HeartbeatULCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340HeartbeatULCmd.java)
|
||||
- [YunKuaiChongV150LoginULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LoginULCmd.java)
|
||||
- [Station.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Station.java)
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java)
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java)
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java)
|
||||
- [DefaultPileService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileService.java)
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java)
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [协议处理框架](#协议处理框架)
|
||||
2. [设备管理模块](#设备管理模块)
|
||||
3. [协议实现模块](#协议实现模块)
|
||||
|
||||
## 协议处理框架
|
||||
|
||||
JChargePointProtocol的协议处理框架由三个核心组件构成:`ProtocolBootstrap`抽象类、`ProtocolMessageProcessor`消息处理器和
|
||||
`ProtocolContext`上下文管理器。这个框架为不同厂商的充电桩通信协议提供了统一的生命周期管理和消息处理机制。
|
||||
|
||||
`ProtocolBootstrap`是所有协议实现的基类,它定义了协议的启动和销毁生命周期。通过`@PostConstruct`和`@PreDestroy`
|
||||
注解,该类在Spring容器初始化和销毁时自动执行`init()`和`destroy()`方法。`init()`方法负责初始化协议配置、监听器和转发器,而
|
||||
`destroy()`方法则负责清理资源。子类需要实现`getProtocolName()`方法来标识协议名称,并通过`messageProcessor()`方法提供具体的
|
||||
`ProtocolMessageProcessor`实现。
|
||||
|
||||
`ProtocolMessageProcessor`是消息处理的核心,它定义了上行和下行消息的处理流程。该类通过`uplinkHandleAsync()`
|
||||
方法异步处理来自充电桩的上行消息,使用`shardingThreadPool`进行线程分片处理,确保高并发下的性能。对于下行消息,
|
||||
`downlinkHandle()`方法提供了统一的异常处理和日志记录机制。具体的协议实现类需要重写`uplinkHandle()`和`doDownlinkHandle()`
|
||||
方法来处理特定协议的消息。
|
||||
|
||||
`ProtocolContext`
|
||||
作为依赖注入的容器,集中管理了系统中的各种基础设施组件,包括统计工厂、配置提供者、会话注册表、服务信息提供者、分区提供者、队列工厂和分片线程池。这些组件通过构造函数注入,使得协议实现可以方便地访问系统资源,而无需直接依赖具体的实现类。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolBootstrap {
|
||||
+ProtocolContext protocolContext
|
||||
+ProtocolCfg protocolCfg
|
||||
+Listener listener
|
||||
+Forwarder forwarder
|
||||
+init() void
|
||||
+destroy() void
|
||||
+health() Health
|
||||
+getProtocolName() String
|
||||
+_init() void
|
||||
+_destroy() void
|
||||
+messageProcessor() ProtocolMessageProcessor
|
||||
}
|
||||
class ProtocolMessageProcessor {
|
||||
+Forwarder forwarder
|
||||
+ProtocolContext protocolContext
|
||||
+uplinkHandleAsync(ListenerToHandlerMsg, MessagesStats) void
|
||||
+downlinkHandle(SessionToHandlerMsg, MessagesStats) void
|
||||
+uplinkHandle(ListenerToHandlerMsg) void
|
||||
+doDownlinkHandle(SessionToHandlerMsg) void
|
||||
}
|
||||
class ProtocolContext {
|
||||
+StatsFactory statsFactory
|
||||
+ProtocolsConfigProvider protocolsConfigProvider
|
||||
+ProtocolSessionRegistryProvider protocolSessionRegistryProvider
|
||||
+ServiceInfoProvider serviceInfoProvider
|
||||
+PartitionProvider partitionProvider
|
||||
+AppQueueFactory appQueueFactory
|
||||
+ShardingThreadPool shardingThreadPool
|
||||
}
|
||||
ProtocolBootstrap <|-- LvnengV340ProtocolBootstrap
|
||||
ProtocolBootstrap <|-- YunkuaichongV150ProtocolBootstrap
|
||||
ProtocolMessageProcessor <|-- LvnengProtocolMessageProcessor
|
||||
ProtocolMessageProcessor <|-- YunKuaiChongProtocolMessageProcessor
|
||||
LvnengV340ProtocolBootstrap --> LvnengProtocolMessageProcessor : "创建"
|
||||
YunkuaichongV150ProtocolBootstrap --> YunKuaiChongProtocolMessageProcessor : "创建"
|
||||
LvnengV340ProtocolBootstrap --> ProtocolContext : "使用"
|
||||
YunkuaichongV150ProtocolBootstrap --> ProtocolContext : "使用"
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java)
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java)
|
||||
- [ProtocolContext.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolContext.java)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L1-L126)
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java#L1-L77)
|
||||
- [ProtocolContext.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolContext.java#L1-L65)
|
||||
|
||||
## 设备管理模块
|
||||
|
||||
设备管理模块采用层次化的数据模型来管理充电基础设施,包含`Station`(充电站)、`Pile`(充电桩)和`Gun`
|
||||
(充电枪)三个核心实体。这三个实体之间形成了清晰的层级关系:一个充电站包含多个充电桩,而每个充电桩又包含多个充电枪。
|
||||
|
||||
`Station`实体代表一个物理的充电站,包含站点的基本信息如名称、编码、地理位置等。`Pile`
|
||||
实体代表一个具体的充电桩,除了名称和编码外,还包含了协议类型、品牌、型号等信息,并通过`stationId`字段与`Station`建立关联。
|
||||
`Gun`实体代表充电桩上的一个充电枪,通过`pileId`字段与`Pile`建立关联。
|
||||
|
||||
系统提供了完整的CRUD(创建、读取、更新、删除)操作API来管理这些实体。例如,`DefaultStationService`提供了`createStation()`、
|
||||
`getStationById()`、`updateStation()`和`deleteStation()`等方法。在删除操作中,系统实现了级联检查机制,确保在删除充电站前必须先删除其下的所有充电桩,从而维护数据的一致性。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Station {
|
||||
+UUID id
|
||||
+LocalDateTime createdTime
|
||||
+LocalDateTime updatedTime
|
||||
+JsonNode additionalInfo
|
||||
+String stationName
|
||||
+String stationCode
|
||||
+Float longitude
|
||||
+Float latitude
|
||||
+String province
|
||||
+String city
|
||||
+String county
|
||||
+String address
|
||||
+Integer version
|
||||
}
|
||||
class Pile {
|
||||
+UUID id
|
||||
+LocalDateTime createdTime
|
||||
+LocalDateTime updatedTime
|
||||
+JsonNode additionalInfo
|
||||
+String pileName
|
||||
+String pileCode
|
||||
+String protocol
|
||||
+UUID stationId
|
||||
+String brand
|
||||
+String model
|
||||
+String manufacturer
|
||||
+PileTypeEnum type
|
||||
+Integer version
|
||||
}
|
||||
class Gun {
|
||||
+UUID id
|
||||
+LocalDateTime createdTime
|
||||
+LocalDateTime updatedTime
|
||||
+JsonNode additionalInfo
|
||||
+String gunNo
|
||||
+String gunName
|
||||
+String gunCode
|
||||
+UUID stationId
|
||||
+UUID pileId
|
||||
+Integer version
|
||||
}
|
||||
Station "1" *-- "0..*" Pile : "包含"
|
||||
Pile "1" *-- "0..*" Gun : "包含"
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [Station.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Station.java)
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java)
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [Station.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Station.java#L1-L65)
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java#L1-L64)
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L56)
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L1-L247)
|
||||
- [DefaultPileService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileService.java#L1-L329)
|
||||
|
||||
## 协议实现模块
|
||||
|
||||
协议实现模块展示了如何通过继承`ProtocolBootstrap`和实现具体的命令处理器来支持特定厂商的通信协议。以云快充(YunKuaiChong)和绿能(Lvneng)为例,系统通过创建特定版本的
|
||||
`ProtocolBootstrap`实现类来支持不同版本的协议。
|
||||
|
||||
对于绿能协议,`LvnengV340ProtocolBootstrap`类继承自`ProtocolBootstrap`,并实现了`messageProcessor()`方法来返回
|
||||
`LvnengProtocolMessageProcessor`实例。该消息处理器负责解析绿能协议的帧结构,包括帧头、长度、加密标识、序号、命令字和校验和。当接收到心跳包时,
|
||||
`LvnengV340HeartbeatULCmd`命令处理器会被调用,它会解析充电桩编码和心跳序号,注册会话,并将心跳请求转发到后端服务。
|
||||
|
||||
对于云快充协议,`YunkuaichongV150ProtocolBootstrap`类同样继承自`ProtocolBootstrap`,并返回
|
||||
`YunKuaiChongProtocolMessageProcessor`实例。该消息处理器处理云快充协议的登录认证流程,通过`YunKuaiChongV150LoginULCmd`
|
||||
命令处理器解析充电桩编码、类型、枪数量等信息,并将登录请求转发到后端。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant 充电桩 as 充电桩
|
||||
participant 协议处理器 as 协议处理器
|
||||
participant 后端服务 as 后端服务
|
||||
充电桩->>协议处理器 : 发送心跳包
|
||||
协议处理器->>协议处理器 : 解析帧头和校验和
|
||||
协议处理器->>协议处理器 : 提取充电桩编码
|
||||
协议处理器->>协议处理器 : 注册会话
|
||||
协议处理器->>后端服务 : 转发心跳请求
|
||||
后端服务-->>协议处理器 : 返回响应
|
||||
协议处理器->>充电桩 : 发送心跳应答
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java)
|
||||
- [LvnengV340HeartbeatULCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340HeartbeatULCmd.java)
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java)
|
||||
- [YunKuaiChongV150LoginULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LoginULCmd.java)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java#L1-L41)
|
||||
- [LvnengV340HeartbeatULCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340HeartbeatULCmd.java#L1-L92)
|
||||
- [YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java#L1-L47)
|
||||
- [YunKuaiChongV150LoginULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LoginULCmd.java#L1-L84)
|
||||
- [LvnengProtocolMessageProcessor.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L1-L186)
|
||||
- [YunKuaiChongProtocolMessageProcessor.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java#L1-L203)
|
||||
980
docs/核心模块详解/设备管理模块/充电枪管理.md
Normal file
980
docs/核心模块详解/设备管理模块/充电枪管理.md
Normal file
@@ -0,0 +1,980 @@
|
||||
# 充电枪管理
|
||||
|
||||
<cite>
|
||||
**本文档引用文件**
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java)
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java)
|
||||
- [GunMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/GunMapper.java)
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java)
|
||||
- [GunRepository.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/GunRepository.java)
|
||||
- [GunRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/GunRepositoryImpl.java)
|
||||
- [GunCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/GunCreateRequest.java)
|
||||
- [GunUpdateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/GunUpdateRequest.java)
|
||||
- [GunWithStatusResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/GunWithStatusResponse.java)
|
||||
- [PageResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PageResponse.java)
|
||||
- [AttrKeyEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/data/kv/AttrKeyEnum.java)
|
||||
- [GunRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/gun/GunRedisCache.java)
|
||||
- [GunRunStatusEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/GunRunStatusEnum.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [简介](#简介)
|
||||
2. [数据模型](#数据模型)
|
||||
3. [RESTful API](#restful-api)
|
||||
4. [服务层实现](#服务层实现)
|
||||
5. [缓存机制](#缓存机制)
|
||||
6. [状态管理](#状态管理)
|
||||
7. [使用示例](#使用示例)
|
||||
8. [级联关系与状态同步](#级联关系与状态同步)
|
||||
|
||||
## 简介
|
||||
|
||||
本文档详细描述了充电枪管理功能的实现,包括数据模型、API接口、服务层逻辑、缓存机制和状态管理。系统通过Gun实体管理充电枪,支持创建、查询、更新和删除操作,并通过属性系统实时跟踪充电枪的运行状态。
|
||||
|
||||
## 数据模型
|
||||
|
||||
### Gun实体
|
||||
|
||||
`Gun`实体是充电枪的核心数据模型,定义了充电枪的基本属性和关系。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Gun {
|
||||
+UUID id
|
||||
+LocalDateTime createdTime
|
||||
+LocalDateTime updatedTime
|
||||
+JsonNode additionalInfo
|
||||
+String gunNo
|
||||
+String gunName
|
||||
+String gunCode
|
||||
+UUID stationId
|
||||
+UUID pileId
|
||||
+Integer version
|
||||
}
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L57)
|
||||
|
||||
**核心属性说明**
|
||||
|
||||
- **id**: 充电枪唯一标识符,UUID类型
|
||||
- **gunNo**: 充电枪编号,如"01"、"02"
|
||||
- **gunName**: 充电枪名称
|
||||
- **gunCode**: 充电枪编码,全局唯一标识
|
||||
- **stationId**: 所属充电站ID,与Station实体关联
|
||||
- **pileId**: 所属充电桩ID,与Pile实体关联
|
||||
|
||||
**实体关系**
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
GUN {
|
||||
uuid id PK
|
||||
string gunNo
|
||||
string gunName
|
||||
string gunCode UK
|
||||
uuid stationId FK
|
||||
uuid pileId FK
|
||||
timestamp createdTime
|
||||
timestamp updatedTime
|
||||
integer version
|
||||
}
|
||||
PILE {
|
||||
uuid id PK
|
||||
string pileCode UK
|
||||
}
|
||||
GUN ||--o{ PILE : "属于"
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L57)
|
||||
|
||||
**实体关系说明**
|
||||
|
||||
- **1对多关系**: 一个充电桩(Pile)可以有多个充电枪(Gun),形成1对多关系
|
||||
- **外键约束**: `pileId`字段作为外键关联到Pile实体
|
||||
- **唯一性约束**: `gunCode`字段具有唯一性约束,确保全局唯一
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L57)
|
||||
|
||||
## RESTful API
|
||||
|
||||
### API概览
|
||||
|
||||
`GunController`提供了完整的RESTful API接口,支持对充电枪的CRUD操作。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[客户端] --> B[POST /api/guns]
|
||||
A --> C[GET /api/guns/{id}]
|
||||
A --> D[PUT /api/guns/{id}]
|
||||
A --> E[DELETE /api/guns/{id}]
|
||||
A --> F[GET /api/guns]
|
||||
A --> G[GET /api/guns/status/{gunCode}]
|
||||
A --> H[GET /api/guns/code/{gunCode}]
|
||||
B --> I[创建充电枪]
|
||||
C --> J[查询单个充电枪]
|
||||
D --> K[更新充电枪]
|
||||
E --> L[删除充电枪]
|
||||
F --> M[分页查询充电枪]
|
||||
G --> N[查询充电枪状态]
|
||||
H --> O[查询充电枪详情]
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L1-L116)
|
||||
|
||||
### API详情
|
||||
|
||||
#### 创建充电枪 (POST /api/guns)
|
||||
|
||||
创建新的充电枪实体。
|
||||
|
||||
**请求参数**
|
||||
|
||||
- **HTTP方法**: POST
|
||||
- **URL**: /api/guns
|
||||
- **Content-Type**: application/json
|
||||
|
||||
**请求体 (GunCreateRequest)**
|
||||
|
||||
```json
|
||||
{
|
||||
"gunName": "快充枪1",
|
||||
"gunNo": "01",
|
||||
"gunCode": "GUN001",
|
||||
"stationId": "uuid-string",
|
||||
"pileId": "uuid-string"
|
||||
}
|
||||
```
|
||||
|
||||
**响应格式**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "创建成功",
|
||||
"data": {
|
||||
"id": "uuid-string",
|
||||
"createdTime": "2023-01-01T00:00:00",
|
||||
"gunName": "快充枪1",
|
||||
"gunNo": "01",
|
||||
"gunCode": "GUN001",
|
||||
"stationId": "uuid-string",
|
||||
"pileId": "uuid-string",
|
||||
"version": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**验证规则**
|
||||
|
||||
- `gunName`: 必填,不允许XSS攻击
|
||||
- `gunNo`: 必填
|
||||
- `gunCode`: 必填,不允许重复
|
||||
- `stationId`: 必填,有效UUID
|
||||
- `pileId`: 必填,有效UUID
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L25-L32)
|
||||
- [GunCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/GunCreateRequest.java#L1-L37)
|
||||
|
||||
#### 查询充电枪 (GET /api/guns)
|
||||
|
||||
分页查询充电枪列表,包含状态信息。
|
||||
|
||||
**请求参数**
|
||||
|
||||
- **HTTP方法**: GET
|
||||
- **URL**: /api/guns
|
||||
- **查询参数**:
|
||||
- `page`: 页码(默认1)
|
||||
- `size`: 每页大小(默认10)
|
||||
- `gunName`: 充电枪名称(可选)
|
||||
- `pileId`: 充电桩ID(可选)
|
||||
|
||||
**响应格式 (PageResponse<GunWithStatusResponse>)**
|
||||
|
||||
```json
|
||||
{
|
||||
"records": [
|
||||
{
|
||||
"id": "uuid-string",
|
||||
"gunName": "快充枪1",
|
||||
"gunNo": "01",
|
||||
"gunCode": "GUN001",
|
||||
"stationId": "uuid-string",
|
||||
"pileId": "uuid-string",
|
||||
"stationName": "充电站A",
|
||||
"pileName": "充电桩1",
|
||||
"pileCode": "PILE001",
|
||||
"runStatus": "CHARGING"
|
||||
}
|
||||
],
|
||||
"total": 1,
|
||||
"totalPages": 1,
|
||||
"page": 1,
|
||||
"size": 10
|
||||
}
|
||||
```
|
||||
|
||||
**分页参数**
|
||||
|
||||
- **records**: 当前页的数据列表
|
||||
- **total**: 总记录数
|
||||
- **totalPages**: 总页数
|
||||
- **page**: 当前页码
|
||||
- **size**: 每页大小
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L62-L68)
|
||||
- [PageResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PageResponse.java#L1-L44)
|
||||
- [GunWithStatusResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/GunWithStatusResponse.java#L1-L96)
|
||||
|
||||
#### 更新充电枪 (PUT /api/guns/{id})
|
||||
|
||||
更新指定ID的充电枪信息。
|
||||
|
||||
**请求参数**
|
||||
|
||||
- **HTTP方法**: PUT
|
||||
- **URL**: /api/guns/{id}
|
||||
- **路径参数**: id (充电枪UUID)
|
||||
- **请求体**: GunUpdateRequest
|
||||
|
||||
**请求体 (GunUpdateRequest)**
|
||||
|
||||
```json
|
||||
{
|
||||
"gunName": "快充枪1-更新",
|
||||
"gunNo": "01",
|
||||
"gunCode": "GUN001",
|
||||
"stationId": "uuid-string",
|
||||
"pileId": "uuid-string"
|
||||
}
|
||||
```
|
||||
|
||||
**响应格式**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "更新成功",
|
||||
"data": {
|
||||
"id": "uuid-string",
|
||||
"updatedTime": "2023-01-01T00:00:00",
|
||||
"gunName": "快充枪1-更新",
|
||||
"gunNo": "01",
|
||||
"gunCode": "GUN001",
|
||||
"stationId": "uuid-string",
|
||||
"pileId": "uuid-string"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**更新规则**
|
||||
|
||||
- 允许修改所有字段
|
||||
- 更新时自动设置`updatedTime`字段
|
||||
- 版本号保持不变
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L34-L43)
|
||||
- [GunUpdateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/GunUpdateRequest.java#L1-L36)
|
||||
|
||||
#### 删除充电枪 (DELETE /api/guns/{id})
|
||||
|
||||
删除指定ID的充电枪。
|
||||
|
||||
**请求参数**
|
||||
|
||||
- **HTTP方法**: DELETE
|
||||
- **URL**: /api/guns/{id}
|
||||
- **路径参数**: id (充电枪UUID)
|
||||
|
||||
**响应格式**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "删除成功",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**删除逻辑**
|
||||
|
||||
- 先检查充电枪是否存在
|
||||
- 执行物理删除操作
|
||||
- 返回成功或失败状态
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L45-L51)
|
||||
|
||||
#### 查询充电枪状态 (GET /api/guns/status/{gunCode})
|
||||
|
||||
根据充电枪编码查询其运行状态。
|
||||
|
||||
**请求参数**
|
||||
|
||||
- **HTTP方法**: GET
|
||||
- **URL**: /api/guns/status/{gunCode}
|
||||
- **路径参数**: gunCode (充电枪编码)
|
||||
|
||||
**响应格式**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "查询成功",
|
||||
"data": "CHARGING"
|
||||
}
|
||||
```
|
||||
|
||||
**状态查询流程**
|
||||
|
||||
1. 根据`gunCode`查找充电枪实体
|
||||
2. 通过`AttributeService`获取`gunRunStatus`属性
|
||||
3. 返回状态值
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L69-L96)
|
||||
|
||||
#### 查询充电枪详情 (GET /api/guns/code/{gunCode})
|
||||
|
||||
根据充电枪编码查询其详细信息,包含状态。
|
||||
|
||||
**请求参数**
|
||||
|
||||
- **HTTP方法**: GET
|
||||
- **URL**: /api/guns/code/{gunCode}
|
||||
- **路径参数**: gunCode (充电枪编码)
|
||||
|
||||
**响应格式**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "查询成功",
|
||||
"data": {
|
||||
"id": "uuid-string",
|
||||
"gunName": "快充枪1",
|
||||
"gunNo": "01",
|
||||
"gunCode": "GUN001",
|
||||
"stationId": "uuid-string",
|
||||
"pileId": "uuid-string",
|
||||
"stationName": "充电站A",
|
||||
"pileName": "充电桩1",
|
||||
"pileCode": "PILE001",
|
||||
"runStatus": "CHARGING"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**详情查询特点**
|
||||
|
||||
- 返回完整的`GunWithStatusResponse`对象
|
||||
- 包含关联的充电站和充电桩信息
|
||||
- 包含当前运行状态
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L98-L115)
|
||||
|
||||
## 服务层实现
|
||||
|
||||
### DefaultGunService架构
|
||||
|
||||
`DefaultGunService`是充电枪业务逻辑的核心实现,协调数据访问和缓存操作。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class DefaultGunService {
|
||||
-GunMapper gunMapper
|
||||
-GunRepository gunRepository
|
||||
-AttributeService attributeService
|
||||
+createGun(GunCreateRequest) Gun
|
||||
+findById(UUID) Gun
|
||||
+updateGun(UUID, GunUpdateRequest) Gun
|
||||
+deleteGun(UUID) void
|
||||
+queryGunsWithStatus(GunQueryRequest) PageResponse
|
||||
+findByPileCodeAndGunNo(String, String) Gun
|
||||
+findByGunCode(String) Gun
|
||||
+findGunWithStatusByCode(String) GunWithStatusResponse
|
||||
+findGunStatus(UUID) String
|
||||
+saveGunStatusChange(UUID, String, Long) void
|
||||
+handleGunRunStatus(String, String, GunRunStatus, long) boolean
|
||||
}
|
||||
class GunService {
|
||||
<<interface>>
|
||||
+createGun(GunCreateRequest) Gun
|
||||
+findById(UUID) Gun
|
||||
+updateGun(UUID, GunUpdateRequest) Gun
|
||||
+deleteGun(UUID) void
|
||||
+queryGunsWithStatus(GunQueryRequest) PageResponse
|
||||
+findByPileCodeAndGunNo(String, String) Gun
|
||||
+findByGunCode(String) Gun
|
||||
+findGunWithStatusByCode(String) GunWithStatusResponse
|
||||
+findGunStatus(UUID) String
|
||||
+saveGunStatusChange(UUID, String, Long) void
|
||||
+handleGunRunStatus(String, String, GunRunStatus, long) boolean
|
||||
}
|
||||
DefaultGunService --|> GunService : 实现
|
||||
DefaultGunService --> GunMapper : 使用
|
||||
DefaultGunService --> GunRepository : 使用
|
||||
DefaultGunService --> AttributeService : 使用
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L1-L246)
|
||||
|
||||
### 核心方法分析
|
||||
|
||||
#### 创建充电枪 (createGun)
|
||||
|
||||
实现充电枪的创建逻辑。
|
||||
|
||||
**处理流程**
|
||||
|
||||
1. 检查`gunCode`是否已存在
|
||||
2. 构建新的`Gun`实体
|
||||
3. 设置默认值(ID、创建时间、版本等)
|
||||
4. 插入数据库
|
||||
|
||||
**验证逻辑**
|
||||
|
||||
- 使用`LambdaQueryWrapper`检查`gunCode`唯一性
|
||||
- 抛出异常阻止重复创建
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L48-L75)
|
||||
|
||||
#### 查询充电枪状态 (findGunStatus)
|
||||
|
||||
从属性系统中查询充电枪的运行状态。
|
||||
|
||||
**实现细节**
|
||||
|
||||
- 使用`AttributeService.find()`异步获取属性
|
||||
- 属性键为`AttrKeyEnum.GUN_RUN_STATUS.getCode()`
|
||||
- 返回字符串格式的状态值
|
||||
|
||||
**异步处理**
|
||||
|
||||
- 使用`ListenableFuture`进行异步调用
|
||||
- 通过`get()`方法阻塞等待结果
|
||||
- 包含异常处理逻辑
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L178-L193)
|
||||
|
||||
#### 保存充电枪状态 (saveGunStatusChange)
|
||||
|
||||
将充电枪状态保存到属性系统。
|
||||
|
||||
**实现细节**
|
||||
|
||||
- 创建`BaseAttributeKvEntry`对象
|
||||
- 使用`StringDataEntry`存储状态值
|
||||
- 调用`attributeService.save()`持久化
|
||||
|
||||
**时间戳处理**
|
||||
|
||||
- 使用传入的`ts`参数或当前时间
|
||||
- 支持精确到毫秒的时间戳
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L195-L208)
|
||||
|
||||
#### 处理充电枪运行状态 (handleGunRunStatus)
|
||||
|
||||
处理从协议层上报的充电枪状态。
|
||||
|
||||
**处理流程**
|
||||
|
||||
1. 将Proto状态转换为数据库枚举
|
||||
2. 根据`pileCode`和`gunNo`查找充电枪
|
||||
3. 检查状态是否发生变化
|
||||
4. 保存新状态到属性系统
|
||||
5. 判断是否需要更新充电桩状态
|
||||
|
||||
**状态转换**
|
||||
|
||||
- 实现Proto状态到数据库枚举的映射
|
||||
- 支持多种状态类型(空闲、充电中、故障等)
|
||||
- 未知状态返回null
|
||||
|
||||
**状态同步**
|
||||
|
||||
- 检查当前状态避免重复更新
|
||||
- 记录状态变化日志
|
||||
- 触发相关业务逻辑
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L210-L244)
|
||||
|
||||
## 缓存机制
|
||||
|
||||
### 缓存架构
|
||||
|
||||
系统采用多级缓存策略提升查询性能。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[应用层] --> B[GunService]
|
||||
B --> C[GunRepository]
|
||||
C --> D[GunRedisCache]
|
||||
D --> E[Redis]
|
||||
C --> F[GunMapper]
|
||||
F --> G[数据库]
|
||||
style D fill:#f9f,stroke:#333
|
||||
style F fill:#bbf,stroke:#333
|
||||
subgraph "缓存层"
|
||||
D
|
||||
E
|
||||
end
|
||||
subgraph "持久层"
|
||||
F
|
||||
G
|
||||
end
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [GunRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/GunRepositoryImpl.java#L1-L97)
|
||||
- [GunRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/gun/GunRedisCache.java#L1-L36)
|
||||
|
||||
### GunRedisCache实现
|
||||
|
||||
`GunRedisCache`是基于Redis的充电枪缓存实现。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class GunRedisCache {
|
||||
+String cacheName
|
||||
+CacheSpecsMap cacheSpecsMap
|
||||
+LettuceConnectionFactory connectionFactory
|
||||
+JCPPRedisSerializer serializer
|
||||
+serialize(Gun) byte[]
|
||||
+deserialize(GunCacheKey, byte[]) Gun
|
||||
}
|
||||
class VersionedRedisCache {
|
||||
<<abstract>>
|
||||
+get(K, Callable<V>) V
|
||||
+evict(K) void
|
||||
+evict(Collection<K>) void
|
||||
}
|
||||
GunRedisCache --|> VersionedRedisCache : 继承
|
||||
GunRedisCache --> Gun : 序列化/反序列化
|
||||
GunRedisCache --> JacksonUtil : JSON转换
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [GunRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/gun/GunRedisCache.java#L1-L36)
|
||||
|
||||
**核心特性**
|
||||
|
||||
- 使用`JCPPRedisSerializer`进行序列化
|
||||
- 基于`JacksonUtil`实现JSON转换
|
||||
- 支持版本化缓存
|
||||
- 配置化缓存策略
|
||||
|
||||
**序列化实现**
|
||||
|
||||
- `serialize()`: 使用Jackson将Gun对象转换为字节数组
|
||||
- `deserialize()`: 从字节数组反序列化为Gun对象
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/gun/GunRedisCache.java#L1-L36)
|
||||
|
||||
### 缓存键设计 (GunCacheKey)
|
||||
|
||||
缓存键设计支持多种查询场景。
|
||||
|
||||
```java
|
||||
// 伪代码表示GunCacheKey的设计
|
||||
public class GunCacheKey {
|
||||
private UUID gunId; // 基于ID的缓存
|
||||
private String pileCode; // 基于桩编码的缓存
|
||||
private String gunNo; // 基于枪编号的缓存
|
||||
private String gunCode; // 基于枪编码的缓存
|
||||
|
||||
// 支持多种构造函数
|
||||
public GunCacheKey(UUID gunId)
|
||||
public GunCacheKey(String pileCode, String gunNo)
|
||||
public GunCacheKey(String gunCode)
|
||||
}
|
||||
```
|
||||
|
||||
**缓存键类型**
|
||||
|
||||
- **基于ID**: `new GunCacheKey(gunId)`
|
||||
- **基于桩编码+枪编号**: `new GunCacheKey(pileCode, gunNo)`
|
||||
- **基于枪编码**: `new GunCacheKey(gunCode)`
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/GunRepositoryImpl.java#L1-L97)
|
||||
|
||||
### 缓存事件处理
|
||||
|
||||
通过事件机制维护缓存一致性。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Service as DefaultGunService
|
||||
participant Repository as GunRepositoryImpl
|
||||
participant Cache as GunRedisCache
|
||||
participant Event as GunCacheEvictEvent
|
||||
Service->>Repository : updateGun()
|
||||
Repository->>Repository : handleEvictEvent()
|
||||
Repository->>Cache : evict()
|
||||
Cache->>Redis : 删除缓存
|
||||
Repository->>Repository : 查询数据库
|
||||
Repository-->>Service : 返回结果
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [GunRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/GunRepositoryImpl.java#L1-L97)
|
||||
|
||||
**事件处理流程**
|
||||
|
||||
1. 服务层执行更新或删除操作
|
||||
2. 触发`GunCacheEvictEvent`事件
|
||||
3. `GunRepositoryImpl`监听并处理事件
|
||||
4. 从Redis缓存中删除相关键
|
||||
5. 后续查询将从数据库获取最新数据
|
||||
|
||||
**缓存失效策略**
|
||||
|
||||
- 写操作后立即失效缓存
|
||||
- 支持批量失效多个缓存键
|
||||
- 保证缓存与数据库的一致性
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/GunRepositoryImpl.java#L25-L45)
|
||||
|
||||
## 状态管理
|
||||
|
||||
### 运行状态枚举 (GunRunStatusEnum)
|
||||
|
||||
定义了充电枪的所有可能运行状态。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class GunRunStatusEnum {
|
||||
+IDLE
|
||||
+INSERTED
|
||||
+CHARGING
|
||||
+CHARGE_COMPLETE
|
||||
+DISCHARGE_READY
|
||||
+DISCHARGING
|
||||
+DISCHARGE_COMPLETE
|
||||
+RESERVED
|
||||
+FAULT
|
||||
}
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [GunRunStatusEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/GunRunStatusEnum.java)
|
||||
|
||||
**状态说明**
|
||||
|
||||
- **IDLE**: 空闲状态,未连接车辆
|
||||
- **INSERTED**: 已插枪,未开始充电
|
||||
- **CHARGING**: 正在充电
|
||||
- **CHARGE_COMPLETE**: 充电完成
|
||||
- **DISCHARGE_READY**: 放电准备
|
||||
- **DISCHARGING**: 正在放电
|
||||
- **DISCHARGE_COMPLETE**: 放电完成
|
||||
- **RESERVED**: 已预约
|
||||
- **FAULT**: 故障状态
|
||||
|
||||
**状态转换**
|
||||
|
||||
- 通过`switch`语句实现Proto状态到枚举的转换
|
||||
- 未知状态返回null,不进行更新
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunRunStatusEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/GunRunStatusEnum.java)
|
||||
|
||||
### 状态获取流程
|
||||
|
||||
从协议会话中获取和更新充电枪状态。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Protocol as 协议层
|
||||
participant Service as DefaultGunService
|
||||
participant Attribute as AttributeService
|
||||
participant Redis as Redis
|
||||
participant DB as 数据库
|
||||
Protocol->>Service : handleGunRunStatus(pileCode, gunNo, protoStatus, ts)
|
||||
Service->>Service : convertProtoStatusToDbStatus()
|
||||
Service->>Repository : findByPileCodeAndGunNo(pileCode, gunNo)
|
||||
Repository->>Redis : 查询缓存
|
||||
Redis-->>Repository : 返回结果
|
||||
Repository-->>Service : 返回Gun实体
|
||||
Service->>Service : findGunStatus(gunId)
|
||||
Service->>Attribute : find(gunId, GUN_RUN_STATUS)
|
||||
Attribute->>Redis : 查询属性缓存
|
||||
Redis-->>Attribute : 返回状态
|
||||
Attribute-->>Service : 返回当前状态
|
||||
alt 状态发生变化
|
||||
Service->>Service : saveGunStatusChange(gunId, status, ts)
|
||||
Service->>Attribute : save(gunId, attribute)
|
||||
Attribute->>Redis : 保存属性
|
||||
Redis-->>Attribute : 确认
|
||||
Attribute-->>Service : 确认
|
||||
Service-->>Protocol : 返回true
|
||||
else 状态未变化
|
||||
Service-->>Protocol : 返回false
|
||||
end
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L210-L244)
|
||||
|
||||
**状态同步机制**
|
||||
|
||||
1. 协议层上报充电枪状态
|
||||
2. 服务层转换状态格式
|
||||
3. 查找对应的充电枪实体
|
||||
4. 获取当前状态进行比较
|
||||
5. 只有状态变化时才更新
|
||||
6. 保存新状态到属性系统
|
||||
|
||||
**性能优化**
|
||||
|
||||
- 使用缓存减少数据库查询
|
||||
- 状态比较避免不必要的更新
|
||||
- 异步属性服务提高响应速度
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L210-L244)
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 为充电桩配置两把充电枪
|
||||
|
||||
展示如何为一个充电桩配置两把充电枪的完整流程。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始]) --> CreatePile["创建充电桩"]
|
||||
CreatePile --> GetPileId["获取充电桩ID"]
|
||||
GetPileId --> CreateGun1["创建第一把充电枪"]
|
||||
CreateGun1 --> SetGun1Props["设置第一把枪属性"]
|
||||
SetGun1Props --> CreateGun2["创建第二把充电枪"]
|
||||
CreateGun2 --> SetGun2Props["设置第二把枪属性"]
|
||||
SetGun2Props --> Verify["验证配置结果"]
|
||||
Verify --> End([完成])
|
||||
style CreatePile fill:#9f9,stroke:#333
|
||||
style CreateGun1 fill:#9f9,stroke:#333
|
||||
style CreateGun2 fill:#9f9,stroke:#333
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L48-L75)
|
||||
|
||||
**实现步骤**
|
||||
|
||||
#### 步骤1: 创建充电桩
|
||||
|
||||
首先创建一个充电桩实体。
|
||||
|
||||
```java
|
||||
// 伪代码:创建充电桩
|
||||
Pile pile = pileService.createPile(createRequest);
|
||||
UUID pileId = pile.getId();
|
||||
```
|
||||
|
||||
#### 步骤2: 创建第一把充电枪
|
||||
|
||||
为充电桩创建第一把充电枪。
|
||||
|
||||
```java
|
||||
// 伪代码:创建第一把充电枪
|
||||
GunCreateRequest gun1Request = GunCreateRequest.builder()
|
||||
.gunName("快充枪1")
|
||||
.gunNo("01")
|
||||
.gunCode("GUN001")
|
||||
.stationId(stationId)
|
||||
.pileId(pileId)
|
||||
.build();
|
||||
|
||||
Gun gun1 = gunService.createGun(gun1Request);
|
||||
```
|
||||
|
||||
#### 步骤3: 创建第二把充电枪
|
||||
|
||||
为同一充电桩创建第二把充电枪。
|
||||
|
||||
```java
|
||||
// 伪代码:创建第二把充电枪
|
||||
GunCreateRequest gun2Request = GunCreateRequest.builder()
|
||||
.gunName("快充枪2")
|
||||
.gunNo("02")
|
||||
.gunCode("GUN002")
|
||||
.stationId(stationId)
|
||||
.pileId(pileId)
|
||||
.build();
|
||||
|
||||
Gun gun2 = gunService.createGun(gun2Request);
|
||||
```
|
||||
|
||||
#### 步骤4: 验证配置结果
|
||||
|
||||
查询充电桩下的所有充电枪。
|
||||
|
||||
```java
|
||||
// 伪代码:验证配置
|
||||
List<Gun> guns = gunService.findByPileId(pileId);
|
||||
assert guns.size() == 2;
|
||||
|
||||
GunWithStatusResponse gun1Status = gunService.findGunWithStatusByCode("GUN001");
|
||||
GunWithStatusResponse gun2Status = gunService.findGunWithStatusByCode("GUN002");
|
||||
```
|
||||
|
||||
**关键要点**
|
||||
|
||||
- 两把充电枪共享同一个`pileId`
|
||||
- `gunNo`在同一充电桩下必须唯一
|
||||
- `gunCode`在整个系统中必须唯一
|
||||
- 可以独立管理每把充电枪的状态
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L48-L75)
|
||||
- [GunMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/GunMapper.java#L1-L132)
|
||||
|
||||
## 级联关系与状态同步
|
||||
|
||||
### 级联关系管理
|
||||
|
||||
充电枪与充电桩之间的级联关系管理。
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
STATION ||--o{ PILE : "拥有"
|
||||
PILE ||--o{ GUN : "拥有"
|
||||
STATION {
|
||||
uuid id PK
|
||||
string stationName
|
||||
}
|
||||
PILE {
|
||||
uuid id PK
|
||||
string pileCode UK
|
||||
uuid stationId FK
|
||||
}
|
||||
GUN {
|
||||
uuid id PK
|
||||
string gunCode UK
|
||||
uuid pileId FK
|
||||
string gunNo
|
||||
}
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L57)
|
||||
|
||||
**级联操作**
|
||||
|
||||
- **创建**: 充电枪必须关联到存在的充电桩
|
||||
- **查询**: 支持通过充电桩查询所有充电枪
|
||||
- **更新**: 可以修改充电枪所属的充电桩
|
||||
- **删除**: 删除充电桩时级联删除所有充电枪
|
||||
|
||||
**外键约束**
|
||||
|
||||
- `pileId`字段确保充电枪必须属于某个充电桩
|
||||
- 数据库层面保证引用完整性
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L57)
|
||||
|
||||
### 状态同步机制
|
||||
|
||||
充电枪状态变化时与充电桩的状态同步。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
GunStatusChange["充电枪状态变化"] --> CheckStatus["检查新状态"]
|
||||
CheckStatus --> |CHARGING| UpdatePile["更新充电桩状态"]
|
||||
CheckStatus --> |DISCHARGING| UpdatePile["更新充电桩状态"]
|
||||
CheckStatus --> |FAULT| UpdatePile["更新充电桩状态"]
|
||||
CheckStatus --> |其他状态| NoUpdate["不更新"]
|
||||
UpdatePile --> PileService["调用PileService"]
|
||||
PileService --> UpdateStatus["更新充电桩状态"]
|
||||
UpdateStatus --> Log["记录日志"]
|
||||
Log --> End([完成])
|
||||
style UpdatePile fill:#f96,stroke:#333
|
||||
style NoUpdate fill:#69f,stroke:#333
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L233-L244)
|
||||
|
||||
**同步规则**
|
||||
|
||||
```java
|
||||
private boolean shouldUpdatePileStatus(GunRunStatusEnum gunStatus) {
|
||||
return switch (gunStatus) {
|
||||
case CHARGING, DISCHARGING -> true; // 充电或放电时更新
|
||||
case FAULT -> true; // 故障时更新
|
||||
default -> false; // 其他状态不更新
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**触发条件**
|
||||
|
||||
- **充电开始**: 充电枪状态变为`CHARGING`
|
||||
- **放电开始**: 充电枪状态变为`DISCHARGING`
|
||||
- **故障发生**: 充电枪状态变为`FAULT`
|
||||
|
||||
**同步流程**
|
||||
|
||||
1. 充电枪状态发生变化
|
||||
2. 调用`shouldUpdatePileStatus()`判断是否需要同步
|
||||
3. 如果需要,通知`PileService`更新充电桩状态
|
||||
4. 更新充电桩的在线状态和运行状态
|
||||
|
||||
**性能考虑**
|
||||
|
||||
- 只在必要时触发同步,减少不必要的操作
|
||||
- 使用异步机制避免阻塞主流程
|
||||
- 缓存充电桩状态减少数据库查询
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L233-L244)
|
||||
699
docs/核心模块详解/设备管理模块/充电桩管理.md
Normal file
699
docs/核心模块详解/设备管理模块/充电桩管理.md
Normal file
@@ -0,0 +1,699 @@
|
||||
# 充电桩管理
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java)
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java)
|
||||
- [PileCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/PileCreateRequest.java)
|
||||
- [PileUpdateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/PileUpdateRequest.java)
|
||||
- [PileWithStatusResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PileWithStatusResponse.java)
|
||||
- [DefaultPileService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileService.java)
|
||||
- [PileRepository.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/PileRepository.java)
|
||||
- [PileRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/PileRepositoryImpl.java)
|
||||
- [PileStatusEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/PileStatusEnum.java)
|
||||
- [PileTypeEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/PileTypeEnum.java)
|
||||
- [StartChargeDTO.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/dto/StartChargeDTO.java)
|
||||
- [RestartPileDTO.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/dto/RestartPileDTO.java)
|
||||
- [DefaultPileProtocolService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java)
|
||||
- [RpcController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [简介](#简介)
|
||||
2. [数据模型](#数据模型)
|
||||
3. [RESTful API](#restful-api)
|
||||
4. [业务逻辑处理](#业务逻辑处理)
|
||||
5. [远程控制操作](#远程控制操作)
|
||||
6. [使用示例](#使用示例)
|
||||
7. [状态机与实时同步](#状态机与实时同步)
|
||||
|
||||
## 简介
|
||||
|
||||
本文档详细阐述了充电桩管理功能的实现,包括充电桩实体的数据模型、RESTful
|
||||
API接口、业务逻辑处理以及远程控制操作。系统采用分层架构,通过Pile实体表示充电桩,PileController提供RESTful
|
||||
API,DefaultPileService处理业务逻辑,PileRepository负责数据持久化,DownlinkCallService实现远程控制指令的发送。
|
||||
|
||||
## 数据模型
|
||||
|
||||
充电桩管理功能的核心是Pile实体,它表示一个物理充电桩,包含其基本信息、状态和与充电站的关系。
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
PILE {
|
||||
uuid id PK
|
||||
timestamp createdTime
|
||||
timestamp updatedTime
|
||||
string pileName
|
||||
string pileCode UK
|
||||
string protocol
|
||||
uuid stationId FK
|
||||
string brand
|
||||
string model
|
||||
string manufacturer
|
||||
string type
|
||||
integer version
|
||||
json additionalInfo
|
||||
}
|
||||
STATION {
|
||||
uuid id PK
|
||||
string stationName
|
||||
string stationCode UK
|
||||
}
|
||||
PILE ||--o{ STATION : "属于"
|
||||
```
|
||||
|
||||
**图源**
|
||||
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java#L1-L63)
|
||||
- [PileTypeEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/PileTypeEnum.java#L1-L22)
|
||||
|
||||
### Pile实体核心属性
|
||||
|
||||
Pile实体定义了充电桩的核心属性,这些属性在数据库中持久化存储。
|
||||
|
||||
| 属性名 | 类型 | 描述 | 约束 |
|
||||
|----------------|---------------|----------|--------------|
|
||||
| id | UUID | 充电桩唯一标识符 | 主键 |
|
||||
| pileName | String | 充电桩名称 | 非空,防XSS攻击 |
|
||||
| pileCode | String | 充电桩编号 | 唯一,非空,防XSS攻击 |
|
||||
| protocol | String | 通信协议类型 | 非空,防XSS攻击 |
|
||||
| stationId | UUID | 所属充电站ID | 外键,非空 |
|
||||
| brand | String | 品牌 | 防XSS攻击 |
|
||||
| model | String | 型号 | 防XSS攻击 |
|
||||
| manufacturer | String | 制造商 | 防XSS攻击 |
|
||||
| type | PileTypeEnum | 充电桩类型 | 枚举值 |
|
||||
| createdTime | LocalDateTime | 创建时间 | 自动填充 |
|
||||
| updatedTime | LocalDateTime | 更新时间 | 自动填充 |
|
||||
| additionalInfo | JsonNode | 附加信息 | JSON格式 |
|
||||
| version | Integer | 版本号 | 用于乐观锁 |
|
||||
|
||||
**节源**
|
||||
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java#L1-L63)
|
||||
|
||||
### PileStatusEnum状态枚举
|
||||
|
||||
充电桩状态枚举定义了充电桩的在线/离线状态,独立于充电枪的工作状态。
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> OFFLINE
|
||||
OFFLINE --> ONLINE : 设备登录成功
|
||||
OFFLINE --> ONLINE : 心跳正常
|
||||
ONLINE --> OFFLINE : 设备断开连接
|
||||
ONLINE --> OFFLINE : 心跳超时
|
||||
OFFLINE --> OFFLINE : 设备未登录
|
||||
ONLINE --> ONLINE : 能正常通信
|
||||
```
|
||||
|
||||
充电桩状态设计原则:
|
||||
|
||||
- 状态独立于充电枪状态,不受枪的工作状态影响
|
||||
- 只关注设备的网络连接状态和基础可用性
|
||||
- 状态转换由设备登录、心跳和连接状态决定
|
||||
|
||||
**节源**
|
||||
|
||||
- [PileStatusEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/PileStatusEnum.java#L1-L50)
|
||||
|
||||
### PileTypeEnum类型枚举
|
||||
|
||||
充电桩类型枚举定义了充电桩的类型,目前支持交流和直流两种类型。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class PileTypeEnum {
|
||||
+AC : PileTypeEnum
|
||||
+DC : PileTypeEnum
|
||||
+getValue() String
|
||||
}
|
||||
```
|
||||
|
||||
| 枚举值 | 描述 |
|
||||
|-----|-------|
|
||||
| AC | 交流充电桩 |
|
||||
| DC | 直流充电桩 |
|
||||
|
||||
**节源**
|
||||
|
||||
- [PileTypeEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/PileTypeEnum.java#L1-L22)
|
||||
|
||||
### 与Station的多对一关系
|
||||
|
||||
每个充电桩属于一个充电站,形成多对一的关系。这种关系通过Pile实体中的stationId字段实现,该字段是外键,指向Station实体的id。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Pile {
|
||||
-UUID id
|
||||
-String pileName
|
||||
-String pileCode
|
||||
-UUID stationId
|
||||
+getStationId() UUID
|
||||
}
|
||||
class Station {
|
||||
-UUID id
|
||||
-String stationName
|
||||
-String stationCode
|
||||
+getId() UUID
|
||||
}
|
||||
Pile --> Station : "属于"
|
||||
```
|
||||
|
||||
**图源**
|
||||
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java#L1-L63)
|
||||
|
||||
## RESTful API
|
||||
|
||||
PileController类暴露了充电桩管理的RESTful API,提供了对充电桩的增删改查和远程控制操作。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "PileController"
|
||||
A[POST /piles]
|
||||
B[GET /piles]
|
||||
C[PUT /piles/{id}]
|
||||
D[DELETE /piles/{id}]
|
||||
E[GET /piles/{id}]
|
||||
F[POST /piles/{id}/start-charge]
|
||||
G[POST /piles/{id}/restart]
|
||||
end
|
||||
Client --> A
|
||||
Client --> B
|
||||
Client --> C
|
||||
Client --> D
|
||||
Client --> E
|
||||
Client --> F
|
||||
Client --> G
|
||||
```
|
||||
|
||||
**图源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L1-L111)
|
||||
|
||||
### 创建充电桩 (POST /piles)
|
||||
|
||||
创建新的充电桩,需要提供充电桩的基本信息。
|
||||
|
||||
#### 请求
|
||||
|
||||
- **方法**: POST
|
||||
- **路径**: /api/piles
|
||||
- **认证**: 需要有效的JWT令牌
|
||||
- **授权**: 需要管理员权限
|
||||
|
||||
#### 请求DTO (PileCreateRequest)
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class PileCreateRequest {
|
||||
+pileName : String
|
||||
+pileCode : String
|
||||
+protocol : String
|
||||
+stationId : UUID
|
||||
+brand : String
|
||||
+model : String
|
||||
+manufacturer : String
|
||||
+type : PileTypeEnum
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必填 | 描述 |
|
||||
|--------------|--------------|----|-------------|
|
||||
| pileName | String | 是 | 充电桩名称 |
|
||||
| pileCode | String | 是 | 充电桩编号 |
|
||||
| protocol | String | 是 | 通信协议 |
|
||||
| stationId | UUID | 是 | 所属充电站ID |
|
||||
| brand | String | 否 | 品牌 |
|
||||
| model | String | 否 | 型号 |
|
||||
| manufacturer | String | 否 | 制造商 |
|
||||
| type | PileTypeEnum | 否 | 充电桩类型,默认为DC |
|
||||
|
||||
#### 响应
|
||||
|
||||
- **成功**: HTTP 200,返回创建的Pile实体
|
||||
- **失败**: HTTP 400,参数验证失败;HTTP 409,充电桩编号已存在
|
||||
|
||||
**节源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L25-L34)
|
||||
- [PileCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/PileCreateRequest.java#L1-L45)
|
||||
|
||||
### 分页查询充电桩 (GET /piles)
|
||||
|
||||
分页查询充电桩列表,支持多种查询条件。
|
||||
|
||||
#### 请求
|
||||
|
||||
- **方法**: GET
|
||||
- **路径**: /api/piles
|
||||
- **认证**: 需要有效的JWT令牌
|
||||
- **授权**: 需要查看权限
|
||||
|
||||
#### 请求参数 (PileQueryRequest)
|
||||
|
||||
| 参数 | 类型 | 描述 |
|
||||
|--------------|----------------|-------------|
|
||||
| page | Integer | 页码,从1开始 |
|
||||
| size | Integer | 每页大小 |
|
||||
| pileName | String | 充电桩名称(模糊查询) |
|
||||
| pileCode | String | 充电桩编号 |
|
||||
| protocol | String | 通信协议 |
|
||||
| stationId | UUID | 所属充电站ID |
|
||||
| brand | String | 品牌 |
|
||||
| model | String | 型号 |
|
||||
| manufacturer | String | 制造商 |
|
||||
| type | PileTypeEnum | 充电桩类型 |
|
||||
| status | PileStatusEnum | 充电桩状态 |
|
||||
|
||||
#### 响应DTO (PileWithStatusResponse)
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class PileWithStatusResponse {
|
||||
+id : UUID
|
||||
+createdTime : LocalDateTime
|
||||
+updatedTime : LocalDateTime
|
||||
+pileName : String
|
||||
+pileCode : String
|
||||
+protocol : String
|
||||
+stationId : UUID
|
||||
+brand : String
|
||||
+model : String
|
||||
+manufacturer : String
|
||||
+type : PileTypeEnum
|
||||
+status : PileStatusEnum
|
||||
+connectedAt : Long
|
||||
+disconnectedAt : Long
|
||||
+lastActiveTime : Long
|
||||
+gunCount : Long
|
||||
}
|
||||
```
|
||||
|
||||
响应包含分页信息和充电桩列表,每个充电桩都包含其状态信息。
|
||||
|
||||
#### 响应
|
||||
|
||||
- **成功**: HTTP 200,返回PageResponse<PileWithStatusResponse>
|
||||
- **失败**: HTTP 400,参数验证失败
|
||||
|
||||
**节源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L68-L77)
|
||||
- [PileQueryRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/PileQueryRequest.java#L1-L36)
|
||||
- [PileWithStatusResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PileWithStatusResponse.java#L1-L116)
|
||||
|
||||
### 更新充电桩 (PUT /piles/{id})
|
||||
|
||||
更新现有充电桩的信息。
|
||||
|
||||
#### 请求
|
||||
|
||||
- **方法**: PUT
|
||||
- **路径**: /api/piles/{id}
|
||||
- **认证**: 需要有效的JWT令牌
|
||||
- **授权**: 需要编辑权限
|
||||
|
||||
#### 请求DTO (PileUpdateRequest)
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class PileUpdateRequest {
|
||||
+pileName : String
|
||||
+protocol : String
|
||||
+brand : String
|
||||
+model : String
|
||||
+manufacturer : String
|
||||
+type : PileTypeEnum
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必填 | 描述 |
|
||||
|--------------|--------------|----|-------|
|
||||
| pileName | String | 是 | 充电桩名称 |
|
||||
| protocol | String | 是 | 通信协议 |
|
||||
| brand | String | 否 | 品牌 |
|
||||
| model | String | 否 | 型号 |
|
||||
| manufacturer | String | 否 | 制造商 |
|
||||
| type | PileTypeEnum | 否 | 充电桩类型 |
|
||||
|
||||
#### 响应
|
||||
|
||||
- **成功**: HTTP 200,返回更新后的Pile实体
|
||||
- **失败**: HTTP 404,充电桩不存在;HTTP 400,参数验证失败
|
||||
|
||||
**节源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L40-L50)
|
||||
- [PileUpdateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/PileUpdateRequest.java#L1-L35)
|
||||
|
||||
### 删除充电桩 (DELETE /piles/{id})
|
||||
|
||||
删除指定ID的充电桩。
|
||||
|
||||
#### 请求
|
||||
|
||||
- **方法**: DELETE
|
||||
- **路径**: /api/piles/{id}
|
||||
- **认证**: 需要有效的JWT令牌
|
||||
- **授权**: 需要删除权限
|
||||
|
||||
#### 响应
|
||||
|
||||
- **成功**: HTTP 200,返回成功消息
|
||||
- **失败**: HTTP 404,充电桩不存在;HTTP 409,充电桩下有充电枪
|
||||
|
||||
**节源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L52-L60)
|
||||
|
||||
## 业务逻辑处理
|
||||
|
||||
DefaultPileService类负责处理充电桩管理的核心业务逻辑,包括数据持久化、缓存交互和状态管理。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as "客户端"
|
||||
participant Controller as "PileController"
|
||||
participant Service as "DefaultPileService"
|
||||
participant Repository as "PileRepository"
|
||||
participant Cache as "PileRedisCache"
|
||||
participant DB as "数据库"
|
||||
Client->>Controller : POST /piles
|
||||
Controller->>Service : createPile(request)
|
||||
Service->>Repository : findPileByCode(code)
|
||||
Repository->>Cache : get(pileCode)
|
||||
Cache-->>Repository : null
|
||||
Repository->>DB : selectByCode(code)
|
||||
DB-->>Repository : null
|
||||
Repository-->>Service : null
|
||||
Service->>DB : insert(pile)
|
||||
DB-->>Service : success
|
||||
Service-->>Controller : Pile
|
||||
Controller-->>Client : 200 OK
|
||||
```
|
||||
|
||||
**图源**
|
||||
|
||||
- [DefaultPileService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileService.java#L1-L329)
|
||||
- [PileRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/PileRepositoryImpl.java#L1-L49)
|
||||
|
||||
### DefaultPileService核心功能
|
||||
|
||||
DefaultPileService实现了PileService接口,处理充电桩的业务逻辑。
|
||||
|
||||
| 方法 | 描述 |
|
||||
|------------------------|----------------|
|
||||
| createPile | 创建充电桩,检查编号唯一性 |
|
||||
| findById | 根据ID查找充电桩 |
|
||||
| findByPileCode | 根据编号查找充电桩 |
|
||||
| updatePile | 更新充电桩信息 |
|
||||
| deletePile | 删除充电桩,检查是否有充电枪 |
|
||||
| queryPilesWithStatus | 分页查询充电桩及状态 |
|
||||
| updatePileStatus | 更新充电桩状态 |
|
||||
| handlePileLogin | 处理充电桩登录 |
|
||||
| handlePileHeartbeat | 处理充电桩心跳 |
|
||||
| handlePileSessionClose | 处理充电桩会话关闭 |
|
||||
|
||||
**节源**
|
||||
|
||||
- [DefaultPileService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileService.java#L1-L329)
|
||||
|
||||
### 数据持久化 (PileRepository)
|
||||
|
||||
PileRepository接口定义了充电桩的数据访问方法,PileRepositoryImpl实现了该接口并提供了缓存支持。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class PileRepository {
|
||||
+findPileByCode(pileCode : String) : Pile
|
||||
}
|
||||
class PileRepositoryImpl {
|
||||
-pileMapper : PileMapper
|
||||
-cache : PileRedisCache
|
||||
+findPileByCode(pileCode : String) : Pile
|
||||
+handleEvictEvent(event : PileCacheEvictEvent) : void
|
||||
}
|
||||
class PileMapper {
|
||||
+selectByCode(pileCode : String) : Pile
|
||||
+insert(pile : Pile) : int
|
||||
+updateById(pile : Pile) : int
|
||||
+deleteById(id : UUID) : int
|
||||
}
|
||||
PileRepository <|-- PileRepositoryImpl
|
||||
PileRepositoryImpl --> PileMapper : "使用"
|
||||
PileRepositoryImpl --> PileRedisCache : "使用"
|
||||
```
|
||||
|
||||
PileRepositoryImpl通过继承CachedVersionedEntityRepository获得了缓存功能,实现了基于Redis的缓存机制。当充电桩数据发生变化时,通过@TransactionalEventListener监听事件并清除缓存。
|
||||
|
||||
**图源**
|
||||
|
||||
- [PileRepository.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/PileRepository.java#L1-L16)
|
||||
- [PileRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/PileRepositoryImpl.java#L1-L49)
|
||||
|
||||
### 缓存交互 (PileRedisCache)
|
||||
|
||||
系统使用Redis作为缓存存储,PileRedisCache负责充电桩数据的缓存操作。PileRepositoryImpl通过cache字段与PileRedisCache交互,实现了读取时的缓存命中和写入时的缓存失效。
|
||||
|
||||
缓存键使用PileCacheKey,支持通过ID和编号两种方式缓存充电桩数据。当充电桩被更新或删除时,PileRepositoryImpl会发布PileCacheEvictEvent事件,触发缓存清除。
|
||||
|
||||
**节源**
|
||||
|
||||
- [PileRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/PileRepositoryImpl.java#L1-L49)
|
||||
|
||||
## 远程控制操作
|
||||
|
||||
系统支持对充电桩进行远程控制操作,如启动充电、重启等。这些操作通过RPC机制实现,由RpcController接收请求,调用PileProtocolService执行。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as "客户端"
|
||||
participant RpcController as "RpcController"
|
||||
participant PileProtocolService as "DefaultPileProtocolService"
|
||||
participant DownlinkCallService as "DownlinkCallService"
|
||||
participant Protocol as "协议层"
|
||||
Client->>RpcController : RPC startCharge
|
||||
RpcController->>RpcController : handleStartCharge()
|
||||
RpcController->>PileProtocolService : startCharge(dto)
|
||||
PileProtocolService->>DownlinkCallService : sendDownlinkMessage()
|
||||
DownlinkCallService->>Protocol : 发送指令
|
||||
Protocol-->>DownlinkCallService : 发送成功
|
||||
DownlinkCallService-->>PileProtocolService : 回调
|
||||
PileProtocolService-->>RpcController : 返回
|
||||
RpcController-->>Client : 响应
|
||||
```
|
||||
|
||||
**图源**
|
||||
|
||||
- [RpcController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java#L107-L145)
|
||||
- [DefaultPileProtocolService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java#L412-L440)
|
||||
|
||||
### 启动充电 (POST /piles/{id}/start-charge)
|
||||
|
||||
远程启动充电桩的充电操作。
|
||||
|
||||
#### 实现流程
|
||||
|
||||
1. RpcController接收启动充电的RPC请求
|
||||
2. 解析StartChargeDTO参数
|
||||
3. 调用PileProtocolService.startCharge方法
|
||||
4. 构造下行消息RemoteStartChargingRequest
|
||||
5. 通过DownlinkCallService发送到协议层
|
||||
6. 协议层将指令发送到充电桩
|
||||
|
||||
#### 请求DTO (StartChargeDTO)
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class StartChargeDTO {
|
||||
+pileCode : String
|
||||
+gunNo : String
|
||||
+limitYuan : BigDecimal
|
||||
+orderNo : String
|
||||
+logicalCardNo : String
|
||||
+physicalCardNo : String
|
||||
+parallelNo : String
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必填 | 描述 |
|
||||
|----------------|------------|----|---------|
|
||||
| pileCode | String | 是 | 充电桩编号 |
|
||||
| gunNo | String | 是 | 充电枪编号 |
|
||||
| limitYuan | BigDecimal | 是 | 限制金额(元) |
|
||||
| orderNo | String | 是 | 订单号 |
|
||||
| logicalCardNo | String | 否 | 逻辑卡号 |
|
||||
| physicalCardNo | String | 否 | 物理卡号 |
|
||||
| parallelNo | String | 否 | 并充序号 |
|
||||
|
||||
**节源**
|
||||
|
||||
- [StartChargeDTO.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/dto/StartChargeDTO.java#L1-L61)
|
||||
- [DefaultPileProtocolService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java#L412-L440)
|
||||
|
||||
### 重启充电桩 (POST /piles/{id}/restart)
|
||||
|
||||
远程重启充电桩。
|
||||
|
||||
#### 实现流程
|
||||
|
||||
1. RpcController接收重启充电桩的RPC请求
|
||||
2. 解析RestartPileDTO参数
|
||||
3. 调用PileProtocolService.restartPile方法
|
||||
4. 构造下行消息RestartPileRequest
|
||||
5. 通过DownlinkCallService发送到协议层
|
||||
6. 协议层将指令发送到充电桩
|
||||
|
||||
#### 请求DTO (RestartPileDTO)
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class RestartPileDTO {
|
||||
+pileCode : String
|
||||
+type : Integer
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必填 | 描述 |
|
||||
|----------|---------|----|-------|
|
||||
| pileCode | String | 是 | 充电桩编号 |
|
||||
| type | Integer | 是 | 重启类型 |
|
||||
|
||||
**节源**
|
||||
|
||||
- [RestartPileDTO.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/dto/RestartPileDTO.java#L1-L32)
|
||||
- [DefaultPileProtocolService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java#L506-L531)
|
||||
|
||||
## 使用示例
|
||||
|
||||
以下示例演示如何为一个充电站添加充电桩并远程启动充电。
|
||||
|
||||
### 为充电站添加充电桩
|
||||
|
||||
```http
|
||||
POST /api/piles HTTP/1.1
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer <token>
|
||||
|
||||
```
|
||||
|
||||
响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "创建成功",
|
||||
"data": {
|
||||
"id": "f1e2d3c4-b5a6-9876-5432-10fedcba9876",
|
||||
"createdTime": "2024-01-01T10:00:00",
|
||||
"pileName": "直流快充桩1号",
|
||||
"pileCode": "DCP001",
|
||||
"protocol": "LVNENG_V340",
|
||||
"stationId": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
|
||||
"brand": "特来电",
|
||||
"model": "DC-80KW",
|
||||
"manufacturer": "特来电新能源有限公司",
|
||||
"type": "DC"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 远程启动充电
|
||||
|
||||
```http
|
||||
POST /rpc HTTP/1.1
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer <token>
|
||||
|
||||
```
|
||||
|
||||
**节源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L25-L34)
|
||||
- [RpcController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java#L107-L145)
|
||||
|
||||
## 状态机与实时同步
|
||||
|
||||
充电桩状态机管理充电桩的在线/离线状态,通过实时同步机制确保状态的准确性。
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> OFFLINE
|
||||
OFFLINE --> ONLINE : login
|
||||
ONLINE --> OFFLINE : session close
|
||||
ONLINE --> ONLINE : heartbeat
|
||||
OFFLINE --> OFFLINE : no activity
|
||||
note right of ONLINE
|
||||
状态属性 :
|
||||
- status : ONLINE
|
||||
- connectedAt : 时间戳
|
||||
- lastActiveTime : 时间戳
|
||||
end note
|
||||
note right of OFFLINE
|
||||
状态属性 :
|
||||
- status : OFFLINE
|
||||
- disconnectedAt : 时间戳
|
||||
end note
|
||||
```
|
||||
|
||||
### 状态机实现
|
||||
|
||||
充电桩状态机基于三个核心事件实现:登录、心跳和会话关闭。
|
||||
|
||||
| 事件 | 当前状态 | 新状态 | 更新的属性 |
|
||||
|------|--------|---------|-------------------------------------|
|
||||
| 登录 | 任意 | ONLINE | status, connectedAt, lastActiveTime |
|
||||
| 心跳 | ONLINE | ONLINE | status, lastActiveTime |
|
||||
| 会话关闭 | ONLINE | OFFLINE | status, disconnectedAt |
|
||||
|
||||
**节源**
|
||||
|
||||
- [DefaultPileService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileService.java#L240-L300)
|
||||
|
||||
### 实时状态同步
|
||||
|
||||
系统通过AttributeService将充电桩状态存储在Redis中,实现状态的实时同步。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[充电桩登录] --> B[调用handlePileLogin]
|
||||
B --> C[更新状态属性]
|
||||
C --> D[保存到Redis]
|
||||
D --> E[状态同步完成]
|
||||
F[充电桩心跳] --> G[调用handlePileHeartbeat]
|
||||
G --> H[更新状态属性]
|
||||
H --> D
|
||||
I[会话关闭] --> J[调用handlePileSessionClose]
|
||||
J --> K[更新状态属性]
|
||||
K --> D
|
||||
```
|
||||
|
||||
状态属性存储在Redis的哈希结构中,键名为`pile:attributes:{pileId}`,字段名为状态属性名,如`STATUS`、`CONNECTED_AT`
|
||||
等。这种设计支持高效的状态查询和更新。
|
||||
|
||||
**节源**
|
||||
|
||||
- [DefaultPileService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileService.java#L240-L300)
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[充电桩登录] --> B[调用handlePileLogin]
|
||||
B --> C[更新状态属性]
|
||||
C --> D[保存到Redis]
|
||||
D --> E[状态同步完成]
|
||||
F[充电桩心跳] --> G[调用handlePileHeartbeat]
|
||||
G --> H[更新状态属性]
|
||||
H --> D
|
||||
I[会话关闭] --> J[调用handlePileSessionClose]
|
||||
J --> K[更新状态属性]
|
||||
K --> D
|
||||
```
|
||||
|
||||
状态属性存储在Redis的哈希结构中,键名为`pile:attributes:{pileId}`,字段名为状态属性名,如`STATUS`、`CONNECTED_AT`
|
||||
等。这种设计支持高效的状态查询和更新。
|
||||
|
||||
**节源**
|
||||
|
||||
- [DefaultPileService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileService.java#L240-L300)
|
||||
444
docs/核心模块详解/设备管理模块/充电站管理.md
Normal file
444
docs/核心模块详解/设备管理模块/充电站管理.md
Normal file
@@ -0,0 +1,444 @@
|
||||
# 充电站管理
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [Station.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Station.java)
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java)
|
||||
- [StationMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/StationMapper.java)
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java)
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java)
|
||||
- [PileMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/PileMapper.java)
|
||||
- [StationCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/StationCreateRequest.java)
|
||||
- [StationUpdateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/StationUpdateRequest.java)
|
||||
- [StationQueryRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/StationQueryRequest.java)
|
||||
- [PageResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PageResponse.java)
|
||||
- [schema-init.sql](file://jcpp-app/src/main/resources/sql/schema-init.sql)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [引言](#引言)
|
||||
2. [数据模型](#数据模型)
|
||||
3. [RESTful API接口](#restful-api接口)
|
||||
4. [服务层实现](#服务层实现)
|
||||
5. [使用示例](#使用示例)
|
||||
6. [分页查询机制](#分页查询机制)
|
||||
7. [级联删除逻辑](#级联删除逻辑)
|
||||
|
||||
## 引言
|
||||
|
||||
充电站管理功能是本系统的核心模块之一,负责充电站的全生命周期管理。该功能提供了完整的CRUD操作,支持通过RESTful
|
||||
API对充电站进行创建、查询、更新和删除。系统采用分层架构设计,包含控制器层、服务层和数据访问层,确保了代码的可维护性和扩展性。充电站实体与充电桩实体之间存在一对多的关系,系统在删除充电站时会进行级联检查,确保数据完整性。
|
||||
|
||||
## 数据模型
|
||||
|
||||
### Station实体
|
||||
|
||||
`Station`实体是充电站管理的核心数据模型,定义了充电站的基本属性和元数据。该实体映射到数据库中的`t_station`表,使用MyBatis
|
||||
Plus框架进行ORM映射。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Station {
|
||||
+UUID id
|
||||
+LocalDateTime createdTime
|
||||
+LocalDateTime updatedTime
|
||||
+JsonNode additionalInfo
|
||||
+String stationName
|
||||
+String stationCode
|
||||
+Float longitude
|
||||
+Float latitude
|
||||
+String province
|
||||
+String city
|
||||
+String county
|
||||
+String address
|
||||
+Integer version
|
||||
}
|
||||
class Pile {
|
||||
+UUID id
|
||||
+LocalDateTime createdTime
|
||||
+LocalDateTime updatedTime
|
||||
+JsonNode additionalInfo
|
||||
+String pileName
|
||||
+String pileCode
|
||||
+String protocol
|
||||
+UUID stationId
|
||||
+String brand
|
||||
+String model
|
||||
+String manufacturer
|
||||
+PileTypeEnum type
|
||||
+Integer version
|
||||
}
|
||||
Station "1" *-- "0..*" Pile : 包含
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [Station.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Station.java#L1-L65)
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java#L1-L64)
|
||||
|
||||
#### 核心属性说明
|
||||
|
||||
- **id**: 充电站唯一标识符,使用UUID类型,作为主键
|
||||
- **createdTime**: 创建时间,记录充电站创建的精确时间戳
|
||||
- **updatedTime**: 更新时间,每次更新时自动更新
|
||||
- **stationName**: 充电站名称,必填字段,用于标识充电站
|
||||
- **stationCode**: 充电站编码,必填字段,具有唯一性约束
|
||||
- **longitude/latitude**: 地理位置坐标,用于地图展示和定位
|
||||
- **province/city/county/address**: 地址信息,分别表示省、市、区县和详细地址
|
||||
- **additionalInfo**: 附加信息,使用JSON格式存储扩展属性
|
||||
- **version**: 版本号,用于乐观锁控制,防止并发更新冲突
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [Station.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Station.java#L1-L65)
|
||||
- [schema-init.sql](file://jcpp-app/src/main/resources/sql/schema-init.sql#L34-L58)
|
||||
|
||||
## RESTful API接口
|
||||
|
||||
### API端点概览
|
||||
|
||||
`StationController`提供了完整的RESTful API端点,用于管理充电站资源。所有API均遵循REST设计原则,使用标准的HTTP方法和状态码。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as "客户端"
|
||||
participant Controller as "StationController"
|
||||
participant Service as "DefaultStationService"
|
||||
participant Mapper as "StationMapper"
|
||||
Client->>Controller : POST /api/stations
|
||||
Controller->>Service : createStation(request)
|
||||
Service->>Mapper : insert(station)
|
||||
Mapper-->>Service : 返回结果
|
||||
Service-->>Controller : 返回充电站
|
||||
Controller-->>Client : 200 OK {station}
|
||||
Client->>Controller : GET /api/stations
|
||||
Controller->>Service : getStations(request)
|
||||
Service->>Mapper : selectPage(wrapper)
|
||||
Mapper-->>Service : 返回分页结果
|
||||
Service-->>Controller : 返回PageResponse
|
||||
Controller-->>Client : 200 OK {PageResponse}
|
||||
Client->>Controller : PUT /api/stations/{id}
|
||||
Controller->>Service : updateStation(id, request)
|
||||
Service->>Mapper : selectById(id)
|
||||
Mapper-->>Service : 返回充电站
|
||||
Service->>Mapper : updateById(station)
|
||||
Mapper-->>Service : 返回结果
|
||||
Service-->>Controller : 返回充电站
|
||||
Controller-->>Client : 200 OK {station}
|
||||
Client->>Controller : DELETE /api/stations/{id}
|
||||
Controller->>Service : deleteStation(id)
|
||||
Service->>Mapper : selectById(id)
|
||||
Mapper-->>Service : 返回充电站
|
||||
Service->>Mapper : countByStationId(id)
|
||||
Mapper-->>Service : 返回数量
|
||||
Service->>Mapper : deleteById(id)
|
||||
Mapper-->>Service : 返回结果
|
||||
Service-->>Controller : 返回成功
|
||||
Controller-->>Client : 200 OK {success}
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L1-L107)
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L1-L247)
|
||||
|
||||
### 详细API说明
|
||||
|
||||
#### 创建充电站 (POST /api/stations)
|
||||
|
||||
创建新的充电站资源。
|
||||
|
||||
- **请求参数**: `StationCreateRequest`对象
|
||||
- **请求体示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"stationName": "三丙家专属充电站",
|
||||
"stationCode": "S20241001001",
|
||||
"longitude": 120.107933,
|
||||
"latitude": 30.267013,
|
||||
"province": "浙江省",
|
||||
"city": "杭州市",
|
||||
"county": "西湖区",
|
||||
"address": "西溪路552-1号"
|
||||
}
|
||||
```
|
||||
|
||||
- **响应格式**: `ApiResponse<Station>`
|
||||
- **权限要求**: `AuthorityEnum.STATION_MANAGE`
|
||||
|
||||
#### 分页查询充电站 (GET /api/stations)
|
||||
|
||||
分页查询充电站列表,支持多种查询条件。
|
||||
|
||||
- **请求参数**:
|
||||
- `page`: 页码(默认0)
|
||||
- `size`: 每页大小(默认10)
|
||||
- `stationName`: 充电站名称(模糊查询)
|
||||
- `stationCode`: 充电站编码(模糊查询)
|
||||
- `province`: 省份(精确查询)
|
||||
- `city`: 城市(精确查询)
|
||||
- `sortField`: 排序字段
|
||||
- `sortOrder`: 排序顺序(asc/desc)
|
||||
- **响应格式**: `ApiResponse<PageResponse<Station>>`
|
||||
- **权限要求**: `AuthorityEnum.STATION_MANAGE`
|
||||
|
||||
#### 更新充电站 (PUT /api/stations/{id})
|
||||
|
||||
更新指定ID的充电站信息。
|
||||
|
||||
- **路径参数**: `id` - 充电站UUID
|
||||
- **请求参数**: `StationUpdateRequest`对象
|
||||
- **请求体示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"stationName": "三丙家专属充电站(更新)",
|
||||
"longitude": 120.108000,
|
||||
"latitude": 30.267100,
|
||||
"province": "浙江省",
|
||||
"city": "杭州市",
|
||||
"county": "西湖区",
|
||||
"address": "西溪路552-1号(更新)"
|
||||
}
|
||||
```
|
||||
|
||||
- **响应格式**: `ApiResponse<Station>`
|
||||
- **权限要求**: `AuthorityEnum.STATION_MANAGE`
|
||||
|
||||
#### 删除充电站 (DELETE /api/stations/{id})
|
||||
|
||||
删除指定ID的充电站。
|
||||
|
||||
- **路径参数**: `id` - 充电站UUID
|
||||
- **响应格式**: `ApiResponse<Void>`
|
||||
- **权限要求**: `AuthorityEnum.STATION_MANAGE`
|
||||
- **业务逻辑**: 删除前会检查该充电站下是否存在充电桩,如果存在则不允许删除
|
||||
|
||||
#### 获取充电站选项 (GET /api/stations/options)
|
||||
|
||||
获取充电站选项列表,用于下拉选择组件。
|
||||
|
||||
- **响应格式**: `ApiResponse<List<StationOption>>`
|
||||
- **权限要求**: `AuthorityEnum.STATION_MANAGE`
|
||||
|
||||
#### 搜索充电站选项 (GET /api/stations/search)
|
||||
|
||||
搜索充电站选项,支持关键字搜索和分页。
|
||||
|
||||
- **请求参数**:
|
||||
- `keyword`: 搜索关键字
|
||||
- `page`: 页码
|
||||
- `size`: 每页大小
|
||||
- **响应格式**: `ApiResponse<List<StationOption>>`
|
||||
- **权限要求**: `AuthorityEnum.STATION_MANAGE`
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L1-L107)
|
||||
- [StationCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/StationCreateRequest.java#L1-L44)
|
||||
- [StationUpdateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/StationUpdateRequest.java#L1-L40)
|
||||
- [StationQueryRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/StationQueryRequest.java#L1-L29)
|
||||
|
||||
## 服务层实现
|
||||
|
||||
### DefaultStationService
|
||||
|
||||
`DefaultStationService`是充电站管理的核心服务实现类,协调`StationMapper`和`PileMapper`进行数据库操作,并处理业务逻辑。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[API请求] --> B{操作类型}
|
||||
B --> |创建| C[createStation]
|
||||
B --> |查询| D[getStations]
|
||||
B --> |更新| E[updateStation]
|
||||
B --> |删除| F[deleteStation]
|
||||
C --> G[构建Station实体]
|
||||
G --> H[设置默认值]
|
||||
H --> I[调用stationMapper.insert]
|
||||
D --> J[构建QueryWrapper]
|
||||
J --> K[添加查询条件]
|
||||
K --> L[调用stationMapper.selectPage]
|
||||
L --> M[构建PageResponse]
|
||||
E --> N[查询现有Station]
|
||||
N --> O[更新字段]
|
||||
O --> P[调用stationMapper.updateById]
|
||||
F --> Q[检查Station存在]
|
||||
Q --> R[检查充电桩数量]
|
||||
R --> |有充电桩| S[抛出异常]
|
||||
R --> |无充电桩| T[调用stationMapper.deleteById]
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L1-L247)
|
||||
|
||||
#### 核心方法说明
|
||||
|
||||
- **getStations**: 实现分页查询功能,根据`StationQueryRequest`中的条件构建查询条件,支持按名称、编码、省份、城市等字段进行查询,并支持排序功能
|
||||
- **getStationById**: 根据ID查询单个充电站信息
|
||||
- **createStation**: 创建新的充电站,自动生成UUID和创建时间,初始化版本号为1
|
||||
- **updateStation**: 更新充电站信息,更新时会自动设置`updatedTime`字段
|
||||
- **deleteStation**: 删除充电站前会进行完整性检查,确保该充电站下没有关联的充电桩
|
||||
- **getStationOptions**: 获取充电站选项列表,用于前端下拉选择
|
||||
- **searchStationOptions**: 支持关键字搜索的充电站选项查询
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L1-L247)
|
||||
- [StationMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/StationMapper.java#L1-L15)
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 创建充电站完整流程
|
||||
|
||||
以下是一个通过API创建新充电站并验证其存在的完整示例:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as "用户"
|
||||
participant Frontend as "前端应用"
|
||||
participant Backend as "后端服务"
|
||||
participant Database as "数据库"
|
||||
User->>Frontend : 填写充电站信息并提交
|
||||
Frontend->>Backend : POST /api/stations
|
||||
Backend->>Backend : 验证请求参数
|
||||
Backend->>Backend : 调用DefaultStationService.createStation
|
||||
Backend->>Backend : 构建Station实体
|
||||
Backend->>Database : 执行INSERT语句
|
||||
Database-->>Backend : 返回插入结果
|
||||
Backend-->>Frontend : 返回创建的充电站信息
|
||||
Frontend-->>User : 显示创建成功消息
|
||||
User->>Frontend : 查询充电站列表
|
||||
Frontend->>Backend : GET /api/stations
|
||||
Backend->>Backend : 调用DefaultStationService.getStations
|
||||
Backend->>Database : 执行SELECT查询
|
||||
Database-->>Backend : 返回查询结果
|
||||
Backend-->>Frontend : 返回分页响应
|
||||
Frontend-->>User : 显示包含新充电站的列表
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L1-L107)
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L1-L247)
|
||||
|
||||
#### 示例代码
|
||||
|
||||
```java
|
||||
// 创建充电站请求
|
||||
StationCreateRequest request = new StationCreateRequest();
|
||||
request.setStationName("新充电站");
|
||||
request.setStationCode("NEW001");
|
||||
request.setLongitude(120.123456f);
|
||||
request.setLatitude(30.654321f);
|
||||
request.setProvince("浙江省");
|
||||
request.setCity("杭州市");
|
||||
request.setCounty("西湖区");
|
||||
request.setAddress("文三路168号");
|
||||
|
||||
// 调用API创建充电站
|
||||
ResponseEntity<ApiResponse<Station>> response = restTemplate.postForEntity(
|
||||
"/api/stations",
|
||||
request,
|
||||
new ParameterizedTypeReference<ApiResponse<Station>>() {}
|
||||
);
|
||||
|
||||
// 验证创建结果
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
Station createdStation = response.getBody().getData();
|
||||
assertThat(createdStation.getStationName()).isEqualTo("新充电站");
|
||||
|
||||
// 查询验证
|
||||
ResponseEntity<ApiResponse<PageResponse<Station>>> queryResponse = restTemplate.getForEntity(
|
||||
"/api/stations?stationName=新充电站",
|
||||
new ParameterizedTypeReference<ApiResponse<PageResponse<Station>>>() {}
|
||||
);
|
||||
|
||||
assertThat(queryResponse.getBody().getData().getTotal()).isGreaterThan(0);
|
||||
```
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L1-L107)
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L1-L247)
|
||||
- [InstallInitializingBean.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/initializing/InstallInitializingBean.java#L218-L233)
|
||||
|
||||
## 分页查询机制
|
||||
|
||||
### 分页实现原理
|
||||
|
||||
系统采用MyBatis Plus的分页插件实现分页查询功能,通过`Page`对象和`IPage`接口提供分页支持。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[客户端请求] --> B[StationController]
|
||||
B --> C[DefaultStationService]
|
||||
C --> D[构建QueryWrapper]
|
||||
D --> E[创建Page对象]
|
||||
E --> F[调用stationMapper.selectPage]
|
||||
F --> G[数据库执行分页查询]
|
||||
G --> H[返回IPage结果]
|
||||
H --> I[构建PageResponse]
|
||||
I --> J[返回客户端]
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L65-L99)
|
||||
- [PageResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PageResponse.java#L1-L43)
|
||||
|
||||
#### PageResponse结构
|
||||
|
||||
`PageResponse`类封装了分页查询的响应数据,包含以下字段:
|
||||
|
||||
- **records**: 当前页的数据记录列表
|
||||
- **total**: 总记录数
|
||||
- **page**: 当前页码
|
||||
- **size**: 每页大小
|
||||
- **totalPages**: 总页数
|
||||
|
||||
分页计算公式:`totalPages = ceil(total / size)`
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [PageResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PageResponse.java#L1-L43)
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L65-L99)
|
||||
|
||||
## 级联删除逻辑
|
||||
|
||||
### 删除业务流程
|
||||
|
||||
系统在删除充电站时实现了严格的级联检查机制,确保数据完整性。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[删除请求] --> B{充电站存在?}
|
||||
B --> |否| C[抛出ITEM_NOT_FOUND异常]
|
||||
B --> |是| D{有充电桩?}
|
||||
D --> |是| E[抛出VERSION_CONFLICT异常]
|
||||
D --> |否| F[执行删除操作]
|
||||
F --> G{删除成功?}
|
||||
G --> |否| H[抛出VERSION_CONFLICT异常]
|
||||
G --> |是| I[返回成功]
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L150-L185)
|
||||
|
||||
#### 详细逻辑说明
|
||||
|
||||
1. **存在性检查**: 首先通过`stationMapper.selectById(id)`检查充电站是否存在,如果不存在则抛出`ITEM_NOT_FOUND`异常
|
||||
2. **关联检查**: 调用`pileMapper.countByStationId(id)`统计该充电站下的充电桩数量,如果数量大于0,则抛出`VERSION_CONFLICT`
|
||||
异常,提示用户先删除所有充电桩
|
||||
3. **执行删除**: 通过`stationMapper.deleteById(id)`执行删除操作
|
||||
4. **结果验证**: 检查受影响的行数,如果为0则说明删除失败,可能是被其他操作删除,抛出`VERSION_CONFLICT`异常
|
||||
|
||||
这种设计确保了数据的一致性和完整性,防止意外删除包含充电桩的充电站。
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L150-L185)
|
||||
- [PileMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/PileMapper.java#L60-L65)
|
||||
658
docs/核心模块详解/设备管理模块/设备管理模块.md
Normal file
658
docs/核心模块详解/设备管理模块/设备管理模块.md
Normal file
@@ -0,0 +1,658 @@
|
||||
# 设备管理模块
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java)
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java)
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java)
|
||||
- [Station.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Station.java)
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java)
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java)
|
||||
- [StationCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/StationCreateRequest.java)
|
||||
- [PileCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/PileCreateRequest.java)
|
||||
- [GunCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/GunCreateRequest.java)
|
||||
- [PageResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PageResponse.java)
|
||||
- [StationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/StationService.java)
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java)
|
||||
- [StationMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/StationMapper.java)
|
||||
- [StationRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/station/StationRedisCache.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [引言](#引言)
|
||||
2. [核心数据模型](#核心数据模型)
|
||||
3. [RESTful API 接口](#restful-api-接口)
|
||||
4. [业务服务层设计](#业务服务层设计)
|
||||
5. [完整使用示例](#完整使用示例)
|
||||
6. [复杂业务逻辑实现](#复杂业务逻辑实现)
|
||||
|
||||
## 引言
|
||||
|
||||
设备管理模块是充电站管理系统的核心组成部分,负责管理充电站(Station)、充电桩(Pile)和充电枪(Gun)三个关键实体。本模块提供了完整的CRUD操作,支持分页查询、级联选择和状态管理等功能。系统采用分层架构设计,包括控制器层、服务层、数据访问层和缓存层,确保了系统的可维护性和高性能。
|
||||
|
||||
## 核心数据模型
|
||||
|
||||
### 实体层次关系
|
||||
|
||||
设备管理模块中的三个核心实体构成了一个清晰的层次结构:一个充电站(Station)可以包含多个充电桩(Pile),而每个充电桩又可以连接多个充电枪(Gun)。这种层级关系通过外键关联实现,确保了数据的一致性和完整性。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Station {
|
||||
+UUID id
|
||||
+String stationName
|
||||
+String stationCode
|
||||
+Float longitude
|
||||
+Float latitude
|
||||
+String province
|
||||
+String city
|
||||
+String county
|
||||
+String address
|
||||
+LocalDateTime createdTime
|
||||
+LocalDateTime updatedTime
|
||||
+JsonNode additionalInfo
|
||||
+Integer version
|
||||
}
|
||||
class Pile {
|
||||
+UUID id
|
||||
+String pileName
|
||||
+String pileCode
|
||||
+String protocol
|
||||
+UUID stationId
|
||||
+String brand
|
||||
+String model
|
||||
+String manufacturer
|
||||
+PileTypeEnum type
|
||||
+LocalDateTime createdTime
|
||||
+LocalDateTime updatedTime
|
||||
+JsonNode additionalInfo
|
||||
+Integer version
|
||||
}
|
||||
class Gun {
|
||||
+UUID id
|
||||
+String gunNo
|
||||
+String gunName
|
||||
+String gunCode
|
||||
+UUID stationId
|
||||
+UUID pileId
|
||||
+LocalDateTime createdTime
|
||||
+LocalDateTime updatedTime
|
||||
+JsonNode additionalInfo
|
||||
+Integer version
|
||||
}
|
||||
Station "1" *-- "0..*" Pile : 包含
|
||||
Pile "1" *-- "0..*" Gun : 包含
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [Station.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Station.java#L1-L65)
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java#L1-L64)
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L56)
|
||||
|
||||
### 数据模型详细说明
|
||||
|
||||
#### 充电站(Station)
|
||||
|
||||
充电站实体代表一个物理的充电站点,包含站点的基本信息和地理位置数据。每个充电站都有唯一的ID标识,通过`stationCode`
|
||||
字段保证编码的唯一性。实体还包含了省份、城市、区县和详细地址等完整的地理位置信息,便于进行区域管理和查询。
|
||||
|
||||
**核心字段说明**
|
||||
|
||||
- `id`: 充电站唯一标识符,使用UUID类型
|
||||
- `stationName`: 充电站名称,必填字段,用于显示
|
||||
- `stationCode`: 充电站编码,必填字段,用于系统识别
|
||||
- `longitude`/`latitude`: 经纬度坐标,用于地图定位
|
||||
- `province`/`city`/`county`/`address`: 完整的地址信息
|
||||
- `version`: 版本号,用于乐观锁控制
|
||||
|
||||
**实体来源**
|
||||
|
||||
- [Station.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Station.java#L1-L65)
|
||||
|
||||
#### 充电桩(Pile)
|
||||
|
||||
充电桩实体代表安装在充电站内的具体充电设备。每个充电桩都归属于一个特定的充电站,通过`stationId`
|
||||
外键进行关联。充电桩包含了设备的品牌、型号、制造商等信息,并指定了通信协议类型,以便系统能够正确处理不同厂商设备的通信需求。
|
||||
|
||||
**核心字段说明**
|
||||
|
||||
- `id`: 充电桩唯一标识符
|
||||
- `pileName`: 充电桩名称
|
||||
- `pileCode`: 充电桩编码
|
||||
- `protocol`: 通信协议类型,决定设备的通信方式
|
||||
- `stationId`: 所属充电站ID,建立与Station的关联
|
||||
- `type`: 充电桩类型(直流/交流)
|
||||
- `version`: 版本号,用于并发控制
|
||||
|
||||
**实体来源**
|
||||
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java#L1-L64)
|
||||
|
||||
#### 充电枪(Gun)
|
||||
|
||||
充电枪实体代表充电桩上的具体充电接口。每个充电枪都归属于一个特定的充电桩,通过`pileId`
|
||||
外键进行关联。充电枪包含了枪号(gunNo)和编码(gunCode)等识别信息,这些信息通常与物理设备上的标签对应,便于现场管理和维护。
|
||||
|
||||
**核心字段说明**
|
||||
|
||||
- `id`: 充电枪唯一标识符
|
||||
- `gunNo`: 充电枪编号,通常为物理标识
|
||||
- `gunName`: 充电枪名称
|
||||
- `gunCode`: 充电枪编码,系统唯一标识
|
||||
- `stationId`: 所属充电站ID(冗余字段,便于查询)
|
||||
- `pileId`: 所属充电桩ID,建立与Pile的关联
|
||||
- `version`: 版本号,支持并发更新
|
||||
|
||||
**实体来源**
|
||||
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L56)
|
||||
|
||||
## RESTful API 接口
|
||||
|
||||
### 控制器概览
|
||||
|
||||
设备管理模块提供了三个主要的REST控制器:`StationController`、`PileController`和`GunController`
|
||||
,分别对应三个核心实体的管理操作。这些控制器遵循RESTful设计原则,使用标准的HTTP方法(GET、POST、PUT、DELETE)来执行相应的CRUD操作。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[客户端] --> B[StationController]
|
||||
A --> C[PileController]
|
||||
A --> D[GunController]
|
||||
B --> E[StationService]
|
||||
C --> F[PileService]
|
||||
D --> G[GunService]
|
||||
E --> H[StationMapper]
|
||||
F --> I[PileMapper]
|
||||
G --> J[GunMapper]
|
||||
E --> K[StationRedisCache]
|
||||
F --> L[PileRedisCache]
|
||||
G --> M[GunRedisCache]
|
||||
style A fill:#f9f,stroke:#333
|
||||
style B fill:#bbf,stroke:#333
|
||||
style C fill:#bbf,stroke:#333
|
||||
style D fill:#bbf,stroke:#333
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L1-L107)
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L1-L111)
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L1-L115)
|
||||
|
||||
### StationController API
|
||||
|
||||
#### 创建充电站
|
||||
|
||||
创建新的充电站实体。
|
||||
|
||||
- **端点**: `POST /api/stations`
|
||||
- **请求体**: `StationCreateRequest`
|
||||
- **响应**: `ApiResponse<Station>`
|
||||
- **权限控制**: 需要管理员权限
|
||||
|
||||
**请求DTO结构**
|
||||
|
||||
```json
|
||||
{
|
||||
"stationName": "string",
|
||||
"stationCode": "string",
|
||||
"longitude": 0,
|
||||
"latitude": 0,
|
||||
"province": "string",
|
||||
"city": "string",
|
||||
"county": "string",
|
||||
"address": "string"
|
||||
}
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L50-L57)
|
||||
- [StationCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/StationCreateRequest.java#L1-L44)
|
||||
|
||||
#### 查询充电站
|
||||
|
||||
支持分页查询和条件筛选。
|
||||
|
||||
- **端点**: `GET /api/stations`
|
||||
- **请求参数**: `StationQueryRequest`
|
||||
- **响应**: `ApiResponse<PageResponse<Station>>`
|
||||
|
||||
**分页响应结构**
|
||||
|
||||
```json
|
||||
{
|
||||
"records": [...],
|
||||
"total": 100,
|
||||
"page": 1,
|
||||
"size": 20,
|
||||
"totalPages": 5
|
||||
}
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L30-L37)
|
||||
- [PageResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PageResponse.java#L1-L43)
|
||||
|
||||
#### 更新充电站
|
||||
|
||||
根据ID更新充电站信息。
|
||||
|
||||
- **端点**: `PUT /api/stations/{id}`
|
||||
- **请求体**: `StationUpdateRequest`
|
||||
- **响应**: `ApiResponse<Station>`
|
||||
|
||||
**来源**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L60-L68)
|
||||
|
||||
#### 删除充电站
|
||||
|
||||
删除指定ID的充电站。
|
||||
|
||||
- **端点**: `DELETE /api/stations/{id}`
|
||||
- **响应**: `ApiResponse<Void>`
|
||||
|
||||
**来源**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L71-L77)
|
||||
|
||||
#### 获取选项列表
|
||||
|
||||
为前端下拉组件提供数据。
|
||||
|
||||
- **端点**: `GET /api/stations/options`
|
||||
- **响应**: `ApiResponse<List<StationOption>>`
|
||||
|
||||
**选项响应结构**
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "uuid",
|
||||
"label": "名称 (编码)",
|
||||
"stationName": "名称",
|
||||
"stationCode": "编码"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L80-L88)
|
||||
- [StationOption.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/StationOption.java#L1-L39)
|
||||
|
||||
### PileController API
|
||||
|
||||
#### 创建充电桩
|
||||
|
||||
创建新的充电桩实体。
|
||||
|
||||
- **端点**: `POST /api/piles`
|
||||
- **请求体**: `PileCreateRequest`
|
||||
- **响应**: `ApiResponse<Pile>`
|
||||
|
||||
**来源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L35-L42)
|
||||
|
||||
#### 查询充电桩状态
|
||||
|
||||
获取充电桩的实时运行状态。
|
||||
|
||||
- **端点**: `GET /api/piles/status/{pileCode}`
|
||||
- **响应**: `ApiResponse<String>`
|
||||
|
||||
**来源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L90-L111)
|
||||
|
||||
### GunController API
|
||||
|
||||
#### 创建充电枪
|
||||
|
||||
创建新的充电枪实体。
|
||||
|
||||
- **端点**: `POST /api/guns`
|
||||
- **请求体**: `GunCreateRequest`
|
||||
- **响应**: `ApiResponse<Gun>`
|
||||
|
||||
**来源**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L35-L42)
|
||||
|
||||
#### 查询充电枪状态
|
||||
|
||||
根据枪编码获取充电枪的运行状态。
|
||||
|
||||
- **端点**: `GET /api/guns/status/{gunCode}`
|
||||
- **响应**: `ApiResponse<String>`
|
||||
|
||||
**来源**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L80-L100)
|
||||
|
||||
#### 按编码查询充电枪
|
||||
|
||||
根据枪编码获取充电枪的详细信息。
|
||||
|
||||
- **端点**: `GET /api/guns/code/{gunCode}`
|
||||
- **响应**: `ApiResponse<GunWithStatusResponse>`
|
||||
|
||||
**来源**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L103-L115)
|
||||
|
||||
## 业务服务层设计
|
||||
|
||||
### 服务层架构
|
||||
|
||||
业务服务层是设备管理模块的核心,负责协调数据访问层和缓存层的操作。`DefaultStationService`、`DefaultPileService`和
|
||||
`DefaultGunService`分别实现了对应的接口,提供了具体的业务逻辑处理。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class StationService {
|
||||
<<interface>>
|
||||
+getStations(StationQueryRequest) PageResponse~Station~
|
||||
+getStationById(UUID) Station
|
||||
+createStation(StationCreateRequest) Station
|
||||
+updateStation(UUID, StationUpdateRequest) Station
|
||||
+deleteStation(UUID) void
|
||||
+getStationOptions() StationOption[]
|
||||
+searchStationOptions(String, int, int) StationOption[]
|
||||
}
|
||||
class DefaultStationService {
|
||||
-stationMapper StationMapper
|
||||
-stationRedisCache StationRedisCache
|
||||
+getStations(StationQueryRequest) PageResponse~Station~
|
||||
+getStationById(UUID) Station
|
||||
+createStation(StationCreateRequest) Station
|
||||
+updateStation(UUID, StationUpdateRequest) Station
|
||||
+deleteStation(UUID) void
|
||||
+getStationOptions() StationOption[]
|
||||
+searchStationOptions(String, int, int) StationOption[]
|
||||
}
|
||||
class StationMapper {
|
||||
<<interface>>
|
||||
+selectPage(StationQueryRequest) Page~Station~
|
||||
+selectById(UUID) Station
|
||||
+insert(Station) int
|
||||
+updateById(Station) int
|
||||
+deleteById(UUID) int
|
||||
+selectOptions() StationOption[]
|
||||
+searchOptions(String, int, int) StationOption[]
|
||||
}
|
||||
class StationRedisCache {
|
||||
-redisTemplate RedisTemplate
|
||||
+get(UUID) Station
|
||||
+put(Station) void
|
||||
+evict(UUID) void
|
||||
+evictAll() void
|
||||
}
|
||||
StationService <|.. DefaultStationService : 实现
|
||||
DefaultStationService --> StationMapper : 使用
|
||||
DefaultStationService --> StationRedisCache : 使用
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [StationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/StationService.java#L1-L67)
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java)
|
||||
- [StationMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/StationMapper.java)
|
||||
- [StationRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/station/StationRedisCache.java)
|
||||
|
||||
### DefaultStationService 实现细节
|
||||
|
||||
#### 创建充电站流程
|
||||
|
||||
`DefaultStationService.createStation()`方法负责创建新的充电站实体。该方法首先验证输入数据的有效性,然后生成新的UUID作为实体ID,设置创建和更新时间戳,最后将实体保存到数据库。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始]) --> ValidateInput["验证输入数据"]
|
||||
ValidateInput --> GenerateId["生成UUID"]
|
||||
GenerateId --> SetTimestamps["设置创建/更新时间"]
|
||||
SetTimestamps --> SaveToDB["保存到数据库"]
|
||||
SaveToDB --> UpdateCache["更新Redis缓存"]
|
||||
UpdateCache --> ReturnResult["返回结果"]
|
||||
ReturnResult --> End([结束])
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L50-L70)
|
||||
|
||||
#### 查询充电站流程
|
||||
|
||||
`DefaultStationService.getStations()`方法实现了分页查询功能。该方法首先尝试从Redis缓存中获取数据,如果缓存未命中,则从数据库查询并将结果存入缓存,以提高后续查询的性能。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始]) --> CheckCache["检查Redis缓存"]
|
||||
CheckCache --> CacheHit{"缓存命中?"}
|
||||
CacheHit --> |是| ReturnFromCache["从缓存返回"]
|
||||
CacheHit --> |否| QueryDB["查询数据库"]
|
||||
QueryDB --> SaveToCache["保存到缓存"]
|
||||
SaveToCache --> ReturnFromDB["从数据库返回"]
|
||||
ReturnFromCache --> End([结束])
|
||||
ReturnFromDB --> End
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L30-L45)
|
||||
|
||||
#### 删除充电站流程
|
||||
|
||||
`DefaultStationService.deleteStation()`方法实现了充电站的删除操作。该方法不仅删除充电站实体本身,还会级联删除其下属的所有充电桩和充电枪,确保数据的一致性。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始]) --> ValidateExistence["验证充电站存在"]
|
||||
ValidateExistence --> DeleteGuns["删除所有充电枪"]
|
||||
DeleteGuns --> DeletePiles["删除所有充电桩"]
|
||||
DeletePiles --> DeleteStation["删除充电站"]
|
||||
DeleteStation --> EvictCache["清除缓存"]
|
||||
EvictCache --> End([结束])
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L120-L150)
|
||||
|
||||
## 完整使用示例
|
||||
|
||||
### 创建包含多个充电桩的充电站
|
||||
|
||||
以下示例展示了如何通过API创建一个包含多个充电桩的充电站。
|
||||
|
||||
#### 步骤1: 创建充电站
|
||||
|
||||
```http
|
||||
POST /api/stations
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"stationName": "高新科技园充电站",
|
||||
"stationCode": "ST001",
|
||||
"longitude": 116.397026,
|
||||
"latitude": 39.909026,
|
||||
"province": "北京市",
|
||||
"city": "北京市",
|
||||
"county": "海淀区",
|
||||
"address": "中关村大街1号"
|
||||
}
|
||||
```
|
||||
|
||||
**响应**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "创建成功",
|
||||
"data": {
|
||||
"id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
|
||||
"stationName": "高新科技园充电站",
|
||||
"stationCode": "ST001",
|
||||
// 其他字段...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L50-L57)
|
||||
|
||||
#### 步骤2: 创建充电桩
|
||||
|
||||
使用上一步返回的充电站ID创建两个充电桩。
|
||||
|
||||
```http
|
||||
POST /api/piles
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"pileName": "快充桩A",
|
||||
"pileCode": "PL001",
|
||||
"protocol": "LVNENG_V340",
|
||||
"stationId": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
|
||||
"brand": "绿能",
|
||||
"model": "GN-800",
|
||||
"manufacturer": "绿能科技有限公司",
|
||||
"type": "DC"
|
||||
}
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L35-L42)
|
||||
|
||||
#### 步骤3: 创建充电枪
|
||||
|
||||
为每个充电桩创建两个充电枪。
|
||||
|
||||
```http
|
||||
POST /api/guns
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"gunName": "快充枪A1",
|
||||
"gunNo": "A1",
|
||||
"gunCode": "GN001",
|
||||
"stationId": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
|
||||
"pileId": "b2c3d4e5-f678-9012-3456-7890abcdef12"
|
||||
}
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L35-L42)
|
||||
|
||||
#### 步骤4: 验证创建结果
|
||||
|
||||
通过查询接口验证整个层级结构是否正确创建。
|
||||
|
||||
```http
|
||||
GET /api/stations/a1b2c3d4-e5f6-7890-1234-567890abcdef
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L40-L47)
|
||||
|
||||
## 复杂业务逻辑实现
|
||||
|
||||
### 分页查询实现
|
||||
|
||||
分页查询功能通过`PageResponse`类和MyBatis Plus的分页插件实现。`StationService.getStations()`方法接收`StationQueryRequest`
|
||||
参数,该参数包含了分页信息(页码和每页大小)以及可能的查询条件。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as 客户端
|
||||
participant Controller as StationController
|
||||
participant Service as DefaultStationService
|
||||
participant Mapper as StationMapper
|
||||
participant DB as 数据库
|
||||
Client->>Controller : GET /api/stations?page=1&size=20
|
||||
Controller->>Service : getStations(request)
|
||||
Service->>Service : 从缓存获取或生成缓存键
|
||||
Service->>Service : 检查缓存是否存在
|
||||
alt 缓存命中
|
||||
Service-->>Controller : 返回缓存数据
|
||||
else 缓存未命中
|
||||
Service->>Mapper : selectPage(request)
|
||||
Mapper->>DB : 执行SQL查询
|
||||
DB-->>Mapper : 返回分页结果
|
||||
Mapper-->>Service : Page<Station>
|
||||
Service->>Service : 转换为PageResponse
|
||||
Service->>Service : 存入缓存
|
||||
Service-->>Controller : PageResponse<Station>
|
||||
end
|
||||
Controller->>Controller : 包装为ApiResponse
|
||||
Controller-->>Client : 返回JSON响应
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L30-L37)
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L30-L45)
|
||||
- [PageResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PageResponse.java#L1-L43)
|
||||
|
||||
### 级联删除实现
|
||||
|
||||
级联删除是设备管理模块中的一个重要功能,确保在删除充电站时,其下属的所有充电桩和充电枪也被正确删除。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始]) --> ValidateId["验证ID有效性"]
|
||||
ValidateId --> CheckExistence["检查充电站是否存在"]
|
||||
CheckExistence --> |不存在| ReturnError["返回404错误"]
|
||||
CheckExistence --> |存在| BeginTransaction["开始数据库事务"]
|
||||
BeginTransaction --> DeleteGuns["删除所有充电枪"]
|
||||
DeleteGuns --> DeletePiles["删除所有充电桩"]
|
||||
DeletePiles --> DeleteStation["删除充电站"]
|
||||
DeleteStation --> ClearCache["清除相关缓存"]
|
||||
ClearCache --> CommitTransaction["提交事务"]
|
||||
CommitTransaction --> ReturnSuccess["返回成功"]
|
||||
ReturnError --> End([结束])
|
||||
ReturnSuccess --> End
|
||||
Exception --> RollbackTransaction["回滚事务"]
|
||||
RollbackTransaction --> ThrowException["抛出异常"]
|
||||
ThrowException --> End
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L120-L150)
|
||||
|
||||
### 缓存管理策略
|
||||
|
||||
系统采用了多级缓存策略,结合了Redis和本地缓存(Caffeine),以提高数据访问性能。
|
||||
|
||||
#### 缓存键设计
|
||||
|
||||
缓存键遵循统一的命名规范,便于管理和监控:
|
||||
|
||||
- 充电站缓存键:`station:{id}`
|
||||
- 充电桩缓存键:`pile:{id}`
|
||||
- 充电枪缓存键:`gun:{id}`
|
||||
|
||||
#### 缓存失效策略
|
||||
|
||||
当实体被创建、更新或删除时,相关的缓存会被自动清除:
|
||||
|
||||
- 创建:新实体存入缓存
|
||||
- 更新:更新缓存中的实体
|
||||
- 删除:从缓存中移除实体
|
||||
|
||||
**来源**
|
||||
|
||||
- [StationRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/station/StationRedisCache.java)
|
||||
- [PileRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/pile/PileRedisCache.java)
|
||||
- [GunRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/gun/GunRedisCache.java)
|
||||
Reference in New Issue
Block a user