mirror of
https://gitee.com/san-bing/JChargePointProtocol
synced 2026-08-15 01:57:24 +08:00
wiki生成
This commit is contained in:
526
docs/API接口参考/API接口参考.md
Normal file
526
docs/API接口参考/API接口参考.md
Normal file
@@ -0,0 +1,526 @@
|
||||
# API接口参考
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [SecurityConfiguration.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/SecurityConfiguration.java)
|
||||
- [BaseController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/BaseController.java)
|
||||
- [UserController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/UserController.java)
|
||||
- [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)
|
||||
- [RpcController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java)
|
||||
- [ProtocolController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/ProtocolController.java)
|
||||
- [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)
|
||||
- [ApiResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/ApiResponse.java)
|
||||
- [LoginResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/LoginResponse.java)
|
||||
- [JCPPErrorCode.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorCode.java)
|
||||
- [JCPPErrorResponseHandler.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorResponseHandler.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)
|
||||
- [StartChargeDTO.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/dto/StartChargeDTO.java)
|
||||
- [StopChargeDTO.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/dto/StopChargeDTO.java)
|
||||
- [RpcRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/RpcRequest.java)
|
||||
- [downlink.proto](file://jcpp-infrastructure-proto/src/main/proto/downlink.proto)
|
||||
- [grpc.proto](file://jcpp-infrastructure-proto/src/main/proto/grpc.proto)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [简介](#简介)
|
||||
2. [RESTful API](#restful-api)
|
||||
1. [认证与安全](#认证与安全)
|
||||
2. [设备管理接口](#设备管理接口)
|
||||
3. [协议管理接口](#协议管理接口)
|
||||
4. [RPC接口](#rpc接口)
|
||||
3. [gRPC接口](#grpc接口)
|
||||
4. [通用响应结构](#通用响应结构)
|
||||
5. [错误码体系](#错误码体系)
|
||||
6. [速率限制](#速率限制)
|
||||
|
||||
## 简介
|
||||
|
||||
本文档为JChargePointProtocol项目提供全面的API接口参考,涵盖RESTful API和gRPC两种通信方式。系统为充电桩管理平台提供完整的设备管理、协议交互和远程控制能力。
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [BaseController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/BaseController.java)
|
||||
|
||||
## RESTful API
|
||||
|
||||
### 认证与安全
|
||||
|
||||
系统采用JWT(JSON Web Token)进行身份验证,支持两种认证方式:
|
||||
|
||||
1. **请求头认证**(推荐):
|
||||
- `Authorization: Bearer <token>`
|
||||
- 或 `X-Authorization: <token>`
|
||||
|
||||
2. **查询参数认证**:
|
||||
- `?token=<token>`
|
||||
|
||||
认证端点:
|
||||
|
||||
- **POST /api/auth/login**:用户登录获取JWT令牌
|
||||
- **GET /api/user/info**:获取当前用户信息
|
||||
|
||||
成功登录后,系统返回包含JWT令牌的响应,后续请求需在请求头中携带该令牌。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as "客户端"
|
||||
participant AuthController as "认证控制器"
|
||||
participant UserService as "用户服务"
|
||||
Client->>AuthController : POST /api/auth/login
|
||||
AuthController->>UserService : 验证用户凭证
|
||||
UserService-->>AuthController : 验证结果
|
||||
AuthController->>AuthController : 生成JWT令牌
|
||||
AuthController-->>Client : 返回LoginResponse包含token
|
||||
Client->>Client : 存储token用于后续请求
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [SecurityConfiguration.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/SecurityConfiguration.java#L40-L70)
|
||||
- [LoginResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/LoginResponse.java)
|
||||
|
||||
### 设备管理接口
|
||||
|
||||
#### 充电站管理
|
||||
|
||||
提供对充电站的CRUD操作和查询功能。
|
||||
|
||||
| HTTP方法 | URL路径 | 描述 |
|
||||
|--------|-----------------------|-------------------|
|
||||
| GET | /api/stations | 分页查询充电站列表 |
|
||||
| GET | /api/stations/{id} | 根据ID获取充电站详情 |
|
||||
| POST | /api/stations | 创建新的充电站 |
|
||||
| PUT | /api/stations/{id} | 更新充电站信息 |
|
||||
| DELETE | /api/stations/{id} | 删除充电站 |
|
||||
| GET | /api/stations/options | 获取充电站选项列表(用于下拉选择) |
|
||||
| GET | /api/stations/search | 搜索充电站选项(支持关键字) |
|
||||
|
||||
**请求体 (POST /api/stations) - StationCreateRequest:**
|
||||
|
||||
```json
|
||||
{
|
||||
"stationName": "string, 充电站名称, 必填",
|
||||
"stationCode": "string, 充电站编码, 必填",
|
||||
"longitude": "number, 经度",
|
||||
"latitude": "number, 纬度",
|
||||
"province": "string, 省份",
|
||||
"city": "string, 城市",
|
||||
"county": "string, 区县",
|
||||
"address": "string, 详细地址"
|
||||
}
|
||||
```
|
||||
|
||||
**响应体:**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "创建成功",
|
||||
"data": {
|
||||
"id": "uuid, 充电站ID",
|
||||
"stationName": "string, 充电站名称",
|
||||
"stationCode": "string, 充电站编码",
|
||||
"longitude": "number, 经度",
|
||||
"latitude": "number, 纬度",
|
||||
"province": "string, 省份",
|
||||
"city": "string, 城市",
|
||||
"county": "string, 区县",
|
||||
"address": "string, 详细地址",
|
||||
"createdTime": "datetime, 创建时间"
|
||||
},
|
||||
"timestamp": "number, 时间戳"
|
||||
}
|
||||
```
|
||||
|
||||
**curl示例:**
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8080/api/stations" \
|
||||
-H "Authorization: Bearer your-jwt-token" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"stationName": "高新科技园充电站",
|
||||
"stationCode": "ST001",
|
||||
"longitude": 113.944,
|
||||
"latitude": 22.543,
|
||||
"province": "广东省",
|
||||
"city": "深圳市",
|
||||
"county": "南山区",
|
||||
"address": "科技园南区1号"
|
||||
}'
|
||||
```
|
||||
|
||||
#### 充电桩管理
|
||||
|
||||
提供对充电桩的管理功能。
|
||||
|
||||
| HTTP方法 | URL路径 | 描述 |
|
||||
|--------|------------------------------|-----------------|
|
||||
| POST | /api/piles | 创建新的充电桩 |
|
||||
| GET | /api/piles/{id} | 根据ID获取充电桩详情 |
|
||||
| PUT | /api/piles/{id} | 更新充电桩信息 |
|
||||
| DELETE | /api/piles/{id} | 删除充电桩 |
|
||||
| GET | /api/piles | 分页查询充电桩列表(包含状态) |
|
||||
| GET | /api/piles/options | 获取充电桩选项列表 |
|
||||
| GET | /api/piles/status/{pileCode} | 根据桩编号获取充电桩状态 |
|
||||
|
||||
**curl示例:**
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/api/piles/status/P001" \
|
||||
-H "Authorization: Bearer your-jwt-token"
|
||||
```
|
||||
|
||||
#### 充电枪管理
|
||||
|
||||
提供对充电枪的管理功能。
|
||||
|
||||
| HTTP方法 | URL路径 | 描述 |
|
||||
|--------|----------------------------|-----------------|
|
||||
| POST | /api/guns | 创建新的充电枪 |
|
||||
| GET | /api/guns/{id} | 根据ID获取充电枪详情 |
|
||||
| PUT | /api/guns/{id} | 更新充电枪信息 |
|
||||
| DELETE | /api/guns/{id} | 删除充电枪 |
|
||||
| GET | /api/guns | 分页查询充电枪列表(包含状态) |
|
||||
| GET | /api/guns/status/{gunCode} | 根据枪编号获取充电枪运行状态 |
|
||||
| GET | /api/guns/code/{gunCode} | 根据充电枪编码获取详细信息 |
|
||||
|
||||
**curl示例:**
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/api/guns/code/G001" \
|
||||
-H "Authorization: Bearer your-jwt-token"
|
||||
```
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [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)
|
||||
- [StationCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/StationCreateRequest.java)
|
||||
|
||||
### 协议管理接口
|
||||
|
||||
提供协议相关的查询功能。
|
||||
|
||||
| HTTP方法 | URL路径 | 描述 |
|
||||
|--------|--------------------------|-------------|
|
||||
| GET | /api/protocols/supported | 获取所有支持的协议列表 |
|
||||
|
||||
**响应体:**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "查询成功",
|
||||
"data": [
|
||||
{
|
||||
"value": "string, 协议标识符",
|
||||
"label": "string, 显示名称"
|
||||
}
|
||||
],
|
||||
"timestamp": "number, 时间戳"
|
||||
}
|
||||
```
|
||||
|
||||
**curl示例:**
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/api/protocols/supported" \
|
||||
-H "Authorization: Bearer your-jwt-token"
|
||||
```
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [ProtocolController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/ProtocolController.java)
|
||||
|
||||
### RPC接口
|
||||
|
||||
提供通用化的充电桩远程过程调用接口,支持多种控制命令。
|
||||
|
||||
| HTTP方法 | URL路径 | 描述 |
|
||||
|--------|------------------------|-------------------|
|
||||
| POST | /api/rpc/oneway | 单向RPC调用(不等待响应) |
|
||||
| POST | /api/rpc/bidirectional | 双向RPC调用(等待响应,待实现) |
|
||||
|
||||
**请求体 - RpcRequest:**
|
||||
|
||||
```json
|
||||
{
|
||||
"method": "string, RPC方法名, 必填",
|
||||
"parameter": "object, 方法参数, JSON格式, 必填",
|
||||
"timeoutMs": "number, 超时时间(毫秒),仅用于双向RPC"
|
||||
}
|
||||
```
|
||||
|
||||
支持的`method`值:
|
||||
|
||||
- `startCharge`: 启动充电
|
||||
- `stopCharge`: 停止充电
|
||||
- `restartPile`: 重启充电桩
|
||||
- `setPricing`: 设置计费策略
|
||||
- `setQrcode`: 设置二维码
|
||||
- `otaRequest`: OTA升级
|
||||
- `offlineCardBalanceUpdate`: 离线卡余额更新
|
||||
- `offlineCardSync`: 离线卡同步
|
||||
- `offlineCardClear`: 离线卡清除
|
||||
- `offlineCardQuery`: 离线卡查询
|
||||
- `timeSync`: 时间同步
|
||||
|
||||
#### 启动充电
|
||||
|
||||
**method**: `startCharge`
|
||||
|
||||
**parameter结构 - StartChargeDTO:**
|
||||
|
||||
```json
|
||||
{
|
||||
"pileCode": "string, 充电桩编码, 必填",
|
||||
"gunNo": "string, 充电枪编号, 必填",
|
||||
"limitYuan": "number, 限制金额(元), 必填",
|
||||
"orderNo": "string, 订单号, 必填",
|
||||
"logicalCardNo": "string, 逻辑卡号",
|
||||
"physicalCardNo": "string, 物理卡号",
|
||||
"parallelNo": "string, 并充序号"
|
||||
}
|
||||
```
|
||||
|
||||
**curl示例:**
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8080/api/rpc/oneway" \
|
||||
-H "Authorization: Bearer your-jwt-token" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"method": "startCharge",
|
||||
"parameter": {
|
||||
"pileCode": "P001",
|
||||
"gunNo": "G001",
|
||||
"limitYuan": 100.00,
|
||||
"orderNo": "ORD20240101001",
|
||||
"logicalCardNo": "LC001",
|
||||
"physicalCardNo": "PC001"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
#### 停止充电
|
||||
|
||||
**method**: `stopCharge`
|
||||
|
||||
**parameter结构 - StopChargeDTO:**
|
||||
|
||||
```json
|
||||
{
|
||||
"pileCode": "string, 充电桩编码, 必填",
|
||||
"gunNo": "string, 充电枪编号, 必填"
|
||||
}
|
||||
```
|
||||
|
||||
**curl示例:**
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8080/api/rpc/oneway" \
|
||||
-H "Authorization: Bearer your-jwt-token" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"method": "stopCharge",
|
||||
"parameter": {
|
||||
"pileCode": "P001",
|
||||
"gunNo": "G001"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [RpcController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java)
|
||||
- [StartChargeDTO.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/dto/StartChargeDTO.java)
|
||||
- [StopChargeDTO.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/dto/StopChargeDTO.java)
|
||||
- [RpcRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/RpcRequest.java)
|
||||
|
||||
## gRPC接口
|
||||
|
||||
系统提供gRPC接口用于高效的双向通信,主要服务于DownlinkGrpcService。
|
||||
|
||||
### 服务定义
|
||||
|
||||
在`grpc.proto`文件中定义了`ProtocolInterface`服务:
|
||||
|
||||
```protobuf
|
||||
service ProtocolInterface {
|
||||
rpc onDownlink(stream RequestMsg) returns (stream ResponseMsg) {}
|
||||
}
|
||||
```
|
||||
|
||||
### 消息类型
|
||||
|
||||
#### RequestMsg
|
||||
|
||||
```protobuf
|
||||
message RequestMsg {
|
||||
int64 ts = 1;
|
||||
TracerProto tracer = 2;
|
||||
ConnectRequestMsg connectRequestMsg = 10;
|
||||
DownlinkRequestMessage downlinkRequestMessage = 11;
|
||||
}
|
||||
```
|
||||
|
||||
#### ResponseMsg
|
||||
|
||||
```protobuf
|
||||
message ResponseMsg {
|
||||
TracerProto tracer = 2;
|
||||
ConnectResponseMsg connectResponseMsg = 12;
|
||||
DownlinkResponseMessage downlinkResponseMsg = 13;
|
||||
}
|
||||
```
|
||||
|
||||
### 连接流程
|
||||
|
||||
1. 客户端建立gRPC连接到服务器
|
||||
2. 发送包含`ConnectRequestMsg`的`RequestMsg`
|
||||
3. 服务器返回包含`ConnectResponseMsg`的`ResponseMsg`
|
||||
4. 连接建立成功后,可发送`DownlinkRequestMessage`进行下行指令
|
||||
|
||||
### DownlinkRequestMessage
|
||||
|
||||
定义在`downlink.proto`中,包含各种充电桩控制指令。
|
||||
|
||||
### Java客户端调用示例
|
||||
|
||||
```java
|
||||
// 创建gRPC通道
|
||||
ManagedChannel channel = ManagedChannelBuilder
|
||||
.forAddress("localhost", 6001)
|
||||
.usePlaintext()
|
||||
.build();
|
||||
|
||||
// 创建Stub
|
||||
ProtocolInterfaceGrpc.ProtocolInterfaceStub stub =
|
||||
ProtocolInterfaceGrpc.newStub(channel);
|
||||
|
||||
// 创建流观察者
|
||||
StreamObserver<RequestMsg> requestObserver = stub.onDownlink(
|
||||
new StreamObserver<ResponseMsg>() {
|
||||
@Override
|
||||
public void onNext(ResponseMsg response) {
|
||||
// 处理服务器响应
|
||||
System.out.println("收到响应: " + response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t) {
|
||||
// 处理错误
|
||||
System.err.println("gRPC错误: " + t.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompleted() {
|
||||
// 流完成
|
||||
System.out.println("连接关闭");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 发送连接请求
|
||||
requestObserver.onNext(
|
||||
RequestMsg.newBuilder()
|
||||
.setConnectRequestMsg(
|
||||
ConnectRequestMsg.newBuilder()
|
||||
.setNodeId("client-001")
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
);
|
||||
|
||||
// 发送下行指令
|
||||
UUID sessionId = UUID.randomUUID();
|
||||
requestObserver.onNext(
|
||||
RequestMsg.newBuilder()
|
||||
.setDownlinkRequestMessage(
|
||||
DownlinkRequestMessage.newBuilder()
|
||||
.setSessionIdMSB(sessionId.getMostSignificantBits())
|
||||
.setSessionIdLSB(sessionId.getLeastSignificantBits())
|
||||
// 设置具体指令内容
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
);
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [DownlinkGrpcService.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkGrpcService.java)
|
||||
- [grpc.proto](file://jcpp-infrastructure-proto/src/main/proto/grpc.proto)
|
||||
- [downlink.proto](file://jcpp-infrastructure-proto/src/main/proto/downlink.proto)
|
||||
|
||||
## 通用响应结构
|
||||
|
||||
所有RESTful API响应均采用统一的`ApiResponse`结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": "boolean, 操作是否成功",
|
||||
"errorCode": "string, 错误码(失败时存在)",
|
||||
"message": "string, 响应消息",
|
||||
"data": "object, 响应数据(成功时存在)",
|
||||
"timestamp": "number, 时间戳"
|
||||
}
|
||||
```
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [ApiResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/ApiResponse.java)
|
||||
|
||||
## 错误码体系
|
||||
|
||||
系统定义了统一的错误码体系`JCPPErrorCode`,用于标准化错误响应。
|
||||
|
||||
| 错误码 | HTTP状态码 | 描述 |
|
||||
|-----|---------|---------|
|
||||
| 2 | 500 | 通用错误 |
|
||||
| 10 | 401 | 认证失败 |
|
||||
| 11 | 401 | JWT令牌过期 |
|
||||
| 15 | 401 | 凭证过期 |
|
||||
| 20 | 403 | 权限拒绝 |
|
||||
| 30 | 400 | 无效参数 |
|
||||
| 31 | 400 | 请求参数错误 |
|
||||
| 32 | 404 | 项目未找到 |
|
||||
| 33 | 429 | 请求过多 |
|
||||
| 34 | 429 | 更新过多 |
|
||||
| 35 | 409 | 版本冲突 |
|
||||
| 40 | 403 | 订阅违规 |
|
||||
| 45 | 401 | 密码违规 |
|
||||
| 46 | 500 | 数据库错误 |
|
||||
|
||||
错误响应示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"errorCode": "AUTHENTICATION",
|
||||
"message": "认证失败",
|
||||
"timestamp": 1700000000000
|
||||
}
|
||||
```
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [JCPPErrorCode.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorCode.java)
|
||||
- [JCPPErrorResponseHandler.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorResponseHandler.java)
|
||||
|
||||
## 速率限制
|
||||
|
||||
系统实现了速率限制机制,防止API被滥用。速率限制通过`@RateLimit`注解实现,配置在需要限制的接口上。
|
||||
|
||||
当请求超过限制时,系统返回`429 Too Many Requests`状态码,错误码为`TOO_MANY_REQUESTS`(33)。
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [RateLimit.java](file://jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/validation/RateLimit.java)
|
||||
636
docs/API接口参考/REST API.md
Normal file
636
docs/API接口参考/REST API.md
Normal file
@@ -0,0 +1,636 @@
|
||||
# REST API
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [UserController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/UserController.java)
|
||||
- [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)
|
||||
- [ProtocolController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/ProtocolController.java)
|
||||
- [RpcController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java)
|
||||
- [BaseController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/BaseController.java)
|
||||
- [ApiResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/ApiResponse.java)
|
||||
- [LoginResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/LoginResponse.java)
|
||||
- [ErrorCode.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/ErrorCode.java)
|
||||
- [JCPPErrorCode.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorCode.java)
|
||||
- [PageRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/PageRequest.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)
|
||||
- [RpcRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/RpcRequest.java)
|
||||
- [StartChargeDTO.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/dto/StartChargeDTO.java)
|
||||
- [SecurityConfiguration.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/SecurityConfiguration.java)
|
||||
- [JCPPErrorResponseHandler.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorResponseHandler.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [简介](#简介)
|
||||
2. [认证机制](#认证机制)
|
||||
3. [通用响应格式](#通用响应格式)
|
||||
4. [分页查询参数](#分页查询参数)
|
||||
5. [全局异常处理](#全局异常处理)
|
||||
6. [错误码列表](#错误码列表)
|
||||
7. [用户认证API](#用户认证api)
|
||||
8. [设备管理API](#设备管理api)
|
||||
9. [协议交互API](#协议交互api)
|
||||
10. [远程过程调用API](#远程过程调用api)
|
||||
11. [curl命令示例](#curl命令示例)
|
||||
|
||||
## 简介
|
||||
|
||||
本文档为JChargePointProtocol系统提供全面的REST API文档,涵盖用户认证、设备管理、协议交互和远程过程调用等核心功能。所有API端点均采用统一的响应格式和错误处理机制,确保接口的一致性和易用性。
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [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)
|
||||
- [ProtocolController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/ProtocolController.java)
|
||||
- [RpcController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java)
|
||||
|
||||
## 认证机制
|
||||
|
||||
系统采用JWT(JSON Web Token)进行身份认证和授权。客户端在成功登录后会获得一个JWT令牌,后续请求需要在请求头中携带该令牌。
|
||||
|
||||
### 认证方式
|
||||
|
||||
支持以下两种方式传递JWT令牌:
|
||||
|
||||
1. **Authorization请求头**(推荐)
|
||||
```
|
||||
Authorization: Bearer <JWT_TOKEN>
|
||||
```
|
||||
|
||||
2. **自定义请求头**
|
||||
```
|
||||
X-Authorization: <JWT_TOKEN>
|
||||
```
|
||||
|
||||
### 认证流程
|
||||
|
||||
1. 用户通过`/api/auth/login`端点进行登录,提供用户名和密码
|
||||
2. 服务器验证凭据,成功后返回包含JWT令牌的响应
|
||||
3. 客户端在后续所有请求的请求头中包含JWT令牌
|
||||
4. 服务器验证令牌的有效性,决定是否授予访问权限
|
||||
|
||||
令牌过期后,客户端需要使用刷新令牌获取新的访问令牌。
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [SecurityConfiguration.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/SecurityConfiguration.java)
|
||||
- [LoginResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/LoginResponse.java)
|
||||
|
||||
## 通用响应格式
|
||||
|
||||
所有API响应均采用统一的`ApiResponse`格式,确保客户端能够一致地处理成功和错误响应。
|
||||
|
||||
### 响应结构
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"errorCode": "SUCCESS",
|
||||
"message": "操作成功",
|
||||
"data": {},
|
||||
"timestamp": 1700000000000
|
||||
}
|
||||
```
|
||||
|
||||
### 字段说明
|
||||
|
||||
- **success**: 布尔值,表示请求是否成功
|
||||
- **errorCode**: 错误码,成功时为"SUCCESS",失败时为具体的错误码
|
||||
- **message**: 响应消息,描述操作结果
|
||||
- **data**: 响应数据,包含实际的业务数据
|
||||
- **timestamp**: 时间戳,记录响应生成的时间
|
||||
|
||||
### 成功响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"errorCode": "SUCCESS",
|
||||
"message": "查询成功",
|
||||
"data": {
|
||||
"id": "123e4567-e89b-12d3-a456-426614174000",
|
||||
"stationName": "测试充电站",
|
||||
"stationCode": "ST001"
|
||||
},
|
||||
"timestamp": 1700000000000
|
||||
}
|
||||
```
|
||||
|
||||
### 错误响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"errorCode": "UNAUTHORIZED",
|
||||
"message": "用户未认证",
|
||||
"timestamp": 1700000000000
|
||||
}
|
||||
```
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [ApiResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/ApiResponse.java)
|
||||
|
||||
## 分页查询参数
|
||||
|
||||
大多数查询接口支持分页功能,通过`PageRequest`类定义分页参数。
|
||||
|
||||
### 分页参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|-----------|---------|----|------|-----------------------|
|
||||
| page | Integer | 否 | 1 | 页码,从1开始 |
|
||||
| size | Integer | 否 | 10 | 每页大小 |
|
||||
| sortField | String | 否 | - | 排序字段 |
|
||||
| sortOrder | String | 否 | desc | 排序方向:asc(升序)或desc(降序) |
|
||||
| search | String | 否 | - | 搜索关键词 |
|
||||
|
||||
### 示例
|
||||
|
||||
获取第2页的充电站列表,每页20条记录,按创建时间降序排列:
|
||||
|
||||
```
|
||||
GET /api/stations?page=2&size=20&sortField=createTime&sortOrder=desc
|
||||
```
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [PageRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/PageRequest.java)
|
||||
|
||||
## 全局异常处理
|
||||
|
||||
系统通过`BaseController`类提供统一的异常处理机制,确保所有异常都能被妥善处理并返回标准化的错误响应。
|
||||
|
||||
### 异常处理流程
|
||||
|
||||
1. 捕获控制器中的各种异常
|
||||
2. 将异常转换为`JCPPException`
|
||||
3. 通过`JCPPErrorResponseHandler`生成标准化的错误响应
|
||||
4. 返回给客户端
|
||||
|
||||
### 支持的异常类型
|
||||
|
||||
- `Exception`: 通用异常
|
||||
- `JCPPException`: JCPP自定义异常
|
||||
- `MethodArgumentNotValidException`: 参数校验异常
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [BaseController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/BaseController.java)
|
||||
- [JCPPErrorResponseHandler.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorResponseHandler.java)
|
||||
|
||||
## 错误码列表
|
||||
|
||||
系统定义了统一的错误码体系,便于客户端识别和处理不同类型的错误。
|
||||
|
||||
### 通用错误码
|
||||
|
||||
| 错误码 | 说明 |
|
||||
|------------------|------------|
|
||||
| SUCCESS | 操作成功 |
|
||||
| SYSTEM_ERROR | 系统异常,请稍后重试 |
|
||||
| BUSINESS_ERROR | 业务处理失败 |
|
||||
| VALIDATION_ERROR | 参数校验失败 |
|
||||
| BINDING_ERROR | 数据绑定异常 |
|
||||
| ILLEGAL_ARGUMENT | 参数错误 |
|
||||
| ILLEGAL_STATE | 状态错误 |
|
||||
|
||||
### 认证授权相关
|
||||
|
||||
| 错误码 | 说明 |
|
||||
|-----------------|---------------|
|
||||
| UNAUTHORIZED | 用户未认证 |
|
||||
| AUTH_FAILED | 用户名或密码错误 |
|
||||
| JWT_AUTH_FAILED | JWT Token认证失败 |
|
||||
| FORBIDDEN | 权限不足 |
|
||||
|
||||
### 资源相关
|
||||
|
||||
| 错误码 | 说明 |
|
||||
|-----------|----------|
|
||||
| NOT_FOUND | 请求的资源不存在 |
|
||||
| CONFLICT | 资源冲突 |
|
||||
|
||||
### 业务特定错误码
|
||||
|
||||
| 错误码 | 说明 |
|
||||
|---------------------|----------|
|
||||
| PILE_CODE_EXISTS | 充电桩编码已存在 |
|
||||
| STATION_NAME_EXISTS | 充电站名称已存在 |
|
||||
| GUN_CODE_EXISTS | 充电枪编号已存在 |
|
||||
| PILE_NOT_FOUND | 充电桩不存在 |
|
||||
| STATION_NOT_FOUND | 充电站不存在 |
|
||||
| GUN_NOT_FOUND | 充电枪不存在 |
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [ErrorCode.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/ErrorCode.java)
|
||||
- [JCPPErrorCode.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorCode.java)
|
||||
|
||||
## 用户认证API
|
||||
|
||||
提供用户登录和获取用户信息的接口。
|
||||
|
||||
### 登录
|
||||
|
||||
- **HTTP方法**: POST
|
||||
- **URL路径**: `/api/auth/login`
|
||||
- **请求头**: 无特殊要求
|
||||
- **请求体**:
|
||||
```json
|
||||
{
|
||||
"username": "string",
|
||||
"password": "string"
|
||||
}
|
||||
```
|
||||
- **响应体**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"errorCode": "SUCCESS",
|
||||
"message": "操作成功",
|
||||
"data": {
|
||||
"token": "string",
|
||||
"refreshToken": "string",
|
||||
"tokenType": "Bearer",
|
||||
"user": {
|
||||
"id": "string",
|
||||
"username": "string",
|
||||
"status": "ENABLE"
|
||||
}
|
||||
},
|
||||
"timestamp": 1700000000000
|
||||
}
|
||||
```
|
||||
|
||||
### 获取用户信息
|
||||
|
||||
- **HTTP方法**: GET
|
||||
- **URL路径**: `/api/user/info`
|
||||
- **请求头**: `Authorization: Bearer <JWT>`
|
||||
- **响应体**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"errorCode": "SUCCESS",
|
||||
"message": "操作成功",
|
||||
"data": {
|
||||
"id": "string",
|
||||
"username": "string",
|
||||
"status": "ENABLE"
|
||||
},
|
||||
"timestamp": 1700000000000
|
||||
}
|
||||
```
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [UserController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/UserController.java)
|
||||
- [LoginResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/LoginResponse.java)
|
||||
|
||||
## 设备管理API
|
||||
|
||||
提供对充电站、充电桩和充电枪的增删改查操作。
|
||||
|
||||
### 充电站管理
|
||||
|
||||
#### 查询充电站列表
|
||||
|
||||
- **HTTP方法**: GET
|
||||
- **URL路径**: `/api/stations`
|
||||
- **请求头**: `Authorization: Bearer <JWT>`
|
||||
- **查询参数**: 继承自`PageRequest`
|
||||
- **响应体**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"errorCode": "SUCCESS",
|
||||
"message": "查询成功",
|
||||
"data": {
|
||||
"content": [
|
||||
{
|
||||
"id": "uuid",
|
||||
"stationName": "string",
|
||||
"stationCode": "string",
|
||||
"longitude": 120.123,
|
||||
"latitude": 30.456,
|
||||
"province": "string",
|
||||
"city": "string",
|
||||
"county": "string",
|
||||
"address": "string"
|
||||
}
|
||||
],
|
||||
"totalElements": 1,
|
||||
"totalPages": 1,
|
||||
"page": 1,
|
||||
"size": 10
|
||||
},
|
||||
"timestamp": 1700000000000
|
||||
}
|
||||
```
|
||||
|
||||
#### 创建充电站
|
||||
|
||||
- **HTTP方法**: POST
|
||||
- **URL路径**: `/api/stations`
|
||||
- **请求头**: `Authorization: Bearer <JWT>`
|
||||
- **请求体**: `StationCreateRequest`
|
||||
```json
|
||||
{
|
||||
"stationName": "string",
|
||||
"stationCode": "string",
|
||||
"longitude": 120.123,
|
||||
"latitude": 30.456,
|
||||
"province": "string",
|
||||
"city": "string",
|
||||
"county": "string",
|
||||
"address": "string"
|
||||
}
|
||||
```
|
||||
- **字段说明**:
|
||||
- stationName: 充电站名称,必填,不能为空
|
||||
- stationCode: 充电站编码,必填,不能为空
|
||||
- longitude: 经度,浮点数
|
||||
- latitude: 纬度,浮点数
|
||||
- province: 省份
|
||||
- city: 城市
|
||||
- county: 区县
|
||||
- address: 详细地址
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java)
|
||||
- [StationCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/StationCreateRequest.java)
|
||||
|
||||
#### 更新充电站
|
||||
|
||||
- **HTTP方法**: PUT
|
||||
- **URL路径**: `/api/stations/{id}`
|
||||
- **请求头**: `Authorization: Bearer <JWT>`
|
||||
- **路径参数**: id - 充电站ID (UUID)
|
||||
- **请求体**: `StationUpdateRequest`
|
||||
```json
|
||||
{
|
||||
"stationName": "string",
|
||||
"longitude": 120.123,
|
||||
"latitude": 30.456,
|
||||
"province": "string",
|
||||
"city": "string",
|
||||
"county": "string",
|
||||
"address": "string"
|
||||
}
|
||||
```
|
||||
|
||||
#### 删除充电站
|
||||
|
||||
- **HTTP方法**: DELETE
|
||||
- **URL路径**: `/api/stations/{id}`
|
||||
- **请求头**: `Authorization: Bearer <JWT>`
|
||||
- **路径参数**: id - 充电站ID (UUID)
|
||||
|
||||
### 充电桩管理
|
||||
|
||||
#### 创建充电桩
|
||||
|
||||
- **HTTP方法**: POST
|
||||
- **URL路径**: `/api/piles`
|
||||
- **请求头**: `Authorization: Bearer <JWT>`
|
||||
- **请求体**: `PileCreateRequest`
|
||||
```json
|
||||
{
|
||||
"pileName": "string",
|
||||
"pileCode": "string",
|
||||
"protocol": "string",
|
||||
"stationId": "uuid",
|
||||
"brand": "string",
|
||||
"model": "string",
|
||||
"manufacturer": "string",
|
||||
"type": "DC"
|
||||
}
|
||||
```
|
||||
- **字段说明**:
|
||||
- pileName: 充电桩名称,必填,不能为空
|
||||
- pileCode: 充电桩编码,必填,不能为空
|
||||
- protocol: 协议,必填,不能为空
|
||||
- stationId: 所属充电站ID,必填,不能为空
|
||||
- brand: 品牌
|
||||
- model: 型号
|
||||
- manufacturer: 制造商
|
||||
- type: 类型,默认为DC(直流)
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [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)
|
||||
|
||||
#### 查询充电桩列表
|
||||
|
||||
- **HTTP方法**: GET
|
||||
- **URL路径**: `/api/piles`
|
||||
- **请求头**: `Authorization: Bearer <JWT>`
|
||||
- **查询参数**: 继承自`PageRequest`
|
||||
- **响应体**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"errorCode": "SUCCESS",
|
||||
"message": "查询成功",
|
||||
"data": {
|
||||
"content": [
|
||||
{
|
||||
"id": "uuid",
|
||||
"pileName": "string",
|
||||
"pileCode": "string",
|
||||
"protocol": "string",
|
||||
"stationId": "uuid",
|
||||
"brand": "string",
|
||||
"model": "string",
|
||||
"manufacturer": "string",
|
||||
"type": "DC",
|
||||
"status": "string"
|
||||
}
|
||||
],
|
||||
"totalElements": 1,
|
||||
"totalPages": 1,
|
||||
"page": 1,
|
||||
"size": 10
|
||||
},
|
||||
"timestamp": 1700000000000
|
||||
}
|
||||
```
|
||||
|
||||
### 充电枪管理
|
||||
|
||||
#### 创建充电枪
|
||||
|
||||
- **HTTP方法**: POST
|
||||
- **URL路径**: `/api/guns`
|
||||
- **请求头**: `Authorization: Bearer <JWT>`
|
||||
- **请求体**: `GunCreateRequest`
|
||||
```json
|
||||
{
|
||||
"gunName": "string",
|
||||
"gunNo": "string",
|
||||
"gunCode": "string",
|
||||
"stationId": "uuid",
|
||||
"pileId": "uuid"
|
||||
}
|
||||
```
|
||||
- **字段说明**:
|
||||
- gunName: 充电枪名称,必填,不能为空
|
||||
- gunNo: 充电枪编号,必填,不能为空
|
||||
- gunCode: 充电枪编码,必填,不能为空
|
||||
- stationId: 所属充电站ID,必填,不能为空
|
||||
- pileId: 所属充电桩ID,必填,不能为空
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java)
|
||||
- [GunCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/GunCreateRequest.java)
|
||||
|
||||
## 协议交互API
|
||||
|
||||
提供协议相关的查询接口。
|
||||
|
||||
### 获取支持的协议列表
|
||||
|
||||
- **HTTP方法**: GET
|
||||
- **URL路径**: `/api/protocols/supported`
|
||||
- **请求头**: `Authorization: Bearer <JWT>`
|
||||
- **响应体**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"errorCode": "SUCCESS",
|
||||
"message": "查询成功",
|
||||
"data": [
|
||||
{
|
||||
"value": "LVNENG_V340",
|
||||
"label": "绿能V3.4.0"
|
||||
},
|
||||
{
|
||||
"value": "YUNKUAICHONG_V150",
|
||||
"label": "云快充V1.5.0"
|
||||
}
|
||||
],
|
||||
"timestamp": 1700000000000
|
||||
}
|
||||
```
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [ProtocolController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/ProtocolController.java)
|
||||
|
||||
## 远程过程调用API
|
||||
|
||||
提供通用化的充电桩下行指令接口。
|
||||
|
||||
### 单向RPC
|
||||
|
||||
- **HTTP方法**: POST
|
||||
- **URL路径**: `/api/rpc/oneway`
|
||||
- **请求头**: `Authorization: Bearer <JWT>`
|
||||
- **请求体**: `RpcRequest`
|
||||
```json
|
||||
{
|
||||
"method": "string",
|
||||
"parameter": {},
|
||||
"timeoutMs": 10000
|
||||
}
|
||||
```
|
||||
- **字段说明**:
|
||||
- method: RPC方法名,必填,不能为空
|
||||
- parameter: 方法参数,JSON格式,必填,不能为空
|
||||
- timeoutMs: 超时时间(毫秒),仅用于双向RPC
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [RpcController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java)
|
||||
- [RpcRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/RpcRequest.java)
|
||||
|
||||
#### 支持的方法
|
||||
|
||||
| 方法名 | 说明 | 参数结构 |
|
||||
|--------------------------|---------|-----------------------------------|
|
||||
| startCharge | 启动充电 | `StartChargeDTO` |
|
||||
| stopCharge | 停止充电 | `StopChargeDTO` |
|
||||
| restartPile | 重启充电桩 | `RestartPileDTO` |
|
||||
| setPricing | 设置计费策略 | `SetPricingDTO` |
|
||||
| setQrcode | 设置二维码 | `SetQrcodeRequest` |
|
||||
| otaRequest | OTA升级 | `OtaRequest` |
|
||||
| offlineCardBalanceUpdate | 离线卡余额更新 | `OfflineCardBalanceUpdateRequest` |
|
||||
| offlineCardSync | 离线卡同步 | `OfflineCardSyncRequest` |
|
||||
| offlineCardClear | 离线卡清除 | `OfflineCardClearRequest` |
|
||||
| offlineCardQuery | 离线卡查询 | `OfflineCardQueryRequest` |
|
||||
| timeSync | 时间同步 | `TimeSyncDTO` |
|
||||
|
||||
### 启动充电示例
|
||||
|
||||
```json
|
||||
{
|
||||
"method": "startCharge",
|
||||
"parameter": {
|
||||
"pileCode": "P001",
|
||||
"gunNo": "G01",
|
||||
"limitYuan": 100.00,
|
||||
"orderNo": "ORDER_001",
|
||||
"logicalCardNo": "LOGICAL_001",
|
||||
"physicalCardNo": "PHYSICAL_001",
|
||||
"parallelNo": "PARALLEL_001"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [StartChargeDTO.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/dto/StartChargeDTO.java)
|
||||
|
||||
## curl命令示例
|
||||
|
||||
以下是一些常用的curl命令示例,演示如何使用API。
|
||||
|
||||
### 登录
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8080/api/auth/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"username": "admin",
|
||||
"password": "password"
|
||||
}'
|
||||
```
|
||||
|
||||
### 查询电站列表
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/api/stations?page=1&size=10" \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
```
|
||||
|
||||
### 下发启动充电指令
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8080/api/rpc/oneway" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||
-d '{
|
||||
"method": "startCharge",
|
||||
"parameter": {
|
||||
"pileCode": "P001",
|
||||
"gunNo": "G01",
|
||||
"limitYuan": 100.00,
|
||||
"orderNo": "ORDER_001"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
**本文档引用的文件**
|
||||
|
||||
- [UserController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/UserController.java)
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java)
|
||||
- [RpcController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java)
|
||||
826
docs/API接口参考/gRPC API.md
Normal file
826
docs/API接口参考/gRPC API.md
Normal file
@@ -0,0 +1,826 @@
|
||||
# JChargePointProtocol gRPC API 文档
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [downlink.proto](file://jcpp-infrastructure-proto/src/main/proto/downlink.proto)
|
||||
- [grpc.proto](file://jcpp-infrastructure-proto/src/main/proto/grpc.proto)
|
||||
- [DownlinkGrpcService.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkGrpcService.java)
|
||||
- [DownlinkGrpcClient.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/grpc/DownlinkGrpcClient.java)
|
||||
- [ProtoConverter.java](file://jcpp-infrastructure-proto/src/main/java/sanbing/jcpp/infrastructure/proto/ProtoConverter.java)
|
||||
- [GrpcDownlinkCallService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/GrpcDownlinkCallService.java)
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml)
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [简介](#简介)
|
||||
2. [项目架构概览](#项目架构概览)
|
||||
3. [gRPC服务定义](#grpc服务定义)
|
||||
4. [消息类型详解](#消息类型详解)
|
||||
5. [Protobuf序列化机制](#protobuf序列化机制)
|
||||
6. [ProtoConverter转换器](#protoconverter转换器)
|
||||
7. [gRPC客户端实现](#grpc客户端实现)
|
||||
8. [服务端点实现](#服务端点实现)
|
||||
9. [错误处理机制](#错误处理机制)
|
||||
10. [性能优化配置](#性能优化配置)
|
||||
11. [适用场景对比](#适用场景对比)
|
||||
12. [最佳实践指南](#最佳实践指南)
|
||||
|
||||
## 简介
|
||||
|
||||
JChargePointProtocol是一个基于gRPC的充电桩通信协议系统,专门设计用于电动汽车充电站的高效通信。该系统采用Protocol
|
||||
Buffers作为序列化机制,提供了高性能、低延迟的双向流式通信能力。
|
||||
|
||||
### 核心特性
|
||||
|
||||
- **高性能通信**:基于gRPC和Protocol Buffers的高效序列化
|
||||
- **双向流式通信**:支持实时数据传输和状态同步
|
||||
- **可扩展架构**:模块化的服务设计,便于功能扩展
|
||||
- **强类型安全**:编译时类型检查,减少运行时错误
|
||||
- **跨语言兼容**:支持多种编程语言的客户端开发
|
||||
|
||||
## 项目架构概览
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "客户端层"
|
||||
APP[应用程序]
|
||||
CLIENT[gRPC客户端]
|
||||
end
|
||||
subgraph "网络层"
|
||||
GATEWAY[网关/负载均衡器]
|
||||
LB[负载均衡策略]
|
||||
end
|
||||
subgraph "服务端层"
|
||||
SERVER[gRPC服务端]
|
||||
SESSION[会话管理]
|
||||
PROTO[协议处理器]
|
||||
end
|
||||
subgraph "存储层"
|
||||
CACHE[缓存系统]
|
||||
DB[(数据库)]
|
||||
end
|
||||
APP --> CLIENT
|
||||
CLIENT --> GATEWAY
|
||||
GATEWAY --> LB
|
||||
LB --> SERVER
|
||||
SERVER --> SESSION
|
||||
SESSION --> PROTO
|
||||
PROTO --> CACHE
|
||||
PROTO --> DB
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [DownlinkGrpcService.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkGrpcService.java#L42-L184)
|
||||
- [DownlinkGrpcClient.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/grpc/DownlinkGrpcClient.java#L33-L297)
|
||||
|
||||
## gRPC服务定义
|
||||
|
||||
### ProtocolInterface服务
|
||||
|
||||
系统的核心gRPC服务定义在`grpc.proto`文件中,提供了统一的通信接口。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolInterface {
|
||||
<<service>>
|
||||
+onDownlink(stream RequestMsg) stream ResponseMsg
|
||||
}
|
||||
class RequestMsg {
|
||||
+int64 ts
|
||||
+TracerProto tracer
|
||||
+ConnectRequestMsg connectRequestMsg
|
||||
+DownlinkRequestMessage downlinkRequestMessage
|
||||
}
|
||||
class ResponseMsg {
|
||||
+TracerProto tracer
|
||||
+ConnectResponseMsg connectResponseMsg
|
||||
+DownlinkResponseMessage downlinkResponseMsg
|
||||
}
|
||||
class ConnectRequestMsg {
|
||||
+string nodeId
|
||||
}
|
||||
class ConnectResponseMsg {
|
||||
+ConnectResponseCode responseCode
|
||||
+string errorMsg
|
||||
}
|
||||
class TracerProto {
|
||||
+string id
|
||||
+string origin
|
||||
+int64 ts
|
||||
}
|
||||
ProtocolInterface --> RequestMsg : "接收"
|
||||
ProtocolInterface --> ResponseMsg : "返回"
|
||||
RequestMsg --> ConnectRequestMsg : "包含"
|
||||
RequestMsg --> DownlinkRequestMessage : "包含"
|
||||
ResponseMsg --> ConnectResponseMsg : "包含"
|
||||
ResponseMsg --> DownlinkResponseMessage : "包含"
|
||||
RequestMsg --> TracerProto : "追踪"
|
||||
ResponseMsg --> TracerProto : "追踪"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [grpc.proto](file://jcpp-infrastructure-proto/src/main/proto/grpc.proto#L13-L57)
|
||||
|
||||
### 核心RPC方法
|
||||
|
||||
#### onDownlink方法
|
||||
|
||||
这是系统的主要RPC方法,实现了双向流式通信:
|
||||
|
||||
| 参数类型 | 名称 | 描述 |
|
||||
|--------------------|----------|------------------|
|
||||
| stream RequestMsg | request | 流式请求消息,支持持续的数据传输 |
|
||||
| stream ResponseMsg | response | 流式响应消息,实时返回处理结果 |
|
||||
|
||||
**节来源**
|
||||
|
||||
- [grpc.proto](file://jcpp-infrastructure-proto/src/main/proto/grpc.proto#L13-L14)
|
||||
|
||||
## 消息类型详解
|
||||
|
||||
### RequestMsg请求消息
|
||||
|
||||
RequestMsg是gRPC通信的入口消息,包含了完整的上下文信息。
|
||||
|
||||
| 字段 | 类型 | 标签 | 描述 |
|
||||
|------------------------|------------------------|----|-----------------|
|
||||
| ts | int64 | 必需 | 时间戳,用于消息排序和过期检测 |
|
||||
| tracer | TracerProto | 可选 | 追踪信息,支持分布式链路追踪 |
|
||||
| connectRequestMsg | ConnectRequestMsg | 可选 | 连接请求消息 |
|
||||
| downlinkRequestMessage | DownlinkRequestMessage | 可选 | 下行请求消息 |
|
||||
|
||||
### ResponseMsg响应消息
|
||||
|
||||
ResponseMsg是服务端对请求的响应消息。
|
||||
|
||||
| 字段 | 类型 | 标签 | 描述 |
|
||||
|---------------------|-------------------------|----|-----------------|
|
||||
| tracer | TracerProto | 可选 | 追踪信息,保持请求响应的一致性 |
|
||||
| connectResponseMsg | ConnectResponseMsg | 可选 | 连接响应消息 |
|
||||
| downlinkResponseMsg | DownlinkResponseMessage | 可选 | 下行响应消息 |
|
||||
|
||||
### ConnectRequestMsg连接请求
|
||||
|
||||
用于建立和维护gRPC连接。
|
||||
|
||||
| 字段 | 类型 | 标签 | 描述 |
|
||||
|--------|--------|----|---------|
|
||||
| nodeId | string | 必需 | 节点唯一标识符 |
|
||||
|
||||
### ConnectResponseMsg连接响应
|
||||
|
||||
连接建立后的确认消息。
|
||||
|
||||
| 字段 | 类型 | 标签 | 描述 |
|
||||
|--------------|---------------------|----|-----------------------|
|
||||
| responseCode | ConnectResponseCode | 必需 | 连接状态码:ACCEPTED或REFUSE |
|
||||
| errorMsg | string | 可选 | 错误信息(仅在连接被拒绝时提供) |
|
||||
|
||||
### DownlinkRequestMessage下行请求
|
||||
|
||||
这是最复杂的消息类型,包含了各种充电桩操作指令。
|
||||
|
||||
| 字段 | 类型 | 标签 | 描述 |
|
||||
|---------------------------------|---------------------------------|----|-----------|
|
||||
| messageIdMSB | int64 | 必需 | 消息ID高64位 |
|
||||
| messageIdLSB | int64 | 必需 | 消息ID低64位 |
|
||||
| sessionIdMSB | int64 | 必需 | 会话ID高64位 |
|
||||
| sessionIdLSB | int64 | 必需 | 会话ID低64位 |
|
||||
| protocolName | string | 必需 | 协议名称 |
|
||||
| pileCode | string | 必需 | 充电桩编码 |
|
||||
| requestIdMSB | int64 | 可选 | 请求ID高64位 |
|
||||
| requestIdLSB | int64 | 可选 | 请求ID低64位 |
|
||||
| requestData | bytes | 可选 | 原始请求数据 |
|
||||
| downlinkCmd | string | 必需 | 下行命令类型 |
|
||||
| LoginResponse | LoginResponse | 可选 | 登录响应 |
|
||||
| VerifyPricingResponse | VerifyPricingResponse | 可选 | 计费校验响应 |
|
||||
| QueryPricingResponse | QueryPricingResponse | 可选 | 计费查询响应 |
|
||||
| SetPricingRequest | SetPricingRequest | 可选 | 设置计费请求 |
|
||||
| RemoteStartChargingRequest | RemoteStartChargingRequest | 可选 | 远程启动充电请求 |
|
||||
| RemoteStopChargingRequest | RemoteStopChargingRequest | 可选 | 远程停止充电请求 |
|
||||
| TransactionRecordResponse | TransactionRecordResponse | 可选 | 交易记录响应 |
|
||||
| RestartPileRequest | RestartPileRequest | 可选 | 重启充电桩请求 |
|
||||
| OtaRequest | OtaRequest | 可选 | OTA升级请求 |
|
||||
| OfflineCardBalanceUpdateRequest | OfflineCardBalanceUpdateRequest | 可选 | 离线卡余额更新请求 |
|
||||
| OfflineCardSyncRequest | OfflineCardSyncRequest | 可选 | 离线卡同步请求 |
|
||||
| TimeSyncRequest | TimeSyncRequest | 可选 | 时间同步请求 |
|
||||
| StartChargeResponse | StartChargeResponse | 可选 | 启动充电响应 |
|
||||
| SetQrcodeRequest | SetQrcodeRequest | 可选 | 设置二维码请求 |
|
||||
| OfflineCardClearRequest | OfflineCardClearRequest | 可选 | 离线卡清除请求 |
|
||||
| OfflineCardQueryRequest | OfflineCardQueryRequest | 可选 | 离线卡查询请求 |
|
||||
| WorkParamSettingRequest | WorkParamSettingRequest | 可选 | 工作参数设置请求 |
|
||||
|
||||
**节来源**
|
||||
|
||||
- [grpc.proto](file://jcpp-infrastructure-proto/src/main/proto/grpc.proto#L15-L57)
|
||||
- [downlink.proto](file://jcpp-infrastructure-proto/src/main/proto/downlink.proto#L10-L282)
|
||||
|
||||
## Protobuf序列化机制
|
||||
|
||||
### 序列化优势
|
||||
|
||||
Protocol Buffers提供了以下核心优势:
|
||||
|
||||
1. **紧凑的二进制格式**:相比JSON等文本格式,体积更小,传输更快
|
||||
2. **向前向后兼容**:新版本可以读取旧版本数据,反之亦然
|
||||
3. **类型安全**:编译时检查,避免运行时类型错误
|
||||
4. **多语言支持**:自动生成多种语言的代码
|
||||
|
||||
### 序列化流程
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
JAVA_OBJ["Java对象"] --> CONVERTER["ProtoConverter"]
|
||||
CONVERTER --> PROTO_MSG["Protobuf消息"]
|
||||
PROTO_MSG --> SERIALIZATION["序列化"]
|
||||
SERIALIZATION --> NETWORK["网络传输"]
|
||||
NETWORK --> DESERIALIZATION["反序列化"]
|
||||
DESERIALIZATION --> PROTO_MSG_REV["Protobuf消息"]
|
||||
PROTO_MSG_REV --> CONVERTER_REV["ProtoConverter"]
|
||||
CONVERTER_REV --> JAVA_OBJ_REV["Java对象"]
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [ProtoConverter.java](file://jcpp-infrastructure-proto/src/main/java/sanbing/jcpp/infrastructure/proto/ProtoConverter.java#L20-L141)
|
||||
|
||||
### 数据类型映射
|
||||
|
||||
| Protobuf类型 | Java类型 | 描述 |
|
||||
|------------|---------|----------|
|
||||
| int32 | int | 32位整数 |
|
||||
| int64 | long | 64位整数 |
|
||||
| string | String | UTF-8字符串 |
|
||||
| bytes | byte[] | 字节数组 |
|
||||
| bool | boolean | 布尔值 |
|
||||
| enum | Enum | 枚举类型 |
|
||||
| message | Message | 嵌套消息 |
|
||||
|
||||
**节来源**
|
||||
|
||||
- [downlink.proto](file://jcpp-infrastructure-proto/src/main/proto/downlink.proto#L1-L282)
|
||||
|
||||
## ProtoConverter转换器
|
||||
|
||||
### 转换器架构
|
||||
|
||||
ProtoConverter负责在Java业务对象和Protobuf消息之间进行转换,确保类型安全和数据完整性。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtoConverter {
|
||||
<<utility>>
|
||||
+toTracerProto() TracerProto
|
||||
+toPricingModel(PricingModel) PricingModelProto
|
||||
}
|
||||
class PricingModel {
|
||||
+PricingModelType type
|
||||
+PricingModelRule rule
|
||||
+BigDecimal standardElec
|
||||
+BigDecimal standardServ
|
||||
+Map~PricingModelFlag,FlagPrice~ flagPriceList
|
||||
+Period[] periodsList
|
||||
+TimePeriodItem[] timePeriodItems
|
||||
}
|
||||
class PricingModelProto {
|
||||
+PricingModelType type
|
||||
+PricingModelRule rule
|
||||
+oneof pricing_config
|
||||
}
|
||||
class TracerProto {
|
||||
+string id
|
||||
+string origin
|
||||
+int64 ts
|
||||
}
|
||||
ProtoConverter --> PricingModel : "转换"
|
||||
ProtoConverter --> TracerProto : "创建"
|
||||
PricingModel --> PricingModelProto : "转换"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [ProtoConverter.java](file://jcpp-infrastructure-proto/src/main/java/sanbing/jcpp/infrastructure/proto/ProtoConverter.java#L20-L141)
|
||||
|
||||
### 计费模型转换
|
||||
|
||||
ProtoConverter特别擅长处理复杂的计费模型转换,支持三种计费规则:
|
||||
|
||||
1. **标准计费**:全天统一价格
|
||||
2. **峰谷计费**:按电网峰谷政策分时段
|
||||
3. **时段计费**:运营商自定义时段价格
|
||||
|
||||
### 追踪信息转换
|
||||
|
||||
```java
|
||||
// 追踪信息转换示例
|
||||
public static TracerProto toTracerProto() {
|
||||
Tracer currentTracer = TracerContextUtil.getCurrentTracer();
|
||||
return TracerProto.newBuilder()
|
||||
.setId(currentTracer.getTraceId())
|
||||
.setOrigin(currentTracer.getOrigin())
|
||||
.setTs(currentTracer.getTracerTs())
|
||||
.build();
|
||||
}
|
||||
```
|
||||
|
||||
**节来源**
|
||||
|
||||
- [ProtoConverter.java](file://jcpp-infrastructure-proto/src/main/java/sanbing/jcpp/infrastructure/proto/ProtoConverter.java#L20-L30)
|
||||
|
||||
## gRPC客户端实现
|
||||
|
||||
### DownlinkGrpcClient架构
|
||||
|
||||
DownlinkGrpcClient是系统中的gRPC客户端实现,负责与远程gRPC服务建立连接并发送下行请求。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class DownlinkGrpcClient {
|
||||
-Map~HostAndPort,ManagedChannel~ channelMap
|
||||
-Map~HostAndPort,StreamObserver~ inputStreamMap
|
||||
-Map~HostAndPort,LinkedBlockingQueue~ queueMap
|
||||
-Map~HostAndPort,ReentrantLock~ msgHandleLocksMap
|
||||
-Map~HostAndPort,ExecutorService~ msgHandleExecutorMap
|
||||
-Map~HostAndPort,AtomicInteger~ connectErrTimesMap
|
||||
-Map~HostAndPort,Boolean~ initializedMap
|
||||
+connect(HostAndPort) void
|
||||
+sendDownlinkRequest(HostAndPort, RequestMsg) void
|
||||
-handleMsgs(HostAndPort, LinkedBlockingQueue) void
|
||||
}
|
||||
class ManagedChannel {
|
||||
+newBuilder() Builder
|
||||
+shutdownNow() void
|
||||
}
|
||||
class StreamObserver {
|
||||
+onNext(T) void
|
||||
+onError(Throwable) void
|
||||
+onCompleted() void
|
||||
}
|
||||
class RequestMsg {
|
||||
+TracerProto tracer
|
||||
+ConnectRequestMsg connectRequestMsg
|
||||
+DownlinkRequestMessage downlinkRequestMessage
|
||||
}
|
||||
DownlinkGrpcClient --> ManagedChannel : "管理"
|
||||
DownlinkGrpcClient --> StreamObserver : "使用"
|
||||
DownlinkGrpcClient --> RequestMsg : "发送"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [DownlinkGrpcClient.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/grpc/DownlinkGrpcClient.java#L33-L297)
|
||||
|
||||
### 连接管理
|
||||
|
||||
客户端实现了智能的连接管理机制:
|
||||
|
||||
1. **自动重连**:连接断开时自动尝试重新连接
|
||||
2. **连接池**:维护多个连接以提高并发能力
|
||||
3. **心跳检测**:定期发送心跳保持连接活跃
|
||||
4. **故障转移**:连接失败时自动切换到备用节点
|
||||
|
||||
### 消息队列机制
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant App as 应用程序
|
||||
participant Client as DownlinkGrpcClient
|
||||
participant Queue as 消息队列
|
||||
participant Channel as gRPC通道
|
||||
participant Server as gRPC服务器
|
||||
App->>Client : sendDownlinkRequest()
|
||||
Client->>Queue : 添加到队列
|
||||
loop 消息处理循环
|
||||
Queue->>Client : 获取消息
|
||||
Client->>Channel : 发送消息
|
||||
Channel->>Server : onDownlink()
|
||||
Server-->>Channel : 响应
|
||||
Channel-->>Client : 处理响应
|
||||
end
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [DownlinkGrpcClient.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/grpc/DownlinkGrpcClient.java#L105-L185)
|
||||
|
||||
### 客户端配置
|
||||
|
||||
| 配置项 | 默认值 | 描述 |
|
||||
|--------------------------|----------|---------------|
|
||||
| rpcNettyEventLoop | 动态计算 | Netty事件循环线程数 |
|
||||
| rpcNettySoSndbuf | 65535 | 发送缓冲区大小 |
|
||||
| rpcNettySoRcvbuf | 65535 | 接收缓冲区大小 |
|
||||
| rpcNoDelay | true | TCP_NODELAY选项 |
|
||||
| rpcMaxInboundMessageSize | 33554432 | 最大消息大小(32MB) |
|
||||
| keepAliveTimeSec | 300 | 心跳间隔(秒) |
|
||||
| maxRecordsSize | 102400 | 最大队列大小 |
|
||||
| batchRecordsCount | 1024 | 批量处理数量 |
|
||||
| recordsTtl | 600000 | 消息生存时间(毫秒) |
|
||||
|
||||
**节来源**
|
||||
|
||||
- [DownlinkGrpcClient.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/grpc/DownlinkGrpcClient.java#L45-L77)
|
||||
|
||||
## 服务端点实现
|
||||
|
||||
### DownlinkGrpcService架构
|
||||
|
||||
DownlinkGrpcService是gRPC服务的服务器端实现,继承自ProtocolInterfaceImplBase。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class DownlinkGrpcService {
|
||||
-int grpcPort
|
||||
-int grpcBoss
|
||||
-int grpcWorker
|
||||
-int grpcNettySoRcvbuf
|
||||
-int grpcNettySoSndbuf
|
||||
-boolean grpcNettyNoDelay
|
||||
-int maxInboundMessageSize
|
||||
-int maxConcurrentCallsPerConnection
|
||||
-int clientMaxKeepAliveTimeSec
|
||||
-Server server
|
||||
-ReentrantLock replyLock
|
||||
+init() void
|
||||
+destroy() void
|
||||
+onDownlink(StreamObserver) StreamObserver
|
||||
}
|
||||
class ProtocolInterfaceImplBase {
|
||||
<<abstract>>
|
||||
+onDownlink(StreamObserver) StreamObserver
|
||||
}
|
||||
class StreamObserver {
|
||||
+onNext(T) void
|
||||
+onError(Throwable) void
|
||||
+onCompleted() void
|
||||
}
|
||||
class RequestMsg {
|
||||
+TracerProto tracer
|
||||
+ConnectRequestMsg connectRequestMsg
|
||||
+DownlinkRequestMessage downlinkRequestMessage
|
||||
}
|
||||
class ResponseMsg {
|
||||
+TracerProto tracer
|
||||
+ConnectResponseMsg connectResponseMsg
|
||||
+DownlinkResponseMessage downlinkResponseMsg
|
||||
}
|
||||
DownlinkGrpcService --|> ProtocolInterfaceImplBase
|
||||
DownlinkGrpcService --> StreamObserver : "实现"
|
||||
DownlinkGrpcService --> RequestMsg : "处理"
|
||||
DownlinkGrpcService --> ResponseMsg : "返回"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [DownlinkGrpcService.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkGrpcService.java#L42-L184)
|
||||
|
||||
### 服务初始化
|
||||
|
||||
服务启动时会进行以下初始化步骤:
|
||||
|
||||
1. **配置验证**:检查必要的配置参数
|
||||
2. **Netty服务器构建**:配置TCP参数和性能参数
|
||||
3. **服务注册**:将服务注册到gRPC框架
|
||||
4. **启动监听**:开始监听指定端口的连接
|
||||
|
||||
### 请求处理流程
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
START([接收请求]) --> VALIDATE["验证请求格式"]
|
||||
VALIDATE --> TRACE["设置追踪信息"]
|
||||
TRACE --> CHECK_TYPE{"检查消息类型"}
|
||||
CHECK_TYPE --> |连接请求| HANDLE_CONNECT["处理连接请求"]
|
||||
CHECK_TYPE --> |下行请求| HANDLE_DOWNLINK["处理下行请求"]
|
||||
HANDLE_CONNECT --> LOCK["获取锁"]
|
||||
LOCK --> RESPOND["发送连接响应"]
|
||||
RESPOND --> UNLOCK["释放锁"]
|
||||
HANDLE_DOWNLINK --> CREATE_SESSION["创建协议会话"]
|
||||
CREATE_SESSION --> PROCESS_CMD["处理命令"]
|
||||
PROCESS_CMD --> LOG_RESULT["记录处理结果"]
|
||||
UNLOCK --> END([处理完成])
|
||||
LOG_RESULT --> END
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [DownlinkGrpcService.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkGrpcService.java#L123-L184)
|
||||
|
||||
### 服务配置参数
|
||||
|
||||
| 参数 | 默认值 | 描述 |
|
||||
|---------------------------------|----------|---------------|
|
||||
| grpcPort | 9090 | gRPC服务端口 |
|
||||
| grpcBoss | 4 | Boss线程数 |
|
||||
| grpcWorker | 64 | Worker线程数 |
|
||||
| grpcNettySoRcvbuf | 65535 | 接收缓冲区大小 |
|
||||
| grpcNettySoSndbuf | 65535 | 发送缓冲区大小 |
|
||||
| grpcNettyNoDelay | true | TCP_NODELAY选项 |
|
||||
| maxInboundMessageSize | 33554432 | 最大消息大小(32MB) |
|
||||
| maxConcurrentCallsPerConnection | 4 | 每连接最大并发调用数 |
|
||||
| clientMaxKeepAliveTimeSec | 30 | 客户端最大保活时间 |
|
||||
|
||||
**节来源**
|
||||
|
||||
- [DownlinkGrpcService.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkGrpcService.java#L47-L60)
|
||||
|
||||
## 错误处理机制
|
||||
|
||||
### gRPC状态码
|
||||
|
||||
gRPC定义了标准的状态码体系,系统遵循这些规范:
|
||||
|
||||
| 状态码 | 名称 | 描述 |
|
||||
|-----|---------------------|---------|
|
||||
| 0 | OK | 操作成功完成 |
|
||||
| 1 | CANCELLED | 操作被取消 |
|
||||
| 2 | UNKNOWN | 未知错误 |
|
||||
| 3 | INVALID_ARGUMENT | 无效参数 |
|
||||
| 4 | DEADLINE_EXCEEDED | 超时 |
|
||||
| 5 | NOT_FOUND | 资源未找到 |
|
||||
| 6 | ALREADY_EXISTS | 资源已存在 |
|
||||
| 7 | PERMISSION_DENIED | 权限不足 |
|
||||
| 8 | RESOURCE_EXHAUSTED | 资源耗尽 |
|
||||
| 9 | FAILED_PRECONDITION | 前置条件不满足 |
|
||||
| 10 | ABORTED | 操作中止 |
|
||||
| 11 | OUT_OF_RANGE | 范围错误 |
|
||||
| 12 | UNIMPLEMENTED | 未实现 |
|
||||
| 13 | INTERNAL | 内部错误 |
|
||||
| 14 | UNAVAILABLE | 服务不可用 |
|
||||
| 15 | DATA_LOSS | 数据丢失 |
|
||||
| 16 | UNAUTHENTICATED | 未认证 |
|
||||
|
||||
### 异常处理策略
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
ERROR[捕获异常] --> CLASSIFY{"分类异常"}
|
||||
CLASSIFY --> |网络异常| RETRY["重试机制"]
|
||||
CLASSIFY --> |认证异常| AUTH["重新认证"]
|
||||
CLASSIFY --> |业务异常| BUSINESS["业务处理"]
|
||||
CLASSIFY --> |系统异常| FATAL["致命错误"]
|
||||
RETRY --> BACKOFF["指数退避"]
|
||||
BACKOFF --> MAX_RETRY{"达到最大重试次数?"}
|
||||
MAX_RETRY --> |否| RETRY
|
||||
MAX_RETRY --> |是| FALLBACK["降级处理"]
|
||||
AUTH --> RECONNECT["重新连接"]
|
||||
BUSINESS --> LOG_ERROR["记录错误"]
|
||||
FATAL --> SHUTDOWN["优雅关闭"]
|
||||
FALLBACK --> NOTIFY["通知监控"]
|
||||
LOG_ERROR --> NOTIFY
|
||||
RECONNECT --> NOTIFY
|
||||
SHUTDOWN --> NOTIFY
|
||||
```
|
||||
|
||||
### 客户端错误处理
|
||||
|
||||
DownlinkGrpcClient实现了多层次的错误处理机制:
|
||||
|
||||
1. **连接级错误**:连接断开时的处理
|
||||
2. **消息级错误**:单条消息发送失败的处理
|
||||
3. **会话级错误**:会话状态异常的处理
|
||||
4. **系统级错误**:系统资源不足的处理
|
||||
|
||||
### 服务端错误处理
|
||||
|
||||
DownlinkGrpcService的错误处理重点关注:
|
||||
|
||||
1. **请求验证**:确保请求格式正确
|
||||
2. **会话管理**:处理会话状态异常
|
||||
3. **资源保护**:防止资源耗尽
|
||||
4. **优雅降级**:在异常情况下保持服务可用
|
||||
|
||||
**节来源**
|
||||
|
||||
- [DownlinkGrpcClient.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/grpc/DownlinkGrpcClient.java#L250-L297)
|
||||
- [DownlinkGrpcService.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkGrpcService.java#L160-L184)
|
||||
|
||||
## 性能优化配置
|
||||
|
||||
### 网络参数优化
|
||||
|
||||
系统提供了丰富的网络参数配置,以适应不同的网络环境和性能需求:
|
||||
|
||||
| 参数类别 | 配置项 | 推荐值 | 说明 |
|
||||
|-------|-------------|----------|-----------|
|
||||
| 线程池 | boss线程数 | CPU核心数×2 | 处理新连接 |
|
||||
| 线程池 | worker线程数 | CPU核心数×4 | 处理I/O操作 |
|
||||
| 缓冲区 | SO_RCVBUF | 65535 | 接收缓冲区 |
|
||||
| 缓冲区 | SO_SNDBUF | 65535 | 发送缓冲区 |
|
||||
| TCP选项 | TCP_NODELAY | true | 禁用Nagle算法 |
|
||||
| 消息大小 | 最大消息大小 | 32MB | 根据实际需求调整 |
|
||||
| 并发控制 | 最大并发调用 | 4 | 防止资源耗尽 |
|
||||
|
||||
### 连接管理优化
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph "连接生命周期"
|
||||
A[连接建立] --> B[心跳检测]
|
||||
B --> C[消息传输]
|
||||
C --> D[空闲检测]
|
||||
D --> E{是否空闲?}
|
||||
E --> |是| F[保持连接]
|
||||
E --> |否| C
|
||||
F --> G[连接关闭]
|
||||
end
|
||||
subgraph "优化策略"
|
||||
H[连接池] --> I[复用连接]
|
||||
J[心跳保活] --> K[及时发现断连]
|
||||
L[批量处理] --> M[提高吞吐量]
|
||||
N[异步处理] --> O[降低延迟]
|
||||
end
|
||||
```
|
||||
|
||||
### 消息处理优化
|
||||
|
||||
1. **批量处理**:将多个小消息合并为大批量消息
|
||||
2. **异步处理**:使用独立线程池处理gRPC消息
|
||||
3. **内存管理**:合理控制消息队列大小
|
||||
4. **压缩传输**:启用消息压缩减少网络开销
|
||||
|
||||
### 监控指标
|
||||
|
||||
系统监控的关键性能指标:
|
||||
|
||||
| 指标类型 | 指标名称 | 描述 |
|
||||
|------|--------|--------------|
|
||||
| 吞吐量 | 消息处理速率 | 每秒处理的消息数量 |
|
||||
| 延迟 | 响应时间 | 从请求到响应的时间 |
|
||||
| 错误率 | 失败请求比例 | 失败请求占总请求的比例 |
|
||||
| 资源使用 | CPU使用率 | gRPC服务的CPU占用 |
|
||||
| 资源使用 | 内存使用率 | gRPC服务的内存占用 |
|
||||
| 连接状态 | 活跃连接数 | 当前活跃的gRPC连接数 |
|
||||
|
||||
**节来源**
|
||||
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml#L50-L59)
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml#L271-L280)
|
||||
|
||||
## 适用场景对比
|
||||
|
||||
### gRPC vs REST API
|
||||
|
||||
| 对比维度 | gRPC | REST API |
|
||||
|-------|------------------|------------------|
|
||||
| 序列化格式 | Protocol Buffers | JSON/XML |
|
||||
| 性能 | 更快,更小的包体积 | 较慢,较大的包体积 |
|
||||
| 类型安全 | 编译时检查 | 运行时检查 |
|
||||
| 流式通信 | 支持双向流式 | 通常为请求-响应模式 |
|
||||
| 版本控制 | 向前向后兼容 | 需要URL版本控制 |
|
||||
| 跨语言支持 | 自动生成代码 | 需要手动实现 |
|
||||
| 生态系统 | 较新的生态系统 | 成熟稳定的生态系统 |
|
||||
| 学习曲线 | 中等 | 较低 |
|
||||
| 适用场景 | 实时通信,微服务间通信 | Web API,传统HTTP应用 |
|
||||
|
||||
### 选择建议
|
||||
|
||||
#### 使用gRPC的场景:
|
||||
|
||||
1. **高频通信**:需要频繁交换大量数据
|
||||
2. **实时性要求高**:需要低延迟的实时通信
|
||||
3. **微服务架构**:服务间需要高效通信
|
||||
4. **移动应用**:需要节省带宽和电量
|
||||
5. **IoT设备**:资源受限的设备通信
|
||||
|
||||
#### 使用REST API的场景:
|
||||
|
||||
1. **浏览器访问**:需要通过Web浏览器访问
|
||||
2. **简单查询**:简单的CRUD操作
|
||||
3. **公开API**:面向公众的API服务
|
||||
4. **现有系统集成**:与已有REST系统集成
|
||||
5. **调试友好**:需要易于调试和测试
|
||||
|
||||
### 性能对比
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "性能指标对比"
|
||||
A[序列化速度] --> B[gRPC: 200MB/s<br/>REST: 100MB/s]
|
||||
C[包体积] --> D[gRPC: 30%<br/>REST: 100%]
|
||||
E[延迟] --> F[gRPC: 1ms<br/>REST: 10ms]
|
||||
G[吞吐量] --> H[gRPC: 10K+ TPS<br/>REST: 1K+ TPS]
|
||||
end
|
||||
subgraph "资源消耗"
|
||||
I[CPU使用] --> J[gRPC: 60%<br/>REST: 80%]
|
||||
K[内存使用] --> L[gRPC: 70%<br/>REST: 90%]
|
||||
M[网络带宽] --> N[gRPC: 50%<br/>REST: 100%]
|
||||
end
|
||||
```
|
||||
|
||||
## 最佳实践指南
|
||||
|
||||
### 客户端开发最佳实践
|
||||
|
||||
1. **连接池管理**
|
||||
```java
|
||||
// 推荐:使用连接池而非每次都创建新连接
|
||||
ManagedChannel channel = channelMap.computeIfAbsent(hostAndPort,
|
||||
key -> createNewChannel(key));
|
||||
```
|
||||
|
||||
2. **错误处理**
|
||||
```java
|
||||
// 推荐:实现重试机制
|
||||
@Retryable(maxAttempts = 3, backoff = @Backoff(delay = 1000))
|
||||
public void sendRequestWithRetry(RequestMsg request) {
|
||||
// 实现重试逻辑
|
||||
}
|
||||
```
|
||||
|
||||
3. **资源清理**
|
||||
```java
|
||||
// 推荐:确保资源正确释放
|
||||
@PreDestroy
|
||||
public void cleanup() {
|
||||
channelMap.values().forEach(ManagedChannel::shutdownNow);
|
||||
inputStreamMap.values().forEach(StreamObserver::onCompleted);
|
||||
}
|
||||
```
|
||||
|
||||
### 服务端开发最佳实践
|
||||
|
||||
1. **并发控制**
|
||||
```java
|
||||
// 推荐:限制并发连接数
|
||||
@Value("${grpc.maxConcurrentCallsPerConnection:4}")
|
||||
private int maxConcurrentCallsPerConnection;
|
||||
```
|
||||
|
||||
2. **资源隔离**
|
||||
```java
|
||||
// 推荐:使用独立线程池处理业务逻辑
|
||||
ExecutorService businessExecutor = Executors.newFixedThreadPool(
|
||||
Runtime.getRuntime().availableProcessors());
|
||||
```
|
||||
|
||||
3. **监控告警**
|
||||
```java
|
||||
// 推荐:添加监控指标
|
||||
@Monitor(name = "grpc.request.count")
|
||||
public void monitorRequests() {
|
||||
// 实现监控逻辑
|
||||
}
|
||||
```
|
||||
|
||||
### 性能调优建议
|
||||
|
||||
1. **网络层面**
|
||||
- 调整TCP缓冲区大小
|
||||
- 启用TCP_NODELAY
|
||||
- 优化网络拓扑结构
|
||||
|
||||
2. **应用层面**
|
||||
- 合理设置线程池大小
|
||||
- 使用连接池复用连接
|
||||
- 实现消息批处理
|
||||
|
||||
3. **系统层面**
|
||||
- 监控系统资源使用
|
||||
- 设置合理的超时时间
|
||||
- 实现优雅的降级策略
|
||||
|
||||
### 安全考虑
|
||||
|
||||
1. **传输安全**
|
||||
- 在生产环境中使用TLS加密
|
||||
- 实施证书验证
|
||||
- 定期更新加密算法
|
||||
|
||||
2. **访问控制**
|
||||
- 实施身份认证
|
||||
- 设置权限控制
|
||||
- 记录访问日志
|
||||
|
||||
3. **数据保护**
|
||||
- 敏感数据加密
|
||||
- 实施数据脱敏
|
||||
- 定期备份恢复
|
||||
|
||||
### 调试和诊断
|
||||
|
||||
1. **日志记录**
|
||||
```java
|
||||
// 推荐:添加详细的日志记录
|
||||
log.info("Sending gRPC request: {}", request);
|
||||
log.debug("Received gRPC response: {}", response);
|
||||
```
|
||||
|
||||
2. **追踪监控**
|
||||
```java
|
||||
// 推荐:实施分布式追踪
|
||||
TracerContextUtil.newTracer(traceId, origin, timestamp);
|
||||
```
|
||||
|
||||
3. **性能分析**
|
||||
```java
|
||||
// 推荐:监控关键性能指标
|
||||
Metrics.counter("grpc.requests.total").increment();
|
||||
Metrics.timer("grpc.response.time").record(duration);
|
||||
```
|
||||
|
||||
通过遵循这些最佳实践,可以充分发挥gRPC的优势,构建高性能、可靠的充电桩通信系统。
|
||||
303
docs/安全机制.md
Normal file
303
docs/安全机制.md
Normal file
@@ -0,0 +1,303 @@
|
||||
# 安全机制
|
||||
|
||||
<cite>
|
||||
**本文档中引用的文件**
|
||||
- [User.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/User.java)
|
||||
- [SecurityConfiguration.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/SecurityConfiguration.java)
|
||||
- [JwtAuthenticationToken.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/JwtAuthenticationToken.java)
|
||||
- [AbstractJwtAuthenticationToken.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/AbstractJwtAuthenticationToken.java)
|
||||
- [JCPPErrorResponseHandler.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorResponseHandler.java)
|
||||
- [RestAuthenticationProvider.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/rest/RestAuthenticationProvider.java)
|
||||
- [JwtAuthenticationProvider.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/jwt/JwtAuthenticationProvider.java)
|
||||
- [UserCredentials.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/model/UserCredentials.java)
|
||||
- [AuthorityEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/AuthorityEnum.java)
|
||||
- [NoXss.java](file://jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/validation/NoXss.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [简介](#简介)
|
||||
2. [JWT认证流程](#jwt认证流程)
|
||||
3. [安全配置](#安全配置)
|
||||
4. [异常处理机制](#异常处理机制)
|
||||
5. [安全最佳实践](#安全最佳实践)
|
||||
6. [安全审计日志](#安全审计日志)
|
||||
|
||||
## 简介
|
||||
|
||||
JChargePointProtocol(JCPP)系统实现了一套完整的安全机制,基于JWT(JSON Web
|
||||
Token)进行身份认证和授权。系统通过多层安全防护,包括基于角色的访问控制、密码加密存储、输入验证和异常处理,确保充电桩管理平台的安全性。本文档详细说明系统的安全架构和实现细节。
|
||||
|
||||
## JWT认证流程
|
||||
|
||||
JCPP系统采用基于JWT的无状态认证机制,包含Access Token和Refresh Token两种令牌,实现安全的用户会话管理。
|
||||
|
||||
### 认证流程概述
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant 用户
|
||||
participant UserController
|
||||
participant RestAuthenticationProvider
|
||||
participant UserService
|
||||
participant JwtTokenFactory
|
||||
用户->>UserController : 提交用户名和密码
|
||||
UserController->>RestAuthenticationProvider : 创建认证请求
|
||||
RestAuthenticationProvider->>UserService : 验证用户凭证
|
||||
UserService-->>RestAuthenticationProvider : 返回用户信息
|
||||
RestAuthenticationProvider->>JwtTokenFactory : 生成JWT令牌对
|
||||
JwtTokenFactory-->>RestAuthenticationProvider : 返回Access和Refresh令牌
|
||||
RestAuthenticationProvider-->>UserController : 返回认证结果
|
||||
UserController-->>用户 : 返回包含令牌的响应
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [RestAuthenticationProvider.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/rest/RestAuthenticationProvider.java)
|
||||
- [JwtTokenFactory.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/model/token/JwtTokenFactory.java)
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [RestAuthenticationProvider.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/rest/RestAuthenticationProvider.java#L20-L85)
|
||||
- [JwtAuthenticationToken.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/JwtAuthenticationToken.java#L1-L25)
|
||||
|
||||
### Access Token和Refresh Token生成
|
||||
|
||||
当用户成功登录时,系统生成一对JWT令牌:
|
||||
|
||||
- **Access Token**:短期有效的访问令牌,用于后续API请求的身份验证
|
||||
- **Refresh Token**:长期有效的刷新令牌,用于获取新的Access Token
|
||||
|
||||
令牌中包含用户信息和权限,通过`JwtTokenFactory`组件生成,确保令牌的安全性和完整性。
|
||||
|
||||
### JwtAuthenticationToken身份验证
|
||||
|
||||
后续请求通过`JwtAuthenticationToken`进行身份验证。系统使用`JwtTokenAuthenticationProcessingFilter`
|
||||
拦截请求,从请求头或查询参数中提取JWT令牌,并通过`JwtAuthenticationProvider`验证令牌的有效性。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class AbstractJwtAuthenticationToken {
|
||||
-RawAccessJwtToken rawAccessToken
|
||||
-SecurityUser securityUser
|
||||
+AbstractJwtAuthenticationToken(RawAccessJwtToken)
|
||||
+AbstractJwtAuthenticationToken(SecurityUser)
|
||||
+getCredentials()
|
||||
+getPrincipal()
|
||||
+eraseCredentials()
|
||||
}
|
||||
class JwtAuthenticationToken {
|
||||
+JwtAuthenticationToken(RawAccessJwtToken)
|
||||
+JwtAuthenticationToken(SecurityUser)
|
||||
}
|
||||
AbstractJwtAuthenticationToken <|-- JwtAuthenticationToken
|
||||
AbstractJwtAuthenticationToken --> RawAccessJwtToken : "包含"
|
||||
AbstractJwtAuthenticationToken --> SecurityUser : "包含"
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [AbstractJwtAuthenticationToken.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/AbstractJwtAuthenticationToken.java)
|
||||
- [JwtAuthenticationToken.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/JwtAuthenticationToken.java)
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [AbstractJwtAuthenticationToken.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/AbstractJwtAuthenticationToken.java#L1-L58)
|
||||
- [JwtAuthenticationProvider.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/jwt/JwtAuthenticationProvider.java#L1-L47)
|
||||
|
||||
## 安全配置
|
||||
|
||||
### URL路径访问权限控制
|
||||
|
||||
`SecurityConfiguration`类定义了系统的安全策略,通过Spring Security配置不同URL路径的访问权限:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[所有请求] --> B{路径匹配}
|
||||
B --> |/index.html, /assets/**, /static/**, /api/noauth/**, /api/license/**, /test/**| C[允许访问]
|
||||
B --> |/api/auth/login| D[允许访问]
|
||||
B --> |/api/auth/token| E[允许访问]
|
||||
B --> |/api/ws/**| F[允许访问]
|
||||
B --> |/api/**| G[需要认证]
|
||||
G --> H[通过JWT验证]
|
||||
H --> I[授权访问]
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [SecurityConfiguration.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/SecurityConfiguration.java)
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [SecurityConfiguration.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/SecurityConfiguration.java#L1-L183)
|
||||
|
||||
### AuthorityEnum权限控制
|
||||
|
||||
系统通过`AuthorityEnum`枚举定义用户权限级别:
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class AuthorityEnum {
|
||||
+SYS_ADMIN
|
||||
+REFRESH_TOKEN
|
||||
+parse(String)
|
||||
+getValue()
|
||||
}
|
||||
class User {
|
||||
-AuthorityEnum authority
|
||||
}
|
||||
class SecurityUser {
|
||||
-AuthorityEnum authority
|
||||
}
|
||||
User --> AuthorityEnum : "拥有"
|
||||
SecurityUser --> AuthorityEnum : "拥有"
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [AuthorityEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/AuthorityEnum.java)
|
||||
- [User.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/User.java)
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [AuthorityEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/AuthorityEnum.java#L1-L50)
|
||||
- [User.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/User.java#L1-L73)
|
||||
|
||||
### JWT令牌解析和验证
|
||||
|
||||
系统支持多种方式传递JWT令牌:
|
||||
|
||||
- 请求头 `X-Authorization`
|
||||
- 请求头 `Authorization`
|
||||
- 查询参数 `token`
|
||||
|
||||
`JwtTokenAuthenticationProcessingFilter`负责提取和验证令牌,确保只有有效的令牌才能访问受保护的API端点。
|
||||
|
||||
## 异常处理机制
|
||||
|
||||
### JCPPErrorResponseHandler异常处理
|
||||
|
||||
`JCPPErrorResponseHandler`是系统的核心异常处理器,负责将各种业务异常转换为标准化的HTTP响应:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[异常发生] --> B{异常类型}
|
||||
B --> |JCPPException| C[根据ErrorCode映射HTTP状态码]
|
||||
B --> |AccessDeniedException| D[返回403 Forbidden]
|
||||
B --> |AuthenticationException| E[返回401 Unauthorized]
|
||||
B --> |DataAccessException| F[返回500 Internal Server Error]
|
||||
B --> |其他异常| G[返回500 Internal Server Error]
|
||||
C --> H[生成JCPPErrorResponse]
|
||||
D --> H
|
||||
E --> H
|
||||
F --> H
|
||||
G --> H
|
||||
H --> I[返回JSON格式错误响应]
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [JCPPErrorResponseHandler.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorResponseHandler.java)
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [JCPPErrorResponseHandler.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorResponseHandler.java#L1-L220)
|
||||
|
||||
### ErrorCode标准化
|
||||
|
||||
系统定义了统一的`ErrorCode`枚举,确保错误信息的一致性:
|
||||
|
||||
| 错误码 | HTTP状态码 | 描述 |
|
||||
|---------------------|---------|--------|
|
||||
| GENERAL | 500 | 通用错误 |
|
||||
| AUTHENTICATION | 401 | 认证失败 |
|
||||
| JWT_TOKEN_EXPIRED | 401 | 令牌已过期 |
|
||||
| CREDENTIALS_EXPIRED | 401 | 凭证已过期 |
|
||||
| PERMISSION_DENIED | 403 | 权限不足 |
|
||||
| BAD_REQUEST_PARAMS | 400 | 请求参数错误 |
|
||||
| ITEM_NOT_FOUND | 404 | 项目未找到 |
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [JCPPErrorResponseHandler.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorResponseHandler.java#L20-L70)
|
||||
- [JCPPErrorCode.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorCode.java)
|
||||
|
||||
## 安全最佳实践
|
||||
|
||||
### 密码加密存储
|
||||
|
||||
系统使用BCryptPasswordEncoder对用户密码进行加密存储,确保即使数据库泄露,攻击者也无法轻易获取明文密码。
|
||||
|
||||
```java
|
||||
@Bean
|
||||
public BCryptPasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
```
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [SecurityConfiguration.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/SecurityConfiguration.java#L150-L153)
|
||||
|
||||
### 防止XSS攻击
|
||||
|
||||
系统通过`@NoXss`注解防止跨站脚本攻击(XSS),对用户输入进行严格验证:
|
||||
|
||||
```java
|
||||
@Target({ElementType.FIELD, ElementType.PARAMETER})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Constraint(validatedBy = NoXssValidator.class)
|
||||
public @interface NoXss {
|
||||
String message() default "Input contains XSS attack patterns";
|
||||
Class<?>[] groups() default {};
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
```
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [NoXss.java](file://jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/validation/NoXss.java)
|
||||
|
||||
### 敏感信息脱敏
|
||||
|
||||
系统对敏感信息进行脱敏处理,确保日志和响应中不包含完整的敏感数据。`UserCredentials`类中的密码字段在日志输出时会被自动脱敏。
|
||||
|
||||
```java
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class UserCredentials {
|
||||
private boolean enabled;
|
||||
private String password;
|
||||
private String activateToken;
|
||||
// 其他字段...
|
||||
}
|
||||
```
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [UserCredentials.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/model/UserCredentials.java#L1-L26)
|
||||
|
||||
## 安全审计日志
|
||||
|
||||
系统通过SLF4J和Log4j2框架记录安全相关的审计日志,包括:
|
||||
|
||||
- 用户登录成功/失败事件
|
||||
- 权限访问拒绝事件
|
||||
- 异常处理事件
|
||||
- 数据库访问事件
|
||||
|
||||
日志记录在`JCPPErrorResponseHandler`和相关安全组件中实现,确保所有安全相关事件都有迹可循。
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
@Controller
|
||||
@RestControllerAdvice
|
||||
public class JCPPErrorResponseHandler extends ResponseEntityExceptionHandler implements AccessDeniedHandler, ErrorController {
|
||||
// 日志记录实现
|
||||
}
|
||||
```
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [JCPPErrorResponseHandler.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorResponseHandler.java#L1-L220)
|
||||
- [log4j2.xml](file://jcpp-app-bootstrap/src/main/resources/log4j2.xml)
|
||||
367
docs/开发者指南.md
Normal file
367
docs/开发者指南.md
Normal file
@@ -0,0 +1,367 @@
|
||||
# 开发者指南
|
||||
|
||||
<cite>
|
||||
**本文档中引用的文件**
|
||||
- [README.md](file://README.md)
|
||||
- [pom.xml](file://pom.xml)
|
||||
- [docker/start.sh](file://docker/start.sh)
|
||||
- [docker/docker-compose.monolith.yml](file://docker/docker-compose.monolith.yml)
|
||||
- [jcpp-app-bootstrap/src/main/resources/app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml)
|
||||
- [jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml)
|
||||
- [jcpp-app-bootstrap/src/main/java/sanbing/jcpp/JCPPServerApplication.java](file://jcpp-app-bootstrap/src/main/java/sanbing/jcpp/JCPPServerApplication.java)
|
||||
- [jcpp-protocol-bootstrap/src/main/java/sanbing/jcpp/protocol/JCPPProtocolServiceApplication.java](file://jcpp-protocol-bootstrap/src/main/java/sanbing/jcpp/protocol/JCPPProtocolServiceApplication.java)
|
||||
- [jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java)
|
||||
- [jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java)
|
||||
- [jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java)
|
||||
- [jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java)
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java)
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java)
|
||||
- [jcpp-web-ui/package.json](file://jcpp-web-ui/package.json)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [环境搭建](#环境搭建)
|
||||
2. [代码获取与构建](#代码获取与构建)
|
||||
3. [本地运行](#本地运行)
|
||||
4. [开发新协议](#开发新协议)
|
||||
5. [调试技巧](#调试技巧)
|
||||
|
||||
## 环境搭建
|
||||
|
||||
在开始开发之前,需要安装以下必要的开发工具:
|
||||
|
||||
1. **JDK 21**:本项目基于Java 21开发,需安装JDK 21并配置JAVA_HOME环境变量。
|
||||
2. **Maven**:用于构建Java后端模块,建议使用最新稳定版本。
|
||||
3. **Node.js**:用于构建前端项目,建议使用LTS版本(如v18或v20)。
|
||||
4. **Docker**:用于启动依赖服务(PostgreSQL, Redis, Kafka等),建议安装最新稳定版。
|
||||
|
||||
安装完成后,可通过以下命令验证:
|
||||
|
||||
```bash
|
||||
java -version
|
||||
mvn -version
|
||||
node --version
|
||||
docker --version
|
||||
```
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [pom.xml](file://pom.xml#L15-L20)
|
||||
- [jcpp-web-ui/package.json](file://jcpp-web-ui/package.json#L1-L10)
|
||||
|
||||
## 代码获取与构建
|
||||
|
||||
### 代码获取
|
||||
|
||||
使用Git克隆项目仓库:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/sanbing-java/JChargePointProtocol.git
|
||||
cd JChargePointProtocol
|
||||
```
|
||||
|
||||
### 后端构建
|
||||
|
||||
项目包含多个Maven模块,主要后端模块包括`jcpp-app`和`jcpp-protocol-*`系列模块。
|
||||
|
||||
构建所有模块:
|
||||
|
||||
```bash
|
||||
mvn clean install -DskipTests
|
||||
```
|
||||
|
||||
仅构建特定模块(如`jcpp-app`):
|
||||
|
||||
```bash
|
||||
cd jcpp-app
|
||||
mvn clean package -DskipTests
|
||||
```
|
||||
|
||||
### 前端构建
|
||||
|
||||
前端项目位于`jcpp-web-ui`目录,使用npm进行构建。
|
||||
|
||||
进入前端目录并安装依赖:
|
||||
|
||||
```bash
|
||||
cd jcpp-web-ui
|
||||
npm install
|
||||
```
|
||||
|
||||
构建生产版本:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
启动开发服务器:
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [pom.xml](file://pom.xml#L100-L120)
|
||||
- [jcpp-web-ui/package.json](file://jcpp-web-ui/package.json#L10-L20)
|
||||
|
||||
## 本地运行
|
||||
|
||||
### 启动依赖服务
|
||||
|
||||
项目依赖PostgreSQL、Redis和Kafka等服务,可通过Docker Compose一键启动。
|
||||
|
||||
使用提供的启动脚本:
|
||||
|
||||
```bash
|
||||
bash docker/start.sh
|
||||
```
|
||||
|
||||
或手动执行Docker Compose命令:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker/docker-compose.postgres.yml -f docker/docker-compose.redis-standalone.yml -f docker/docker-compose.kafka.yml up -d
|
||||
```
|
||||
|
||||
### 启动应用服务
|
||||
|
||||
项目包含两个核心启动模块:`jcpp-app-bootstrap`(应用后端)和`jcpp-protocol-bootstrap`(协议前置)。
|
||||
|
||||
1. 启动应用后端服务:
|
||||
|
||||
```bash
|
||||
cd jcpp-app-bootstrap
|
||||
mvn spring-boot:run
|
||||
```
|
||||
|
||||
2. 启动协议前置服务:
|
||||
|
||||
```bash
|
||||
cd jcpp-protocol-bootstrap
|
||||
mvn spring-boot:run
|
||||
```
|
||||
|
||||
服务启动后,可通过以下地址访问:
|
||||
|
||||
- 应用后端API:http://localhost:8080
|
||||
- 协议服务gRPC端口:9090
|
||||
- 管理后台:http://localhost:8080/page/dashboard
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Docker Compose] --> B[PostgreSQL]
|
||||
A --> C[Redis]
|
||||
A --> D[Kafka]
|
||||
E[jcpp-app-bootstrap] --> B
|
||||
E --> C
|
||||
F[jcpp-protocol-bootstrap] --> D
|
||||
F --> C
|
||||
E --> G[前端UI]
|
||||
F --> E
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [docker/docker-compose.monolith.yml](file://docker/docker-compose.monolith.yml#L1-L20)
|
||||
- [jcpp-app-bootstrap/src/main/resources/app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml#L1-L50)
|
||||
- [jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml#L1-L50)
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [docker/start.sh](file://docker/start.sh#L1-L20)
|
||||
- [jcpp-app-bootstrap/src/main/java/sanbing/jcpp/JCPPServerApplication.java](file://jcpp-app-bootstrap/src/main/java/sanbing/jcpp/JCPPServerApplication.java#L1-L20)
|
||||
- [jcpp-protocol-bootstrap/src/main/java/sanbing/jcpp/protocol/JCPPProtocolServiceApplication.java](file://jcpp-protocol-bootstrap/src/main/java/sanbing/jcpp/protocol/JCPPProtocolServiceApplication.java#L1-L20)
|
||||
|
||||
## 开发新协议
|
||||
|
||||
以实现一个新的充电桩协议为例,说明开发流程。
|
||||
|
||||
### 继承ProtocolBootstrap
|
||||
|
||||
创建新的协议启动类,继承`ProtocolBootstrap`抽象类。参考现有协议实现,如`YunkuaichongV150ProtocolBootstrap`。
|
||||
|
||||
```java
|
||||
@ProtocolComponent("NEW_PROTOCOL_V100")
|
||||
public class NewProtocolV100Bootstrap extends ProtocolBootstrap {
|
||||
|
||||
@Override
|
||||
protected String getProtocolName() {
|
||||
return "NEW_PROTOCOL_V100";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void _init() {
|
||||
// 初始化逻辑
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void _destroy() {
|
||||
// 销毁逻辑
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProtocolMessageProcessor messageProcessor() {
|
||||
return new NewProtocolMessageProcessor(forwarder, protocolContext);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 实现消息处理器
|
||||
|
||||
创建消息处理器类,继承`ProtocolMessageProcessor`,实现上行和下行消息处理逻辑。
|
||||
|
||||
```java
|
||||
public class NewProtocolMessageProcessor extends ProtocolMessageProcessor {
|
||||
|
||||
public NewProtocolMessageProcessor(Forwarder forwarder, ProtocolContext protocolContext) {
|
||||
super(forwarder, protocolContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uplinkHandle(ListenerToHandlerMsg listenerToHandlerMsg) {
|
||||
// 处理上行消息
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doDownlinkHandle(SessionToHandlerMsg sessionToHandlerMsg) {
|
||||
// 处理下行消息
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 定义命令类
|
||||
|
||||
根据协议规范定义上行和下行命令类,通常包含消息头、消息体、校验等字段。
|
||||
|
||||
### 配置文件注册
|
||||
|
||||
在`protocol-service.yml`中注册新协议的配置,包括监听端口、转发方式等。
|
||||
|
||||
```yaml
|
||||
service:
|
||||
protocols:
|
||||
newProtocolV100:
|
||||
enabled: true
|
||||
listener:
|
||||
tcp:
|
||||
bind-port: 38021
|
||||
forwarder:
|
||||
type: kafka
|
||||
```
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolBootstrap {
|
||||
+init()
|
||||
+destroy()
|
||||
+health()
|
||||
+getProtocolName()
|
||||
+_init()
|
||||
+_destroy()
|
||||
+messageProcessor()
|
||||
}
|
||||
class NewProtocolV100Bootstrap {
|
||||
+getProtocolName()
|
||||
+_init()
|
||||
+_destroy()
|
||||
+messageProcessor()
|
||||
}
|
||||
class ProtocolMessageProcessor {
|
||||
+uplinkHandleAsync()
|
||||
+downlinkHandle()
|
||||
+uplinkHandle()
|
||||
+doDownlinkHandle()
|
||||
}
|
||||
class NewProtocolMessageProcessor {
|
||||
+uplinkHandle()
|
||||
+doDownlinkHandle()
|
||||
}
|
||||
ProtocolBootstrap <|-- NewProtocolV100Bootstrap
|
||||
ProtocolMessageProcessor <|-- NewProtocolMessageProcessor
|
||||
NewProtocolV100Bootstrap --> NewProtocolMessageProcessor : "creates"
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L1-L50)
|
||||
- [jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java#L1-L30)
|
||||
- [jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java#L1-L20)
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L1-L127)
|
||||
- [jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java#L1-L78)
|
||||
- [jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/YunkuaichongV150ProtocolBootstrap.java#L1-L48)
|
||||
- [jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java#L1-L48)
|
||||
|
||||
## 调试技巧
|
||||
|
||||
### 查看日志
|
||||
|
||||
应用日志默认输出到控制台,并保存在`logs/`目录下。关键日志文件包括:
|
||||
|
||||
- `logs/accesslog/`:HTTP访问日志
|
||||
- `logs/gc/gc.log`:JVM GC日志
|
||||
- `logs/heapdump/`:内存溢出时的堆转储文件
|
||||
|
||||
可通过配置`app-service.yml`调整日志级别:
|
||||
|
||||
```yaml
|
||||
logging:
|
||||
level:
|
||||
sanbing: DEBUG
|
||||
```
|
||||
|
||||
### 远程调试
|
||||
|
||||
通过JVM参数启用远程调试,修改启动脚本`docker/start.sh`:
|
||||
|
||||
```bash
|
||||
export JAVA_OPTS_EXTEND="-Xdebug -Xrunjdwp:transport=dt_socket,address=0.0.0.0:8000,server=y,suspend=n"
|
||||
```
|
||||
|
||||
在IDE中配置远程调试连接:
|
||||
|
||||
- 主机:localhost
|
||||
- 端口:8000
|
||||
- 调试器:Java
|
||||
|
||||
### RPC调用调试
|
||||
|
||||
通过`RpcController`提供的API接口发送调试指令:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/rpc/oneway \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"method": "startCharge",
|
||||
"parameter": {"pileCode": "P123", "gunNo": "1"}
|
||||
}'
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Dev as 开发者
|
||||
participant IDE as IDE
|
||||
participant App as jcpp-app-bootstrap
|
||||
participant Protocol as jcpp-protocol-bootstrap
|
||||
Dev->>IDE : 配置远程调试
|
||||
IDE->>App : 连接调试端口8000
|
||||
Dev->>App : 发送RPC指令
|
||||
App->>Protocol : 通过Kafka转发
|
||||
Protocol->>App : 处理协议消息
|
||||
App-->>Dev : 返回响应结果
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java#L1-L70)
|
||||
- [docker/start.sh](file://docker/start.sh#L15-L18)
|
||||
- [jcpp-app-bootstrap/src/main/resources/app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml#L1-L10)
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [docker/start.sh](file://docker/start.sh#L15-L18)
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java#L30-L150)
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java#L1-L1000)
|
||||
237
docs/技术栈与依赖.md
Normal file
237
docs/技术栈与依赖.md
Normal file
@@ -0,0 +1,237 @@
|
||||
# 技术栈与依赖
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [pom.xml](file://pom.xml)
|
||||
- [jcpp-app/pom.xml](file://jcpp-app/pom.xml)
|
||||
- [jcpp-infrastructure-cache/pom.xml](file://jcpp-infrastructure-cache/pom.xml)
|
||||
- [jcpp-infrastructure-queue/pom.xml](file://jcpp-infrastructure-queue/pom.xml)
|
||||
- [jcpp-app-bootstrap/src/main/resources/app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml)
|
||||
- [jcpp-infrastructure-proto/src/main/proto/grpc.proto](file://jcpp-infrastructure-proto/src/main/proto/grpc.proto)
|
||||
- [jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java)
|
||||
- [jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java)
|
||||
- [jcpp-web-ui/package.json](file://jcpp-web-ui/package.json)
|
||||
- [jcpp-web-ui/tsconfig.json](file://jcpp-web-ui/tsconfig.json)
|
||||
- [jcpp-web-ui/src/App.tsx](file://jcpp-web-ui/src/App.tsx)
|
||||
- [docker/app.Dockerfile](file://docker/app.Dockerfile)
|
||||
- [docker/docker-compose.monolith.yml](file://docker/docker-compose.monolith.yml)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [后端技术栈](#后端技术栈)
|
||||
2. [前端技术栈](#前端技术栈)
|
||||
3. [中间件与存储](#中间件与存储)
|
||||
4. [构建与部署](#构建与部署)
|
||||
|
||||
## 后端技术栈
|
||||
|
||||
### Spring Boot 基础框架
|
||||
|
||||
Spring Boot 作为本项目的核心基础框架,提供了自动配置、起步依赖和嵌入式服务器等特性,极大地简化了Java应用的开发和部署。项目基于Spring
|
||||
Boot 3.5.6版本构建,利用其强大的生态系统来管理依赖、配置和生命周期。通过`spring-boot-starter-parent`
|
||||
作为父POM,实现了版本统一管理和标准化构建流程。
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [pom.xml](file://pom.xml#L10-L15)
|
||||
|
||||
### MyBatis 数据库访问机制
|
||||
|
||||
项目采用MyBatis-Plus作为持久层框架,基于MyBatis进行了功能增强,提供了CRUD操作的封装,减少了模板代码的编写。通过
|
||||
`mybatis-plus-spring-boot3-starter`依赖集成,实现了与Spring Boot的无缝对接。项目中的实体类(如`Pile`、`Station`、`Gun`
|
||||
)通过Mapper接口与XML映射文件进行数据库操作,支持动态SQL和分页查询。
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [jcpp-app/pom.xml](file://jcpp-app/pom.xml#L25-L30)
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper)
|
||||
|
||||
### Netty TCP网络通信原理
|
||||
|
||||
Netty被用于处理TCP网络通信,特别是在充电桩协议解析模块中。`TcpListener`类使用Netty的`ServerBootstrap`创建TCP服务器,通过
|
||||
`NioEventLoopGroup`管理事件循环,实现了高性能的异步非阻塞I/O通信。项目中为不同协议(如云快充、绿能)配置了独立的TCP监听端口(38001-38011),并使用自定义的
|
||||
`JCPPLengthFieldBasedFrameDecoder`进行消息拆包,解决了TCP粘包问题。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant 充电桩 as 充电桩设备
|
||||
participant Netty as Netty TCP Server
|
||||
participant 协议处理器 as ProtocolMessageProcessor
|
||||
participant Kafka as Kafka Queue
|
||||
充电桩->>Netty : 发送二进制协议数据
|
||||
Netty->>Netty : JCPPLengthFieldBasedFrameDecoder拆包
|
||||
Netty->>协议处理器 : 解析协议并处理上行消息
|
||||
协议处理器->>Kafka : 将消息转发到protocol_uplink主题
|
||||
Kafka-->>应用服务 : 消费消息并更新业务状态
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java#L40-L80)
|
||||
- [jcpp-app-bootstrap/src/main/resources/app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml#L300-L350)
|
||||
|
||||
### gRPC与Protobuf服务间通信
|
||||
|
||||
项目采用gRPC与Protobuf实现高性能的服务间通信。通过`.proto`文件定义服务接口和消息结构,使用Protocol
|
||||
Buffers进行序列化,相比JSON具有更小的体积和更快的解析速度。`grpc.proto`文件定义了`ProtocolInterface`服务,包含`onDownlink`
|
||||
双向流式RPC方法,用于处理下行控制指令。这种设计支持实时、低延迟的通信,特别适合充电桩控制系统中需要快速响应的场景。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolInterface {
|
||||
+onDownlink(stream RequestMsg) returns (stream ResponseMsg)
|
||||
}
|
||||
class RequestMsg {
|
||||
+int64 ts
|
||||
+TracerProto tracer
|
||||
+ConnectRequestMsg connectRequestMsg
|
||||
+DownlinkRequestMessage downlinkRequestMessage
|
||||
}
|
||||
class ResponseMsg {
|
||||
+TracerProto tracer
|
||||
+ConnectResponseMsg connectResponseMsg
|
||||
+DownlinkResponseMessage downlinkResponseMsg
|
||||
}
|
||||
class ConnectRequestMsg {
|
||||
+string nodeId
|
||||
}
|
||||
class ConnectResponseMsg {
|
||||
+ConnectResponseCode responseCode
|
||||
+string errorMsg
|
||||
}
|
||||
ProtocolInterface --> RequestMsg : "请求"
|
||||
ProtocolInterface --> ResponseMsg : "响应"
|
||||
RequestMsg --> ConnectRequestMsg : "包含"
|
||||
ResponseMsg --> ConnectResponseMsg : "包含"
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [jcpp-infrastructure-proto/src/main/proto/grpc.proto](file://jcpp-infrastructure-proto/src/main/proto/grpc.proto#L10-L30)
|
||||
- [jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java#L40-L60)
|
||||
|
||||
## 前端技术栈
|
||||
|
||||
### React组件化架构
|
||||
|
||||
前端采用React框架构建用户界面,实现了组件化开发模式。项目结构清晰地划分了`components`、`contexts`、`services`等目录,通过
|
||||
`App.tsx`作为根组件组织路由和布局。使用`React.FC`函数组件和Hooks(如`useEffect`)管理状态和副作用,实现了声明式的UI开发。路由系统基于
|
||||
`react-router-dom`,通过`ProtectedRoute`组件实现权限控制,确保只有认证用户才能访问特定页面。
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [jcpp-web-ui/src/App.tsx](file://jcpp-web-ui/src/App.tsx#L1-L50)
|
||||
- [jcpp-web-ui/src/components](file://jcpp-web-ui/src/components)
|
||||
|
||||
### TypeScript类型安全优势
|
||||
|
||||
TypeScript为前端开发提供了静态类型检查,增强了代码的可维护性和可靠性。通过`tsconfig.json`配置,启用了严格模式(
|
||||
`"strict": true`
|
||||
),确保类型安全。项目中定义了清晰的类型接口,如API响应、表单数据等,减少了运行时错误。与React结合使用,提供了更好的开发体验和智能提示,特别是在处理复杂状态和props传递时,类型系统能有效防止常见错误。
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [jcpp-web-ui/tsconfig.json](file://jcpp-web-ui/tsconfig.json#L1-L15)
|
||||
- [jcpp-web-ui/package.json](file://jcpp-web-ui/package.json#L10-L15)
|
||||
|
||||
### Ant Design UI组件库
|
||||
|
||||
Ant Design作为UI组件库,提供了丰富、美观且功能完整的React组件。项目中使用`antd`版本5.27.4,通过`ConfigProvider`设置中文语言包(
|
||||
`zhCN`),实现了国际化支持。组件如`Layout`、`Dashboard`、`Form`等被广泛应用于管理后台,提供了统一的设计语言和用户体验。结合
|
||||
`@ant-design/icons`,实现了现代化的图标展示,提升了界面的视觉效果和交互性。
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [jcpp-web-ui/package.json](file://jcpp-web-ui/package.json#L5-L10)
|
||||
- [jcpp-web-ui/src/App.tsx](file://jcpp-web-ui/src/App.tsx#L10-L20)
|
||||
|
||||
## 中间件与存储
|
||||
|
||||
### PostgreSQL持久化存储
|
||||
|
||||
PostgreSQL被选为关系型数据库,用于持久化存储充电桩、站点、用户等核心业务数据。通过`spring-boot-starter-jdbc`和`postgresql`
|
||||
驱动集成,使用HikariCP连接池管理数据库连接。配置中设置了最大连接池大小为64,优化了数据库访问性能。项目中的`schema-init.sql`
|
||||
脚本定义了表结构,确保了数据的一致性和完整性。
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [jcpp-app/pom.xml](file://jcpp-app/pom.xml#L20-L25)
|
||||
- [jcpp-app/src/main/resources/sql/schema-init.sql](file://jcpp-app/src/main/resources/sql/schema-init.sql)
|
||||
|
||||
### Redis多级缓存架构
|
||||
|
||||
项目实现了Caffeine+Redis的多级缓存架构,以提高系统性能和响应速度。`jcpp-infrastructure-cache`
|
||||
模块封装了缓存逻辑,支持Caffeine本地缓存和Redis分布式缓存两种模式。通过`CacheSpecs`配置不同实体(如piles、guns)的缓存策略,包括TTL和最大大小。
|
||||
`AttributeRedisCache`和`PileRedisCache`等类实现了具体的缓存操作,利用Redis的高性能读写能力,减轻了数据库压力。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[客户端请求] --> B{本地缓存存在?}
|
||||
B --> |是| C[返回Caffeine缓存数据]
|
||||
B --> |否| D[查询Redis缓存]
|
||||
D --> E{Redis缓存存在?}
|
||||
E --> |是| F[更新Caffeine缓存]
|
||||
E --> |否| G[查询数据库]
|
||||
G --> H[更新Redis缓存]
|
||||
H --> I[更新Caffeine缓存]
|
||||
I --> J[返回数据]
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [jcpp-infrastructure-cache/pom.xml](file://jcpp-infrastructure-cache/pom.xml#L20-L30)
|
||||
- [jcpp-app-bootstrap/src/main/resources/app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml#L200-L250)
|
||||
|
||||
### Kafka消息解耦与高并发
|
||||
|
||||
Kafka在系统中扮演着消息中间件的角色,用于解耦服务和处理高并发消息流。`jcpp-infrastructure-queue`
|
||||
模块封装了Kafka客户端,支持生产者和消费者模式。配置中设置了`protocol_uplink`
|
||||
主题,用于接收来自充电桩的上行消息。通过分区(partitions)和消费者组(consumer
|
||||
groups)实现消息的并行处理,提高了系统的吞吐量。Kafka的持久化特性确保了消息不丢失,即使在服务重启后也能继续处理。
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [jcpp-infrastructure-queue/pom.xml](file://jcpp-infrastructure-queue/pom.xml#L20-L30)
|
||||
- [jcpp-app-bootstrap/src/main/resources/app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml#L100-L150)
|
||||
|
||||
## 构建与部署
|
||||
|
||||
### Maven多模块项目管理
|
||||
|
||||
项目采用Maven进行多模块管理,通过父POM(`jcpp-parent`)统一管理所有子模块的依赖和插件版本。项目包含多个模块,如`jcpp-app`、
|
||||
`jcpp-protocol-api`、`jcpp-infrastructure-cache`等,每个模块都有明确的职责。`pom.xml`中配置了`protobuf-maven-plugin`用于编译
|
||||
`.proto`文件,`frontend-maven-plugin`用于构建前端资源。这种模块化设计提高了代码的可维护性和复用性。
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [pom.xml](file://pom.xml#L100-L200)
|
||||
- [jcpp-app/pom.xml](file://jcpp-app/pom.xml)
|
||||
|
||||
### Docker容器化部署
|
||||
|
||||
系统通过Docker实现容器化部署,使用`app.Dockerfile`
|
||||
定义应用镜像。采用多阶段构建策略,首先使用基础镜像编译Maven项目,然后提取JAR包的各个层(dependencies、spring-boot-loader等),最后构建运行时镜像。
|
||||
`docker-compose.monolith.yml`定义了服务网络和端口映射,将应用服务暴露在8080端口,同时开放了多个TCP协议端口(38001-38011)。这种部署方式确保了环境一致性,简化了部署流程。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Docker构建流程"
|
||||
A[Maven构建] --> B[提取JAR层]
|
||||
B --> C[构建运行时镜像]
|
||||
C --> D[运行容器]
|
||||
end
|
||||
subgraph "容器网络"
|
||||
D --> E[暴露HTTP端口 8080]
|
||||
D --> F[暴露TCP协议端口 38001-38011]
|
||||
end
|
||||
subgraph "外部连接"
|
||||
E --> G[前端应用]
|
||||
F --> H[充电桩设备]
|
||||
end
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [docker/app.Dockerfile](file://docker/app.Dockerfile)
|
||||
- [docker/docker-compose.monolith.yml](file://docker/docker-compose.monolith.yml)
|
||||
398
docs/数据模型与数据库设计.md
Normal file
398
docs/数据模型与数据库设计.md
Normal file
@@ -0,0 +1,398 @@
|
||||
# 数据模型与数据库设计
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [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)
|
||||
- [Attribute.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Attribute.java)
|
||||
- [schema-init.sql](file://jcpp-app/src/main/resources/sql/schema-init.sql)
|
||||
- [StationMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/StationMapper.java)
|
||||
- [PileMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/PileMapper.java)
|
||||
- [GunMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/GunMapper.java)
|
||||
- [AttributeMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/AttributeMapper.java)
|
||||
- [AttributeMapper.xml](file://jcpp-app/src/main/resources/mapper/AttributeMapper.xml)
|
||||
- [AttrKeyEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/data/kv/AttrKeyEnum.java)
|
||||
- [PileTypeEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/PileTypeEnum.java)
|
||||
- [StatusCleanupInitializingBean.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/initializing/StatusCleanupInitializingBean.java)
|
||||
- [SqlBlockingQueueWrapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/batch/SqlBlockingQueueWrapper.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [核心实体数据模型](#核心实体数据模型)
|
||||
2. [实体关系与ER图](#实体关系与er图)
|
||||
3. [属性实体设计](#属性实体设计)
|
||||
4. [数据库表结构与索引](#数据库表结构与索引)
|
||||
5. [数据访问层设计](#数据访问层设计)
|
||||
6. [数据生命周期管理](#数据生命周期管理)
|
||||
|
||||
## 核心实体数据模型
|
||||
|
||||
### 充电站 (Station)
|
||||
|
||||
充电站实体表示物理充电站点,包含站点的基本信息和地理位置。
|
||||
|
||||
**属性说明:**
|
||||
|
||||
- `id`: UUID类型,主键,全局唯一标识符
|
||||
- `createdTime`: 时间戳,记录创建时间
|
||||
- `updatedTime`: 时间戳,记录最后更新时间
|
||||
- `additionalInfo`: JSON类型,存储额外的扩展信息
|
||||
- `stationName`: 字符串类型,站点名称,非空
|
||||
- `stationCode`: 字符串类型,站点编码,全局唯一,非空
|
||||
- `longitude`: 浮点类型,经度坐标
|
||||
- `latitude`: 浮点类型,纬度坐标
|
||||
- `province`: 字符串类型,省份信息
|
||||
- `city`: 字符串类型,城市信息
|
||||
- `county`: 字符串类型,区县信息
|
||||
- `address`: 字符串类型,详细地址
|
||||
- `version`: 整数类型,版本号,用于乐观锁控制
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [Station.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Station.java#L1-L65)
|
||||
|
||||
### 充电桩 (Pile)
|
||||
|
||||
充电桩实体表示充电站内的具体充电设备,与充电站存在一对多关系。
|
||||
|
||||
**属性说明:**
|
||||
|
||||
- `id`: UUID类型,主键,全局唯一标识符
|
||||
- `createdTime`: 时间戳,记录创建时间
|
||||
- `updatedTime`: 时间戳,记录最后更新时间
|
||||
- `additionalInfo`: JSON类型,存储额外的扩展信息
|
||||
- `pileName`: 字符串类型,充电桩名称,非空
|
||||
- `pileCode`: 字符串类型,充电桩编码,全局唯一,非空
|
||||
- `protocol`: 字符串类型,通信协议类型,非空
|
||||
- `stationId`: UUID类型,外键,关联到充电站实体
|
||||
- `brand`: 字符串类型,品牌信息
|
||||
- `model`: 字符串类型,型号信息
|
||||
- `manufacturer`: 字符串类型,制造商信息
|
||||
- `type`: 枚举类型,充电桩类型(交流AC/直流DC),非空
|
||||
- `version`: 整数类型,版本号,用于乐观锁控制
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java#L1-L64)
|
||||
- [PileTypeEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/PileTypeEnum.java#L1-L22)
|
||||
|
||||
### 充电枪 (Gun)
|
||||
|
||||
充电枪实体表示充电桩上的具体充电接口,与充电桩存在一对多关系。
|
||||
|
||||
**属性说明:**
|
||||
|
||||
- `id`: UUID类型,主键,全局唯一标识符
|
||||
- `createdTime`: 时间戳,记录创建时间
|
||||
- `updatedTime`: 时间戳,记录最后更新时间
|
||||
- `additionalInfo`: 字符串类型,存储额外的扩展信息
|
||||
- `gunNo`: 字符串类型,枪编号,在同一充电桩下唯一,非空
|
||||
- `gunName`: 字符串类型,充电枪名称,非空
|
||||
- `gunCode`: 字符串类型,充电枪编码,全局唯一,非空
|
||||
- `stationId`: UUID类型,外键,关联到充电站实体
|
||||
- `pileId`: UUID类型,外键,关联到充电桩实体
|
||||
- `version`: 整数类型,版本号,用于乐观锁控制
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L56)
|
||||
|
||||
## 实体关系与ER图
|
||||
|
||||
充电站、充电桩和充电枪之间存在明确的层次结构关系:一个充电站包含多个充电桩,一个充电桩包含多个充电枪。
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
STATION {
|
||||
uuid id PK
|
||||
timestamp created_time
|
||||
timestamp updated_time
|
||||
jsonb additional_info
|
||||
varchar station_name
|
||||
varchar station_code UK
|
||||
double precision longitude
|
||||
double precision latitude
|
||||
varchar province
|
||||
varchar city
|
||||
varchar county
|
||||
varchar address
|
||||
int version
|
||||
}
|
||||
PILE {
|
||||
uuid id PK
|
||||
timestamp created_time
|
||||
timestamp updated_time
|
||||
jsonb additional_info
|
||||
varchar pile_name
|
||||
varchar pile_code UK
|
||||
varchar protocol
|
||||
uuid station_id FK
|
||||
varchar brand
|
||||
varchar model
|
||||
varchar manufacturer
|
||||
varchar type
|
||||
int version
|
||||
}
|
||||
GUN {
|
||||
uuid id PK
|
||||
timestamp created_time
|
||||
timestamp updated_time
|
||||
varchar additional_info
|
||||
varchar gun_no
|
||||
varchar gun_name
|
||||
varchar gun_code UK
|
||||
uuid station_id FK
|
||||
uuid pile_id FK
|
||||
int version
|
||||
}
|
||||
STATION ||--o{ PILE : "包含"
|
||||
PILE ||--o{ GUN : "包含"
|
||||
```
|
||||
|
||||
**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)
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L56)
|
||||
- [schema-init.sql](file://jcpp-app/src/main/resources/sql/schema-init.sql#L45-L130)
|
||||
|
||||
## 属性实体设计
|
||||
|
||||
### Attribute实体架构
|
||||
|
||||
Attribute实体采用灵活的键值对(K-V)存储模式,用于存储设备的动态属性,如电压、电流、状态等实时数据。
|
||||
|
||||
**表结构设计特点:**
|
||||
|
||||
- **复合主键**: 由`entity_id`和`attr_key`组成,确保每个实体的每个属性键唯一
|
||||
- **多值类型字段**: 为支持不同数据类型,表中包含多种类型的值字段
|
||||
- **时间戳**: `last_update_ts`记录属性最后更新时间
|
||||
- **版本控制**: `version`字段用于乐观锁控制
|
||||
|
||||
**多值类型字段:**
|
||||
|
||||
- `bool_v`: 布尔值,存储true/false类型数据
|
||||
- `str_v`: 字符串值,存储文本数据,最大长度10,000,000字符
|
||||
- `long_v`: 长整型值,存储大整数
|
||||
- `dbl_v`: 双精度值,存储浮点数
|
||||
- `json_v`: JSON值,存储复杂结构化数据
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [Attribute.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Attribute.java#L1-L102)
|
||||
|
||||
### 属性与核心实体的关联
|
||||
|
||||
Attribute实体通过`entity_id`字段与Station、Pile和Gun实体关联,实现一对多的关系。
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
STATION ||--o{ ATTRIBUTE : "拥有"
|
||||
PILE ||--o{ ATTRIBUTE : "拥有"
|
||||
GUN ||--o{ ATTRIBUTE : "拥有"
|
||||
ATTRIBUTE {
|
||||
uuid entity_id PK,FK
|
||||
varchar attr_key PK
|
||||
boolean bool_v
|
||||
varchar str_v
|
||||
bigint long_v
|
||||
double precision dbl_v
|
||||
json json_v
|
||||
bigint last_update_ts
|
||||
int version
|
||||
}
|
||||
```
|
||||
|
||||
**属性键枚举 (AttrKeyEnum)**
|
||||
系统定义了标准的属性键枚举,确保属性命名的一致性:
|
||||
|
||||
- `STATUS`: 状态
|
||||
- `CONNECTED_AT`: 连接时间
|
||||
- `DISCONNECTED_AT`: 断开连接时间
|
||||
- `LAST_ACTIVE_TIME`: 最后活跃时间
|
||||
- `GUN_RUN_STATUS`: 充电枪运行状态
|
||||
- `LOCK_STATUS`: 地锁状态
|
||||
- `PARK_STATUS`: 车位状态
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [Attribute.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Attribute.java#L1-L102)
|
||||
- [AttrKeyEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/data/kv/AttrKeyEnum.java#L1-L69)
|
||||
|
||||
## 数据库表结构与索引
|
||||
|
||||
### 表结构详情
|
||||
|
||||
根据`schema-init.sql`文件,数据库包含以下主要表:
|
||||
|
||||
**t_station (充电站表)**
|
||||
|
||||
- 主键: `id`
|
||||
- 唯一索引: `uni_station_code` on `station_code`
|
||||
- 字段: id, created_time, updated_time, additional_info, station_name, station_code, longitude, latitude, province,
|
||||
city, county, address, version
|
||||
|
||||
**t_pile (充电桩表)**
|
||||
|
||||
- 主键: `id`
|
||||
- 外键: `station_id` references `t_station(id)`
|
||||
- 唯一索引: `uni_pile_code` on `pile_code`
|
||||
- 字段: id, created_time, updated_time, additional_info, pile_name, pile_code, protocol, station_id, brand, model,
|
||||
manufacturer, type, version
|
||||
|
||||
**t_gun (充电枪表)**
|
||||
|
||||
- 主键: `id`
|
||||
- 外键: `station_id` references `t_station(id)`, `pile_id` references `t_pile(id)`
|
||||
- 唯一索引: `uni_gun_pile_gun_no` on (`pile_id`, `gun_no`), `uni_gun_code` on `gun_code`
|
||||
- 字段: id, created_time, updated_time, additional_info, gun_no, gun_name, gun_code, station_id, pile_id, version
|
||||
|
||||
**t_attr (属性表)**
|
||||
|
||||
- 复合主键: (`entity_id`, `attr_key`)
|
||||
- 字段: entity_id, attr_key, bool_v, str_v, long_v, dbl_v, json_v, last_update_ts, version
|
||||
|
||||
### 索引设计与查询优化
|
||||
|
||||
数据库设计了多个索引以优化查询性能:
|
||||
|
||||
**唯一性约束索引:**
|
||||
|
||||
- `uni_station_code`: 确保充电站编码全局唯一
|
||||
- `uni_pile_code`: 确保充电桩编码全局唯一
|
||||
- `uni_gun_code`: 确保充电枪编码全局唯一
|
||||
- `uni_gun_pile_gun_no`: 确保同一充电桩下枪编号唯一
|
||||
|
||||
**查询性能优化:**
|
||||
这些索引不仅保证了数据的完整性,还显著提升了基于编码的查询性能。例如,通过充电桩编码查询充电桩信息时,可以直接利用
|
||||
`uni_pile_code`索引进行快速查找。
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [schema-init.sql](file://jcpp-app/src/main/resources/sql/schema-init.sql#L1-L130)
|
||||
|
||||
## 数据访问层设计
|
||||
|
||||
### MyBatis Mapper接口设计
|
||||
|
||||
数据访问层采用MyBatis框架,通过Mapper接口与XML映射文件配合工作。
|
||||
|
||||
**核心Mapper接口:**
|
||||
|
||||
- `StationMapper`: 继承自`BaseMapper<Station>`,提供基础的CRUD操作
|
||||
- `PileMapper`: 扩展了基础操作,包含自定义查询方法
|
||||
- `GunMapper`: 扩展了基础操作,包含自定义查询方法
|
||||
- `AttributeMapper`: 提供属性数据的特定访问方法
|
||||
|
||||
### Mapper接口与XML映射配合
|
||||
|
||||
Mapper接口定义了数据访问方法,而具体的SQL语句在对应的XML文件中实现,这种分离设计提高了代码的可维护性。
|
||||
|
||||
**PileMapper示例:**
|
||||
|
||||
```java
|
||||
IPage<PileWithStatusResponse> selectPileWithStatusPage(
|
||||
Page<PileWithStatusResponse> page,
|
||||
@Param("request") PileQueryRequest request,
|
||||
@Param("statusKey") AttrKeyEnum statusKey,
|
||||
@Param("connectedAtKey") AttrKeyEnum connectedAtKey,
|
||||
@Param("disconnectedAtKey") AttrKeyEnum disconnectedAtKey,
|
||||
@Param("lastActiveTimeKey") AttrKeyEnum lastActiveTimeKey
|
||||
);
|
||||
```
|
||||
|
||||
对应的SQL在`PileMapper.xml`中定义,但项目中使用了注解方式直接在接口中定义SQL,体现了MyBatis-Plus的特性。
|
||||
|
||||
**AttributeMapper XML映射:**
|
||||
|
||||
```xml
|
||||
<mapper namespace="sanbing.jcpp.app.dal.mapper.AttributeMapper">
|
||||
<select id="findByEntity" resultType="sanbing.jcpp.app.dal.entity.Attribute">
|
||||
SELECT * FROM t_attr WHERE entity_id = #{entityId}
|
||||
</select>
|
||||
|
||||
<select id="findByEntityAndKey" resultType="sanbing.jcpp.app.dal.entity.Attribute">
|
||||
SELECT * FROM t_attr WHERE entity_id = #{entityId} AND attr_key = #{attrKey}
|
||||
</select>
|
||||
|
||||
<delete id="deleteByEntityIdAndKey">
|
||||
DELETE FROM t_attr WHERE entity_id = #{entityId} AND attr_key = #{attrKey}
|
||||
</delete>
|
||||
</mapper>
|
||||
```
|
||||
|
||||
这种设计模式的优势:
|
||||
|
||||
1. **关注点分离**: Java接口定义方法签名,XML文件定义SQL实现
|
||||
2. **可维护性**: SQL语句集中管理,便于修改和优化
|
||||
3. **类型安全**: MyBatis通过接口提供类型安全的数据访问
|
||||
4. **灵活性**: 复杂SQL可以在XML中使用动态SQL标签构建
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [StationMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/StationMapper.java#L1-L15)
|
||||
- [PileMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/PileMapper.java#L1-L77)
|
||||
- [GunMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/GunMapper.java#L1-L131)
|
||||
- [AttributeMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/AttributeMapper.java#L1-L53)
|
||||
- [AttributeMapper.xml](file://jcpp-app/src/main/resources/mapper/AttributeMapper.xml#L1-L43)
|
||||
|
||||
## 数据生命周期管理
|
||||
|
||||
### 状态清洗与初始化
|
||||
|
||||
系统在启动时执行状态清洗操作,确保充电桩状态的一致性。
|
||||
|
||||
**StatusCleanupInitializingBean组件:**
|
||||
|
||||
- 在Spring容器初始化时执行
|
||||
- 执行充电桩状态的全量清洗
|
||||
- 如果失败会阻止应用启动,确保数据状态一致性
|
||||
- 分页处理充电桩,每次处理1000个,避免内存溢出
|
||||
|
||||
**状态决策逻辑:**
|
||||
根据会话状态、数据库状态和超时时间决定目标状态:
|
||||
|
||||
- 检查充电桩是否有活跃的会话连接
|
||||
- 结合当前数据库状态和配置的超时阈值
|
||||
- 决定最终的目标状态(在线/离线)
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [StatusCleanupInitializingBean.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/initializing/StatusCleanupInitializingBean.java#L1-L169)
|
||||
|
||||
### 批量数据处理与队列机制
|
||||
|
||||
系统实现了高效的批量数据处理机制,用于优化数据库写入性能。
|
||||
|
||||
**SqlBlockingQueueWrapper设计:**
|
||||
|
||||
- 使用阻塞队列实现数据批量处理
|
||||
- 支持多线程并行处理
|
||||
- 可配置批处理大小和最大延迟时间
|
||||
- 提供统计信息打印功能
|
||||
|
||||
**批处理参数:**
|
||||
|
||||
- `logName`: 日志名称
|
||||
- `batchSize`: 批处理大小
|
||||
- `maxDelay`: 最大延迟时间(毫秒)
|
||||
- `statsPrintIntervalMs`: 统计信息打印间隔
|
||||
- `statsNamePrefix`: 统计名称前缀
|
||||
- `batchSortEnabled`: 是否启用批处理排序
|
||||
- `withResponse`: 是否需要响应
|
||||
|
||||
**数据处理流程:**
|
||||
|
||||
1. 数据元素被添加到阻塞队列
|
||||
2. 单线程消费者定期从队列中获取数据
|
||||
3. 当达到批处理大小或超时后,执行批量保存
|
||||
4. 支持对批处理数据进行排序,避免集群模式下的死锁
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [SqlBlockingQueueWrapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/batch/SqlBlockingQueueWrapper.java#L1-L58)
|
||||
- [SqlBlockingQueue.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/batch/SqlBlockingQueue.java#L1-L58)
|
||||
- [SqlBlockingQueueParams.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/batch/SqlBlockingQueueParams.java#L1-L24)
|
||||
- [ScheduledLogExecutorComponent.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/batch/ScheduledLogExecutorComponent.java#L1-L40)
|
||||
199
docs/架构设计/微服务架构.md
Normal file
199
docs/架构设计/微服务架构.md
Normal file
@@ -0,0 +1,199 @@
|
||||
# 微服务架构
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [JCPPServerApplication.java](file://jcpp-app-bootstrap/src/main/java/sanbing/jcpp/JCPPServerApplication.java)
|
||||
- [JCPPProtocolServiceApplication.java](file://jcpp-protocol-bootstrap/src/main/java/sanbing/jcpp/protocol/JCPPProtocolServiceApplication.java)
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml)
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml)
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java)
|
||||
- [ProtocolController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/ProtocolController.java)
|
||||
- [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)
|
||||
- [DownlinkGrpcClient.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/grpc/DownlinkGrpcClient.java)
|
||||
- [ProtocolUplinkConsumerService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java)
|
||||
- [ProtocolUplinkMsg.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/ProtocolUplinkMsg.java)
|
||||
- [app.Dockerfile](file://docker/app.Dockerfile)
|
||||
- [protocol.Dockerfile](file://docker/protocol.Dockerfile)
|
||||
- [docker-compose.monolith.yml](file://docker/docker-compose.monolith.yml)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [引言](#引言)
|
||||
2. [微服务职责划分](#微服务职责划分)
|
||||
3. [服务启动入口与配置](#服务启动入口与配置)
|
||||
4. [服务间通信机制](#服务间通信机制)
|
||||
5. [部署拓扑与中间件依赖](#部署拓扑与中间件依赖)
|
||||
6. [Docker与容器化部署](#docker与容器化部署)
|
||||
7. [部署拓扑图](#部署拓扑图)
|
||||
|
||||
## 引言
|
||||
|
||||
JChargePointProtocol是一个用于充电桩管理的微服务架构系统,采用模块化设计将业务逻辑与协议处理分离。该系统由两个核心微服务组成:jcpp-app(主应用服务)和jcpp-protocol-api(协议处理核心),通过清晰的职责划分实现高内聚、低耦合的系统架构。本文档详细阐述这两个微服务的架构设计、通信机制、配置管理及部署方案。
|
||||
|
||||
## 微服务职责划分
|
||||
|
||||
### jcpp-app(主应用服务)
|
||||
|
||||
jcpp-app微服务负责系统的业务逻辑处理和用户交互,是整个系统的后端核心。其主要职责包括:
|
||||
|
||||
- **业务逻辑处理**:实现充电桩、充电枪、充电站等实体的增删改查操作,处理用户管理、权限控制、计费策略等核心业务逻辑。
|
||||
- **REST API暴露**:通过Spring MVC提供标准的RESTful API接口,供前端UI或其他客户端调用,如充电桩管理、用户认证、数据查询等接口。
|
||||
- **数据库交互**:使用MyBatis作为持久层框架,与PostgreSQL数据库进行交互,管理充电桩、用户、会话等结构化数据。
|
||||
- **用户管理**:实现基于JWT的认证授权机制,管理用户登录、权限验证和会话生命周期。
|
||||
|
||||
**微服务职责来源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L1-L112)
|
||||
- [ProtocolController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/ProtocolController.java#L1-L41)
|
||||
|
||||
### jcpp-protocol-api(协议处理核心)
|
||||
|
||||
jcpp-protocol-api微服务专注于充电桩通信协议的处理,是系统的通信前置。其主要职责包括:
|
||||
|
||||
- **TCP长连接处理**:使用Netty框架监听指定端口(如38001-38011),接收来自充电桩的TCP连接请求,维护长连接会话。
|
||||
- **协议编解码**:针对不同厂商的充电桩协议(如云快充V150/V160/V170、绿能V340),实现消息的编码与解码,处理二进制、JSON等格式的数据包。
|
||||
- **消息路由**:根据协议类型和消息内容,将上行消息路由到相应的处理器进行业务逻辑处理,并将下行指令正确发送到指定的充电桩。
|
||||
- **gRPC接口暴露**:提供gRPC服务接口,允许jcpp-app等服务通过高性能的远程过程调用方式向充电桩发送控制指令。
|
||||
|
||||
**微服务职责来源**
|
||||
|
||||
- [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)
|
||||
|
||||
## 服务启动入口与配置
|
||||
|
||||
### 启动入口
|
||||
|
||||
系统通过两个独立的Spring Boot应用作为微服务的启动入口:
|
||||
|
||||
- **jcpp-app启动入口**:`JCPPServerApplication`类是jcpp-app微服务的主启动类。它通过`@SpringBootApplication`注解启用Spring
|
||||
Boot自动配置,并通过`main`方法启动应用。启动时会自动加载`app-service.yml`配置文件,并在启动完成后输出启动耗时日志。
|
||||
|
||||
- **jcpp-protocol-api启动入口**:`JCPPProtocolServiceApplication`类是jcpp-protocol-api微服务的主启动类。它同样基于Spring
|
||||
Boot,但通过`scanBasePackages`指定了特定的包扫描范围,确保只加载协议相关的组件。其`main`方法负责启动协议服务。
|
||||
|
||||
**启动入口来源**
|
||||
|
||||
- [JCPPServerApplication.java](file://jcpp-app-bootstrap/src/main/java/sanbing/jcpp/JCPPServerApplication.java#L1-L55)
|
||||
- [JCPPProtocolServiceApplication.java](file://jcpp-protocol-bootstrap/src/main/java/sanbing/jcpp/protocol/JCPPProtocolServiceApplication.java#L1-L59)
|
||||
|
||||
### 配置文件
|
||||
|
||||
每个微服务都有独立的YAML配置文件,实现配置隔离:
|
||||
|
||||
- **app-service.yml**
|
||||
:jcpp-app微服务的配置文件,定义了HTTP服务器端口(8080)、数据库连接(PostgreSQL)、缓存配置(Caffeine/Redis)、Kafka队列、安全设置(JWT)等。通过环境变量(如
|
||||
`SPRING_DATASOURCE_URL`)支持不同环境的配置注入。
|
||||
|
||||
- **protocol-service.yml**
|
||||
:jcpp-protocol-api微服务的配置文件,定义了HTTP服务器端口(8081)、gRPC服务端口(9090)、各协议监听器的TCP端口(如云快充V150在38001端口)、以及Kafka生产者配置。该文件明确将
|
||||
`service.type`设置为`protocol`,表明其为纯协议处理服务。
|
||||
|
||||
**配置文件来源**
|
||||
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml#L1-L432)
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml#L1-L274)
|
||||
|
||||
## 服务间通信机制
|
||||
|
||||
### 异步消息传递(Kafka)
|
||||
|
||||
两个微服务通过Apache Kafka进行异步消息传递,实现解耦和削峰填谷:
|
||||
|
||||
- **消息类型**:`ProtocolUplinkMsg`
|
||||
是核心的上行消息类型,封装了来自充电桩的原始数据。当jcpp-protocol-api接收到充电桩的上行消息时,会将其序列化为Protobuf格式,并通过Kafka生产者发送到名为
|
||||
`protocol_uplink`的主题。
|
||||
|
||||
- **消息消费**:jcpp-app微服务中包含`ProtocolUplinkConsumerService`消费者,它订阅`protocol_uplink`主题,从Kafka拉取
|
||||
`ProtocolUplinkMsg`消息。消费后,消息会被反序列化并分发到相应的业务处理器,如更新充电桩状态、记录充电数据等。
|
||||
|
||||
**异步通信来源**
|
||||
|
||||
- [ProtocolUplinkMsg.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/ProtocolUplinkMsg.java#L1-L24)
|
||||
- [ProtocolUplinkConsumerService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java)
|
||||
|
||||
### 同步远程调用(gRPC)
|
||||
|
||||
对于需要即时响应的控制指令,系统采用gRPC进行同步远程调用:
|
||||
|
||||
- **gRPC服务端**:jcpp-protocol-api通过`DownlinkGrpcService`类暴露gRPC服务。它继承自
|
||||
`ProtocolInterfaceGrpc.ProtocolInterfaceImplBase`,实现了`onDownlink`方法,用于接收来自jcpp-app的下行控制请求(如启动充电、停止充电、设置电价等)。
|
||||
|
||||
- **gRPC客户端**:jcpp-app通过`DownlinkGrpcClient`类作为gRPC客户端。它维护与jcpp-protocol-api的长连接,并提供
|
||||
`sendDownlinkRequest`方法。当业务需要向充电桩发送指令时,jcpp-app会构造`RequestMsg`,通过gRPC客户端发送给jcpp-protocol-api。
|
||||
|
||||
- **通信流程**:jcpp-app -> (gRPC) -> jcpp-protocol-api -> (TCP) -> 充电桩。gRPC调用确保了指令的可靠、低延迟传输。
|
||||
|
||||
**同步通信来源**
|
||||
|
||||
- [DownlinkGrpcService.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkGrpcService.java#L1-L185)
|
||||
- [DownlinkGrpcClient.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/grpc/DownlinkGrpcClient.java#L1-L298)
|
||||
|
||||
## 部署拓扑与中间件依赖
|
||||
|
||||
系统依赖于多种中间件来实现其功能:
|
||||
|
||||
- **PostgreSQL**:作为主数据库,由jcpp-app服务连接,用于持久化存储充电桩、用户、站点等核心业务数据。
|
||||
- **Redis**:作为缓存层,由jcpp-app服务连接,用于缓存充电桩状态、会话信息等高频访问数据,减轻数据库压力。
|
||||
- **Kafka**:作为消息中间件,是两个微服务间通信的桥梁。jcpp-protocol-api将上行消息发布到Kafka,jcpp-app从Kafka消费这些消息。
|
||||
|
||||
**中间件依赖来源**
|
||||
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml#L30-L100)
|
||||
|
||||
## Docker与容器化部署
|
||||
|
||||
系统通过Docker实现容器化部署,确保环境一致性:
|
||||
|
||||
- **Docker镜像构建**:提供了`app.Dockerfile`和`protocol.Dockerfile`
|
||||
两个Dockerfile。它们都基于相同的Java基础镜像,采用多阶段构建。首先在构建阶段编译打包应用,然后在运行阶段提取JAR包的分层内容,实现更小的镜像体积和更快的启动速度。
|
||||
|
||||
- **Docker Compose**:通过`docker-compose.monolith.yml`文件定义了本地开发环境的多服务部署。它创建了一个名为
|
||||
`sanbing-network`的自定义网络,并定义了`jcpp-node-0`服务,该服务使用`app.Dockerfile`
|
||||
构建,将容器的8080端口映射到宿主机,并暴露了多个TCP端口(38001等)用于充电桩连接。
|
||||
|
||||
**容器化部署来源**
|
||||
|
||||
- [app.Dockerfile](file://docker/app.Dockerfile#L1-L47)
|
||||
- [protocol.Dockerfile](file://docker/protocol.Dockerfile#L1-L47)
|
||||
- [docker-compose.monolith.yml](file://docker/docker-compose.monolith.yml#L1-L29)
|
||||
|
||||
## 部署拓扑图
|
||||
|
||||
以下Mermaid图展示了JChargePointProtocol系统的部署拓扑和各组件间的连接关系。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "客户端"
|
||||
WebUI[jcpp-web-ui]
|
||||
end
|
||||
subgraph "应用服务层"
|
||||
App[jcpp-app]
|
||||
Protocol[jcpp-protocol-api]
|
||||
end
|
||||
subgraph "中间件"
|
||||
Kafka[(Kafka)]
|
||||
Redis[(Redis)]
|
||||
PostgreSQL[(PostgreSQL)]
|
||||
end
|
||||
subgraph "设备层"
|
||||
Charger[充电桩]
|
||||
end
|
||||
WebUI --> |HTTP/REST| App
|
||||
App --> |gRPC| Protocol
|
||||
Protocol --> |TCP| Charger
|
||||
Protocol --> |Publish| Kafka
|
||||
Kafka --> |Subscribe| App
|
||||
App --> |读写| PostgreSQL
|
||||
App --> |读写| Redis
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [app.Dockerfile](file://docker/app.Dockerfile#L1-L47)
|
||||
- [protocol.Dockerfile](file://docker/protocol.Dockerfile#L1-L47)
|
||||
- [docker-compose.monolith.yml](file://docker/docker-compose.monolith.yml#L1-L29)
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml#L1-L432)
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml#L1-L274)
|
||||
401
docs/架构设计/数据流分析.md
Normal file
401
docs/架构设计/数据流分析.md
Normal file
@@ -0,0 +1,401 @@
|
||||
# JChargePointProtocol 数据流分析文档
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java)
|
||||
- [TcpListener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java)
|
||||
- [TcpChannelHandler.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpChannelHandler.java)
|
||||
- [KafkaForwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/KafkaForwarder.java)
|
||||
- [ProtocolUplinkConsumerService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java)
|
||||
- [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)
|
||||
- [UserController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/UserController.java)
|
||||
- [DownlinkCallService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/DownlinkCallService.java)
|
||||
- [DefaultPileService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileService.java)
|
||||
- [uplink.proto](file://jcpp-infrastructure-proto/src/main/proto/uplink.proto)
|
||||
- [downlink.proto](file://jcpp-infrastructure-proto/src/main/proto/downlink.proto)
|
||||
- [grpc.proto](file://jcpp-infrastructure-proto/src/main/proto/grpc.proto)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [概述](#概述)
|
||||
2. [上行数据流分析](#上行数据流分析)
|
||||
3. [下行指令流分析](#下行指令流分析)
|
||||
4. [消息序列化与传输](#消息序列化与传输)
|
||||
5. [关键组件架构](#关键组件架构)
|
||||
6. [数据流时序图](#数据流时序图)
|
||||
7. [性能考虑](#性能考虑)
|
||||
8. [故障排除指南](#故障排除指南)
|
||||
9. [总结](#总结)
|
||||
|
||||
## 概述
|
||||
|
||||
JChargePointProtocol是一个基于Java的企业级充电桩通信协议框架,采用微服务架构设计,支持多种通信协议和消息传输机制。该系统主要包含两个核心数据流:上行数据流(充电桩→服务器)和下行指令流(服务器→充电桩),通过TCP连接、Kafka消息队列和gRPC等多种技术实现高效可靠的消息传递。
|
||||
|
||||
## 上行数据流分析
|
||||
|
||||
### 数据流路径
|
||||
|
||||
上行数据流从充电桩设备开始,经过多个处理阶段最终到达业务服务层:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Pile as 充电桩设备
|
||||
participant TCP as TcpListener
|
||||
participant Handler as TcpChannelHandler
|
||||
participant Processor as ProtocolMessageProcessor
|
||||
participant Kafka as KafkaForwarder
|
||||
participant Consumer as ProtocolUplinkConsumerService
|
||||
participant Service as DefaultPileService
|
||||
Pile->>TCP : TCP原始数据包
|
||||
TCP->>Handler : 解码后的ProtocolUplinkMsg
|
||||
Handler->>Processor : 异步处理消息
|
||||
Processor->>Kafka : 发布到Kafka Topic
|
||||
Kafka->>Consumer : 从Kafka消费消息
|
||||
Consumer->>Service : 调用业务服务处理
|
||||
Service->>Service : 更新数据库状态
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [TcpListener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java#L30-L70)
|
||||
- [TcpChannelHandler.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpChannelHandler.java#L99-L128)
|
||||
- [KafkaForwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/KafkaForwarder.java#L145-L169)
|
||||
- [ProtocolUplinkConsumerService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java#L120-L200)
|
||||
|
||||
### 关键处理节点
|
||||
|
||||
#### 1. TCP监听器层
|
||||
|
||||
TCP监听器负责建立与充电桩的网络连接,处理原始字节流并将其转换为结构化的消息对象。
|
||||
|
||||
**节来源**
|
||||
|
||||
- [TcpListener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java#L30-L70)
|
||||
|
||||
#### 2. 消息处理器层
|
||||
|
||||
消息处理器负责解析不同格式的上行消息(字节数组、JSON、字符串),并异步处理这些消息以提高系统吞吐量。
|
||||
|
||||
**节来源**
|
||||
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java#L25-L45)
|
||||
|
||||
#### 3. Kafka转发层
|
||||
|
||||
Kafka转发器将处理后的消息发布到指定的Kafka主题,支持Protobuf和JSON两种序列化格式,并添加分布式追踪信息。
|
||||
|
||||
**节来源**
|
||||
|
||||
- [KafkaForwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/KafkaForwarder.java#L145-L169)
|
||||
|
||||
#### 4. 消费者服务层
|
||||
|
||||
消费者服务从Kafka队列中消费消息,根据消息类型路由到相应的业务处理方法,支持多种充电相关事件的处理。
|
||||
|
||||
**节来源**
|
||||
|
||||
- [ProtocolUplinkConsumerService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java#L120-L200)
|
||||
|
||||
### 消息类型与处理
|
||||
|
||||
上行消息包含多种类型,每种类型对应不同的业务场景:
|
||||
|
||||
| 消息类型 | 描述 | 处理方法 |
|
||||
|--------------------------|---------|----------------------------|
|
||||
| LoginRequest | 充电桩登录请求 | pileLogin |
|
||||
| HeartBeatRequest | 心跳检测 | heartBeat |
|
||||
| GunRunStatusProto | 枪运行状态 | postGunRunStatus |
|
||||
| ChargingProgressProto | 充电进度 | postChargingProgress |
|
||||
| TransactionRecordRequest | 交易记录 | onTransactionRecordRequest |
|
||||
| BmsChargingErrorProto | BMS充电错误 | onBmsChargingErrorProto |
|
||||
|
||||
## 下行指令流分析
|
||||
|
||||
### 数据流路径
|
||||
|
||||
下行指令流从管理平台开始,通过REST API或gRPC接口传递到目标充电桩:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Admin as 管理员
|
||||
participant Controller as UserController
|
||||
participant CallService as DownlinkCallService
|
||||
participant GrpcService as DownlinkGrpcService
|
||||
participant Processor as ProtocolMessageProcessor
|
||||
participant TCP as TcpChannelHandler
|
||||
participant Pile as 充电桩设备
|
||||
Admin->>Controller : REST API请求
|
||||
Controller->>CallService : 调用下行指令服务
|
||||
CallService->>GrpcService : gRPC调用
|
||||
GrpcService->>Processor : 封装下行消息
|
||||
Processor->>TCP : 通过TCP发送
|
||||
TCP->>Pile : 下行指令数据包
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [UserController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/UserController.java#L30-L50)
|
||||
- [DownlinkCallService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/DownlinkCallService.java#L72-L109)
|
||||
- [DownlinkGrpcService.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkGrpcService.java#L123-L151)
|
||||
- [TcpChannelHandler.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpChannelHandler.java#L110-L130)
|
||||
|
||||
### 关键处理节点
|
||||
|
||||
#### 1. 控制器层
|
||||
|
||||
控制器接收来自管理平台的REST API请求,验证权限后调用相应的服务处理指令。
|
||||
|
||||
**节来源**
|
||||
|
||||
- [UserController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/UserController.java#L30-L50)
|
||||
|
||||
#### 2. 服务调用层
|
||||
|
||||
服务调用层负责选择合适的通信方式(REST或gRPC)将指令发送到目标节点。
|
||||
|
||||
**节来源**
|
||||
|
||||
- [DownlinkCallService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/DownlinkCallService.java#L72-L109)
|
||||
|
||||
#### 3. gRPC服务层
|
||||
|
||||
gRPC服务层处理双向流式通信,接收来自客户端的下行指令并转发给相应的协议会话。
|
||||
|
||||
**节来源**
|
||||
|
||||
- [DownlinkGrpcService.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkGrpcService.java#L123-L151)
|
||||
|
||||
#### 4. 协议处理器层
|
||||
|
||||
协议处理器将下行指令封装为特定格式的消息,并通过TCP连接发送给充电桩。
|
||||
|
||||
**节来源**
|
||||
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java#L45-L65)
|
||||
|
||||
### 指令类型与处理
|
||||
|
||||
下行指令包含多种类型,支持远程控制充电桩的各种功能:
|
||||
|
||||
| 指令类型 | 描述 | 参数 |
|
||||
|----------------------------|--------|--------------------------|
|
||||
| RemoteStartChargingRequest | 远程启动充电 | pileCode, gunNo, tradeNo |
|
||||
| RemoteStopChargingRequest | 远程停止充电 | pileCode, gunNo |
|
||||
| SetPricingRequest | 设置计费策略 | pricingModel |
|
||||
| RestartPileRequest | 重启充电桩 | type |
|
||||
| TimeSyncRequest | 时间同步 | time |
|
||||
|
||||
## 消息序列化与传输
|
||||
|
||||
### Protobuf序列化
|
||||
|
||||
系统采用Google Protocol Buffers作为主要的消息序列化格式,提供高效的二进制序列化和跨语言兼容性。
|
||||
|
||||
**节来源**
|
||||
|
||||
- [uplink.proto](file://jcpp-infrastructure-proto/src/main/proto/uplink.proto#L1-L50)
|
||||
- [downlink.proto](file://jcpp-infrastructure-proto/src/main/proto/downlink.proto#L1-L50)
|
||||
|
||||
### Kafka传输机制
|
||||
|
||||
Kafka作为消息中间件,提供高吞吐量、低延迟的消息传递能力:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[ProtocolMessageProcessor] --> B{序列化类型}
|
||||
B --> |Protobuf| C[二进制序列化]
|
||||
B --> |JSON| D[JSON序列化]
|
||||
C --> E[Kafka Producer]
|
||||
D --> E
|
||||
E --> F[Kafka Broker]
|
||||
F --> G[ProtocolUplinkConsumerService]
|
||||
G --> H[业务服务处理]
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [KafkaForwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/KafkaForwarder.java#L169-L200)
|
||||
|
||||
### gRPC通信协议
|
||||
|
||||
gRPC提供高性能的双向流式通信,支持实时指令下发:
|
||||
|
||||
**节来源**
|
||||
|
||||
- [grpc.proto](file://jcpp-infrastructure-proto/src/main/proto/grpc.proto#L15-L35)
|
||||
|
||||
## 关键组件架构
|
||||
|
||||
### 系统架构概览
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "客户端层"
|
||||
A[管理平台]
|
||||
B[充电桩设备]
|
||||
end
|
||||
subgraph "传输层"
|
||||
C[TCP连接]
|
||||
D[gRPC服务]
|
||||
E[Kafka集群]
|
||||
end
|
||||
subgraph "协议处理层"
|
||||
F[TcpListener]
|
||||
G[ProtocolMessageProcessor]
|
||||
H[KafkaForwarder]
|
||||
end
|
||||
subgraph "业务服务层"
|
||||
I[ProtocolUplinkConsumerService]
|
||||
J[DefaultPileService]
|
||||
K[业务逻辑处理]
|
||||
end
|
||||
A --> D
|
||||
B --> C
|
||||
C --> F
|
||||
D --> G
|
||||
F --> G
|
||||
G --> H
|
||||
H --> I
|
||||
I --> J
|
||||
J --> K
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [TcpListener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java#L30-L70)
|
||||
- [KafkaForwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/KafkaForwarder.java#L31-L71)
|
||||
- [ProtocolUplinkConsumerService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java#L60-L100)
|
||||
|
||||
### 组件职责分离
|
||||
|
||||
每个组件都有明确的职责边界,确保系统的可维护性和扩展性:
|
||||
|
||||
| 组件层级 | 主要职责 | 关键特性 |
|
||||
|------|-----------|---------|
|
||||
| 传输层 | 网络通信和消息路由 | 高并发、低延迟 |
|
||||
| 协议层 | 协议解析和消息处理 | 可扩展、标准化 |
|
||||
| 业务层 | 业务逻辑和状态管理 | 事务性、一致性 |
|
||||
|
||||
## 数据流时序图
|
||||
|
||||
### 完整数据流时序
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Pile as 充电桩
|
||||
participant TCP as TcpListener
|
||||
participant Handler as TcpChannelHandler
|
||||
participant Processor as ProtocolMessageProcessor
|
||||
participant Kafka as KafkaForwarder
|
||||
participant Consumer as ProtocolUplinkConsumerService
|
||||
participant Service as DefaultPileService
|
||||
participant DB as 数据库
|
||||
Note over Pile,DB : 上行数据流
|
||||
Pile->>TCP : 发送原始数据包
|
||||
TCP->>Handler : 接收并解码
|
||||
Handler->>Processor : 异步处理消息
|
||||
Processor->>Kafka : 发布到Kafka
|
||||
Kafka->>Consumer : 消费消息
|
||||
Consumer->>Service : 路由到业务方法
|
||||
Service->>DB : 更新状态信息
|
||||
Note over Pile,DB : 下行指令流
|
||||
Admin->>Service : 发起指令请求
|
||||
Service->>Processor : 创建下行消息
|
||||
Processor->>TCP : 通过TCP发送
|
||||
TCP->>Pile : 下发指令
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [TcpChannelHandler.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpChannelHandler.java#L99-L128)
|
||||
- [KafkaForwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/KafkaForwarder.java#L145-L169)
|
||||
- [ProtocolUplinkConsumerService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java#L120-L200)
|
||||
|
||||
### 消息头信息
|
||||
|
||||
消息在传输过程中携带重要的追踪和路由信息:
|
||||
|
||||
| 字段名称 | 类型 | 描述 | 示例值 |
|
||||
|----------------------|--------|---------|-----------------|
|
||||
| MSG_MD_TRACER_ID | String | 分布式追踪ID | "trace-12345" |
|
||||
| MSG_MD_TRACER_ORIGIN | String | 追踪来源 | "jcpp-protocol" |
|
||||
| MSG_MD_TRACER_TS | Long | 追踪时间戳 | 1640995200000 |
|
||||
| MessageKey | String | 消息唯一标识 | "msg-uuid-123" |
|
||||
|
||||
## 性能考虑
|
||||
|
||||
### 异步处理机制
|
||||
|
||||
系统采用异步处理模式,避免阻塞主线程,提高整体吞吐量:
|
||||
|
||||
- **线程池管理**:使用分片线程池处理不同会话的消息
|
||||
- **批量处理**:支持消息批处理以减少系统开销
|
||||
- **背压控制**:通过Kafka的缓冲机制防止系统过载
|
||||
|
||||
### 缓存策略
|
||||
|
||||
- **会话缓存**:使用Caffeine本地缓存和Redis分布式缓存
|
||||
- **配置缓存**:缓存充电桩配置信息减少数据库查询
|
||||
- **状态缓存**:缓存充电桩状态信息支持快速查询
|
||||
|
||||
### 监控指标
|
||||
|
||||
系统提供丰富的监控指标用于性能分析:
|
||||
|
||||
- **消息统计**:吞吐量、延迟、错误率
|
||||
- **连接监控**:活跃连接数、连接池状态
|
||||
- **队列监控**:Kafka队列积压、消费者滞后
|
||||
|
||||
## 故障排除指南
|
||||
|
||||
### 常见问题诊断
|
||||
|
||||
#### 1. 连接问题
|
||||
|
||||
- **症状**:充电桩无法连接到服务器
|
||||
- **排查步骤**:
|
||||
- 检查TCP监听器状态
|
||||
- 验证防火墙配置
|
||||
- 确认端口可用性
|
||||
|
||||
#### 2. 消息丢失
|
||||
|
||||
- **症状**:部分消息未能到达目标
|
||||
- **排查步骤**:
|
||||
- 检查Kafka分区分配
|
||||
- 验证消费者组配置
|
||||
- 监控消息序列化错误
|
||||
|
||||
#### 3. 性能问题
|
||||
|
||||
- **症状**:消息处理延迟过高
|
||||
- **排查步骤**:
|
||||
- 分析线程池使用情况
|
||||
- 检查数据库连接池
|
||||
- 监控GC性能
|
||||
|
||||
### 日志分析
|
||||
|
||||
系统提供详细的日志记录,支持问题定位:
|
||||
|
||||
- **TRACE级别**:详细的流程跟踪
|
||||
- **DEBUG级别**:调试信息和状态变更
|
||||
- **INFO级别**:正常操作记录
|
||||
- **WARN级别**:潜在问题警告
|
||||
- **ERROR级别**:错误和异常信息
|
||||
|
||||
## 总结
|
||||
|
||||
JChargePointProtocol通过精心设计的多层架构,实现了高效可靠的充电桩通信系统。上行数据流通过TCP连接接收充电桩状态信息,经由Kafka消息队列异步处理后更新业务状态;下行指令流通过REST
|
||||
API或gRPC接口实现远程控制功能。整个系统采用Protobuf序列化、异步处理和分布式缓存等技术,确保了高并发场景下的稳定性和性能。
|
||||
|
||||
系统的主要优势包括:
|
||||
|
||||
- **高可靠性**:多重备份和故障恢复机制
|
||||
- **高性能**:异步处理和优化的序列化格式
|
||||
- **可扩展性**:模块化设计支持功能扩展
|
||||
- **可观测性**:完善的监控和日志体系
|
||||
|
||||
通过合理的设计和技术选型,该系统能够满足大规模充电桩网络的通信需求,为智能充电基础设施提供坚实的技术支撑。
|
||||
234
docs/架构设计/架构模式.md
Normal file
234
docs/架构设计/架构模式.md
Normal file
@@ -0,0 +1,234 @@
|
||||
# 架构模式
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java)
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java)
|
||||
- [Forwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/Forwarder.java)
|
||||
- [KafkaForwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/KafkaForwarder.java)
|
||||
- [MemoryForwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/MemoryForwarder.java)
|
||||
- [AppQueueFactory.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/provider/AppQueueFactory.java)
|
||||
- [KafkaAppQueueFactory.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/provider/KafkaAppQueueFactory.java)
|
||||
- [InMemoryAppQueueFactory.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/provider/InMemoryAppQueueFactory.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)
|
||||
- [LvnengV340LoginULCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340LoginULCmd.java)
|
||||
- [YunKuaiChongV150LoginULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LoginULCmd.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [引言](#引言)
|
||||
2. [模板方法模式](#模板方法模式)
|
||||
3. [策略模式](#策略模式)
|
||||
4. [工厂模式](#工厂模式)
|
||||
5. [六边形架构](#六边形架构)
|
||||
6. [设计模式综合类图](#设计模式综合类图)
|
||||
7. [结论](#结论)
|
||||
|
||||
## 引言
|
||||
|
||||
JChargePointProtocol
|
||||
是一个用于处理充电桩通信协议的系统,其架构设计体现了多种经典的设计模式。本文档深入分析了该系统中应用的四种核心设计模式:模板方法模式、策略模式、工厂模式和六边形架构。这些模式共同构建了一个可扩展、可测试且松耦合的系统,能够灵活支持多种充电桩通信协议(如绿能V3.40、云快充V1.50等)。通过分析这些模式的具体实现,我们可以理解系统如何实现协议初始化的标准化、消息转发的灵活性、对象创建的解耦以及核心业务逻辑与外部适配器的清晰分离。
|
||||
|
||||
## 模板方法模式
|
||||
|
||||
模板方法模式在 JChargePointProtocol 中通过 `ProtocolBootstrap`
|
||||
抽象基类实现。该模式定义了一个算法的骨架(固定流程),而将一些步骤的实现延迟到子类中,从而允许子类在不改变算法结构的情况下重新定义算法的某些特定步骤。
|
||||
|
||||
在本系统中,`ProtocolBootstrap` 类定义了协议服务启动和销毁的固定流程。其核心方法 `init()` 和 `destroy()` 使用了 Spring 框架的
|
||||
`@PostConstruct` 和 `@PreDestroy` 注解,确保在 Spring 容器初始化和销毁 Bean 时自动执行。`init()`
|
||||
方法的流程是固定的:首先记录初始化日志,然后从配置提供者加载协议配置,接着根据配置创建相应的 `Forwarder`(消息转发器)和
|
||||
`Listener`(监听器),最后调用子类实现的 `_init()` 方法。同样,`destroy()` 方法也遵循固定流程:先销毁 `Listener`,再销毁
|
||||
`Forwarder`,最后调用子类的 `_destroy()` 方法。
|
||||
|
||||
具体的协议实现类,如 `LvnengV340ProtocolBootstrap`,继承了 `ProtocolBootstrap` 并实现了其抽象方法。`getProtocolName()`
|
||||
方法返回具体的协议名称(如 "LVNENG_V340"),`messageProcessor()` 方法返回该协议专用的消息处理器(
|
||||
`LvnengProtocolMessageProcessor`)。值得注意的是,`_init()` 和 `_destroy()` 方法在 `LvnengV340ProtocolBootstrap`
|
||||
中为空实现,这表明对于绿能V3.40协议,除了基类提供的标准初始化流程外,不需要额外的初始化或销毁逻辑。这种设计使得所有协议都遵循统一的生命周期管理,保证了系统的一致性和健壮性,同时为特定协议提供了扩展点。
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L1-L126)
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java#L1-L41)
|
||||
|
||||
## 策略模式
|
||||
|
||||
策略模式在 JChargePointProtocol 中通过 `Forwarder` 接口及其具体实现类 `KafkaForwarder` 和 `MemoryForwarder`
|
||||
来体现。该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户端。
|
||||
|
||||
在本系统中,消息转发策略是核心功能之一。`Forwarder` 是一个抽象类,它定义了所有转发器必须实现的公共接口,如 `sendMessage()`
|
||||
用于发送消息,`destroy()` 用于资源清理,以及 `health()` 用于健康检查。`Forwarder` 的构造函数接收通用的配置和依赖项,如
|
||||
`StatsFactory` 用于统计、`PartitionProvider` 用于分区等。
|
||||
|
||||
具体的转发策略由其子类实现。`KafkaForwarder` 实现了通过 Kafka 消息队列进行消息转发的策略。它使用 KafkaProducer 将消息发送到指定的
|
||||
Kafka 主题,并支持 JSON 或 Protobuf 编码。`MemoryForwarder` 则实现了内存队列的转发策略,它依赖于 `AppQueueFactory`
|
||||
创建的内存生产者,将消息直接放入内存队列中。这两种策略的切换完全由配置文件决定。在 `ProtocolBootstrap` 的 `init()`
|
||||
方法中,系统根据配置中的 `ForwarderType`(kafka 或 memory)来实例化相应的 `Forwarder`
|
||||
子类。这种设计极大地提高了系统的灵活性,开发者可以在不修改核心代码的情况下,通过更改配置来切换消息传输机制,例如在开发和测试环境中使用内存队列以简化部署,在生产环境中使用
|
||||
Kafka 以保证可靠性和可扩展性。
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [Forwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/Forwarder.java#L1-L113)
|
||||
- [KafkaForwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/KafkaForwarder.java#L1-L200)
|
||||
- [MemoryForwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/MemoryForwarder.java#L1-L85)
|
||||
|
||||
## 工厂模式
|
||||
|
||||
工厂模式在 JChargePointProtocol 中通过 `AppQueueFactory` 接口及其具体实现类 `KafkaAppQueueFactory` 和
|
||||
`InMemoryAppQueueFactory` 来实现。该模式提供了一种创建对象的接口,但由子类决定实例化哪一个类,从而将对象的创建与使用分离。
|
||||
|
||||
`AppQueueFactory` 是一个简单的工厂接口,它定义了两个方法:`createProtocolUplinkMsgConsumer()` 用于创建上行消息消费者,
|
||||
`createProtocolUplinkMsgProducer(String topic)` 用于创建指定主题的上行消息生产者。这个接口是客户端(如 `ProtocolBootstrap`
|
||||
)获取队列组件的统一入口。
|
||||
|
||||
具体的对象创建逻辑由实现了 `AppQueueFactory` 的工厂类完成。`KafkaAppQueueFactory` 负责创建基于 Kafka 的消费者和生产者。它的
|
||||
`createProtocolUplinkMsgConsumer()` 方法会构建一个 `KafkaConsumerTemplate`,并配置 Kafka 的消费者设置、主题、客户端ID、反序列化器等。类似地,
|
||||
`createProtocolUplinkMsgProducer()` 方法会构建一个 `KafkaProducerTemplate`。`InMemoryAppQueueFactory`
|
||||
则负责创建基于内存的消费者和生产者,它使用一个共享的 `InMemoryStorage` 实例来存储消息。
|
||||
|
||||
这两个工厂类的加载由 Spring 的条件注解 `@ConditionalOnExpression` 控制。当配置项 `queue.type` 为 "kafka" 时,Spring 容器会创建
|
||||
`KafkaAppQueueFactory` 的 Bean;当 `queue.type` 为 "memory" 时,则创建 `InMemoryAppQueueFactory` 的 Bean。`ProtocolContext`
|
||||
类通过依赖注入获得正确的 `AppQueueFactory` 实例。这种工厂模式的使用,使得 `ProtocolBootstrap` 等核心组件完全不知道具体创建的是
|
||||
Kafka 还是内存队列,实现了与具体实现的彻底解耦,简化了代码并提高了可维护性。
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [AppQueueFactory.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/provider/AppQueueFactory.java#L1-L20)
|
||||
- [KafkaAppQueueFactory.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/provider/KafkaAppQueueFactory.java#L1-L84)
|
||||
- [InMemoryAppQueueFactory.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/provider/InMemoryAppQueueFactory.java#L1-L50)
|
||||
- [ProtocolContext.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolContext.java#L1-L65)
|
||||
|
||||
## 六边形架构
|
||||
|
||||
JChargePointProtocol
|
||||
系统清晰地体现了六边形架构(也称为端口和适配器架构)的设计思想。该架构的核心是将系统的核心业务逻辑(领域)与外部系统(如数据库、消息队列、用户界面)分离开来,通过定义明确的“端口”(接口)进行通信,外部系统通过“适配器”来实现这些端口。
|
||||
|
||||
在本系统中,核心领域是协议处理逻辑,它独立于任何特定的传输或存储技术。`ProtocolMessageProcessor` 是核心领域的一个关键组件,它定义了处理上行(
|
||||
`uplinkHandle`)和下行(`doDownlinkHandle`)消息的抽象方法。具体的协议实现(如 `LvnengProtocolMessageProcessor`
|
||||
)继承此类并实现具体的业务逻辑。
|
||||
|
||||
外部适配器则负责与核心领域交互。例如,`TcpListener` 是一个适配器,它监听 TCP 端口,接收来自充电桩的原始字节流。当收到消息后,它通过
|
||||
`ProtocolMessageProcessor` 的端口将消息传递给核心领域进行处理。另一个适配器是 `Forwarder`,它作为核心领域与消息队列(Kafka
|
||||
或内存)之间的桥梁。当核心领域需要将处理结果转发给后端应用时,它调用 `Forwarder` 的 `sendMessage()` 方法,而具体的
|
||||
`KafkaForwarder` 或 `MemoryForwarder` 适配器则负责与实际的消息队列系统进行通信。
|
||||
|
||||
REST 控制器(如 `DownlinkController`)也是一个适配器,它接收来自管理后台的 HTTP
|
||||
请求,将其转换为内部消息,并通过核心领域的端口进行处理。这种架构的优势在于,核心业务逻辑不依赖于任何外部框架或技术。如果需要更换消息队列系统,只需编写一个新的
|
||||
`Forwarder` 适配器并修改配置,而核心的协议处理代码无需改动。这极大地提升了系统的可测试性(可以轻松地为适配器编写模拟对象)和可维护性。
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java#L1-L77)
|
||||
- [LvnengV340LoginULCmd.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340LoginULCmd.java#L1-L120)
|
||||
- [YunKuaiChongV150LoginULCmd.java](file://jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LoginULCmd.java#L1-L84)
|
||||
|
||||
## 设计模式综合类图
|
||||
|
||||
```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 {
|
||||
+PROTOCOL_NAME : String
|
||||
+getProtocolName() : String
|
||||
+_init() : void
|
||||
+_destroy() : void
|
||||
+messageProcessor() : ProtocolMessageProcessor
|
||||
}
|
||||
class Forwarder {
|
||||
+protocolName : String
|
||||
+forwarderMessagesStats : MessagesStats
|
||||
+partitionProvider : PartitionProvider
|
||||
+serviceInfoProvider : ServiceInfoProvider
|
||||
+isMonolith : boolean
|
||||
+producer : QueueProducer
|
||||
+health() : Health
|
||||
+destroy() : void
|
||||
+sendMessage(msg : UplinkQueueMessage) : void
|
||||
+sendMessage(msg : UplinkQueueMessage, consumer : BiConsumer) : void
|
||||
}
|
||||
class KafkaForwarder {
|
||||
+kafkaCfg : KafkaCfg
|
||||
+jcppPartition : boolean
|
||||
+kafkaProducer : KafkaProducer
|
||||
+KafkaForwarder(...)
|
||||
+health() : Health
|
||||
+destroy() : void
|
||||
+sendMessage(...) : void
|
||||
}
|
||||
class MemoryForwarder {
|
||||
+memoryCfg : MemoryCfg
|
||||
+MemoryForwarder(...)
|
||||
+health() : Health
|
||||
+destroy() : void
|
||||
+sendMessage(...) : void
|
||||
}
|
||||
class AppQueueFactory {
|
||||
+createProtocolUplinkMsgConsumer() : QueueConsumer
|
||||
+createProtocolUplinkMsgProducer(topic : String) : QueueProducer
|
||||
}
|
||||
class KafkaAppQueueFactory {
|
||||
+kafkaSettings : KafkaSettings
|
||||
+appSettings : QueueAppSettings
|
||||
+consumerStatsService : KafkaConsumerStatsService
|
||||
+serviceInfoProvider : ServiceInfoProvider
|
||||
+appAdmin : QueueAdmin
|
||||
+KafkaAppQueueFactory(...)
|
||||
+createProtocolUplinkMsgConsumer() : QueueConsumer
|
||||
+createProtocolUplinkMsgProducer(topic : String) : QueueProducer
|
||||
}
|
||||
class InMemoryAppQueueFactory {
|
||||
+storage : InMemoryStorage
|
||||
+appSettings : QueueAppSettings
|
||||
+InMemoryAppQueueFactory(...)
|
||||
+createProtocolUplinkMsgConsumer() : QueueConsumer
|
||||
+createProtocolUplinkMsgProducer(topic : String) : QueueProducer
|
||||
}
|
||||
class ProtocolMessageProcessor {
|
||||
+forwarder : Forwarder
|
||||
+protocolContext : ProtocolContext
|
||||
+uplinkHandleAsync(...) : void
|
||||
+uplinkHandle(...) : void
|
||||
+downlinkHandle(...) : void
|
||||
+doDownlinkHandle(...) : void
|
||||
}
|
||||
ProtocolBootstrap <|-- LvnengV340ProtocolBootstrap : "extends"
|
||||
ProtocolBootstrap o-- Forwarder : "uses"
|
||||
ProtocolBootstrap o-- Listener : "uses"
|
||||
Forwarder <|-- KafkaForwarder : "extends"
|
||||
Forwarder <|-- MemoryForwarder : "extends"
|
||||
AppQueueFactory <|-- KafkaAppQueueFactory : "implements"
|
||||
AppQueueFactory <|-- InMemoryAppQueueFactory : "implements"
|
||||
ProtocolMessageProcessor o-- Forwarder : "uses"
|
||||
ProtocolMessageProcessor o-- ProtocolContext : "uses"
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java)
|
||||
- [LvnengV340ProtocolBootstrap.java](file://jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/LvnengV340ProtocolBootstrap.java)
|
||||
- [Forwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/Forwarder.java)
|
||||
- [KafkaForwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/KafkaForwarder.java)
|
||||
- [MemoryForwarder.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/forwarder/MemoryForwarder.java)
|
||||
- [AppQueueFactory.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/provider/AppQueueFactory.java)
|
||||
- [KafkaAppQueueFactory.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/provider/KafkaAppQueueFactory.java)
|
||||
- [InMemoryAppQueueFactory.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/provider/InMemoryAppQueueFactory.java)
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java)
|
||||
|
||||
## 结论
|
||||
|
||||
JChargePointProtocol
|
||||
通过巧妙地组合使用模板方法模式、策略模式、工厂模式和六边形架构,构建了一个高度模块化、可扩展且易于维护的系统。模板方法模式确保了所有协议服务生命周期的一致性;策略模式提供了消息转发机制的灵活切换;工厂模式实现了对象创建的解耦;而六边形架构则清晰地划分了核心业务逻辑与外部依赖。这些设计模式的协同作用,使得系统能够轻松地支持新的充电桩协议,同时保持核心代码的稳定性和可测试性。这种架构设计为处理复杂、多变的物联网通信场景提供了一个优秀的实践范例。
|
||||
198
docs/架构设计/架构设计.md
Normal file
198
docs/架构设计/架构设计.md
Normal file
@@ -0,0 +1,198 @@
|
||||
# 架构设计
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [jcpp-app-bootstrap/src/main/java/sanbing/jcpp/JCPPServerApplication.java](file://jcpp-app-bootstrap/src/main/java/sanbing/jcpp/JCPPServerApplication.java)
|
||||
- [jcpp-protocol-bootstrap/src/main/java/sanbing/jcpp/protocol/JCPPProtocolServiceApplication.java](file://jcpp-protocol-bootstrap/src/main/java/sanbing/jcpp/protocol/JCPPProtocolServiceApplication.java)
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/BaseController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/BaseController.java)
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java)
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/ProtocolController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/ProtocolController.java)
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java)
|
||||
- [jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java)
|
||||
- [jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java)
|
||||
- [jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaProducerTemplate.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaProducerTemplate.java)
|
||||
- [jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/JCPPRedisCacheConfiguration.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/JCPPRedisCacheConfiguration.java)
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/GrpcDownlinkCallService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/GrpcDownlinkCallService.java)
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/RestDownlinkCallService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/RestDownlinkCallService.java)
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/PileRepository.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/PileRepository.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [简介](#简介)
|
||||
2. [微服务架构划分](#微服务架构划分)
|
||||
3. [六边形架构实现](#六边形架构实现)
|
||||
4. [数据流分析](#数据流分析)
|
||||
5. [系统上下文图](#系统上下文图)
|
||||
6. [组件交互图](#组件交互图)
|
||||
7. [架构决策与权衡](#架构决策与权衡)
|
||||
8. [结论](#结论)
|
||||
|
||||
## 简介
|
||||
|
||||
JChargePointProtocol
|
||||
是一个高性能、分布式、支持海量并发量的充电桩服务端系统,旨在为充电应用提供基础能力。该系统采用微服务架构设计,支持多种充电桩协议(如云快充、绿能等),并通过清晰的职责划分和现代化的技术栈实现高可扩展性和可维护性。本文档详细描述了系统的架构设计,包括微服务划分、六边形架构的实现、数据流处理以及关键的架构决策。
|
||||
|
||||
**本节不涉及具体源文件分析,因此无来源信息**
|
||||
|
||||
## 微服务架构划分
|
||||
|
||||
JChargePointProtocol 系统主要划分为两个核心微服务域:`jcpp-app` 和 `jcpp-protocol-*`,每个服务域都有明确的职责边界。
|
||||
|
||||
`jcpp-app` 服务作为业务逻辑与API网关的核心,负责处理所有与业务相关的操作。它暴露RESTful
|
||||
API接口供前端应用和其他外部系统调用,处理用户认证、权限控制、业务规则验证等横切关注点。该服务还负责与数据库进行交互,执行数据的持久化和查询操作,并通过缓存机制提升系统性能。从架构角度看,
|
||||
`jcpp-app` 是系统的业务中枢,协调各个业务实体(如充电桩、枪口、站点等)的状态和行为。
|
||||
|
||||
`jcpp-protocol-*` 服务域则专注于协议处理的核心功能,包括 `jcpp-protocol-api`、`jcpp-protocol-yunkuaichong`、
|
||||
`jcpp-protocol-lvneng`
|
||||
等模块。这些服务负责处理与充电桩设备的底层通信,解析和生成特定协议格式的报文。它们通过TCP长连接与设备保持通信,处理上行数据的解码和下行指令的编码。这种分离使得协议相关的复杂性被封装在独立的服务中,便于针对不同协议进行独立开发、测试和部署。
|
||||
|
||||
这种架构划分实现了关注点分离的原则:`jcpp-app` 专注于业务领域逻辑,而 `jcpp-protocol-*`
|
||||
专注于通信协议细节。两者通过定义良好的接口(如Kafka消息队列和gRPC调用)进行通信,降低了系统耦合度,提高了可维护性和可扩展性。
|
||||
|
||||
**本节不涉及具体源文件分析,因此无来源信息**
|
||||
|
||||
## 六边形架构实现
|
||||
|
||||
JChargePointProtocol 系统在代码层面体现了六边形架构(端口与适配器)的设计思想,将核心业务逻辑与外部系统依赖进行解耦。
|
||||
|
||||
在该架构中,**控制器(Controller)作为输入适配器**,负责将外部请求适配到内部业务逻辑。例如,`PileController` 类(位于
|
||||
`jcpp-app`
|
||||
模块)作为充电桩管理的输入适配器,接收HTTP请求,将其转换为内部服务方法调用。它处理请求参数的验证、异常的统一处理,并将内部服务的响应转换为HTTP响应格式。这种设计使得核心业务逻辑不受HTTP协议和框架的约束,可以轻松替换或扩展不同的输入方式(如gRPC、消息队列等)。
|
||||
|
||||
**仓库(Repository)作为输出适配器**,负责将内部业务逻辑与数据存储系统进行解耦。例如,`PileRepository`
|
||||
接口定义了访问充电桩数据的契约,而具体的实现类(如 `PileRepositoryImpl`
|
||||
)则负责与MyBatis框架和PostgreSQL数据库进行交互。此外,系统还通过多级缓存(Caffeine本地缓存和Redis分布式缓存)作为另一种输出适配器,
|
||||
`AttributeRedisCache` 和 `PileCaffeineCache` 等类实现了对缓存系统的访问。这种分层设计使得核心业务逻辑无需关心数据存储的具体实现,可以在不影响业务逻辑的情况下更换数据库或缓存方案。
|
||||
|
||||
六边形架构的核心在于将业务逻辑置于中心,所有外部依赖都通过适配器与之交互。这种设计极大地提高了代码的可测试性,因为核心业务逻辑可以在不依赖数据库、网络等外部资源的情况下进行单元测试。同时,它也增强了系统的灵活性,使得系统能够更容易地适应变化,例如支持新的通信协议或更换消息中间件。
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/BaseController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/BaseController.java#L1-L117)
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L1-L112)
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/PileRepository.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/PileRepository.java#L1-L17)
|
||||
|
||||
## 数据流分析
|
||||
|
||||
JChargePointProtocol 系统的数据流设计清晰地分离了上行(uplink)和下行(downlink)两个方向,确保了数据处理的高效性和可靠性。
|
||||
|
||||
### 上行数据流(Uplink)
|
||||
|
||||
上行数据流始于充电桩设备通过TCP连接发送原始报文。`jcpp-protocol-*` 服务中的 `TcpListener` 组件接收这些字节流,并通过
|
||||
`TcpMsgDecoder` 进行解码,将其转换为结构化的 `ProtocolUplinkMsg` 对象。随后,`ProtocolMessageProcessor` 的
|
||||
`uplinkHandleAsync` 方法被调用,该方法在独立的线程池中异步处理上行消息,以避免阻塞IO线程。处理后的业务数据通过Kafka消息队列发布,
|
||||
`jcpp-app` 服务中的 `ProtocolUplinkConsumerService` 作为消费者订阅这些消息,进行业务逻辑处理(如状态更新、计费计算等),最终将结果持久化到PostgreSQL数据库中。
|
||||
|
||||
### 下行数据流(Downlink)
|
||||
|
||||
下行数据流始于 `jcpp-app` 服务中的业务操作,例如用户通过API请求启动充电。`RpcController` 接收该请求,调用
|
||||
`PileProtocolService` 服务。该服务通过内部调用决定使用gRPC还是REST方式与 `jcpp-protocol-*` 服务通信。如果使用gRPC,则
|
||||
`GrpcDownlinkCallService` 被调用,通过 `DownlinkGrpcClient` 发送 `DownlinkRequestMessage`;如果使用REST,则
|
||||
`RestDownlinkCallService` 通过 `RestTemplate` 发送HTTP请求到 `DownlinkController`。`jcpp-protocol-*` 服务接收到下行指令后,
|
||||
`ProtocolMessageProcessor` 的 `doDownlinkHandle` 方法将其编码为特定协议的字节流,并通过TCP通道发送到目标充电桩设备。
|
||||
|
||||
这种基于消息队列和RPC调用的异步通信模式,不仅解耦了业务处理和协议处理,还提供了良好的可伸缩性和容错能力。Kafka作为消息中间件,保证了上行消息的可靠传递和顺序性。
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java#L1-L78)
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java#L1-L197)
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/GrpcDownlinkCallService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/GrpcDownlinkCallService.java#L1-L51)
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/RestDownlinkCallService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/RestDownlinkCallService.java#L1-L64)
|
||||
|
||||
## 系统上下文图
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "外部系统"
|
||||
User[用户]
|
||||
ChargingPile[充电桩设备]
|
||||
end
|
||||
subgraph "JChargePointProtocol系统"
|
||||
subgraph "jcpp-app"
|
||||
APIGateway[API网关]
|
||||
BusinessLogic[业务逻辑]
|
||||
Database[(PostgreSQL)]
|
||||
Cache[(Redis)]
|
||||
end
|
||||
subgraph "jcpp-protocol-*"
|
||||
ProtocolAPI[协议API]
|
||||
Kafka[(Kafka消息队列)]
|
||||
TCP[TCP通信]
|
||||
end
|
||||
end
|
||||
User --> |HTTP/HTTPS| APIGateway
|
||||
APIGateway --> BusinessLogic
|
||||
BusinessLogic --> Database
|
||||
BusinessLogic --> Cache
|
||||
BusinessLogic --> |gRPC/REST| ProtocolAPI
|
||||
ProtocolAPI --> Kafka
|
||||
ChargingPile --> |TCP| TCP
|
||||
TCP --> ProtocolAPI
|
||||
ProtocolAPI --> |发布消息| Kafka
|
||||
Kafka --> |订阅消息| BusinessLogic
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [jcpp-app-bootstrap/src/main/java/sanbing/jcpp/JCPPServerApplication.java](file://jcpp-app-bootstrap/src/main/java/sanbing/jcpp/JCPPServerApplication.java#L1-L55)
|
||||
- [jcpp-protocol-bootstrap/src/main/java/sanbing/jcpp/protocol/JCPPProtocolServiceApplication.java](file://jcpp-protocol-bootstrap/src/main/java/sanbing/jcpp/protocol/JCPPProtocolServiceApplication.java#L1-L59)
|
||||
|
||||
## 组件交互图
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as "用户"
|
||||
participant AppController as "jcpp-app<br/>Controller"
|
||||
participant AppService as "jcpp-app<br/>Service"
|
||||
participant ProtocolAPI as "jcpp-protocol-*<br/>DownlinkController"
|
||||
participant ProtocolProcessor as "jcpp-protocol-*<br/>ProtocolMessageProcessor"
|
||||
participant Device as "充电桩设备"
|
||||
User->>AppController : 发送启动充电请求
|
||||
AppController->>AppService : 调用业务服务
|
||||
AppService->>ProtocolAPI : gRPC/REST调用
|
||||
ProtocolAPI->>ProtocolProcessor : 处理下行指令
|
||||
ProtocolProcessor->>Device : 通过TCP发送协议报文
|
||||
Device-->>ProtocolProcessor : 发送上行响应
|
||||
ProtocolProcessor->>Kafka : 发布上行消息
|
||||
Kafka-->>AppService : 消费上行消息
|
||||
AppService-->>AppController : 返回处理结果
|
||||
AppController-->>User : 返回响应
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java#L1-L197)
|
||||
- [jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/adapter/DownlinkController.java#L1-L76)
|
||||
- [jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java#L1-L78)
|
||||
|
||||
## 架构决策与权衡
|
||||
|
||||
JChargePointProtocol 系统在架构设计上做出了一系列关键决策,这些决策背后体现了对性能、可靠性、可维护性和可扩展性的权衡。
|
||||
|
||||
### 选择Kafka而非RabbitMQ
|
||||
|
||||
系统选择Kafka作为消息中间件,主要基于其在高吞吐量和持久化方面的优势。充电桩系统需要处理海量的上行数据(如实时状态、充电记录等),Kafka的分布式架构和分区机制能够轻松应对每秒数万条消息的吞吐量需求。其基于日志的存储模型提供了强大的消息持久化能力,确保即使在消费者处理失败的情况下,消息也不会丢失。相比之下,RabbitMQ虽然在消息路由和灵活性上更胜一筹,但在处理大规模、高频率的流式数据时,其性能和扩展性可能成为瓶颈。Kafka的“发布-订阅”模型也更符合本系统中“一个上行消息可能被多个下游服务消费”的场景。
|
||||
|
||||
### 多级缓存策略
|
||||
|
||||
系统采用了多级缓存策略(Caffeine +
|
||||
Redis)来平衡性能和一致性。Caffeine作为本地缓存,提供了极低的访问延迟(纳秒级),用于缓存高频访问且不常变更的数据(如充电桩配置)。Redis作为分布式缓存,解决了多实例部署下的数据共享问题。当本地缓存未命中时,系统会查询Redis。这种设计显著减少了对数据库的直接访问,提升了系统整体性能。然而,这也引入了缓存一致性挑战。系统通过事件驱动的方式(如
|
||||
`AttributeCacheEvictEvent`)来处理缓存失效,当数据在数据库中被更新时,会发布缓存清除事件,通知所有节点清除本地缓存,从而在一定程度上保证了数据的一致性。这种权衡是在极致性能和强一致性之间找到的平衡点。
|
||||
|
||||
### gRPC与REST的并存
|
||||
|
||||
系统同时支持gRPC和REST两种服务间通信方式,通过配置项 `service.downlink.rpc.type`
|
||||
进行动态切换。这为系统部署提供了灵活性:在对性能要求极高的内部网络中,可以选择高效的二进制协议gRPC;而在需要与外部系统集成或调试时,可以选择更通用的RESTful
|
||||
API。这种设计虽然增加了实现的复杂性(需要维护两套客户端),但极大地提升了系统的适应性和可集成性。
|
||||
|
||||
**本节不涉及具体源文件分析,因此无来源信息**
|
||||
|
||||
## 结论
|
||||
|
||||
JChargePointProtocol 系统通过清晰的微服务划分、六边形架构的实践、高效的数据流设计以及深思熟虑的架构决策,构建了一个高性能、高可扩展且易于维护的充电桩服务端平台。
|
||||
`jcpp-app` 和 `jcpp-protocol-*`
|
||||
服务域的职责分离,确保了业务逻辑与协议细节的解耦。六边形架构的实现使得核心业务逻辑独立于外部框架和依赖。基于Kafka的消息队列和多级缓存策略有效解决了海量数据处理和性能瓶颈问题。整体架构设计充分考虑了实际业务场景的需求,在性能、可靠性、可维护性之间取得了良好的平衡,为支持更多充电桩协议和更大规模的部署奠定了坚实的基础。
|
||||
|
||||
**本节不涉及具体源文件分析,因此无来源信息**
|
||||
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)
|
||||
538
docs/消息队列集成.md
Normal file
538
docs/消息队列集成.md
Normal file
@@ -0,0 +1,538 @@
|
||||
# 消息队列集成
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [KafkaAppQueueFactory.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/provider/KafkaAppQueueFactory.java)
|
||||
- [AppQueueFactory.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/provider/AppQueueFactory.java)
|
||||
- [KafkaConsumerTemplate.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaConsumerTemplate.java)
|
||||
- [KafkaProducerTemplate.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaProducerTemplate.java)
|
||||
- [ProtocolUplinkConsumerService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java)
|
||||
- [KafkaSettings.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaSettings.java)
|
||||
- [KafkaTopicConfigs.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaTopicConfigs.java)
|
||||
- [ProtoQueueMsg.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/ProtoQueueMsg.java)
|
||||
- [DefaultQueueMsgHeaders.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/DefaultQueueMsgHeaders.java)
|
||||
- [QueueAppSettings.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/settings/QueueAppSettings.java)
|
||||
- [KafkaConsumerStatsService.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaConsumerStatsService.java)
|
||||
- [ProtocolUplinkMsg.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/ProtocolUplinkMsg.java)
|
||||
- [uplink.proto](file://jcpp-infrastructure-proto/src/main/proto/uplink.proto)
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml)
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [引言](#引言)
|
||||
2. [系统架构概述](#系统架构概述)
|
||||
3. [Kafka作为核心消息中间件的选择](#kafka作为核心消息中间件的选择)
|
||||
4. [KafkaAppQueueFactory设计与实现](#kafkaappqueuefactory设计与实现)
|
||||
5. [ProtocolUplinkConsumerService详解](#protocoluplinkconsumerservice详解)
|
||||
6. [消息序列化与格式](#消息序列化与格式)
|
||||
7. [消息可靠性保证机制](#消息可靠性保证机制)
|
||||
8. [Kafka主题配置与管理](#kafka主题配置与管理)
|
||||
9. [监控与性能指标](#监控与性能指标)
|
||||
10. [故障处理与最佳实践](#故障处理与最佳实践)
|
||||
11. [总结](#总结)
|
||||
|
||||
## 引言
|
||||
|
||||
JChargePointProtocol系统采用Kafka作为核心消息中间件,构建了一个高可用、高性能的消息队列集成架构。该系统通过消息队列实现了协议处理服务和业务应用服务之间的解耦,确保了系统的可扩展性和可靠性。
|
||||
|
||||
本文档详细阐述了系统如何选择Kafka作为消息中间件,以及Kafka在整体架构中的关键作用,包括消息的生产、消费、序列化、可靠性保证等各个方面。
|
||||
|
||||
## 系统架构概述
|
||||
|
||||
系统采用分层架构设计,通过消息队列实现不同服务组件之间的解耦:
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "协议处理层"
|
||||
PC[协议客户端<br/>TCP连接]
|
||||
PL[协议监听器<br/>TcpListener]
|
||||
PM[协议消息处理器<br/>ProtocolMessageProcessor]
|
||||
PF[协议转发器<br/>Forwarder]
|
||||
end
|
||||
subgraph "消息队列层"
|
||||
KQF[KafkaAppQueueFactory]
|
||||
KP[KafkaProducerTemplate]
|
||||
KC[KafkaConsumerTemplate]
|
||||
KT[Kafka主题<br/>protocol_uplink]
|
||||
end
|
||||
subgraph "业务应用层"
|
||||
PUCS[ProtocolUplinkConsumerService]
|
||||
PS[业务处理器<br/>PileProtocolService]
|
||||
AS[应用服务<br/>其他服务]
|
||||
end
|
||||
PC --> PL
|
||||
PL --> PM
|
||||
PM --> PF
|
||||
PF --> KQF
|
||||
KQF --> KP
|
||||
KP --> KT
|
||||
KT --> KC
|
||||
KC --> PUCS
|
||||
PUCS --> PS
|
||||
PS --> AS
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [KafkaAppQueueFactory.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/provider/KafkaAppQueueFactory.java#L20-L85)
|
||||
- [ProtocolUplinkConsumerService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java#L40-L100)
|
||||
|
||||
## Kafka作为核心消息中间件的选择
|
||||
|
||||
### 选择Kafka的核心原因
|
||||
|
||||
1. **高吞吐量和低延迟**:Kafka能够处理每秒数百万条消息,满足充电桩高频数据传输需求
|
||||
2. **持久化存储**:消息持久化保证数据不丢失,支持离线处理和重放
|
||||
3. **分布式架构**:天然支持水平扩展,适应大规模部署需求
|
||||
4. **分区和副本机制**:提供高可用性和数据冗余
|
||||
5. **流式处理能力**:支持实时数据处理和分析
|
||||
|
||||
### 解耦协议处理和服务业务
|
||||
|
||||
Kafka在系统中扮演着关键的解耦角色:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant P as 协议处理服务
|
||||
participant K as Kafka队列
|
||||
participant A as 应用业务服务
|
||||
P->>K : 生产消息充电桩上行数据
|
||||
Note over P,K : 异步处理,无需等待
|
||||
K->>K : 持久化存储
|
||||
K->>A : 消费消息
|
||||
A->>A : 处理业务逻辑
|
||||
A->>K : 确认消费成功
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [KafkaProducerTemplate.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaProducerTemplate.java#L70-L100)
|
||||
- [KafkaConsumerTemplate.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaConsumerTemplate.java#L50-L80)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [KafkaAppQueueFactory.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/provider/KafkaAppQueueFactory.java#L20-L30)
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml#L107-L156)
|
||||
|
||||
## KafkaAppQueueFactory设计与实现
|
||||
|
||||
### 工厂模式的应用
|
||||
|
||||
KafkaAppQueueFactory实现了AppQueueFactory接口,提供了Kafka相关队列组件的创建功能:
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class AppQueueFactory {
|
||||
<<interface>>
|
||||
+createProtocolUplinkMsgConsumer() QueueConsumer
|
||||
+createProtocolUplinkMsgProducer(String) QueueProducer
|
||||
}
|
||||
class KafkaAppQueueFactory {
|
||||
-KafkaSettings kafkaSettings
|
||||
-QueueAppSettings appSettings
|
||||
-KafkaConsumerStatsService consumerStatsService
|
||||
-ServiceInfoProvider serviceInfoProvider
|
||||
-QueueAdmin appAdmin
|
||||
+createProtocolUplinkMsgConsumer() QueueConsumer
|
||||
+createProtocolUplinkMsgProducer(String) QueueProducer
|
||||
-destroy() void
|
||||
}
|
||||
class KafkaConsumerTemplate {
|
||||
-KafkaConsumer consumer
|
||||
-KafkaDecoder decoder
|
||||
-KafkaConsumerStatsService statsService
|
||||
-String groupId
|
||||
+decode(ConsumerRecord) T
|
||||
+doPoll(long) List
|
||||
+doCommit() void
|
||||
}
|
||||
class KafkaProducerTemplate {
|
||||
-KafkaProducer producer
|
||||
-String topic
|
||||
-String clientId
|
||||
-QueueAdmin admin
|
||||
+send(TopicPartitionInfo, T, QueueCallback) void
|
||||
+addAnalyticHeaders(List) void
|
||||
}
|
||||
AppQueueFactory <|-- KafkaAppQueueFactory
|
||||
KafkaAppQueueFactory --> KafkaConsumerTemplate
|
||||
KafkaAppQueueFactory --> KafkaProducerTemplate
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [AppQueueFactory.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/provider/AppQueueFactory.java#L12-L20)
|
||||
- [KafkaAppQueueFactory.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/provider/KafkaAppQueueFactory.java#L20-L85)
|
||||
|
||||
### 生产者和消费者的创建
|
||||
|
||||
#### ProtocolUplinkMsgConsumer的创建
|
||||
|
||||
KafkaAppQueueFactory根据配置创建ProtocolUplinkMsgConsumer,支持多种解码方式:
|
||||
|
||||
- **Protobuf解码**:默认方式,高效且类型安全
|
||||
- **JSON解码**:兼容性更好,便于调试
|
||||
|
||||
#### ProtocolUplinkMsgProducer的创建
|
||||
|
||||
生产者负责将消息发送到指定的Kafka主题,支持动态主题切换和批量发送优化。
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [KafkaAppQueueFactory.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/provider/KafkaAppQueueFactory.java#L35-L85)
|
||||
- [QueueAppSettings.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/settings/QueueAppSettings.java#L15-L32)
|
||||
|
||||
## ProtocolUplinkConsumerService详解
|
||||
|
||||
### 消费者服务的核心职责
|
||||
|
||||
ProtocolUplinkConsumerService是系统中处理充电桩上行消息的主要组件,负责:
|
||||
|
||||
1. **消息订阅**:订阅Kafka主题,接收来自协议处理服务的消息
|
||||
2. **消息分发**:根据消息类型将消息路由到相应的业务处理器
|
||||
3. **并发处理**:支持多线程并发处理提高吞吐量
|
||||
4. **错误处理**:提供完善的异常处理和重试机制
|
||||
|
||||
### 消息处理流程
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始消费]) --> Poll[Poll消息]
|
||||
Poll --> Decode[解码消息]
|
||||
Decode --> Validate{消息验证}
|
||||
Validate --> |有效| Process[处理消息]
|
||||
Validate --> |无效| Error[记录错误]
|
||||
Process --> Route{路由判断}
|
||||
Route --> |登录请求| Login[处理登录]
|
||||
Route --> |心跳| Heartbeat[处理心跳]
|
||||
Route --> |充电状态| Charge[处理充电状态]
|
||||
Route --> |其他| Other[处理其他类型]
|
||||
Login --> Callback[回调处理]
|
||||
Heartbeat --> Callback
|
||||
Charge --> Callback
|
||||
Other --> Callback
|
||||
Callback --> Commit[提交偏移量]
|
||||
Error --> Commit
|
||||
Commit --> End([结束])
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [ProtocolUplinkConsumerService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java#L150-L250)
|
||||
|
||||
### 消息路由机制
|
||||
|
||||
ProtocolUplinkConsumerService根据消息内容的不同类型调用相应的业务处理器:
|
||||
|
||||
| 消息类型 | 处理方法 | 功能描述 |
|
||||
|-----------------------------|-------------------------------|-----------|
|
||||
| LoginRequest | pileLogin | 处理充电桩登录请求 |
|
||||
| HeartBeatRequest | heartBeat | 处理心跳检测 |
|
||||
| ChargingProgressProto | postChargingProgress | 处理充电进度信息 |
|
||||
| TransactionRecordRequest | onTransactionRecordRequest | 处理交易记录 |
|
||||
| BmsChargingErrorProto | onBmsChargingErrorProto | 处理BMS充电错误 |
|
||||
| RemoteStartChargingResponse | onRemoteStartChargingResponse | 处理远程启动响应 |
|
||||
|
||||
### 并发处理与性能优化
|
||||
|
||||
系统采用多线程并发处理机制:
|
||||
|
||||
- **消费者线程池**:支持按分区创建独立的消费者线程
|
||||
- **消息批处理**:支持批量处理提高吞吐量
|
||||
- **超时控制**:防止长时间阻塞影响系统性能
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [ProtocolUplinkConsumerService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java#L80-L150)
|
||||
- [ProtocolUplinkConsumerService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java#L250-L350)
|
||||
|
||||
## 消息序列化与格式
|
||||
|
||||
### Protobuf序列化
|
||||
|
||||
系统主要采用Google Protobuf进行消息序列化,具有以下优势:
|
||||
|
||||
1. **高效压缩**:二进制格式,传输效率高
|
||||
2. **类型安全**:强类型定义,减少运行时错误
|
||||
3. **向前兼容**:支持协议版本演进
|
||||
4. **跨语言支持**:Java、Python、Go等多种语言支持
|
||||
|
||||
### UplinkQueueMessage结构
|
||||
|
||||
消息格式定义在Protocol Buffer中,包含以下核心字段:
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class UplinkQueueMessage {
|
||||
+int64 messageIdMSB
|
||||
+int64 messageIdLSB
|
||||
+int64 sessionIdMSB
|
||||
+int64 sessionIdLSB
|
||||
+string messageKey
|
||||
+string protocolName
|
||||
+int64 ts
|
||||
+bytes requestData
|
||||
+LoginRequest loginRequest
|
||||
+HeartBeatRequest heartBeatRequest
|
||||
+ChargingProgressProto chargingProgressProto
|
||||
+TransactionRecordRequest transactionRecordRequest
|
||||
+其他消息类型...
|
||||
}
|
||||
class LoginRequest {
|
||||
+string pileCode
|
||||
+string credential
|
||||
+string remoteAddress
|
||||
+string nodeId
|
||||
+string nodeHostAddress
|
||||
+int32 nodeRestPort
|
||||
+int32 nodeGrpcPort
|
||||
}
|
||||
class ChargingProgressProto {
|
||||
+string pileCode
|
||||
+string gunNo
|
||||
+string tradeNo
|
||||
+string outputVoltage
|
||||
+string outputCurrent
|
||||
+int32 soc
|
||||
+int32 totalChargingDurationMin
|
||||
+string totalChargingEnergyKWh
|
||||
+string totalChargingCostYuan
|
||||
}
|
||||
UplinkQueueMessage --> LoginRequest
|
||||
UplinkQueueMessage --> ChargingProgressProto
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [uplink.proto](file://jcpp-infrastructure-proto/src/main/proto/uplink.proto#L10-L40)
|
||||
- [ProtoQueueMsg.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/ProtoQueueMsg.java#L10-L43)
|
||||
|
||||
### 消息头(Headers)的使用
|
||||
|
||||
系统通过消息头传递元数据信息:
|
||||
|
||||
- **追踪信息**:用于分布式追踪和日志关联
|
||||
- **统计信息**:性能监控和分析
|
||||
- **路由信息**:消息路由和过滤
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [ProtoQueueMsg.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/ProtoQueueMsg.java#L10-L43)
|
||||
- [DefaultQueueMsgHeaders.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/DefaultQueueMsgHeaders.java#L10-L31)
|
||||
|
||||
## 消息可靠性保证机制
|
||||
|
||||
### ACK机制
|
||||
|
||||
Kafka提供了多层次的确认机制:
|
||||
|
||||
1. **生产者确认**:
|
||||
- `acks=all`:所有副本都确认
|
||||
- `acks=1`:Leader确认
|
||||
- `acks=0`:不等待确认
|
||||
|
||||
2. **消费者确认**:
|
||||
- 手动提交:处理完成后手动确认
|
||||
- 自动提交:配置自动提交偏移量
|
||||
|
||||
### 重试策略
|
||||
|
||||
系统实现了多层次的重试机制:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Send[发送消息] --> Success{发送成功?}
|
||||
Success --> |是| Complete[完成]
|
||||
Success --> |否| Retry{重试次数检查}
|
||||
Retry --> |未超限| Delay[延迟重试]
|
||||
Retry --> |已超限| DLQ[死信队列]
|
||||
Delay --> Backoff[指数退避]
|
||||
Backoff --> Send
|
||||
DLQ --> Manual[人工干预]
|
||||
```
|
||||
|
||||
### 死信队列(DLQ)处理
|
||||
|
||||
对于无法正常处理的消息,系统提供死信队列机制:
|
||||
|
||||
- **自动转移**:达到最大重试次数后自动转移到DLQ
|
||||
- **人工干预**:提供专门的工具和界面处理DLQ消息
|
||||
- **监控告警**:DLQ消息数量超过阈值时触发告警
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [KafkaSettings.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaSettings.java#L50-L60)
|
||||
- [KafkaProducerTemplate.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaProducerTemplate.java#L90-L120)
|
||||
|
||||
## Kafka主题配置与管理
|
||||
|
||||
### 主题配置
|
||||
|
||||
系统使用统一的主题命名规范和配置策略:
|
||||
|
||||
| 配置项 | 默认值 | 说明 |
|
||||
|--------|-----------------|----------|
|
||||
| 主题名称 | protocol_uplink | 标准主题名称 |
|
||||
| 分区数 | 10 | 支持水平扩展 |
|
||||
| 副本因子 | 1 | 生产环境建议≥3 |
|
||||
| 保留时间 | 86400000ms | 24小时 |
|
||||
| 分段大小 | 52428800B | 50MB |
|
||||
| 最大保留大小 | 1048576000B | 1GB |
|
||||
|
||||
### KafkaAdmin管理
|
||||
|
||||
系统通过KafkaAdmin类提供主题管理功能:
|
||||
|
||||
- **自动创建主题**:首次使用时自动创建主题
|
||||
- **配置验证**:检查主题配置的有效性
|
||||
- **分区管理**:支持动态调整分区数量
|
||||
|
||||
### 配置示例
|
||||
|
||||
```yaml
|
||||
queue:
|
||||
kafka:
|
||||
topic-properties:
|
||||
app: "retention.ms:86400000;segment.bytes:52428800;retention.bytes:1048576000;partitions:10;min.insync.replicas:1"
|
||||
```
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [KafkaTopicConfigs.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaTopicConfigs.java#L20-L34)
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml#L140-L145)
|
||||
|
||||
## 监控与性能指标
|
||||
|
||||
### 消费延迟监控
|
||||
|
||||
系统提供了完善的监控指标体系:
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph "监控指标"
|
||||
A[消费延迟]
|
||||
B[消息吞吐量]
|
||||
C[错误率]
|
||||
D[分区偏移量]
|
||||
E[消费者组状态]
|
||||
end
|
||||
subgraph "监控工具"
|
||||
F[KafkaConsumerStatsService]
|
||||
G[日志系统]
|
||||
H[指标收集]
|
||||
end
|
||||
A --> F
|
||||
B --> F
|
||||
C --> F
|
||||
D --> F
|
||||
E --> F
|
||||
F --> G
|
||||
F --> H
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [KafkaConsumerStatsService.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaConsumerStatsService.java#L40-L80)
|
||||
|
||||
### 关键性能指标
|
||||
|
||||
1. **消费延迟**:消息从生产到消费的时间差
|
||||
2. **处理速率**:每秒处理的消息数量
|
||||
3. **错误率**:处理失败的消息比例
|
||||
4. **分区平衡**:各分区的负载分布情况
|
||||
|
||||
### 监控配置
|
||||
|
||||
```yaml
|
||||
queue:
|
||||
kafka:
|
||||
consumer-stats:
|
||||
enabled: true
|
||||
print-interval-ms: 60000
|
||||
kafka-response-timeout-ms: 1000
|
||||
app:
|
||||
stats:
|
||||
enabled: true
|
||||
print-interval-ms: 60000
|
||||
timer-top-n: 5
|
||||
```
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [KafkaConsumerStatsService.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaConsumerStatsService.java#L30-L50)
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml#L145-L150)
|
||||
|
||||
## 故障处理与最佳实践
|
||||
|
||||
### 常见故障场景
|
||||
|
||||
1. **网络分区**:Kafka集群网络中断
|
||||
2. **消费者组失效**:消费者进程异常退出
|
||||
3. **消息积压**:消费速度跟不上生产速度
|
||||
4. **数据损坏**:消息格式错误或损坏
|
||||
|
||||
### 故障恢复策略
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Detect[检测故障] --> Classify{故障分类}
|
||||
Classify --> |网络问题| Network[网络恢复]
|
||||
Classify --> |消费者故障| Consumer[重启消费者]
|
||||
Classify --> |数据问题| Data[数据修复]
|
||||
Classify --> |系统故障| System[系统恢复]
|
||||
Network --> Verify[验证恢复]
|
||||
Consumer --> Verify
|
||||
Data --> Verify
|
||||
System --> Verify
|
||||
Verify --> Success{恢复成功?}
|
||||
Success --> |是| Monitor[持续监控]
|
||||
Success --> |否| Escalate[升级处理]
|
||||
```
|
||||
|
||||
### 最佳实践建议
|
||||
|
||||
1. **配置优化**:
|
||||
- 合理设置分区数量
|
||||
- 配置合适的副本因子
|
||||
- 优化网络和磁盘IO
|
||||
|
||||
2. **监控告警**:
|
||||
- 设置关键指标阈值
|
||||
- 建立自动化告警机制
|
||||
- 准备应急预案
|
||||
|
||||
3. **运维管理**:
|
||||
- 定期备份重要数据
|
||||
- 制定灾难恢复计划
|
||||
- 进行定期演练
|
||||
|
||||
### 性能调优指南
|
||||
|
||||
| 参数 | 推荐值 | 说明 |
|
||||
|----------------------|-----------|-----------|
|
||||
| max.poll.records | 8192 | 单次拉取最大记录数 |
|
||||
| fetch.max.bytes | 134217728 | 单次拉取最大字节数 |
|
||||
| session.timeout.ms | 10000 | 消费者会话超时时间 |
|
||||
| max.poll.interval.ms | 300000 | 最大拉取间隔 |
|
||||
| linger.ms | 1 | 发送延迟时间 |
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [KafkaSettings.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaSettings.java#L80-L120)
|
||||
- [ProtocolUplinkConsumerService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java#L50-L80)
|
||||
|
||||
## 总结
|
||||
|
||||
JChargePointProtocol系统通过精心设计的消息队列集成方案,实现了协议处理服务和业务应用服务之间的高效解耦。Kafka作为核心消息中间件,不仅提供了高吞吐量、低延迟的消息传递能力,还通过其丰富的功能特性确保了系统的可靠性和可扩展性。
|
||||
|
||||
系统的关键优势包括:
|
||||
|
||||
1. **架构解耦**:通过消息队列实现服务间的松耦合
|
||||
2. **高可靠性**:多重确认机制和容错处理
|
||||
3. **高性能**:优化的序列化格式和并发处理
|
||||
4. **可观测性**:完善的监控和诊断能力
|
||||
5. **可扩展性**:支持水平扩展和动态配置
|
||||
|
||||
这种设计模式为大型分布式系统提供了可靠的基础设施支撑,特别适合充电桩等IoT设备密集的场景。通过持续的监控和优化,系统能够稳定运行在高并发环境下,为业务发展提供坚实的技术保障。
|
||||
631
docs/监控与运维.md
Normal file
631
docs/监控与运维.md
Normal file
@@ -0,0 +1,631 @@
|
||||
# JChargePointProtocol 监控与运维手册
|
||||
|
||||
<cite>
|
||||
**本文档中引用的文件**
|
||||
- [log4j2.xml](file://jcpp-app-bootstrap/src/main/resources/log4j2.xml)
|
||||
- [log4j2.xml](file://jcpp-protocol-bootstrap/src/main/resources/log4j2.xml)
|
||||
- [DefaultStatsFactory.java](file://jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/DefaultStatsFactory.java)
|
||||
- [DefaultCounter.java](file://jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/DefaultCounter.java)
|
||||
- [StatsTimer.java](file://jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/StatsTimer.java)
|
||||
- [MessagesStats.java](file://jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/MessagesStats.java)
|
||||
- [DefaultMessagesStats.java](file://jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/DefaultMessagesStats.java)
|
||||
- [KafkaConsumerStatsService.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaConsumerStatsService.java)
|
||||
- [SystemUtil.java](file://jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/SystemUtil.java)
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml)
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml)
|
||||
- [docker-compose.kafka.yml](file://docker/docker-compose.kafka.yml)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [概述](#概述)
|
||||
2. [日志管理系统](#日志管理系统)
|
||||
3. [性能监控体系](#性能监控体系)
|
||||
4. [消息队列监控](#消息队列监控)
|
||||
5. [系统资源监控](#系统资源监控)
|
||||
6. [故障排查指南](#故障排查指南)
|
||||
7. [运维最佳实践](#运维最佳实践)
|
||||
8. [监控集成方案](#监控集成方案)
|
||||
|
||||
## 概述
|
||||
|
||||
JChargePointProtocol是一个高性能的充电站协议处理平台,采用微服务架构设计,支持多种充电设备协议的接入和处理。本手册详细介绍了系统的监控与运维机制,帮助运维人员有效监控系统状态、及时发现和解决问题。
|
||||
|
||||
## 日志管理系统
|
||||
|
||||
### Log4j2配置详解
|
||||
|
||||
系统采用Log4j2作为日志框架,提供了灵活的日志配置和强大的日志管理能力。
|
||||
|
||||
#### 配置结构分析
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A["Log4j2配置"] --> B["属性配置"]
|
||||
A --> C["Appender配置"]
|
||||
A --> D["Logger配置"]
|
||||
B --> B1["LOG_DIR - 日志目录"]
|
||||
B --> B2["LOG_PATTERN - 输出格式"]
|
||||
C --> C1["Console - 控制台输出"]
|
||||
C --> C2["RollingFile - 文件轮转"]
|
||||
D --> D1["Root Logger"]
|
||||
D --> D2["Async Logger"]
|
||||
D --> D3["业务模块Logger"]
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [log4j2.xml](file://jcpp-app-bootstrap/src/main/resources/log4j2.xml#L1-L72)
|
||||
- [log4j2.xml](file://jcpp-protocol-bootstrap/src/main/resources/log4j2.xml#L1-L66)
|
||||
|
||||
#### 日志级别配置
|
||||
|
||||
系统支持多层级的日志级别配置:
|
||||
|
||||
| Logger名称 | 默认级别 | 环境变量 | 用途 |
|
||||
|-----------------------|-------|---------------------|---------|
|
||||
| Root Logger | INFO | - | 全局基础日志 |
|
||||
| sanbing.jcpp | INFO | - | 核心框架日志 |
|
||||
| sanbing.jcpp.app | TRACE | APP_LOG_LEVEL | 应用层详细日志 |
|
||||
| sanbing.jcpp.protocol | TRACE | PROTOCOLS_LOG_LEVEL | 协议处理日志 |
|
||||
|
||||
#### 输出格式配置
|
||||
|
||||
日志输出格式包含以下关键信息:
|
||||
|
||||
- 时间戳:精确到毫秒
|
||||
- TraceId:分布式追踪标识
|
||||
- 线程名:便于问题定位
|
||||
- 日志级别:ERROR、WARN、INFO、DEBUG
|
||||
- 类名:类的简短名称
|
||||
- 日志消息:实际日志内容
|
||||
- 异常堆栈:完整异常信息
|
||||
|
||||
#### 日志轮转策略
|
||||
|
||||
系统采用复合轮转策略:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["日志文件"] --> B{"文件大小检查"}
|
||||
B --> |超过1GB| C["触发SizeBasedTriggeringPolicy"]
|
||||
B --> |时间检查| D{"时间轮转检查"}
|
||||
D --> |超过24小时| E["触发TimeBasedTriggeringPolicy"]
|
||||
C --> F["执行文件轮转"]
|
||||
E --> F
|
||||
F --> G["删除超过10GB历史日志"]
|
||||
G --> H["保留最新日志文件"]
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [log4j2.xml](file://jcpp-app-bootstrap/src/main/resources/log4j2.xml#L25-L45)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [log4j2.xml](file://jcpp-app-bootstrap/src/main/resources/log4j2.xml#L1-L72)
|
||||
- [log4j2.xml](file://jcpp-protocol-bootstrap/src/main/resources/log4j2.xml#L1-L66)
|
||||
|
||||
## 性能监控体系
|
||||
|
||||
### StatsFactory核心架构
|
||||
|
||||
系统通过StatsFactory提供统一的性能指标收集机制,支持多种监控指标类型。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class StatsFactory {
|
||||
<<interface>>
|
||||
+createStatsCounter(key, statsName, tags) StatsCounter
|
||||
+createDefaultCounter(key, tags) DefaultCounter
|
||||
+createMessagesStats(key, tags) MessagesStats
|
||||
+createTimer(key, tags) Timer
|
||||
+createGauge(key, number, tags) T
|
||||
}
|
||||
class DefaultStatsFactory {
|
||||
-MeterRegistry meterRegistry
|
||||
-Boolean metricsEnabled
|
||||
-Double[] timerPercentiles
|
||||
+createStatsCounter() StatsCounter
|
||||
+createDefaultCounter() DefaultCounter
|
||||
+createMessagesStats() MessagesStats
|
||||
+createTimer() Timer
|
||||
+createGauge() T
|
||||
}
|
||||
class StatsCounter {
|
||||
-AtomicInteger counter
|
||||
-Counter micrometerCounter
|
||||
+increment() void
|
||||
+add(delta) void
|
||||
+get() int
|
||||
+clear() void
|
||||
}
|
||||
class MessagesStats {
|
||||
<<interface>>
|
||||
+incrementTotal() void
|
||||
+incrementSuccessful() void
|
||||
+incrementFailed() void
|
||||
+getTotal() int
|
||||
+getSuccessful() int
|
||||
+getFailed() int
|
||||
+reset() void
|
||||
}
|
||||
class StatsTimer {
|
||||
-String name
|
||||
-Timer timer
|
||||
-int count
|
||||
-long totalTime
|
||||
+record(timeMs) void
|
||||
+getAvg() double
|
||||
+reset() void
|
||||
}
|
||||
StatsFactory <|-- DefaultStatsFactory
|
||||
DefaultStatsFactory --> StatsCounter
|
||||
DefaultStatsFactory --> MessagesStats
|
||||
DefaultStatsFactory --> StatsTimer
|
||||
MessagesStats <|-- DefaultMessagesStats
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [DefaultStatsFactory.java](file://jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/DefaultStatsFactory.java#L1-L127)
|
||||
- [DefaultCounter.java](file://jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/DefaultCounter.java#L1-L40)
|
||||
- [MessagesStats.java](file://jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/MessagesStats.java#L1-L36)
|
||||
- [StatsTimer.java](file://jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/StatsTimer.java#L1-L47)
|
||||
|
||||
### 关键性能指标
|
||||
|
||||
#### API请求监控
|
||||
|
||||
系统通过StatsTimer跟踪API请求的延迟性能:
|
||||
|
||||
| 指标名称 | 计算方式 | 用途 |
|
||||
|--------|------------------------------|----------|
|
||||
| 平均响应时间 | totalTime / count | 评估系统响应性能 |
|
||||
| 请求总数 | 累计计数 | 监控系统负载 |
|
||||
| 成功率 | successfulCount / totalCount | 评估系统稳定性 |
|
||||
|
||||
#### QPS监控
|
||||
|
||||
通过DefaultCounter实现每秒查询率统计:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as 客户端
|
||||
participant Controller as 控制器
|
||||
participant StatsFactory as 统计工厂
|
||||
participant Counter as 计数器
|
||||
Client->>Controller : 发送请求
|
||||
Controller->>StatsFactory : 创建计数器
|
||||
StatsFactory->>Counter : increment()
|
||||
Counter->>Counter : 原子递增
|
||||
Controller->>Controller : 处理业务逻辑
|
||||
Controller-->>Client : 返回响应
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [DefaultCounter.java](file://jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/DefaultCounter.java#L20-L35)
|
||||
|
||||
#### 缓存命中率监控
|
||||
|
||||
系统通过缓存访问统计计算命中率:
|
||||
|
||||
| 指标 | 计算公式 | 监控意义 |
|
||||
|-------|-----------------------------------|--------|
|
||||
| 命中率 | hitCount / (hitCount + missCount) | 缓存效率评估 |
|
||||
| 命中次数 | hitCounter.get() | 缓存有效性 |
|
||||
| 未命中次数 | missCounter.get() | 缓存优化方向 |
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [DefaultStatsFactory.java](file://jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/DefaultStatsFactory.java#L1-L127)
|
||||
- [DefaultCounter.java](file://jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/DefaultCounter.java#L1-L40)
|
||||
- [StatsTimer.java](file://jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/StatsTimer.java#L1-L47)
|
||||
- [MessagesStats.java](file://jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/MessagesStats.java#L1-L36)
|
||||
- [DefaultMessagesStats.java](file://jcpp-infrastructure-stats/src/main/java/sanbing/jcpp/infrastructure/stats/DefaultMessagesStats.java#L1-L57)
|
||||
|
||||
## 消息队列监控
|
||||
|
||||
### Kafka消费者统计
|
||||
|
||||
系统提供详细的Kafka消费者组监控功能,实时跟踪消息处理状态。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["KafkaConsumerStatsService"] --> B["消费者组注册"]
|
||||
B --> C["定时统计任务"]
|
||||
C --> D["获取消费者偏移量"]
|
||||
D --> E["获取主题末尾偏移量"]
|
||||
E --> F["计算消息滞后量"]
|
||||
F --> G{"存在滞后消息?"}
|
||||
G --> |是| H["记录滞后统计"]
|
||||
G --> |否| I["跳过统计"]
|
||||
H --> J["输出日志"]
|
||||
I --> K["等待下次调度"]
|
||||
J --> K
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [KafkaConsumerStatsService.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaConsumerStatsService.java#L40-L100)
|
||||
|
||||
#### 消息滞后监控指标
|
||||
|
||||
| 指标名称 | 含义 | 监控阈值建议 |
|
||||
|--------|-------------|-----------|
|
||||
| 消费者组ID | Kafka消费者组标识 | 实时监控 |
|
||||
| 主题名称 | 消息主题 | 按业务划分 |
|
||||
| 分区编号 | Kafka分区标识 | 单分区监控 |
|
||||
| 已消费偏移量 | 当前消费位置 | 跟踪消费进度 |
|
||||
| 末尾偏移量 | 主题最新消息位置 | 监控消息增长 |
|
||||
| 消息滞后量 | 未消费消息数量 | 超过1000需关注 |
|
||||
|
||||
#### 消费者组健康检查
|
||||
|
||||
系统自动监控消费者组的健康状态:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Scheduler as 统计调度器
|
||||
participant AdminClient as Kafka管理客户端
|
||||
participant Consumer as Kafka消费者
|
||||
participant Logger as 日志系统
|
||||
Scheduler->>AdminClient : 获取消费者组偏移量
|
||||
AdminClient-->>Scheduler : 返回偏移量信息
|
||||
Scheduler->>Consumer : 获取主题末尾偏移量
|
||||
Consumer-->>Scheduler : 返回末尾偏移量
|
||||
Scheduler->>Scheduler : 计算消息滞后量
|
||||
alt 存在滞后消息
|
||||
Scheduler->>Logger : 记录滞后统计
|
||||
else 正常状态
|
||||
Scheduler->>Scheduler : 跳过记录
|
||||
end
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [KafkaConsumerStatsService.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaConsumerStatsService.java#L60-L90)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [KafkaConsumerStatsService.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/kafka/KafkaConsumerStatsService.java#L1-L161)
|
||||
|
||||
## 系统资源监控
|
||||
|
||||
### 系统指标采集
|
||||
|
||||
系统通过SystemUtil类提供底层系统资源监控能力。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class SystemUtil {
|
||||
-HardwareAbstractionLayer HARDWARE
|
||||
+getMemoryUsage() Optional~Integer~
|
||||
+getTotalMemory() Optional~Long~
|
||||
+getCpuUsage() Optional~Integer~
|
||||
+getCpuCount() Optional~Integer~
|
||||
+getDiscSpaceUsage() Optional~Integer~
|
||||
+getTotalDiscSpace() Optional~Long~
|
||||
-toPercent(used, total) int
|
||||
}
|
||||
class ServiceInfoProvider {
|
||||
<<interface>>
|
||||
+getServiceInfo() ServiceInfo
|
||||
+generateNewServiceInfoWithCurrentSystemInfo() ServiceInfo
|
||||
+isMonolith() boolean
|
||||
}
|
||||
class DefaultServiceInfoProvider {
|
||||
-String serviceId
|
||||
-String serviceType
|
||||
-ServiceInfo serviceInfo
|
||||
-String hostAddress
|
||||
-int restPort
|
||||
-int grpcPort
|
||||
+getServiceInfo() ServiceInfo
|
||||
+generateNewServiceInfoWithCurrentSystemInfo() ServiceInfo
|
||||
}
|
||||
ServiceInfoProvider <|-- DefaultServiceInfoProvider
|
||||
DefaultServiceInfoProvider --> SystemUtil
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [SystemUtil.java](file://jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/SystemUtil.java#L1-L98)
|
||||
- [DefaultServiceInfoProvider.java](file://jcpp-infrastructure-queue/src/main/java/sanbing/jcpp/infrastructure/queue/discovery/DefaultServiceInfoProvider.java#L84-L112)
|
||||
|
||||
### 资源监控指标
|
||||
|
||||
#### CPU监控
|
||||
|
||||
| 指标 | 获取方式 | 监控意义 |
|
||||
|--------|----------------------------------------------------|--------|
|
||||
| CPU使用率 | HARDWARE.getProcessor().getSystemCpuLoad() | 系统负载评估 |
|
||||
| CPU核心数 | HARDWARE.getProcessor().getLogicalProcessorCount() | 并发能力参考 |
|
||||
|
||||
#### 内存监控
|
||||
|
||||
| 指标 | 获取方式 | 监控意义 |
|
||||
|-------|-----------------------------------|--------|
|
||||
| 内存使用率 | (total - available) / total * 100 | 内存压力评估 |
|
||||
| 总内存容量 | HARDWARE.getMemory().getTotal() | 内存资源配置 |
|
||||
|
||||
#### 磁盘监控
|
||||
|
||||
| 指标 | 获取方式 | 监控意义 |
|
||||
|-------|--------------------------------------|--------|
|
||||
| 磁盘使用率 | (total - usable) / total * 100 | 磁盘空间压力 |
|
||||
| 总磁盘容量 | Files.getFileStore().getTotalSpace() | 存储资源规划 |
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [SystemUtil.java](file://jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/SystemUtil.java#L1-L98)
|
||||
|
||||
## 故障排查指南
|
||||
|
||||
### 常见故障场景
|
||||
|
||||
#### 服务无法启动
|
||||
|
||||
**症状表现**:
|
||||
|
||||
- 应用启动失败
|
||||
- 端口绑定错误
|
||||
- 依赖服务不可用
|
||||
|
||||
**排查步骤**:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["服务启动失败"] --> B{"检查端口占用"}
|
||||
B --> |端口被占用| C["修改端口配置"]
|
||||
B --> |端口正常| D{"检查依赖服务"}
|
||||
D --> |数据库不可用| E["检查数据库连接"]
|
||||
D --> |Redis不可用| F["检查Redis连接"]
|
||||
D --> |Kafka不可用| G["检查Kafka集群"]
|
||||
D --> |依赖正常| H["检查配置文件"]
|
||||
C --> I["重启服务"]
|
||||
E --> I
|
||||
F --> I
|
||||
G --> I
|
||||
H --> I
|
||||
```
|
||||
|
||||
**诊断命令**:
|
||||
|
||||
```bash
|
||||
# 检查端口占用
|
||||
netstat -tlnp | grep :8080
|
||||
|
||||
# 检查进程状态
|
||||
ps aux | grep jcpp
|
||||
|
||||
# 查看启动日志
|
||||
tail -f logs/jcpp-app.log
|
||||
```
|
||||
|
||||
#### 消息积压问题
|
||||
|
||||
**症状表现**:
|
||||
|
||||
- Kafka消费者滞后增加
|
||||
- 消息处理延迟
|
||||
- 系统响应变慢
|
||||
|
||||
**排查流程**:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Admin as 管理员
|
||||
participant Monitor as 监控系统
|
||||
participant Kafka as Kafka集群
|
||||
participant Consumer as 消费者组
|
||||
Admin->>Monitor : 触发积压检查
|
||||
Monitor->>Kafka : 查询消费者偏移量
|
||||
Kafka-->>Monitor : 返回偏移量信息
|
||||
Monitor->>Kafka : 查询主题末尾偏移量
|
||||
Kafka-->>Monitor : 返回末尾偏移量
|
||||
Monitor->>Monitor : 计算滞后量
|
||||
alt 滞后量过大
|
||||
Monitor->>Admin : 发送告警通知
|
||||
Admin->>Consumer : 检查消费者处理能力
|
||||
Consumer-->>Admin : 返回处理状态
|
||||
else 滞后量正常
|
||||
Monitor->>Admin : 记录正常状态
|
||||
end
|
||||
```
|
||||
|
||||
**解决措施**:
|
||||
|
||||
1. 增加消费者实例数量
|
||||
2. 优化消息处理逻辑
|
||||
3. 调整批处理大小
|
||||
4. 检查消费者组重新平衡
|
||||
|
||||
#### 高延迟问题
|
||||
|
||||
**症状表现**:
|
||||
|
||||
- API响应时间增加
|
||||
- 用户体验下降
|
||||
- 系统吞吐量降低
|
||||
|
||||
**分析方法**:
|
||||
|
||||
| 排查维度 | 检查项目 | 解决方案 |
|
||||
|------|--------|---------|
|
||||
| 应用层 | GC日志分析 | 调整JVM参数 |
|
||||
| 数据库层 | 慢SQL分析 | 添加索引优化 |
|
||||
| 网络层 | 连接池配置 | 增加连接数 |
|
||||
| 缓存层 | 缓存命中率 | 优化缓存策略 |
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml#L1-L432)
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml#L1-L35)
|
||||
|
||||
## 运维最佳实践
|
||||
|
||||
### 日常维护任务
|
||||
|
||||
#### 数据库备份策略
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["数据库备份"] --> B["全量备份"]
|
||||
A --> C["增量备份"]
|
||||
B --> D["每周日执行"]
|
||||
C --> E["每日凌晨执行"]
|
||||
D --> F["保留4周"]
|
||||
E --> G["保留7天"]
|
||||
F --> H["归档存储"]
|
||||
G --> H
|
||||
H --> I["异地备份"]
|
||||
I --> J["定期验证"]
|
||||
```
|
||||
|
||||
#### 系统健康检查清单
|
||||
|
||||
| 检查项目 | 检查频率 | 关注指标 | 告警阈值 |
|
||||
|--------|------|-----------|---------|
|
||||
| 服务可用性 | 实时 | 响应时间 | >1000ms |
|
||||
| CPU使用率 | 5分钟 | 平均值 | >80% |
|
||||
| 内存使用率 | 5分钟 | 平均值 | >85% |
|
||||
| 磁盘使用率 | 1小时 | 占用比例 | >90% |
|
||||
| 错误率 | 实时 | 错误数量/总请求数 | >5% |
|
||||
|
||||
#### 配置管理规范
|
||||
|
||||
1. **环境隔离**:开发、测试、生产环境配置严格分离
|
||||
2. **版本控制**:所有配置文件纳入版本控制系统
|
||||
3. **变更审批**:重大配置变更需经过审批流程
|
||||
4. **回滚准备**:每次配置变更都应准备回滚方案
|
||||
|
||||
### 性能优化建议
|
||||
|
||||
#### JVM调优参数
|
||||
|
||||
```yaml
|
||||
# 生产环境推荐配置
|
||||
JAVA_OPTS: >
|
||||
-Xms2g -Xmx4g
|
||||
-XX:+UseG1GC
|
||||
-XX:MaxGCPauseMillis=200
|
||||
-XX:+HeapDumpOnOutOfMemoryError
|
||||
-XX:HeapDumpPath=/logs/
|
||||
-Djava.awt.headless=true
|
||||
```
|
||||
|
||||
#### 数据库连接池优化
|
||||
|
||||
| 参数 | 推荐值 | 说明 |
|
||||
|-------------------|--------|--------|
|
||||
| maximumPoolSize | 64 | 最大连接数 |
|
||||
| minimumIdle | 10 | 最小空闲连接 |
|
||||
| connectionTimeout | 30000 | 连接超时时间 |
|
||||
| idleTimeout | 600000 | 空闲连接超时 |
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml#L1-L432)
|
||||
|
||||
## 监控集成方案
|
||||
|
||||
### Prometheus集成
|
||||
|
||||
系统内置Prometheus指标导出功能,支持与主流监控系统集成。
|
||||
|
||||
#### 指标暴露配置
|
||||
|
||||
```yaml
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: 'prometheus,health'
|
||||
endpoint:
|
||||
health:
|
||||
show-details: always
|
||||
```
|
||||
|
||||
#### 关键监控指标
|
||||
|
||||
| 指标名称 | 类型 | 说明 |
|
||||
|------------------------------------|-----------|-----------|
|
||||
| jcpp_api_requests_total | Counter | API请求总数 |
|
||||
| jcpp_api_requests_duration_seconds | Histogram | API请求耗时分布 |
|
||||
| jcpp_cache_hit_rate | Gauge | 缓存命中率 |
|
||||
| jcpp_queue_lag | Gauge | 消息队列滞后量 |
|
||||
| jcpp_system_cpu_usage | Gauge | CPU使用率 |
|
||||
| jcpp_system_memory_usage | Gauge | 内存使用率 |
|
||||
|
||||
### Grafana仪表板
|
||||
|
||||
#### 系统概览面板
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A["Grafana仪表板"] --> B["系统资源监控"]
|
||||
A --> C["应用性能监控"]
|
||||
A --> D["业务指标监控"]
|
||||
B --> B1["CPU使用率"]
|
||||
B --> B2["内存使用率"]
|
||||
B --> B3["磁盘空间"]
|
||||
C --> C1["API响应时间"]
|
||||
C --> C2["错误率"]
|
||||
C --> C3["QPS"]
|
||||
D --> D1["充电订单量"]
|
||||
D --> D2["设备在线率"]
|
||||
D --> D3["支付成功率"]
|
||||
```
|
||||
|
||||
#### 告警规则配置
|
||||
|
||||
```yaml
|
||||
groups:
|
||||
- name: jcpp-alerts
|
||||
rules:
|
||||
- alert: HighCpuUsage
|
||||
expr: jcpp_system_cpu_usage > 80
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "CPU使用率过高"
|
||||
|
||||
- alert: HighMemoryUsage
|
||||
expr: jcpp_system_memory_usage > 85
|
||||
for: 3m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "内存使用率过高"
|
||||
```
|
||||
|
||||
### Docker监控
|
||||
|
||||
#### 容器化部署监控
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A["Docker Compose"] --> B["应用容器"]
|
||||
A --> C["Kafka集群"]
|
||||
A --> D["监控组件"]
|
||||
B --> B1["JCPP应用"]
|
||||
B --> B2["协议处理服务"]
|
||||
C --> C1["Kafka Broker"]
|
||||
C --> C2["Zookeeper"]
|
||||
D --> D1["Prometheus"]
|
||||
D --> D2["Grafana"]
|
||||
D --> D3["Kafka Exporter"]
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
|
||||
- [docker-compose.kafka.yml](file://docker/docker-compose.kafka.yml#L1-L67)
|
||||
|
||||
**章节来源**
|
||||
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml#L80-L85)
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml#L25-L30)
|
||||
- [docker-compose.kafka.yml](file://docker/docker-compose.kafka.yml#L1-L67)
|
||||
279
docs/系统概述.md
Normal file
279
docs/系统概述.md
Normal file
@@ -0,0 +1,279 @@
|
||||
# 系统概述
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [README.md](file://README.md)
|
||||
- [pom.xml](file://pom.xml)
|
||||
- [JCPPServerApplication.java](file://jcpp-app-bootstrap/src/main/java/sanbing/jcpp/JCPPServerApplication.java)
|
||||
- [JCPPProtocolServiceApplication.java](file://jcpp-protocol-bootstrap/src/main/java/sanbing/jcpp/protocol/JCPPProtocolServiceApplication.java)
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java)
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java)
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.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)
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java)
|
||||
- [PileService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/PileService.java)
|
||||
- [AttrKeyEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/data/kv/AttrKeyEnum.java)
|
||||
- [docker-compose.monolith.yml](file://docker/docker-compose.monolith.yml)
|
||||
- [package.json](file://jcpp-web-ui/package.json)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构概述](#架构概述)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖分析](#依赖分析)
|
||||
7. [性能考虑](#性能考虑)
|
||||
8. [故障排除指南](#故障排除指南)
|
||||
9. [结论](#结论)
|
||||
|
||||
## 简介
|
||||
|
||||
JChargePointProtocol是一个高性能、分布式、支持海量并发量的充电桩Java服务端平台,旨在为电动汽车充电网络提供基础能力。该项目设计支持多达100种充电桩协议,目前已实现对云快充和绿能等主流品牌充电桩协议的支持。系统采用微服务架构,通过统一的管理平台实现多品牌充电桩协议的集中管理,为充电应用提供稳定可靠的基础服务。
|
||||
|
||||
该平台在电动汽车充电网络中扮演着关键角色,作为充电桩与上层应用之间的桥梁,负责处理设备通信、协议转换、数据采集和远程控制等核心功能。系统支持通过TCP长连接与充电桩进行实时通信,利用Kafka实现异步消息处理,并通过gRPC提供高性能的指令下发能力,确保了系统的高可用性和可扩展性。
|
||||
|
||||
## 项目结构
|
||||
|
||||
JChargePointProtocol项目采用模块化的微服务架构设计,各组件职责明确,协同工作。项目主要由三个核心服务组成:jcpp-app主服务、jcpp-protocol协议处理服务和jcpp-web-ui前端界面,通过Docker容器化部署实现服务的独立运行和弹性扩展。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "前端界面"
|
||||
WebUI[jcpp-web-ui]
|
||||
end
|
||||
subgraph "应用服务"
|
||||
App[jcpp-app]
|
||||
Protocol[jcpp-protocol]
|
||||
end
|
||||
subgraph "基础设施"
|
||||
Kafka[Kafka]
|
||||
Redis[Redis]
|
||||
Postgres[PostgreSQL]
|
||||
end
|
||||
WebUI --> App
|
||||
App --> Protocol
|
||||
Protocol --> Kafka
|
||||
App --> Kafka
|
||||
App --> Redis
|
||||
App --> Postgres
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [pom.xml](file://pom.xml)
|
||||
- [docker-compose.monolith.yml](file://docker/docker-compose.monolith.yml)
|
||||
- [package.json](file://jcpp-web-ui/package.json)
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [pom.xml](file://pom.xml#L1-L699)
|
||||
- [docker-compose.monolith.yml](file://docker/docker-compose.monolith.yml#L1-L29)
|
||||
- [package.json](file://jcpp-web-ui/package.json#L1-L49)
|
||||
|
||||
## 核心组件
|
||||
|
||||
JChargePointProtocol系统的核心功能模块包括设备管理、协议处理、远程控制、数据采集与监控。这些模块协同工作,实现了对充电桩的全面管理和控制。设备管理模块负责充电桩、充电枪和充电站的全生命周期管理,包括创建、更新、删除和查询操作。协议处理模块是系统的核心,负责处理不同品牌充电桩的通信协议,实现协议的解析和封装。
|
||||
|
||||
远程控制模块提供了对充电桩的远程操作能力,如启动充电、停止充电、重启设备等。数据采集与监控模块负责收集充电桩的实时数据,包括状态信息、充电数据和故障报警,并提供实时监控功能。系统通过属性键枚举(AttrKeyEnum)定义了标准化的状态属性,如STATUS(状态)、CONNECTED_AT(连接时间)、LAST_ACTIVE_TIME(最后活跃时间)等,确保了数据的一致性和可管理性。
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L1-L112)
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L1-L108)
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L1-L116)
|
||||
- [AttrKeyEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/data/kv/AttrKeyEnum.java#L1-L70)
|
||||
|
||||
## 架构概述
|
||||
|
||||
JChargePointProtocol采用微服务架构,整体布局清晰,各服务职责分明。系统主要由jcpp-app主服务、jcpp-protocol协议处理服务和jcpp-web-ui前端界面三大部分组成。jcpp-app主服务作为业务逻辑处理中心,负责设备管理、用户认证和API接口提供。jcpp-protocol协议处理服务专注于充电桩协议的解析和处理,支持多品牌协议的扩展。jcpp-web-ui前端界面提供直观的管理界面,方便管理员进行操作和监控。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "前端层"
|
||||
WebUI[jcpp-web-ui]
|
||||
end
|
||||
subgraph "应用层"
|
||||
App[jcpp-app]
|
||||
Protocol[jcpp-protocol]
|
||||
end
|
||||
subgraph "通信层"
|
||||
Kafka[Kafka]
|
||||
gRPC[gRPC]
|
||||
TCP[TCP长连接]
|
||||
end
|
||||
subgraph "数据层"
|
||||
Redis[Redis]
|
||||
Postgres[PostgreSQL]
|
||||
end
|
||||
WebUI --> App
|
||||
App --> Protocol
|
||||
Protocol --> TCP
|
||||
App --> Kafka
|
||||
Protocol --> Kafka
|
||||
App --> Redis
|
||||
App --> Postgres
|
||||
Protocol --> Redis
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [JCPPServerApplication.java](file://jcpp-app-bootstrap/src/main/java/sanbing/jcpp/JCPPServerApplication.java#L1-L55)
|
||||
- [JCPPProtocolServiceApplication.java](file://jcpp-protocol-bootstrap/src/main/java/sanbing/jcpp/protocol/JCPPProtocolServiceApplication.java#L1-L59)
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L1-L127)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### 设备管理组件分析
|
||||
|
||||
设备管理组件是JChargePointProtocol系统的基础,负责充电桩、充电枪和充电站的全生命周期管理。该组件通过RESTful
|
||||
API提供标准化的接口,支持设备的创建、查询、更新和删除操作。充电桩实体(Pile)包含丰富的属性信息,如桩编号(pileCode)、协议类型(protocol)、品牌(brand)和型号(model),为设备管理提供了完整的数据支持。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
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 Station {
|
||||
+UUID id
|
||||
+String stationName
|
||||
+String stationCode
|
||||
+String address
|
||||
+Double longitude
|
||||
+Double latitude
|
||||
}
|
||||
class Gun {
|
||||
+UUID id
|
||||
+String gunCode
|
||||
+UUID pileId
|
||||
+Integer gunNumber
|
||||
+Double maxPower
|
||||
+Double voltageRange
|
||||
}
|
||||
Pile --> Station : "属于"
|
||||
Gun --> Pile : "属于"
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java#L1-L65)
|
||||
- [PileService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/PileService.java#L1-L124)
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L1-L112)
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L1-L108)
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L1-L116)
|
||||
|
||||
### 协议处理组件分析
|
||||
|
||||
协议处理组件是JChargePointProtocol系统的核心,负责处理不同品牌充电桩的通信协议。该组件采用抽象基类ProtocolBootstrap的设计模式,为各种充电桩协议提供统一的初始化和销毁接口。ProtocolMessageProcessor作为消息处理器的基类,定义了上行和下行消息处理的统一框架,确保了协议处理的一致性和可扩展性。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant 充电桩 as 充电桩
|
||||
participant TCP监听器 as TcpListener
|
||||
participant 协议处理器 as ProtocolMessageProcessor
|
||||
participant Kafka转发器 as KafkaForwarder
|
||||
充电桩->>TCP监听器 : TCP连接请求
|
||||
TCP监听器->>TCP监听器 : 创建TcpSession
|
||||
充电桩->>TCP监听器 : 发送心跳数据
|
||||
TCP监听器->>协议处理器 : uplinkHandleAsync()
|
||||
协议处理器->>Kafka转发器 : 转发上行消息
|
||||
Kafka转发器-->>后端服务 : 持久化处理
|
||||
后端服务->>协议处理器 : 下行指令
|
||||
协议处理器->>协议处理器 : doDownlinkHandle()
|
||||
协议处理器->>TCP监听器 : 写入响应
|
||||
TCP监听器->>充电桩 : 发送响应数据
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [ProtocolBootstrap.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolBootstrap.java#L1-L127)
|
||||
- [ProtocolMessageProcessor.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/ProtocolMessageProcessor.java#L1-L78)
|
||||
- [TcpListener.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpListener.java#L1-L50)
|
||||
|
||||
### 通信机制分析
|
||||
|
||||
JChargePointProtocol系统通过多种通信机制实现高效的数据交换和指令传输。系统使用TCP长连接与充电桩保持实时通信,通过Netty框架实现高性能的网络IO处理。IdleEventHandler组件负责检测空闲连接,当检测到读空闲状态时自动关闭连接,确保了连接资源的有效管理。Kafka作为消息中间件,实现了系统组件间的异步消息传递,提高了系统的吞吐量和可靠性。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([TCP连接建立]) --> IdleCheck["配置IdleStateHandler"]
|
||||
IdleCheck --> ReadIdle{"检测到读空闲?"}
|
||||
ReadIdle --> |是| CloseConnection["关闭连接"]
|
||||
ReadIdle --> |否| ContinueProcessing["继续处理消息"]
|
||||
ContinueProcessing --> MessageReceived["接收充电桩消息"]
|
||||
MessageReceived --> ProtocolProcessing["协议解析处理"]
|
||||
ProtocolProcessing --> KafkaForward["转发到Kafka"]
|
||||
KafkaForward --> DataPersistence["数据持久化"]
|
||||
DataPersistence --> End([处理完成])
|
||||
style Start fill:#9f9,stroke:#333
|
||||
style End fill:#f9f,stroke:#333
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [ChannelHandlerInitializer.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/ChannelHandlerInitializer.java#L1-L120)
|
||||
- [IdleEventHandler.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/handler/IdleEventHandler.java#L1-L36)
|
||||
- [TcpSession.java](file://jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/TcpSession.java#L1-L100)
|
||||
|
||||
## 依赖分析
|
||||
|
||||
JChargePointProtocol系统的组件间依赖关系清晰,通过合理的架构设计实现了高内聚低耦合。系统依赖于多种外部组件和服务,包括Kafka用于消息队列、Redis用于缓存、PostgreSQL用于数据持久化。jcpp-app服务依赖于jcpp-protocol服务进行协议处理,同时两者都依赖于基础设施服务。通过Docker
|
||||
Compose配置文件定义了服务间的网络连接和端口映射,确保了服务的可部署性和可维护性。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
App[jcpp-app] --> Protocol[jcpp-protocol]
|
||||
App --> Kafka[Kafka]
|
||||
App --> Redis[Redis]
|
||||
App --> Postgres[PostgreSQL]
|
||||
Protocol --> Kafka
|
||||
Protocol --> Redis
|
||||
Protocol --> TCP[TCP网络]
|
||||
WebUI[jcpp-web-ui] --> App
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [pom.xml](file://pom.xml#L1-L699)
|
||||
- [docker-compose.monolith.yml](file://docker/docker-compose.monolith.yml#L1-L29)
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [pom.xml](file://pom.xml#L1-L699)
|
||||
- [docker-compose.monolith.yml](file://docker/docker-compose.monolith.yml#L1-L29)
|
||||
|
||||
## 性能考虑
|
||||
|
||||
JChargePointProtocol系统在设计时充分考虑了性能因素,采用了多种优化策略确保系统的高并发处理能力。系统使用Netty框架处理TCP连接,利用其事件驱动的非阻塞IO模型,能够高效处理海量并发连接。通过Kafka实现异步消息处理,将耗时的操作(如数据持久化)与实时通信解耦,提高了系统的响应速度。gRPC的使用确保了服务间通信的高性能,特别是在指令下发场景下表现出色。
|
||||
|
||||
系统还采用了多级缓存策略,结合Caffeine本地缓存和Redis分布式缓存,有效减少了数据库访问压力。ShardingThreadPool的使用实现了任务的分片处理,避免了线程竞争,提高了处理效率。通过StatsFactory和MessagesStats组件,系统能够实时监控消息处理的性能指标,为性能优化提供了数据支持。
|
||||
|
||||
## 故障排除指南
|
||||
|
||||
当系统出现连接问题时,首先检查TCP监听器是否正常启动,端口是否被正确绑定。对于消息丢失问题,检查Kafka集群状态和主题配置,确保消息能够正常生产和消费。如果出现协议解析错误,检查充电桩发送的数据格式是否符合协议规范,以及协议处理器的解析逻辑是否正确。对于性能瓶颈,可以通过监控工具查看各组件的资源使用情况,重点关注CPU、内存和网络IO指标。
|
||||
|
||||
在处理充电桩心跳数据时,如果发现状态更新不及时,检查AttributeService的异步处理逻辑,确保状态属性能够及时更新。对于远程控制指令无法下发的问题,检查gRPC服务是否正常运行,以及充电桩的TCP连接状态是否正常。通过查看系统日志,特别是ProtocolMessageProcessor和TcpListener组件的日志,可以快速定位问题根源。
|
||||
|
||||
## 结论
|
||||
|
||||
JChargePointProtocol项目作为一个高性能的充电桩协议处理平台,通过合理的微服务架构设计和先进的技术选型,实现了对多品牌充电桩协议的统一管理。系统采用TCP长连接与充电桩通信,利用Kafka进行异步消息处理,并通过gRPC实现高性能指令下发,确保了系统的高可用性和可扩展性。项目结构清晰,核心组件职责明确,为电动汽车充电网络提供了稳定可靠的基础服务。
|
||||
|
||||
该平台不仅满足了当前充电桩管理的需求,还具备良好的扩展性,能够支持更多品牌和型号的充电桩协议。通过持续优化和功能完善,JChargePointProtocol有望成为电动汽车充电领域的标准解决方案,为充电基础设施的智能化管理做出重要贡献。
|
||||
378
docs/缓存架构.md
Normal file
378
docs/缓存架构.md
Normal file
@@ -0,0 +1,378 @@
|
||||
# 缓存架构
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [CachedVersionedEntityRepository.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/CachedVersionedEntityRepository.java)
|
||||
- [VersionedCache.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/VersionedCache.java)
|
||||
- [VersionedCaffeineCache.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/VersionedCaffeineCache.java)
|
||||
- [VersionedRedisCache.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/VersionedRedisCache.java)
|
||||
- [JCPPCaffeineCacheConfiguration.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/JCPPCaffeineCacheConfiguration.java)
|
||||
- [JCPPRedisCacheConfiguration.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/JCPPRedisCacheConfiguration.java)
|
||||
- [PileCacheKey.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/pile/PileCacheKey.java)
|
||||
- [PileCacheEvictEvent.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/pile/PileCacheEvictEvent.java)
|
||||
- [PileRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/PileRepositoryImpl.java)
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [引言](#引言)
|
||||
2. [多级缓存架构设计](#多级缓存架构设计)
|
||||
3. [缓存一致性机制](#缓存一致性机制)
|
||||
4. [缓存读写流程](#缓存读写流程)
|
||||
5. [缓存键设计](#缓存键设计)
|
||||
6. [缓存失效策略](#缓存失效策略)
|
||||
7. [性能监控与优化](#性能监控与优化)
|
||||
8. [结论](#结论)
|
||||
|
||||
## 引言
|
||||
|
||||
JChargePointProtocol系统采用多级缓存架构来优化充电桩相关数据的访问性能。该架构结合了Caffeine本地缓存和Redis分布式缓存的优势,在保证高性能的同时确保数据一致性。本文档深入分析这一缓存架构的设计原理、实现机制和最佳实践。
|
||||
|
||||
## 多级缓存架构设计
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
Client[客户端请求] --> ReadCache[读取缓存]
|
||||
ReadCache --> CheckCaffeine{检查Caffeine<br>本地缓存}
|
||||
CheckCaffeine --> |命中| ReturnFromCaffeine[返回Caffeine数据]
|
||||
CheckCaffeine --> |未命中| CheckRedis{检查Redis<br>分布式缓存}
|
||||
CheckRedis --> |命中| ReturnFromRedis[返回Redis数据]
|
||||
CheckRedis --> |未命中| QueryDB[查询数据库]
|
||||
QueryDB --> UpdateRedis[更新Redis缓存]
|
||||
UpdateRedis --> UpdateCaffeine[更新Caffeine缓存]
|
||||
UpdateCaffeine --> ReturnFromDB[返回数据库数据]
|
||||
WriteOperation[写入操作] --> UpdateDB[更新数据库]
|
||||
UpdateDB --> DeleteRedis[删除Redis缓存]
|
||||
DeleteRedis --> DeleteCaffeine[删除Caffeine缓存]
|
||||
DeleteCaffeine --> Complete[操作完成]
|
||||
style ReadCache fill:#f9f,stroke:#333
|
||||
style WriteOperation fill:#f9f,stroke:#333
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [PileRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/PileRepositoryImpl.java#L35-L45)
|
||||
- [VersionedCaffeineCache.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/VersionedCaffeineCache.java#L30-L50)
|
||||
- [VersionedRedisCache.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/VersionedRedisCache.java#L80-L100)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [JCPPCaffeineCacheConfiguration.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/JCPPCaffeineCacheConfiguration.java)
|
||||
- [JCPPRedisCacheConfiguration.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/JCPPRedisCacheConfiguration.java)
|
||||
|
||||
### Caffeine与Redis组合的优势
|
||||
|
||||
JChargePointProtocol采用Caffeine(本地缓存)和Redis(分布式缓存)的组合设计,主要基于以下考虑:
|
||||
|
||||
1. **性能分层**:Caffeine作为第一级缓存,提供微秒级的访问速度,减少对远程Redis的访问压力。
|
||||
2. **高可用性**:即使Redis服务暂时不可用,本地缓存仍能提供一定程度的服务能力。
|
||||
3. **网络开销优化**:避免频繁的网络往返,特别适合高并发场景下的充电桩状态查询。
|
||||
4. **资源利用**:充分利用应用服务器的内存资源,同时通过Redis实现多实例间的数据共享。
|
||||
|
||||
Caffeine缓存通过`JCPPCaffeineCacheConfiguration`配置,支持基于权重的最大容量限制和写后过期策略。Redis缓存通过
|
||||
`JCPPRedisCacheConfiguration`配置,提供了连接池管理、序列化配置和分布式环境下的缓存管理。
|
||||
|
||||
## 缓存一致性机制
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class VersionedCache {
|
||||
+get(K key)
|
||||
+put(K key, V value)
|
||||
+evict(K key)
|
||||
+evict(K key, Integer version)
|
||||
+getVersion(V value)
|
||||
}
|
||||
class VersionedCaffeineCache {
|
||||
-doGet(K key)
|
||||
-doPut(K key, V value, Integer version)
|
||||
-wrapValue(V value, Integer version)
|
||||
}
|
||||
class VersionedRedisCache {
|
||||
-SET_VERSIONED_VALUE_LUA_SCRIPT
|
||||
-doPut(rawKey, value, version, expiration, connection)
|
||||
-init()
|
||||
}
|
||||
class HasVersion {
|
||||
+getVersion()
|
||||
+setVersion(Integer version)
|
||||
}
|
||||
class Pile {
|
||||
-UUID id
|
||||
-String pileCode
|
||||
-Integer version
|
||||
}
|
||||
class PileCacheKey {
|
||||
-UUID pileId
|
||||
-String pileCode
|
||||
-isVersioned()
|
||||
}
|
||||
VersionedCache <|-- VersionedCaffeineCache
|
||||
VersionedCache <|-- VersionedRedisCache
|
||||
HasVersion <|-- Pile
|
||||
VersionedCacheKey <|-- PileCacheKey
|
||||
VersionedCaffeineCache --> JCPPPair : "包装版本和值"
|
||||
VersionedRedisCache --> LUA : "使用Lua脚本"
|
||||
Pile --> PileCacheKey : "通过ID或编码创建键"
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [VersionedCache.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/VersionedCache.java)
|
||||
- [VersionedCaffeineCache.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/VersionedCaffeineCache.java)
|
||||
- [VersionedRedisCache.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/VersionedRedisCache.java)
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java#L60)
|
||||
- [PileCacheKey.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/pile/PileCacheKey.java)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [CachedVersionedEntityRepository.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/CachedVersionedEntityRepository.java)
|
||||
- [VersionedCache.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/VersionedCache.java)
|
||||
|
||||
### CachedVersionedEntityRepository实现机制
|
||||
|
||||
`CachedVersionedEntityRepository`是缓存一致性机制的核心实现,其工作原理如下:
|
||||
|
||||
1. **版本号机制**:实体类(如`Pile`)实现`HasVersion`接口,包含`version`字段,每次更新时版本号递增。
|
||||
2. **条件更新**:在向缓存写入数据时,只有当新数据的版本号大于缓存中现有数据的版本号时,才会执行更新操作。
|
||||
3. **原子性保证**:Redis层面使用Lua脚本确保"检查版本-更新值"操作的原子性,避免并发更新导致的数据不一致。
|
||||
|
||||
在`VersionedRedisCache`中,通过Lua脚本实现了版本控制逻辑:
|
||||
|
||||
- 获取当前缓存值的版本号(前8字节)
|
||||
- 比较新版本号与当前版本号
|
||||
- 仅当新版本号更大时才更新缓存
|
||||
|
||||
这种设计有效避免了脏读问题,确保了缓存与数据库之间的一致性。
|
||||
|
||||
## 缓存读写流程
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as 客户端
|
||||
participant Repo as PileRepositoryImpl
|
||||
participant Caffeine as Caffeine缓存
|
||||
participant Redis as Redis缓存
|
||||
participant DB as 数据库
|
||||
Client->>Repo : findPileByCode(pileCode)
|
||||
Repo->>Caffeine : get(PileCacheKey)
|
||||
Caffeine-->>Repo : 缓存命中/未命中
|
||||
alt Caffeine命中
|
||||
Repo-->>Client : 返回数据
|
||||
else Caffeine未命中
|
||||
Repo->>Redis : get(PileCacheKey)
|
||||
Redis-->>Repo : 缓存命中/未命中
|
||||
alt Redis命中
|
||||
Repo->>Caffeine : put(数据)
|
||||
Repo-->>Client : 返回数据
|
||||
else Redis未命中
|
||||
Repo->>DB : selectByCode(pileCode)
|
||||
DB-->>Repo : 返回实体
|
||||
Repo->>Redis : put(实体, version)
|
||||
Repo->>Caffeine : put(实体)
|
||||
Repo-->>Client : 返回实体
|
||||
end
|
||||
end
|
||||
Note over Client,Repo : 读取流程:Caffeine → Redis → DB
|
||||
Client->>Repo : updatePile(pile)
|
||||
Repo->>DB : update(pile)
|
||||
DB-->>Repo : 更新成功
|
||||
Repo->>Repo : 发布PileCacheEvictEvent
|
||||
Repo->>Caffeine : evict(相关缓存键)
|
||||
Repo->>Redis : evict(相关缓存键)
|
||||
Repo-->>Client : 操作完成
|
||||
Note over Client,Repo : 写入流程:更新DB → 删除两级缓存
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [PileRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/PileRepositoryImpl.java#L35-L45)
|
||||
- [VersionedCaffeineCache.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/VersionedCaffeineCache.java#L30-L50)
|
||||
- [VersionedRedisCache.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/VersionedRedisCache.java#L80-L100)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [PileRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/PileRepositoryImpl.java)
|
||||
- [AbstractCachedEntityRepository.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/AbstractCachedEntityRepository.java)
|
||||
|
||||
### 读取流程
|
||||
|
||||
缓存的读取遵循"先本地,后远程"的原则:
|
||||
|
||||
1. 首先尝试从Caffeine本地缓存中获取数据
|
||||
2. 如果本地缓存未命中,则查询Redis分布式缓存
|
||||
3. 如果Redis缓存也未命中,则访问数据库获取数据
|
||||
4. 将数据库查询结果依次写入Redis和Caffeine缓存,供后续请求使用
|
||||
|
||||
这种分层查询策略最大限度地利用了本地缓存的高性能优势,同时保证了数据的最终一致性。
|
||||
|
||||
### 写入流程
|
||||
|
||||
写入操作采用"先数据库,后缓存"的策略:
|
||||
|
||||
1. 首先更新数据库中的数据
|
||||
2. 发布缓存失效事件(如`PileCacheEvictEvent`)
|
||||
3. 在事件处理中删除两级缓存中的相关数据
|
||||
|
||||
这种"写后失效"(Write-Through with Cache-Aside)模式确保了数据的一致性,避免了缓存与数据库之间的数据偏差。
|
||||
|
||||
## 缓存键设计
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class PileCacheKey {
|
||||
-UUID pileId
|
||||
-String pileCode
|
||||
+PileCacheKey(UUID pileId)
|
||||
+PileCacheKey(String pileCode)
|
||||
+toString()
|
||||
+isVersioned()
|
||||
}
|
||||
class VersionedCacheKey {
|
||||
+isVersioned()
|
||||
}
|
||||
PileCacheKey --> VersionedCacheKey : 实现
|
||||
note right of PileCacheKey
|
||||
缓存键设计原则:
|
||||
1. 支持多种查询方式
|
||||
2. 版本控制标识
|
||||
3. 序列化兼容性
|
||||
end
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [PileCacheKey.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/pile/PileCacheKey.java)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [PileCacheKey.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/pile/PileCacheKey.java)
|
||||
|
||||
### PileCacheKey设计原则
|
||||
|
||||
`PileCacheKey`的设计体现了以下核心原则:
|
||||
|
||||
1. **多维度查询支持**:同时支持通过充电桩ID(`pileId`)和桩编码(`pileCode`)两种方式创建缓存键,满足不同场景的查询需求。
|
||||
2. **版本控制标识**:通过`isVersioned()`方法区分是否需要版本控制,当通过`pileId`查询时不需要版本控制,而通过`pileCode`
|
||||
查询时需要版本控制。
|
||||
3. **简洁的toString实现**:`toString()`方法优先返回`pileId`,不存在时返回`pileCode`,确保缓存键的可读性和一致性。
|
||||
4. **序列化兼容**:使用`@Serial`注解和`serialVersionUID`确保序列化兼容性,避免版本升级导致的问题。
|
||||
|
||||
这种设计既满足了功能需求,又考虑了性能和可维护性。
|
||||
|
||||
## 缓存失效策略
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([缓存失效触发]) --> ActiveEviction["主动失效策略"]
|
||||
Start --> PassiveEviction["被动失效策略"]
|
||||
ActiveEviction --> EventDriven["事件驱动失效"]
|
||||
EventDriven --> PileEvictEvent["PileCacheEvictEvent"]
|
||||
PileEvictEvent --> HandleEvict["handleEvictEvent处理"]
|
||||
HandleEvict --> EvictCaffeine["删除Caffeine缓存"]
|
||||
HandleEvict --> EvictRedis["删除Redis缓存"]
|
||||
PassiveEviction --> TTL["TTL过期"]
|
||||
TTL --> CaffeineTTL["Caffeine TTL配置"]
|
||||
CaffeineTTL --> expireAfterWrite["expireAfterWrite"]
|
||||
TTL --> RedisTTL["Redis TTL配置"]
|
||||
RedisTTL --> cacheTtl["cacheTtl参数"]
|
||||
EvictCaffeine --> End([缓存失效完成])
|
||||
EvictRedis --> End
|
||||
expireAfterWrite --> End
|
||||
cacheTtl --> End
|
||||
style ActiveEviction fill:#f96,stroke:#333
|
||||
style PassiveEviction fill:#69f,stroke:#333
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [PileCacheEvictEvent.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/pile/PileCacheEvictEvent.java)
|
||||
- [PileRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/PileRepositoryImpl.java#L40-L48)
|
||||
- [JCPPCaffeineCacheConfiguration.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/JCPPCaffeineCacheConfiguration.java#L60-L70)
|
||||
- [VersionedRedisCache.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/VersionedRedisCache.java#L50-L60)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [PileCacheEvictEvent.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/pile/PileCacheEvictEvent.java)
|
||||
- [PileRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/PileRepositoryImpl.java#L40-L48)
|
||||
|
||||
### 主动失效
|
||||
|
||||
主动失效通过事件驱动机制实现:
|
||||
|
||||
- 当充电桩数据被修改或删除时,发布`PileCacheEvictEvent`事件
|
||||
- `PileRepositoryImpl`中的`@TransactionalEventListener`监听并处理该事件
|
||||
- 在事件处理方法`handleEvictEvent`中,删除与该充电桩相关的所有缓存键
|
||||
|
||||
这种设计确保了数据变更后缓存能够及时失效,避免了脏数据的传播。
|
||||
|
||||
### 被动失效
|
||||
|
||||
被动失效依赖于TTL(Time To Live)机制:
|
||||
|
||||
- Caffeine缓存通过`expireAfterWrite`配置写后过期时间
|
||||
- Redis缓存通过`cacheTtl`参数配置过期时间
|
||||
- 当缓存项超过设定的生存时间后自动失效
|
||||
|
||||
被动失效作为主动失效的补充,提供了额外的安全保障,防止因事件机制故障导致的缓存数据长期不一致。
|
||||
|
||||
## 性能监控与优化
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
Metrics[性能监控指标] --> HitRate["缓存命中率"]
|
||||
Metrics --> Latency["访问延迟"]
|
||||
Metrics --> Memory["内存使用"]
|
||||
Metrics --> QPS["查询吞吐量"]
|
||||
HitRate --> CaffeineHit["Caffeine命中率"]
|
||||
HitRate --> RedisHit["Redis命中率"]
|
||||
Latency --> LocalLatency["本地缓存延迟"]
|
||||
Latency --> RemoteLatency["远程缓存延迟"]
|
||||
Memory --> CaffeineMem["Caffeine内存"]
|
||||
Memory --> RedisMem["Redis内存"]
|
||||
QPS --> ReadQPS["读取QPS"]
|
||||
QPS --> WriteQPS["写入QPS"]
|
||||
Optimization[优化建议] --> SizeTuning["容量调优"]
|
||||
Optimization --> TTLTuning["TTL调优"]
|
||||
Optimization --> PatternAnalysis["访问模式分析"]
|
||||
Optimization --> Monitoring["监控告警"]
|
||||
SizeTuning --> MaxSize["设置合理的maxSize"]
|
||||
TTLTuning --> OptimalTTL["根据业务需求设置TTL"]
|
||||
PatternAnalysis --> Hotspot["识别热点数据"]
|
||||
Monitoring --> Alert["设置命中率告警"]
|
||||
style HitRate fill:#ff6,stroke:#333
|
||||
style Optimization fill:#6f6,stroke:#333
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [JCPPCaffeineCacheConfiguration.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/JCPPCaffeineCacheConfiguration.java#L60-L70)
|
||||
- [CacheSpecs.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/CacheSpecs.java)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [JCPPCaffeineCacheConfiguration.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/JCPPCaffeineCacheConfiguration.java)
|
||||
- [CacheSpecsMap.java](file://jcpp-infrastructure-cache/src/main/java/sanbing/jcpp/infrastructure/cache/CacheSpecsMap.java)
|
||||
|
||||
### 性能监控指标
|
||||
|
||||
建议监控以下关键性能指标:
|
||||
|
||||
1. **缓存命中率**:衡量缓存有效性的核心指标,应分别监控Caffeine和Redis的命中率。
|
||||
2. **访问延迟**:记录从各级缓存获取数据的响应时间,识别性能瓶颈。
|
||||
3. **内存使用**:监控Caffeine和Redis的内存占用情况,防止内存溢出。
|
||||
4. **查询吞吐量**:统计单位时间内的缓存读写操作数量。
|
||||
|
||||
### 优化建议
|
||||
|
||||
1. **容量调优**:根据实际内存资源和访问模式,合理设置Caffeine的`maxSize`和Redis的内存限制。
|
||||
2. **TTL调优**:根据业务数据的变更频率,设置合适的TTL值,平衡数据新鲜度和缓存效率。
|
||||
3. **访问模式分析**:通过监控识别热点数据,考虑对热点数据进行特殊处理或预加载。
|
||||
4. **监控告警**:设置缓存命中率的告警阈值,当命中率异常下降时及时排查问题。
|
||||
|
||||
## 结论
|
||||
|
||||
JChargePointProtocol的多级缓存架构通过Caffeine和Redis的有机结合,在性能和数据一致性之间取得了良好平衡。
|
||||
`CachedVersionedEntityRepository`
|
||||
通过版本号机制有效解决了缓存一致性问题,避免了脏读现象。缓存键的精心设计支持了多种查询场景,而主动与被动相结合的失效策略确保了数据的及时更新。通过合理的性能监控和持续优化,该缓存架构能够有效支撑系统的高并发访问需求。
|
||||
314
docs/部署与配置.md
Normal file
314
docs/部署与配置.md
Normal file
@@ -0,0 +1,314 @@
|
||||
# 部署与配置
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [docker-compose.monolith.yml](file://docker/docker-compose.monolith.yml)
|
||||
- [docker-compose.postgres.yml](file://docker/docker-compose.postgres.yml)
|
||||
- [docker-compose.redis-standalone.yml](file://docker/docker-compose.redis-standalone.yml)
|
||||
- [docker-compose.kafka.yml](file://docker/docker-compose.kafka.yml)
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml)
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml)
|
||||
- [app.Dockerfile](file://docker/app.Dockerfile)
|
||||
- [protocol.Dockerfile](file://docker/protocol.Dockerfile)
|
||||
- [start.sh](file://docker/start.sh)
|
||||
- [log4j2.xml](file://jcpp-app-bootstrap/src/main/resources/log4j2.xml)
|
||||
- [log4j2.xml](file://jcpp-protocol-bootstrap/src/main/resources/log4j2.xml)
|
||||
- [kafka.env](file://docker/kafka.env)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [Docker部署指南](#docker部署指南)
|
||||
2. [核心配置文件详解](#核心配置文件详解)
|
||||
3. [环境管理与配置](#环境管理与配置)
|
||||
4. [部署后验证](#部署后验证)
|
||||
|
||||
## Docker部署指南
|
||||
|
||||
JChargePointProtocol项目提供了基于Docker的完整部署方案,通过多个`docker-compose.*.yml`
|
||||
文件实现模块化部署。用户可以根据需要选择部署单体服务、数据库、缓存和消息队列等组件。
|
||||
|
||||
### 单体服务部署
|
||||
|
||||
使用`docker-compose.monolith.yml`文件部署包含应用和协议处理功能的单体服务。该服务通过`app.Dockerfile`
|
||||
构建,暴露8080端口用于HTTP服务,38001-38011端口用于不同协议的TCP监听。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "单体服务"
|
||||
App[jcpp-node-0]
|
||||
App --> Undertow[Undertow Web服务器]
|
||||
App --> Netty[Netty协议处理器]
|
||||
end
|
||||
App --> Postgres[PostgreSQL]
|
||||
App --> Redis[Redis]
|
||||
App --> Kafka[Kafka]
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [docker-compose.monolith.yml](file://docker/docker-compose.monolith.yml)
|
||||
- [app.Dockerfile](file://docker/app.Dockerfile)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [docker-compose.monolith.yml](file://docker/docker-compose.monolith.yml)
|
||||
|
||||
### 数据库部署
|
||||
|
||||
使用`docker-compose.postgres.yml`文件部署PostgreSQL数据库服务。该服务使用Bitnami提供的PostgreSQL镜像,配置了持久化卷
|
||||
`jcpp_pg_data`以确保数据持久化。数据库名为`jcpp`,默认用户名和密码均为`postgres`,监听5432端口。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "数据库服务"
|
||||
Postgres[PostgreSQL]
|
||||
Volume[jcpp_pg_data卷]
|
||||
end
|
||||
Postgres --> Volume
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [docker-compose.postgres.yml](file://docker/docker-compose.postgres.yml)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [docker-compose.postgres.yml](file://docker/docker-compose.postgres.yml)
|
||||
|
||||
### 缓存部署
|
||||
|
||||
项目提供了三种Redis部署模式:单机模式(`docker-compose.redis-standalone.yml`)、哨兵模式和集群模式。推荐在生产环境中使用集群模式以确保高可用性。单机模式配置了密码
|
||||
`sanbing`,监听6379端口。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "缓存服务"
|
||||
Redis[Redis]
|
||||
end
|
||||
Redis --> Password[密码认证]
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [docker-compose.redis-standalone.yml](file://docker/docker-compose.redis-standalone.yml)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [docker-compose.redis-standalone.yml](file://docker/docker-compose.redis-standalone.yml)
|
||||
|
||||
### 消息队列部署
|
||||
|
||||
使用`docker-compose.kafka.yml`文件部署Kafka消息队列系统,包含Zookeeper、Kafka Broker、Kafka Exporter和Kafka
|
||||
UI四个组件。Zookeeper用于服务发现和配置管理,Kafka Broker处理消息,Kafka Exporter提供监控指标,Kafka UI提供Web管理界面。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
Zookeeper[Zookeeper]
|
||||
Kafka[Kafka Broker]
|
||||
Exporter[Kafka Exporter]
|
||||
UI[Kafka UI]
|
||||
Kafka --> Zookeeper
|
||||
Exporter --> Kafka
|
||||
UI --> Kafka
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [docker-compose.kafka.yml](file://docker/docker-compose.kafka.yml)
|
||||
- [kafka.env](file://docker/kafka.env)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [docker-compose.kafka.yml](file://docker/docker-compose.kafka.yml)
|
||||
|
||||
## 核心配置文件详解
|
||||
|
||||
### 应用服务配置 (app-service.yml)
|
||||
|
||||
`app-service.yml`是应用服务的核心配置文件,定义了服务运行所需的各种参数。
|
||||
|
||||
#### 服务与Web服务器配置
|
||||
|
||||
- **server.port**: HTTP服务监听端口,默认8080,可通过`HTTP_BIND_PORT`环境变量覆盖
|
||||
- **server.undertow**: Undertow服务器配置,包括IO线程数(默认4)和工作线程数(默认128)
|
||||
- **spring.datasource**: 数据库连接配置,包括URL、用户名、密码和Hikari连接池大小(默认64)
|
||||
|
||||
#### 安全与认证配置
|
||||
|
||||
- **security.jwt**: JWT令牌配置,包括过期时间、刷新令牌时间和签名密钥
|
||||
- **security.settings.passwordPolicy**: 密码策略配置,定义密码最小长度(默认6)等安全要求
|
||||
|
||||
#### 缓存配置
|
||||
|
||||
- **cache.type**: 缓存类型,可选`caffeine`(本地缓存)或`redis`(分布式缓存)
|
||||
- **redis**: Redis连接配置,包括主机、端口、密码和连接池参数
|
||||
|
||||
#### 协议服务配置
|
||||
|
||||
- **service.type**: 服务类型,可选`monolith`(单体)、`app`(应用后端)或`protocol`(协议前置)
|
||||
- **service.protocol.sessions**: 协议会话配置,包括默认不活动超时时间(默认600秒)
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class AppServiceConfig {
|
||||
+String server.port
|
||||
+String server.undertow.threads.io
|
||||
+String server.undertow.threads.worker
|
||||
+String spring.datasource.url
|
||||
+String spring.datasource.hikari.maximum-pool-size
|
||||
+String security.jwt.tokenExpirationTime
|
||||
+String cache.type
|
||||
+String redis.password
|
||||
+String service.type
|
||||
+String service.protocol.sessions.default-inactivity-timeout-in-sec
|
||||
}
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml)
|
||||
|
||||
### 协议服务配置 (protocol-service.yml)
|
||||
|
||||
`protocol-service.yml`是协议服务的核心配置文件,专注于协议处理相关的配置。
|
||||
|
||||
#### 服务类型与线程池
|
||||
|
||||
- **service.type**: 服务类型,默认为`protocol`,表示纯协议解析前置服务
|
||||
- **service.thread-pool.sharding**: 分片线程池配置,包括并行度(默认8)和哈希函数
|
||||
|
||||
#### 协议监听器配置
|
||||
|
||||
- **service.protocols.*.listener.tcp.bind-port**: 不同协议版本的TCP监听端口,如云快充V150使用38001端口
|
||||
- **service.protocols.*.listener.tcp.worker-group-thread-count**: Netty工作线程组大小,默认16
|
||||
|
||||
#### 消息转发配置
|
||||
|
||||
- **service.protocols.*.forwarder.type**: 消息转发类型,在协议服务中通常为`kafka`
|
||||
- **service.protocols.*.forwarder.kafka.topic**: Kafka主题名称,默认为`protocol_uplink`
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProtocolServiceConfig {
|
||||
+String service.type
|
||||
+String service.thread-pool.sharding.parallelism
|
||||
+String service.protocols.yunkuaichongV150.listener.tcp.bind-port
|
||||
+String service.protocols.yunkuaichongV150.listener.tcp.worker-group-thread-count
|
||||
+String service.protocols.yunkuaichongV150.forwarder.type
|
||||
+String service.protocols.yunkuaichongV150.forwarder.kafka.topic
|
||||
}
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml)
|
||||
|
||||
## 环境管理与配置
|
||||
|
||||
### 配置文件管理
|
||||
|
||||
项目通过Spring Boot的配置机制支持多环境配置。核心配置文件`app-service.yml`和`protocol-service.yml`中的所有参数都支持通过环境变量覆盖,遵循
|
||||
`${ENV_VAR_NAME:default_value}`的格式。
|
||||
|
||||
#### 开发环境
|
||||
|
||||
在开发环境中,可以使用内存队列(`queue.type=memory`)来简化部署,避免依赖Kafka。数据库连接可以指向本地PostgreSQL实例。
|
||||
|
||||
#### 生产环境
|
||||
|
||||
在生产环境中,应使用完整的Docker Compose配置,包括PostgreSQL、Redis集群和Kafka。配置文件应设置适当的线程池大小和连接池参数以应对高并发。
|
||||
|
||||
### 环境变量使用
|
||||
|
||||
环境变量是管理不同环境配置的主要方式。以下是一些关键的环境变量:
|
||||
|
||||
- **HTTP_BIND_PORT**: HTTP服务端口
|
||||
- **SPRING_DATASOURCE_URL**: 数据库连接字符串
|
||||
- **REDIS_PASSWORD**: Redis密码
|
||||
- **KAFKA_SERVERS**: Kafka Broker地址列表
|
||||
- **SERVICE_TYPE**: 服务类型
|
||||
- **APP_LOG_LEVEL**: 应用日志级别
|
||||
- **PROTOCOLS_LOG_LEVEL**: 协议日志级别
|
||||
|
||||
环境变量可以在`docker-compose.yml`文件的`environment`部分设置,也可以在启动脚本中通过`export`命令设置。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[环境变量] --> B[覆盖配置文件默认值]
|
||||
B --> C{环境类型}
|
||||
C --> D[开发环境]
|
||||
C --> E[测试环境]
|
||||
C --> F[生产环境]
|
||||
D --> G[使用内存队列]
|
||||
D --> H[本地数据库]
|
||||
E --> I[独立测试数据库]
|
||||
E --> J[独立Redis]
|
||||
F --> K[集群化部署]
|
||||
F --> L[高可用配置]
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml)
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [app-service.yml](file://jcpp-app-bootstrap/src/main/resources/app-service.yml)
|
||||
- [protocol-service.yml](file://jcpp-protocol-bootstrap/src/main/resources/protocol-service.yml)
|
||||
|
||||
## 部署后验证
|
||||
|
||||
### 服务日志检查
|
||||
|
||||
部署后应首先检查服务日志以确认服务正常启动。日志配置由`log4j2.xml`文件定义,主要日志文件位于`logs/jcpp`目录下。
|
||||
|
||||
#### 日志文件说明
|
||||
|
||||
- **jcpp-app.log**: 应用服务主日志
|
||||
- **jcpp-protocol.log**: 协议服务主日志
|
||||
- **accesslog**: HTTP访问日志
|
||||
- **gc.log**: JVM垃圾回收日志
|
||||
- **heapdump**: 内存溢出时的堆转储文件
|
||||
|
||||
#### 日志级别配置
|
||||
|
||||
通过`APP_LOG_LEVEL`和`PROTOCOLS_LOG_LEVEL`环境变量可以控制日志级别。推荐在生产环境中使用`INFO`级别,在调试时使用`TRACE`级别。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[日志检查] --> B[查看启动日志]
|
||||
B --> C{是否包含错误}
|
||||
C --> |是| D[分析错误原因]
|
||||
C --> |否| E[检查服务端口]
|
||||
E --> F[验证API功能]
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [log4j2.xml](file://jcpp-app-bootstrap/src/main/resources/log4j2.xml)
|
||||
- [log4j2.xml](file://jcpp-protocol-bootstrap/src/main/resources/log4j2.xml)
|
||||
|
||||
**本节来源**
|
||||
|
||||
- [log4j2.xml](file://jcpp-app-bootstrap/src/main/resources/log4j2.xml)
|
||||
- [log4j2.xml](file://jcpp-protocol-bootstrap/src/main/resources/log4j2.xml)
|
||||
|
||||
### API功能测试
|
||||
|
||||
通过调用API接口验证服务功能是否正常。主要测试以下功能:
|
||||
|
||||
1. **健康检查**: 访问`/actuator/health`端点确认服务健康状态
|
||||
2. **协议连接**: 使用TCP客户端连接协议端口(如38001)测试协议监听器是否正常工作
|
||||
3. **核心业务API**: 调用充电桩管理、枪管理等API验证业务功能
|
||||
|
||||
测试时应确保所有依赖服务(PostgreSQL、Redis、Kafka)都已正常运行,并且网络连接正常。
|
||||
Reference in New Issue
Block a user