mirror of
https://gitee.com/san-bing/JChargePointProtocol
synced 2026-07-15 11:17:52 +08:00
wiki生成
This commit is contained in:
980
docs/核心模块详解/设备管理模块/充电枪管理.md
Normal file
980
docs/核心模块详解/设备管理模块/充电枪管理.md
Normal file
@@ -0,0 +1,980 @@
|
||||
# 充电枪管理
|
||||
|
||||
<cite>
|
||||
**本文档引用文件**
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java)
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java)
|
||||
- [GunMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/GunMapper.java)
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java)
|
||||
- [GunRepository.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/GunRepository.java)
|
||||
- [GunRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/GunRepositoryImpl.java)
|
||||
- [GunCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/GunCreateRequest.java)
|
||||
- [GunUpdateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/GunUpdateRequest.java)
|
||||
- [GunWithStatusResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/GunWithStatusResponse.java)
|
||||
- [PageResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PageResponse.java)
|
||||
- [AttrKeyEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/data/kv/AttrKeyEnum.java)
|
||||
- [GunRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/gun/GunRedisCache.java)
|
||||
- [GunRunStatusEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/GunRunStatusEnum.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [简介](#简介)
|
||||
2. [数据模型](#数据模型)
|
||||
3. [RESTful API](#restful-api)
|
||||
4. [服务层实现](#服务层实现)
|
||||
5. [缓存机制](#缓存机制)
|
||||
6. [状态管理](#状态管理)
|
||||
7. [使用示例](#使用示例)
|
||||
8. [级联关系与状态同步](#级联关系与状态同步)
|
||||
|
||||
## 简介
|
||||
|
||||
本文档详细描述了充电枪管理功能的实现,包括数据模型、API接口、服务层逻辑、缓存机制和状态管理。系统通过Gun实体管理充电枪,支持创建、查询、更新和删除操作,并通过属性系统实时跟踪充电枪的运行状态。
|
||||
|
||||
## 数据模型
|
||||
|
||||
### Gun实体
|
||||
|
||||
`Gun`实体是充电枪的核心数据模型,定义了充电枪的基本属性和关系。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Gun {
|
||||
+UUID id
|
||||
+LocalDateTime createdTime
|
||||
+LocalDateTime updatedTime
|
||||
+JsonNode additionalInfo
|
||||
+String gunNo
|
||||
+String gunName
|
||||
+String gunCode
|
||||
+UUID stationId
|
||||
+UUID pileId
|
||||
+Integer version
|
||||
}
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L57)
|
||||
|
||||
**核心属性说明**
|
||||
|
||||
- **id**: 充电枪唯一标识符,UUID类型
|
||||
- **gunNo**: 充电枪编号,如"01"、"02"
|
||||
- **gunName**: 充电枪名称
|
||||
- **gunCode**: 充电枪编码,全局唯一标识
|
||||
- **stationId**: 所属充电站ID,与Station实体关联
|
||||
- **pileId**: 所属充电桩ID,与Pile实体关联
|
||||
|
||||
**实体关系**
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
GUN {
|
||||
uuid id PK
|
||||
string gunNo
|
||||
string gunName
|
||||
string gunCode UK
|
||||
uuid stationId FK
|
||||
uuid pileId FK
|
||||
timestamp createdTime
|
||||
timestamp updatedTime
|
||||
integer version
|
||||
}
|
||||
PILE {
|
||||
uuid id PK
|
||||
string pileCode UK
|
||||
}
|
||||
GUN ||--o{ PILE : "属于"
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L57)
|
||||
|
||||
**实体关系说明**
|
||||
|
||||
- **1对多关系**: 一个充电桩(Pile)可以有多个充电枪(Gun),形成1对多关系
|
||||
- **外键约束**: `pileId`字段作为外键关联到Pile实体
|
||||
- **唯一性约束**: `gunCode`字段具有唯一性约束,确保全局唯一
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L57)
|
||||
|
||||
## RESTful API
|
||||
|
||||
### API概览
|
||||
|
||||
`GunController`提供了完整的RESTful API接口,支持对充电枪的CRUD操作。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[客户端] --> B[POST /api/guns]
|
||||
A --> C[GET /api/guns/{id}]
|
||||
A --> D[PUT /api/guns/{id}]
|
||||
A --> E[DELETE /api/guns/{id}]
|
||||
A --> F[GET /api/guns]
|
||||
A --> G[GET /api/guns/status/{gunCode}]
|
||||
A --> H[GET /api/guns/code/{gunCode}]
|
||||
B --> I[创建充电枪]
|
||||
C --> J[查询单个充电枪]
|
||||
D --> K[更新充电枪]
|
||||
E --> L[删除充电枪]
|
||||
F --> M[分页查询充电枪]
|
||||
G --> N[查询充电枪状态]
|
||||
H --> O[查询充电枪详情]
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L1-L116)
|
||||
|
||||
### API详情
|
||||
|
||||
#### 创建充电枪 (POST /api/guns)
|
||||
|
||||
创建新的充电枪实体。
|
||||
|
||||
**请求参数**
|
||||
|
||||
- **HTTP方法**: POST
|
||||
- **URL**: /api/guns
|
||||
- **Content-Type**: application/json
|
||||
|
||||
**请求体 (GunCreateRequest)**
|
||||
|
||||
```json
|
||||
{
|
||||
"gunName": "快充枪1",
|
||||
"gunNo": "01",
|
||||
"gunCode": "GUN001",
|
||||
"stationId": "uuid-string",
|
||||
"pileId": "uuid-string"
|
||||
}
|
||||
```
|
||||
|
||||
**响应格式**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "创建成功",
|
||||
"data": {
|
||||
"id": "uuid-string",
|
||||
"createdTime": "2023-01-01T00:00:00",
|
||||
"gunName": "快充枪1",
|
||||
"gunNo": "01",
|
||||
"gunCode": "GUN001",
|
||||
"stationId": "uuid-string",
|
||||
"pileId": "uuid-string",
|
||||
"version": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**验证规则**
|
||||
|
||||
- `gunName`: 必填,不允许XSS攻击
|
||||
- `gunNo`: 必填
|
||||
- `gunCode`: 必填,不允许重复
|
||||
- `stationId`: 必填,有效UUID
|
||||
- `pileId`: 必填,有效UUID
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L25-L32)
|
||||
- [GunCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/GunCreateRequest.java#L1-L37)
|
||||
|
||||
#### 查询充电枪 (GET /api/guns)
|
||||
|
||||
分页查询充电枪列表,包含状态信息。
|
||||
|
||||
**请求参数**
|
||||
|
||||
- **HTTP方法**: GET
|
||||
- **URL**: /api/guns
|
||||
- **查询参数**:
|
||||
- `page`: 页码(默认1)
|
||||
- `size`: 每页大小(默认10)
|
||||
- `gunName`: 充电枪名称(可选)
|
||||
- `pileId`: 充电桩ID(可选)
|
||||
|
||||
**响应格式 (PageResponse<GunWithStatusResponse>)**
|
||||
|
||||
```json
|
||||
{
|
||||
"records": [
|
||||
{
|
||||
"id": "uuid-string",
|
||||
"gunName": "快充枪1",
|
||||
"gunNo": "01",
|
||||
"gunCode": "GUN001",
|
||||
"stationId": "uuid-string",
|
||||
"pileId": "uuid-string",
|
||||
"stationName": "充电站A",
|
||||
"pileName": "充电桩1",
|
||||
"pileCode": "PILE001",
|
||||
"runStatus": "CHARGING"
|
||||
}
|
||||
],
|
||||
"total": 1,
|
||||
"totalPages": 1,
|
||||
"page": 1,
|
||||
"size": 10
|
||||
}
|
||||
```
|
||||
|
||||
**分页参数**
|
||||
|
||||
- **records**: 当前页的数据列表
|
||||
- **total**: 总记录数
|
||||
- **totalPages**: 总页数
|
||||
- **page**: 当前页码
|
||||
- **size**: 每页大小
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L62-L68)
|
||||
- [PageResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PageResponse.java#L1-L44)
|
||||
- [GunWithStatusResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/GunWithStatusResponse.java#L1-L96)
|
||||
|
||||
#### 更新充电枪 (PUT /api/guns/{id})
|
||||
|
||||
更新指定ID的充电枪信息。
|
||||
|
||||
**请求参数**
|
||||
|
||||
- **HTTP方法**: PUT
|
||||
- **URL**: /api/guns/{id}
|
||||
- **路径参数**: id (充电枪UUID)
|
||||
- **请求体**: GunUpdateRequest
|
||||
|
||||
**请求体 (GunUpdateRequest)**
|
||||
|
||||
```json
|
||||
{
|
||||
"gunName": "快充枪1-更新",
|
||||
"gunNo": "01",
|
||||
"gunCode": "GUN001",
|
||||
"stationId": "uuid-string",
|
||||
"pileId": "uuid-string"
|
||||
}
|
||||
```
|
||||
|
||||
**响应格式**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "更新成功",
|
||||
"data": {
|
||||
"id": "uuid-string",
|
||||
"updatedTime": "2023-01-01T00:00:00",
|
||||
"gunName": "快充枪1-更新",
|
||||
"gunNo": "01",
|
||||
"gunCode": "GUN001",
|
||||
"stationId": "uuid-string",
|
||||
"pileId": "uuid-string"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**更新规则**
|
||||
|
||||
- 允许修改所有字段
|
||||
- 更新时自动设置`updatedTime`字段
|
||||
- 版本号保持不变
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L34-L43)
|
||||
- [GunUpdateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/GunUpdateRequest.java#L1-L36)
|
||||
|
||||
#### 删除充电枪 (DELETE /api/guns/{id})
|
||||
|
||||
删除指定ID的充电枪。
|
||||
|
||||
**请求参数**
|
||||
|
||||
- **HTTP方法**: DELETE
|
||||
- **URL**: /api/guns/{id}
|
||||
- **路径参数**: id (充电枪UUID)
|
||||
|
||||
**响应格式**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "删除成功",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**删除逻辑**
|
||||
|
||||
- 先检查充电枪是否存在
|
||||
- 执行物理删除操作
|
||||
- 返回成功或失败状态
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L45-L51)
|
||||
|
||||
#### 查询充电枪状态 (GET /api/guns/status/{gunCode})
|
||||
|
||||
根据充电枪编码查询其运行状态。
|
||||
|
||||
**请求参数**
|
||||
|
||||
- **HTTP方法**: GET
|
||||
- **URL**: /api/guns/status/{gunCode}
|
||||
- **路径参数**: gunCode (充电枪编码)
|
||||
|
||||
**响应格式**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "查询成功",
|
||||
"data": "CHARGING"
|
||||
}
|
||||
```
|
||||
|
||||
**状态查询流程**
|
||||
|
||||
1. 根据`gunCode`查找充电枪实体
|
||||
2. 通过`AttributeService`获取`gunRunStatus`属性
|
||||
3. 返回状态值
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L69-L96)
|
||||
|
||||
#### 查询充电枪详情 (GET /api/guns/code/{gunCode})
|
||||
|
||||
根据充电枪编码查询其详细信息,包含状态。
|
||||
|
||||
**请求参数**
|
||||
|
||||
- **HTTP方法**: GET
|
||||
- **URL**: /api/guns/code/{gunCode}
|
||||
- **路径参数**: gunCode (充电枪编码)
|
||||
|
||||
**响应格式**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "查询成功",
|
||||
"data": {
|
||||
"id": "uuid-string",
|
||||
"gunName": "快充枪1",
|
||||
"gunNo": "01",
|
||||
"gunCode": "GUN001",
|
||||
"stationId": "uuid-string",
|
||||
"pileId": "uuid-string",
|
||||
"stationName": "充电站A",
|
||||
"pileName": "充电桩1",
|
||||
"pileCode": "PILE001",
|
||||
"runStatus": "CHARGING"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**详情查询特点**
|
||||
|
||||
- 返回完整的`GunWithStatusResponse`对象
|
||||
- 包含关联的充电站和充电桩信息
|
||||
- 包含当前运行状态
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L98-L115)
|
||||
|
||||
## 服务层实现
|
||||
|
||||
### DefaultGunService架构
|
||||
|
||||
`DefaultGunService`是充电枪业务逻辑的核心实现,协调数据访问和缓存操作。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class DefaultGunService {
|
||||
-GunMapper gunMapper
|
||||
-GunRepository gunRepository
|
||||
-AttributeService attributeService
|
||||
+createGun(GunCreateRequest) Gun
|
||||
+findById(UUID) Gun
|
||||
+updateGun(UUID, GunUpdateRequest) Gun
|
||||
+deleteGun(UUID) void
|
||||
+queryGunsWithStatus(GunQueryRequest) PageResponse
|
||||
+findByPileCodeAndGunNo(String, String) Gun
|
||||
+findByGunCode(String) Gun
|
||||
+findGunWithStatusByCode(String) GunWithStatusResponse
|
||||
+findGunStatus(UUID) String
|
||||
+saveGunStatusChange(UUID, String, Long) void
|
||||
+handleGunRunStatus(String, String, GunRunStatus, long) boolean
|
||||
}
|
||||
class GunService {
|
||||
<<interface>>
|
||||
+createGun(GunCreateRequest) Gun
|
||||
+findById(UUID) Gun
|
||||
+updateGun(UUID, GunUpdateRequest) Gun
|
||||
+deleteGun(UUID) void
|
||||
+queryGunsWithStatus(GunQueryRequest) PageResponse
|
||||
+findByPileCodeAndGunNo(String, String) Gun
|
||||
+findByGunCode(String) Gun
|
||||
+findGunWithStatusByCode(String) GunWithStatusResponse
|
||||
+findGunStatus(UUID) String
|
||||
+saveGunStatusChange(UUID, String, Long) void
|
||||
+handleGunRunStatus(String, String, GunRunStatus, long) boolean
|
||||
}
|
||||
DefaultGunService --|> GunService : 实现
|
||||
DefaultGunService --> GunMapper : 使用
|
||||
DefaultGunService --> GunRepository : 使用
|
||||
DefaultGunService --> AttributeService : 使用
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L1-L246)
|
||||
|
||||
### 核心方法分析
|
||||
|
||||
#### 创建充电枪 (createGun)
|
||||
|
||||
实现充电枪的创建逻辑。
|
||||
|
||||
**处理流程**
|
||||
|
||||
1. 检查`gunCode`是否已存在
|
||||
2. 构建新的`Gun`实体
|
||||
3. 设置默认值(ID、创建时间、版本等)
|
||||
4. 插入数据库
|
||||
|
||||
**验证逻辑**
|
||||
|
||||
- 使用`LambdaQueryWrapper`检查`gunCode`唯一性
|
||||
- 抛出异常阻止重复创建
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L48-L75)
|
||||
|
||||
#### 查询充电枪状态 (findGunStatus)
|
||||
|
||||
从属性系统中查询充电枪的运行状态。
|
||||
|
||||
**实现细节**
|
||||
|
||||
- 使用`AttributeService.find()`异步获取属性
|
||||
- 属性键为`AttrKeyEnum.GUN_RUN_STATUS.getCode()`
|
||||
- 返回字符串格式的状态值
|
||||
|
||||
**异步处理**
|
||||
|
||||
- 使用`ListenableFuture`进行异步调用
|
||||
- 通过`get()`方法阻塞等待结果
|
||||
- 包含异常处理逻辑
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L178-L193)
|
||||
|
||||
#### 保存充电枪状态 (saveGunStatusChange)
|
||||
|
||||
将充电枪状态保存到属性系统。
|
||||
|
||||
**实现细节**
|
||||
|
||||
- 创建`BaseAttributeKvEntry`对象
|
||||
- 使用`StringDataEntry`存储状态值
|
||||
- 调用`attributeService.save()`持久化
|
||||
|
||||
**时间戳处理**
|
||||
|
||||
- 使用传入的`ts`参数或当前时间
|
||||
- 支持精确到毫秒的时间戳
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L195-L208)
|
||||
|
||||
#### 处理充电枪运行状态 (handleGunRunStatus)
|
||||
|
||||
处理从协议层上报的充电枪状态。
|
||||
|
||||
**处理流程**
|
||||
|
||||
1. 将Proto状态转换为数据库枚举
|
||||
2. 根据`pileCode`和`gunNo`查找充电枪
|
||||
3. 检查状态是否发生变化
|
||||
4. 保存新状态到属性系统
|
||||
5. 判断是否需要更新充电桩状态
|
||||
|
||||
**状态转换**
|
||||
|
||||
- 实现Proto状态到数据库枚举的映射
|
||||
- 支持多种状态类型(空闲、充电中、故障等)
|
||||
- 未知状态返回null
|
||||
|
||||
**状态同步**
|
||||
|
||||
- 检查当前状态避免重复更新
|
||||
- 记录状态变化日志
|
||||
- 触发相关业务逻辑
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L210-L244)
|
||||
|
||||
## 缓存机制
|
||||
|
||||
### 缓存架构
|
||||
|
||||
系统采用多级缓存策略提升查询性能。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[应用层] --> B[GunService]
|
||||
B --> C[GunRepository]
|
||||
C --> D[GunRedisCache]
|
||||
D --> E[Redis]
|
||||
C --> F[GunMapper]
|
||||
F --> G[数据库]
|
||||
style D fill:#f9f,stroke:#333
|
||||
style F fill:#bbf,stroke:#333
|
||||
subgraph "缓存层"
|
||||
D
|
||||
E
|
||||
end
|
||||
subgraph "持久层"
|
||||
F
|
||||
G
|
||||
end
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [GunRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/GunRepositoryImpl.java#L1-L97)
|
||||
- [GunRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/gun/GunRedisCache.java#L1-L36)
|
||||
|
||||
### GunRedisCache实现
|
||||
|
||||
`GunRedisCache`是基于Redis的充电枪缓存实现。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class GunRedisCache {
|
||||
+String cacheName
|
||||
+CacheSpecsMap cacheSpecsMap
|
||||
+LettuceConnectionFactory connectionFactory
|
||||
+JCPPRedisSerializer serializer
|
||||
+serialize(Gun) byte[]
|
||||
+deserialize(GunCacheKey, byte[]) Gun
|
||||
}
|
||||
class VersionedRedisCache {
|
||||
<<abstract>>
|
||||
+get(K, Callable<V>) V
|
||||
+evict(K) void
|
||||
+evict(Collection<K>) void
|
||||
}
|
||||
GunRedisCache --|> VersionedRedisCache : 继承
|
||||
GunRedisCache --> Gun : 序列化/反序列化
|
||||
GunRedisCache --> JacksonUtil : JSON转换
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [GunRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/gun/GunRedisCache.java#L1-L36)
|
||||
|
||||
**核心特性**
|
||||
|
||||
- 使用`JCPPRedisSerializer`进行序列化
|
||||
- 基于`JacksonUtil`实现JSON转换
|
||||
- 支持版本化缓存
|
||||
- 配置化缓存策略
|
||||
|
||||
**序列化实现**
|
||||
|
||||
- `serialize()`: 使用Jackson将Gun对象转换为字节数组
|
||||
- `deserialize()`: 从字节数组反序列化为Gun对象
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/gun/GunRedisCache.java#L1-L36)
|
||||
|
||||
### 缓存键设计 (GunCacheKey)
|
||||
|
||||
缓存键设计支持多种查询场景。
|
||||
|
||||
```java
|
||||
// 伪代码表示GunCacheKey的设计
|
||||
public class GunCacheKey {
|
||||
private UUID gunId; // 基于ID的缓存
|
||||
private String pileCode; // 基于桩编码的缓存
|
||||
private String gunNo; // 基于枪编号的缓存
|
||||
private String gunCode; // 基于枪编码的缓存
|
||||
|
||||
// 支持多种构造函数
|
||||
public GunCacheKey(UUID gunId)
|
||||
public GunCacheKey(String pileCode, String gunNo)
|
||||
public GunCacheKey(String gunCode)
|
||||
}
|
||||
```
|
||||
|
||||
**缓存键类型**
|
||||
|
||||
- **基于ID**: `new GunCacheKey(gunId)`
|
||||
- **基于桩编码+枪编号**: `new GunCacheKey(pileCode, gunNo)`
|
||||
- **基于枪编码**: `new GunCacheKey(gunCode)`
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/GunRepositoryImpl.java#L1-L97)
|
||||
|
||||
### 缓存事件处理
|
||||
|
||||
通过事件机制维护缓存一致性。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Service as DefaultGunService
|
||||
participant Repository as GunRepositoryImpl
|
||||
participant Cache as GunRedisCache
|
||||
participant Event as GunCacheEvictEvent
|
||||
Service->>Repository : updateGun()
|
||||
Repository->>Repository : handleEvictEvent()
|
||||
Repository->>Cache : evict()
|
||||
Cache->>Redis : 删除缓存
|
||||
Repository->>Repository : 查询数据库
|
||||
Repository-->>Service : 返回结果
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [GunRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/GunRepositoryImpl.java#L1-L97)
|
||||
|
||||
**事件处理流程**
|
||||
|
||||
1. 服务层执行更新或删除操作
|
||||
2. 触发`GunCacheEvictEvent`事件
|
||||
3. `GunRepositoryImpl`监听并处理事件
|
||||
4. 从Redis缓存中删除相关键
|
||||
5. 后续查询将从数据库获取最新数据
|
||||
|
||||
**缓存失效策略**
|
||||
|
||||
- 写操作后立即失效缓存
|
||||
- 支持批量失效多个缓存键
|
||||
- 保证缓存与数据库的一致性
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/GunRepositoryImpl.java#L25-L45)
|
||||
|
||||
## 状态管理
|
||||
|
||||
### 运行状态枚举 (GunRunStatusEnum)
|
||||
|
||||
定义了充电枪的所有可能运行状态。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class GunRunStatusEnum {
|
||||
+IDLE
|
||||
+INSERTED
|
||||
+CHARGING
|
||||
+CHARGE_COMPLETE
|
||||
+DISCHARGE_READY
|
||||
+DISCHARGING
|
||||
+DISCHARGE_COMPLETE
|
||||
+RESERVED
|
||||
+FAULT
|
||||
}
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [GunRunStatusEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/GunRunStatusEnum.java)
|
||||
|
||||
**状态说明**
|
||||
|
||||
- **IDLE**: 空闲状态,未连接车辆
|
||||
- **INSERTED**: 已插枪,未开始充电
|
||||
- **CHARGING**: 正在充电
|
||||
- **CHARGE_COMPLETE**: 充电完成
|
||||
- **DISCHARGE_READY**: 放电准备
|
||||
- **DISCHARGING**: 正在放电
|
||||
- **DISCHARGE_COMPLETE**: 放电完成
|
||||
- **RESERVED**: 已预约
|
||||
- **FAULT**: 故障状态
|
||||
|
||||
**状态转换**
|
||||
|
||||
- 通过`switch`语句实现Proto状态到枚举的转换
|
||||
- 未知状态返回null,不进行更新
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [GunRunStatusEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/GunRunStatusEnum.java)
|
||||
|
||||
### 状态获取流程
|
||||
|
||||
从协议会话中获取和更新充电枪状态。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Protocol as 协议层
|
||||
participant Service as DefaultGunService
|
||||
participant Attribute as AttributeService
|
||||
participant Redis as Redis
|
||||
participant DB as 数据库
|
||||
Protocol->>Service : handleGunRunStatus(pileCode, gunNo, protoStatus, ts)
|
||||
Service->>Service : convertProtoStatusToDbStatus()
|
||||
Service->>Repository : findByPileCodeAndGunNo(pileCode, gunNo)
|
||||
Repository->>Redis : 查询缓存
|
||||
Redis-->>Repository : 返回结果
|
||||
Repository-->>Service : 返回Gun实体
|
||||
Service->>Service : findGunStatus(gunId)
|
||||
Service->>Attribute : find(gunId, GUN_RUN_STATUS)
|
||||
Attribute->>Redis : 查询属性缓存
|
||||
Redis-->>Attribute : 返回状态
|
||||
Attribute-->>Service : 返回当前状态
|
||||
alt 状态发生变化
|
||||
Service->>Service : saveGunStatusChange(gunId, status, ts)
|
||||
Service->>Attribute : save(gunId, attribute)
|
||||
Attribute->>Redis : 保存属性
|
||||
Redis-->>Attribute : 确认
|
||||
Attribute-->>Service : 确认
|
||||
Service-->>Protocol : 返回true
|
||||
else 状态未变化
|
||||
Service-->>Protocol : 返回false
|
||||
end
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L210-L244)
|
||||
|
||||
**状态同步机制**
|
||||
|
||||
1. 协议层上报充电枪状态
|
||||
2. 服务层转换状态格式
|
||||
3. 查找对应的充电枪实体
|
||||
4. 获取当前状态进行比较
|
||||
5. 只有状态变化时才更新
|
||||
6. 保存新状态到属性系统
|
||||
|
||||
**性能优化**
|
||||
|
||||
- 使用缓存减少数据库查询
|
||||
- 状态比较避免不必要的更新
|
||||
- 异步属性服务提高响应速度
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L210-L244)
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 为充电桩配置两把充电枪
|
||||
|
||||
展示如何为一个充电桩配置两把充电枪的完整流程。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始]) --> CreatePile["创建充电桩"]
|
||||
CreatePile --> GetPileId["获取充电桩ID"]
|
||||
GetPileId --> CreateGun1["创建第一把充电枪"]
|
||||
CreateGun1 --> SetGun1Props["设置第一把枪属性"]
|
||||
SetGun1Props --> CreateGun2["创建第二把充电枪"]
|
||||
CreateGun2 --> SetGun2Props["设置第二把枪属性"]
|
||||
SetGun2Props --> Verify["验证配置结果"]
|
||||
Verify --> End([完成])
|
||||
style CreatePile fill:#9f9,stroke:#333
|
||||
style CreateGun1 fill:#9f9,stroke:#333
|
||||
style CreateGun2 fill:#9f9,stroke:#333
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L48-L75)
|
||||
|
||||
**实现步骤**
|
||||
|
||||
#### 步骤1: 创建充电桩
|
||||
|
||||
首先创建一个充电桩实体。
|
||||
|
||||
```java
|
||||
// 伪代码:创建充电桩
|
||||
Pile pile = pileService.createPile(createRequest);
|
||||
UUID pileId = pile.getId();
|
||||
```
|
||||
|
||||
#### 步骤2: 创建第一把充电枪
|
||||
|
||||
为充电桩创建第一把充电枪。
|
||||
|
||||
```java
|
||||
// 伪代码:创建第一把充电枪
|
||||
GunCreateRequest gun1Request = GunCreateRequest.builder()
|
||||
.gunName("快充枪1")
|
||||
.gunNo("01")
|
||||
.gunCode("GUN001")
|
||||
.stationId(stationId)
|
||||
.pileId(pileId)
|
||||
.build();
|
||||
|
||||
Gun gun1 = gunService.createGun(gun1Request);
|
||||
```
|
||||
|
||||
#### 步骤3: 创建第二把充电枪
|
||||
|
||||
为同一充电桩创建第二把充电枪。
|
||||
|
||||
```java
|
||||
// 伪代码:创建第二把充电枪
|
||||
GunCreateRequest gun2Request = GunCreateRequest.builder()
|
||||
.gunName("快充枪2")
|
||||
.gunNo("02")
|
||||
.gunCode("GUN002")
|
||||
.stationId(stationId)
|
||||
.pileId(pileId)
|
||||
.build();
|
||||
|
||||
Gun gun2 = gunService.createGun(gun2Request);
|
||||
```
|
||||
|
||||
#### 步骤4: 验证配置结果
|
||||
|
||||
查询充电桩下的所有充电枪。
|
||||
|
||||
```java
|
||||
// 伪代码:验证配置
|
||||
List<Gun> guns = gunService.findByPileId(pileId);
|
||||
assert guns.size() == 2;
|
||||
|
||||
GunWithStatusResponse gun1Status = gunService.findGunWithStatusByCode("GUN001");
|
||||
GunWithStatusResponse gun2Status = gunService.findGunWithStatusByCode("GUN002");
|
||||
```
|
||||
|
||||
**关键要点**
|
||||
|
||||
- 两把充电枪共享同一个`pileId`
|
||||
- `gunNo`在同一充电桩下必须唯一
|
||||
- `gunCode`在整个系统中必须唯一
|
||||
- 可以独立管理每把充电枪的状态
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L48-L75)
|
||||
- [GunMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/GunMapper.java#L1-L132)
|
||||
|
||||
## 级联关系与状态同步
|
||||
|
||||
### 级联关系管理
|
||||
|
||||
充电枪与充电桩之间的级联关系管理。
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
STATION ||--o{ PILE : "拥有"
|
||||
PILE ||--o{ GUN : "拥有"
|
||||
STATION {
|
||||
uuid id PK
|
||||
string stationName
|
||||
}
|
||||
PILE {
|
||||
uuid id PK
|
||||
string pileCode UK
|
||||
uuid stationId FK
|
||||
}
|
||||
GUN {
|
||||
uuid id PK
|
||||
string gunCode UK
|
||||
uuid pileId FK
|
||||
string gunNo
|
||||
}
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L57)
|
||||
|
||||
**级联操作**
|
||||
|
||||
- **创建**: 充电枪必须关联到存在的充电桩
|
||||
- **查询**: 支持通过充电桩查询所有充电枪
|
||||
- **更新**: 可以修改充电枪所属的充电桩
|
||||
- **删除**: 删除充电桩时级联删除所有充电枪
|
||||
|
||||
**外键约束**
|
||||
|
||||
- `pileId`字段确保充电枪必须属于某个充电桩
|
||||
- 数据库层面保证引用完整性
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L57)
|
||||
|
||||
### 状态同步机制
|
||||
|
||||
充电枪状态变化时与充电桩的状态同步。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
GunStatusChange["充电枪状态变化"] --> CheckStatus["检查新状态"]
|
||||
CheckStatus --> |CHARGING| UpdatePile["更新充电桩状态"]
|
||||
CheckStatus --> |DISCHARGING| UpdatePile["更新充电桩状态"]
|
||||
CheckStatus --> |FAULT| UpdatePile["更新充电桩状态"]
|
||||
CheckStatus --> |其他状态| NoUpdate["不更新"]
|
||||
UpdatePile --> PileService["调用PileService"]
|
||||
PileService --> UpdateStatus["更新充电桩状态"]
|
||||
UpdateStatus --> Log["记录日志"]
|
||||
Log --> End([完成])
|
||||
style UpdatePile fill:#f96,stroke:#333
|
||||
style NoUpdate fill:#69f,stroke:#333
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L233-L244)
|
||||
|
||||
**同步规则**
|
||||
|
||||
```java
|
||||
private boolean shouldUpdatePileStatus(GunRunStatusEnum gunStatus) {
|
||||
return switch (gunStatus) {
|
||||
case CHARGING, DISCHARGING -> true; // 充电或放电时更新
|
||||
case FAULT -> true; // 故障时更新
|
||||
default -> false; // 其他状态不更新
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**触发条件**
|
||||
|
||||
- **充电开始**: 充电枪状态变为`CHARGING`
|
||||
- **放电开始**: 充电枪状态变为`DISCHARGING`
|
||||
- **故障发生**: 充电枪状态变为`FAULT`
|
||||
|
||||
**同步流程**
|
||||
|
||||
1. 充电枪状态发生变化
|
||||
2. 调用`shouldUpdatePileStatus()`判断是否需要同步
|
||||
3. 如果需要,通知`PileService`更新充电桩状态
|
||||
4. 更新充电桩的在线状态和运行状态
|
||||
|
||||
**性能考虑**
|
||||
|
||||
- 只在必要时触发同步,减少不必要的操作
|
||||
- 使用异步机制避免阻塞主流程
|
||||
- 缓存充电桩状态减少数据库查询
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L233-L244)
|
||||
699
docs/核心模块详解/设备管理模块/充电桩管理.md
Normal file
699
docs/核心模块详解/设备管理模块/充电桩管理.md
Normal file
@@ -0,0 +1,699 @@
|
||||
# 充电桩管理
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java)
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java)
|
||||
- [PileCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/PileCreateRequest.java)
|
||||
- [PileUpdateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/PileUpdateRequest.java)
|
||||
- [PileWithStatusResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PileWithStatusResponse.java)
|
||||
- [DefaultPileService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileService.java)
|
||||
- [PileRepository.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/PileRepository.java)
|
||||
- [PileRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/PileRepositoryImpl.java)
|
||||
- [PileStatusEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/PileStatusEnum.java)
|
||||
- [PileTypeEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/PileTypeEnum.java)
|
||||
- [StartChargeDTO.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/dto/StartChargeDTO.java)
|
||||
- [RestartPileDTO.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/dto/RestartPileDTO.java)
|
||||
- [DefaultPileProtocolService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java)
|
||||
- [RpcController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [简介](#简介)
|
||||
2. [数据模型](#数据模型)
|
||||
3. [RESTful API](#restful-api)
|
||||
4. [业务逻辑处理](#业务逻辑处理)
|
||||
5. [远程控制操作](#远程控制操作)
|
||||
6. [使用示例](#使用示例)
|
||||
7. [状态机与实时同步](#状态机与实时同步)
|
||||
|
||||
## 简介
|
||||
|
||||
本文档详细阐述了充电桩管理功能的实现,包括充电桩实体的数据模型、RESTful
|
||||
API接口、业务逻辑处理以及远程控制操作。系统采用分层架构,通过Pile实体表示充电桩,PileController提供RESTful
|
||||
API,DefaultPileService处理业务逻辑,PileRepository负责数据持久化,DownlinkCallService实现远程控制指令的发送。
|
||||
|
||||
## 数据模型
|
||||
|
||||
充电桩管理功能的核心是Pile实体,它表示一个物理充电桩,包含其基本信息、状态和与充电站的关系。
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
PILE {
|
||||
uuid id PK
|
||||
timestamp createdTime
|
||||
timestamp updatedTime
|
||||
string pileName
|
||||
string pileCode UK
|
||||
string protocol
|
||||
uuid stationId FK
|
||||
string brand
|
||||
string model
|
||||
string manufacturer
|
||||
string type
|
||||
integer version
|
||||
json additionalInfo
|
||||
}
|
||||
STATION {
|
||||
uuid id PK
|
||||
string stationName
|
||||
string stationCode UK
|
||||
}
|
||||
PILE ||--o{ STATION : "属于"
|
||||
```
|
||||
|
||||
**图源**
|
||||
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java#L1-L63)
|
||||
- [PileTypeEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/PileTypeEnum.java#L1-L22)
|
||||
|
||||
### Pile实体核心属性
|
||||
|
||||
Pile实体定义了充电桩的核心属性,这些属性在数据库中持久化存储。
|
||||
|
||||
| 属性名 | 类型 | 描述 | 约束 |
|
||||
|----------------|---------------|----------|--------------|
|
||||
| id | UUID | 充电桩唯一标识符 | 主键 |
|
||||
| pileName | String | 充电桩名称 | 非空,防XSS攻击 |
|
||||
| pileCode | String | 充电桩编号 | 唯一,非空,防XSS攻击 |
|
||||
| protocol | String | 通信协议类型 | 非空,防XSS攻击 |
|
||||
| stationId | UUID | 所属充电站ID | 外键,非空 |
|
||||
| brand | String | 品牌 | 防XSS攻击 |
|
||||
| model | String | 型号 | 防XSS攻击 |
|
||||
| manufacturer | String | 制造商 | 防XSS攻击 |
|
||||
| type | PileTypeEnum | 充电桩类型 | 枚举值 |
|
||||
| createdTime | LocalDateTime | 创建时间 | 自动填充 |
|
||||
| updatedTime | LocalDateTime | 更新时间 | 自动填充 |
|
||||
| additionalInfo | JsonNode | 附加信息 | JSON格式 |
|
||||
| version | Integer | 版本号 | 用于乐观锁 |
|
||||
|
||||
**节源**
|
||||
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java#L1-L63)
|
||||
|
||||
### PileStatusEnum状态枚举
|
||||
|
||||
充电桩状态枚举定义了充电桩的在线/离线状态,独立于充电枪的工作状态。
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> OFFLINE
|
||||
OFFLINE --> ONLINE : 设备登录成功
|
||||
OFFLINE --> ONLINE : 心跳正常
|
||||
ONLINE --> OFFLINE : 设备断开连接
|
||||
ONLINE --> OFFLINE : 心跳超时
|
||||
OFFLINE --> OFFLINE : 设备未登录
|
||||
ONLINE --> ONLINE : 能正常通信
|
||||
```
|
||||
|
||||
充电桩状态设计原则:
|
||||
|
||||
- 状态独立于充电枪状态,不受枪的工作状态影响
|
||||
- 只关注设备的网络连接状态和基础可用性
|
||||
- 状态转换由设备登录、心跳和连接状态决定
|
||||
|
||||
**节源**
|
||||
|
||||
- [PileStatusEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/PileStatusEnum.java#L1-L50)
|
||||
|
||||
### PileTypeEnum类型枚举
|
||||
|
||||
充电桩类型枚举定义了充电桩的类型,目前支持交流和直流两种类型。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class PileTypeEnum {
|
||||
+AC : PileTypeEnum
|
||||
+DC : PileTypeEnum
|
||||
+getValue() String
|
||||
}
|
||||
```
|
||||
|
||||
| 枚举值 | 描述 |
|
||||
|-----|-------|
|
||||
| AC | 交流充电桩 |
|
||||
| DC | 直流充电桩 |
|
||||
|
||||
**节源**
|
||||
|
||||
- [PileTypeEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/PileTypeEnum.java#L1-L22)
|
||||
|
||||
### 与Station的多对一关系
|
||||
|
||||
每个充电桩属于一个充电站,形成多对一的关系。这种关系通过Pile实体中的stationId字段实现,该字段是外键,指向Station实体的id。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Pile {
|
||||
-UUID id
|
||||
-String pileName
|
||||
-String pileCode
|
||||
-UUID stationId
|
||||
+getStationId() UUID
|
||||
}
|
||||
class Station {
|
||||
-UUID id
|
||||
-String stationName
|
||||
-String stationCode
|
||||
+getId() UUID
|
||||
}
|
||||
Pile --> Station : "属于"
|
||||
```
|
||||
|
||||
**图源**
|
||||
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java#L1-L63)
|
||||
|
||||
## RESTful API
|
||||
|
||||
PileController类暴露了充电桩管理的RESTful API,提供了对充电桩的增删改查和远程控制操作。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "PileController"
|
||||
A[POST /piles]
|
||||
B[GET /piles]
|
||||
C[PUT /piles/{id}]
|
||||
D[DELETE /piles/{id}]
|
||||
E[GET /piles/{id}]
|
||||
F[POST /piles/{id}/start-charge]
|
||||
G[POST /piles/{id}/restart]
|
||||
end
|
||||
Client --> A
|
||||
Client --> B
|
||||
Client --> C
|
||||
Client --> D
|
||||
Client --> E
|
||||
Client --> F
|
||||
Client --> G
|
||||
```
|
||||
|
||||
**图源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L1-L111)
|
||||
|
||||
### 创建充电桩 (POST /piles)
|
||||
|
||||
创建新的充电桩,需要提供充电桩的基本信息。
|
||||
|
||||
#### 请求
|
||||
|
||||
- **方法**: POST
|
||||
- **路径**: /api/piles
|
||||
- **认证**: 需要有效的JWT令牌
|
||||
- **授权**: 需要管理员权限
|
||||
|
||||
#### 请求DTO (PileCreateRequest)
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class PileCreateRequest {
|
||||
+pileName : String
|
||||
+pileCode : String
|
||||
+protocol : String
|
||||
+stationId : UUID
|
||||
+brand : String
|
||||
+model : String
|
||||
+manufacturer : String
|
||||
+type : PileTypeEnum
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必填 | 描述 |
|
||||
|--------------|--------------|----|-------------|
|
||||
| pileName | String | 是 | 充电桩名称 |
|
||||
| pileCode | String | 是 | 充电桩编号 |
|
||||
| protocol | String | 是 | 通信协议 |
|
||||
| stationId | UUID | 是 | 所属充电站ID |
|
||||
| brand | String | 否 | 品牌 |
|
||||
| model | String | 否 | 型号 |
|
||||
| manufacturer | String | 否 | 制造商 |
|
||||
| type | PileTypeEnum | 否 | 充电桩类型,默认为DC |
|
||||
|
||||
#### 响应
|
||||
|
||||
- **成功**: HTTP 200,返回创建的Pile实体
|
||||
- **失败**: HTTP 400,参数验证失败;HTTP 409,充电桩编号已存在
|
||||
|
||||
**节源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L25-L34)
|
||||
- [PileCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/PileCreateRequest.java#L1-L45)
|
||||
|
||||
### 分页查询充电桩 (GET /piles)
|
||||
|
||||
分页查询充电桩列表,支持多种查询条件。
|
||||
|
||||
#### 请求
|
||||
|
||||
- **方法**: GET
|
||||
- **路径**: /api/piles
|
||||
- **认证**: 需要有效的JWT令牌
|
||||
- **授权**: 需要查看权限
|
||||
|
||||
#### 请求参数 (PileQueryRequest)
|
||||
|
||||
| 参数 | 类型 | 描述 |
|
||||
|--------------|----------------|-------------|
|
||||
| page | Integer | 页码,从1开始 |
|
||||
| size | Integer | 每页大小 |
|
||||
| pileName | String | 充电桩名称(模糊查询) |
|
||||
| pileCode | String | 充电桩编号 |
|
||||
| protocol | String | 通信协议 |
|
||||
| stationId | UUID | 所属充电站ID |
|
||||
| brand | String | 品牌 |
|
||||
| model | String | 型号 |
|
||||
| manufacturer | String | 制造商 |
|
||||
| type | PileTypeEnum | 充电桩类型 |
|
||||
| status | PileStatusEnum | 充电桩状态 |
|
||||
|
||||
#### 响应DTO (PileWithStatusResponse)
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class PileWithStatusResponse {
|
||||
+id : UUID
|
||||
+createdTime : LocalDateTime
|
||||
+updatedTime : LocalDateTime
|
||||
+pileName : String
|
||||
+pileCode : String
|
||||
+protocol : String
|
||||
+stationId : UUID
|
||||
+brand : String
|
||||
+model : String
|
||||
+manufacturer : String
|
||||
+type : PileTypeEnum
|
||||
+status : PileStatusEnum
|
||||
+connectedAt : Long
|
||||
+disconnectedAt : Long
|
||||
+lastActiveTime : Long
|
||||
+gunCount : Long
|
||||
}
|
||||
```
|
||||
|
||||
响应包含分页信息和充电桩列表,每个充电桩都包含其状态信息。
|
||||
|
||||
#### 响应
|
||||
|
||||
- **成功**: HTTP 200,返回PageResponse<PileWithStatusResponse>
|
||||
- **失败**: HTTP 400,参数验证失败
|
||||
|
||||
**节源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L68-L77)
|
||||
- [PileQueryRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/PileQueryRequest.java#L1-L36)
|
||||
- [PileWithStatusResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PileWithStatusResponse.java#L1-L116)
|
||||
|
||||
### 更新充电桩 (PUT /piles/{id})
|
||||
|
||||
更新现有充电桩的信息。
|
||||
|
||||
#### 请求
|
||||
|
||||
- **方法**: PUT
|
||||
- **路径**: /api/piles/{id}
|
||||
- **认证**: 需要有效的JWT令牌
|
||||
- **授权**: 需要编辑权限
|
||||
|
||||
#### 请求DTO (PileUpdateRequest)
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class PileUpdateRequest {
|
||||
+pileName : String
|
||||
+protocol : String
|
||||
+brand : String
|
||||
+model : String
|
||||
+manufacturer : String
|
||||
+type : PileTypeEnum
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必填 | 描述 |
|
||||
|--------------|--------------|----|-------|
|
||||
| pileName | String | 是 | 充电桩名称 |
|
||||
| protocol | String | 是 | 通信协议 |
|
||||
| brand | String | 否 | 品牌 |
|
||||
| model | String | 否 | 型号 |
|
||||
| manufacturer | String | 否 | 制造商 |
|
||||
| type | PileTypeEnum | 否 | 充电桩类型 |
|
||||
|
||||
#### 响应
|
||||
|
||||
- **成功**: HTTP 200,返回更新后的Pile实体
|
||||
- **失败**: HTTP 404,充电桩不存在;HTTP 400,参数验证失败
|
||||
|
||||
**节源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L40-L50)
|
||||
- [PileUpdateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/PileUpdateRequest.java#L1-L35)
|
||||
|
||||
### 删除充电桩 (DELETE /piles/{id})
|
||||
|
||||
删除指定ID的充电桩。
|
||||
|
||||
#### 请求
|
||||
|
||||
- **方法**: DELETE
|
||||
- **路径**: /api/piles/{id}
|
||||
- **认证**: 需要有效的JWT令牌
|
||||
- **授权**: 需要删除权限
|
||||
|
||||
#### 响应
|
||||
|
||||
- **成功**: HTTP 200,返回成功消息
|
||||
- **失败**: HTTP 404,充电桩不存在;HTTP 409,充电桩下有充电枪
|
||||
|
||||
**节源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L52-L60)
|
||||
|
||||
## 业务逻辑处理
|
||||
|
||||
DefaultPileService类负责处理充电桩管理的核心业务逻辑,包括数据持久化、缓存交互和状态管理。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as "客户端"
|
||||
participant Controller as "PileController"
|
||||
participant Service as "DefaultPileService"
|
||||
participant Repository as "PileRepository"
|
||||
participant Cache as "PileRedisCache"
|
||||
participant DB as "数据库"
|
||||
Client->>Controller : POST /piles
|
||||
Controller->>Service : createPile(request)
|
||||
Service->>Repository : findPileByCode(code)
|
||||
Repository->>Cache : get(pileCode)
|
||||
Cache-->>Repository : null
|
||||
Repository->>DB : selectByCode(code)
|
||||
DB-->>Repository : null
|
||||
Repository-->>Service : null
|
||||
Service->>DB : insert(pile)
|
||||
DB-->>Service : success
|
||||
Service-->>Controller : Pile
|
||||
Controller-->>Client : 200 OK
|
||||
```
|
||||
|
||||
**图源**
|
||||
|
||||
- [DefaultPileService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileService.java#L1-L329)
|
||||
- [PileRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/PileRepositoryImpl.java#L1-L49)
|
||||
|
||||
### DefaultPileService核心功能
|
||||
|
||||
DefaultPileService实现了PileService接口,处理充电桩的业务逻辑。
|
||||
|
||||
| 方法 | 描述 |
|
||||
|------------------------|----------------|
|
||||
| createPile | 创建充电桩,检查编号唯一性 |
|
||||
| findById | 根据ID查找充电桩 |
|
||||
| findByPileCode | 根据编号查找充电桩 |
|
||||
| updatePile | 更新充电桩信息 |
|
||||
| deletePile | 删除充电桩,检查是否有充电枪 |
|
||||
| queryPilesWithStatus | 分页查询充电桩及状态 |
|
||||
| updatePileStatus | 更新充电桩状态 |
|
||||
| handlePileLogin | 处理充电桩登录 |
|
||||
| handlePileHeartbeat | 处理充电桩心跳 |
|
||||
| handlePileSessionClose | 处理充电桩会话关闭 |
|
||||
|
||||
**节源**
|
||||
|
||||
- [DefaultPileService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileService.java#L1-L329)
|
||||
|
||||
### 数据持久化 (PileRepository)
|
||||
|
||||
PileRepository接口定义了充电桩的数据访问方法,PileRepositoryImpl实现了该接口并提供了缓存支持。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class PileRepository {
|
||||
+findPileByCode(pileCode : String) : Pile
|
||||
}
|
||||
class PileRepositoryImpl {
|
||||
-pileMapper : PileMapper
|
||||
-cache : PileRedisCache
|
||||
+findPileByCode(pileCode : String) : Pile
|
||||
+handleEvictEvent(event : PileCacheEvictEvent) : void
|
||||
}
|
||||
class PileMapper {
|
||||
+selectByCode(pileCode : String) : Pile
|
||||
+insert(pile : Pile) : int
|
||||
+updateById(pile : Pile) : int
|
||||
+deleteById(id : UUID) : int
|
||||
}
|
||||
PileRepository <|-- PileRepositoryImpl
|
||||
PileRepositoryImpl --> PileMapper : "使用"
|
||||
PileRepositoryImpl --> PileRedisCache : "使用"
|
||||
```
|
||||
|
||||
PileRepositoryImpl通过继承CachedVersionedEntityRepository获得了缓存功能,实现了基于Redis的缓存机制。当充电桩数据发生变化时,通过@TransactionalEventListener监听事件并清除缓存。
|
||||
|
||||
**图源**
|
||||
|
||||
- [PileRepository.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/PileRepository.java#L1-L16)
|
||||
- [PileRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/PileRepositoryImpl.java#L1-L49)
|
||||
|
||||
### 缓存交互 (PileRedisCache)
|
||||
|
||||
系统使用Redis作为缓存存储,PileRedisCache负责充电桩数据的缓存操作。PileRepositoryImpl通过cache字段与PileRedisCache交互,实现了读取时的缓存命中和写入时的缓存失效。
|
||||
|
||||
缓存键使用PileCacheKey,支持通过ID和编号两种方式缓存充电桩数据。当充电桩被更新或删除时,PileRepositoryImpl会发布PileCacheEvictEvent事件,触发缓存清除。
|
||||
|
||||
**节源**
|
||||
|
||||
- [PileRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/PileRepositoryImpl.java#L1-L49)
|
||||
|
||||
## 远程控制操作
|
||||
|
||||
系统支持对充电桩进行远程控制操作,如启动充电、重启等。这些操作通过RPC机制实现,由RpcController接收请求,调用PileProtocolService执行。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as "客户端"
|
||||
participant RpcController as "RpcController"
|
||||
participant PileProtocolService as "DefaultPileProtocolService"
|
||||
participant DownlinkCallService as "DownlinkCallService"
|
||||
participant Protocol as "协议层"
|
||||
Client->>RpcController : RPC startCharge
|
||||
RpcController->>RpcController : handleStartCharge()
|
||||
RpcController->>PileProtocolService : startCharge(dto)
|
||||
PileProtocolService->>DownlinkCallService : sendDownlinkMessage()
|
||||
DownlinkCallService->>Protocol : 发送指令
|
||||
Protocol-->>DownlinkCallService : 发送成功
|
||||
DownlinkCallService-->>PileProtocolService : 回调
|
||||
PileProtocolService-->>RpcController : 返回
|
||||
RpcController-->>Client : 响应
|
||||
```
|
||||
|
||||
**图源**
|
||||
|
||||
- [RpcController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java#L107-L145)
|
||||
- [DefaultPileProtocolService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java#L412-L440)
|
||||
|
||||
### 启动充电 (POST /piles/{id}/start-charge)
|
||||
|
||||
远程启动充电桩的充电操作。
|
||||
|
||||
#### 实现流程
|
||||
|
||||
1. RpcController接收启动充电的RPC请求
|
||||
2. 解析StartChargeDTO参数
|
||||
3. 调用PileProtocolService.startCharge方法
|
||||
4. 构造下行消息RemoteStartChargingRequest
|
||||
5. 通过DownlinkCallService发送到协议层
|
||||
6. 协议层将指令发送到充电桩
|
||||
|
||||
#### 请求DTO (StartChargeDTO)
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class StartChargeDTO {
|
||||
+pileCode : String
|
||||
+gunNo : String
|
||||
+limitYuan : BigDecimal
|
||||
+orderNo : String
|
||||
+logicalCardNo : String
|
||||
+physicalCardNo : String
|
||||
+parallelNo : String
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必填 | 描述 |
|
||||
|----------------|------------|----|---------|
|
||||
| pileCode | String | 是 | 充电桩编号 |
|
||||
| gunNo | String | 是 | 充电枪编号 |
|
||||
| limitYuan | BigDecimal | 是 | 限制金额(元) |
|
||||
| orderNo | String | 是 | 订单号 |
|
||||
| logicalCardNo | String | 否 | 逻辑卡号 |
|
||||
| physicalCardNo | String | 否 | 物理卡号 |
|
||||
| parallelNo | String | 否 | 并充序号 |
|
||||
|
||||
**节源**
|
||||
|
||||
- [StartChargeDTO.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/dto/StartChargeDTO.java#L1-L61)
|
||||
- [DefaultPileProtocolService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java#L412-L440)
|
||||
|
||||
### 重启充电桩 (POST /piles/{id}/restart)
|
||||
|
||||
远程重启充电桩。
|
||||
|
||||
#### 实现流程
|
||||
|
||||
1. RpcController接收重启充电桩的RPC请求
|
||||
2. 解析RestartPileDTO参数
|
||||
3. 调用PileProtocolService.restartPile方法
|
||||
4. 构造下行消息RestartPileRequest
|
||||
5. 通过DownlinkCallService发送到协议层
|
||||
6. 协议层将指令发送到充电桩
|
||||
|
||||
#### 请求DTO (RestartPileDTO)
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class RestartPileDTO {
|
||||
+pileCode : String
|
||||
+type : Integer
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必填 | 描述 |
|
||||
|----------|---------|----|-------|
|
||||
| pileCode | String | 是 | 充电桩编号 |
|
||||
| type | Integer | 是 | 重启类型 |
|
||||
|
||||
**节源**
|
||||
|
||||
- [RestartPileDTO.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/dto/RestartPileDTO.java#L1-L32)
|
||||
- [DefaultPileProtocolService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java#L506-L531)
|
||||
|
||||
## 使用示例
|
||||
|
||||
以下示例演示如何为一个充电站添加充电桩并远程启动充电。
|
||||
|
||||
### 为充电站添加充电桩
|
||||
|
||||
```http
|
||||
POST /api/piles HTTP/1.1
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer <token>
|
||||
|
||||
```
|
||||
|
||||
响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "创建成功",
|
||||
"data": {
|
||||
"id": "f1e2d3c4-b5a6-9876-5432-10fedcba9876",
|
||||
"createdTime": "2024-01-01T10:00:00",
|
||||
"pileName": "直流快充桩1号",
|
||||
"pileCode": "DCP001",
|
||||
"protocol": "LVNENG_V340",
|
||||
"stationId": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
|
||||
"brand": "特来电",
|
||||
"model": "DC-80KW",
|
||||
"manufacturer": "特来电新能源有限公司",
|
||||
"type": "DC"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 远程启动充电
|
||||
|
||||
```http
|
||||
POST /rpc HTTP/1.1
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer <token>
|
||||
|
||||
```
|
||||
|
||||
**节源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L25-L34)
|
||||
- [RpcController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/RpcController.java#L107-L145)
|
||||
|
||||
## 状态机与实时同步
|
||||
|
||||
充电桩状态机管理充电桩的在线/离线状态,通过实时同步机制确保状态的准确性。
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> OFFLINE
|
||||
OFFLINE --> ONLINE : login
|
||||
ONLINE --> OFFLINE : session close
|
||||
ONLINE --> ONLINE : heartbeat
|
||||
OFFLINE --> OFFLINE : no activity
|
||||
note right of ONLINE
|
||||
状态属性 :
|
||||
- status : ONLINE
|
||||
- connectedAt : 时间戳
|
||||
- lastActiveTime : 时间戳
|
||||
end note
|
||||
note right of OFFLINE
|
||||
状态属性 :
|
||||
- status : OFFLINE
|
||||
- disconnectedAt : 时间戳
|
||||
end note
|
||||
```
|
||||
|
||||
### 状态机实现
|
||||
|
||||
充电桩状态机基于三个核心事件实现:登录、心跳和会话关闭。
|
||||
|
||||
| 事件 | 当前状态 | 新状态 | 更新的属性 |
|
||||
|------|--------|---------|-------------------------------------|
|
||||
| 登录 | 任意 | ONLINE | status, connectedAt, lastActiveTime |
|
||||
| 心跳 | ONLINE | ONLINE | status, lastActiveTime |
|
||||
| 会话关闭 | ONLINE | OFFLINE | status, disconnectedAt |
|
||||
|
||||
**节源**
|
||||
|
||||
- [DefaultPileService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileService.java#L240-L300)
|
||||
|
||||
### 实时状态同步
|
||||
|
||||
系统通过AttributeService将充电桩状态存储在Redis中,实现状态的实时同步。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[充电桩登录] --> B[调用handlePileLogin]
|
||||
B --> C[更新状态属性]
|
||||
C --> D[保存到Redis]
|
||||
D --> E[状态同步完成]
|
||||
F[充电桩心跳] --> G[调用handlePileHeartbeat]
|
||||
G --> H[更新状态属性]
|
||||
H --> D
|
||||
I[会话关闭] --> J[调用handlePileSessionClose]
|
||||
J --> K[更新状态属性]
|
||||
K --> D
|
||||
```
|
||||
|
||||
状态属性存储在Redis的哈希结构中,键名为`pile:attributes:{pileId}`,字段名为状态属性名,如`STATUS`、`CONNECTED_AT`
|
||||
等。这种设计支持高效的状态查询和更新。
|
||||
|
||||
**节源**
|
||||
|
||||
- [DefaultPileService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileService.java#L240-L300)
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[充电桩登录] --> B[调用handlePileLogin]
|
||||
B --> C[更新状态属性]
|
||||
C --> D[保存到Redis]
|
||||
D --> E[状态同步完成]
|
||||
F[充电桩心跳] --> G[调用handlePileHeartbeat]
|
||||
G --> H[更新状态属性]
|
||||
H --> D
|
||||
I[会话关闭] --> J[调用handlePileSessionClose]
|
||||
J --> K[更新状态属性]
|
||||
K --> D
|
||||
```
|
||||
|
||||
状态属性存储在Redis的哈希结构中,键名为`pile:attributes:{pileId}`,字段名为状态属性名,如`STATUS`、`CONNECTED_AT`
|
||||
等。这种设计支持高效的状态查询和更新。
|
||||
|
||||
**节源**
|
||||
|
||||
- [DefaultPileService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileService.java#L240-L300)
|
||||
444
docs/核心模块详解/设备管理模块/充电站管理.md
Normal file
444
docs/核心模块详解/设备管理模块/充电站管理.md
Normal file
@@ -0,0 +1,444 @@
|
||||
# 充电站管理
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [Station.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Station.java)
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java)
|
||||
- [StationMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/StationMapper.java)
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java)
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java)
|
||||
- [PileMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/PileMapper.java)
|
||||
- [StationCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/StationCreateRequest.java)
|
||||
- [StationUpdateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/StationUpdateRequest.java)
|
||||
- [StationQueryRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/StationQueryRequest.java)
|
||||
- [PageResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PageResponse.java)
|
||||
- [schema-init.sql](file://jcpp-app/src/main/resources/sql/schema-init.sql)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [引言](#引言)
|
||||
2. [数据模型](#数据模型)
|
||||
3. [RESTful API接口](#restful-api接口)
|
||||
4. [服务层实现](#服务层实现)
|
||||
5. [使用示例](#使用示例)
|
||||
6. [分页查询机制](#分页查询机制)
|
||||
7. [级联删除逻辑](#级联删除逻辑)
|
||||
|
||||
## 引言
|
||||
|
||||
充电站管理功能是本系统的核心模块之一,负责充电站的全生命周期管理。该功能提供了完整的CRUD操作,支持通过RESTful
|
||||
API对充电站进行创建、查询、更新和删除。系统采用分层架构设计,包含控制器层、服务层和数据访问层,确保了代码的可维护性和扩展性。充电站实体与充电桩实体之间存在一对多的关系,系统在删除充电站时会进行级联检查,确保数据完整性。
|
||||
|
||||
## 数据模型
|
||||
|
||||
### Station实体
|
||||
|
||||
`Station`实体是充电站管理的核心数据模型,定义了充电站的基本属性和元数据。该实体映射到数据库中的`t_station`表,使用MyBatis
|
||||
Plus框架进行ORM映射。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Station {
|
||||
+UUID id
|
||||
+LocalDateTime createdTime
|
||||
+LocalDateTime updatedTime
|
||||
+JsonNode additionalInfo
|
||||
+String stationName
|
||||
+String stationCode
|
||||
+Float longitude
|
||||
+Float latitude
|
||||
+String province
|
||||
+String city
|
||||
+String county
|
||||
+String address
|
||||
+Integer version
|
||||
}
|
||||
class Pile {
|
||||
+UUID id
|
||||
+LocalDateTime createdTime
|
||||
+LocalDateTime updatedTime
|
||||
+JsonNode additionalInfo
|
||||
+String pileName
|
||||
+String pileCode
|
||||
+String protocol
|
||||
+UUID stationId
|
||||
+String brand
|
||||
+String model
|
||||
+String manufacturer
|
||||
+PileTypeEnum type
|
||||
+Integer version
|
||||
}
|
||||
Station "1" *-- "0..*" Pile : 包含
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [Station.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Station.java#L1-L65)
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java#L1-L64)
|
||||
|
||||
#### 核心属性说明
|
||||
|
||||
- **id**: 充电站唯一标识符,使用UUID类型,作为主键
|
||||
- **createdTime**: 创建时间,记录充电站创建的精确时间戳
|
||||
- **updatedTime**: 更新时间,每次更新时自动更新
|
||||
- **stationName**: 充电站名称,必填字段,用于标识充电站
|
||||
- **stationCode**: 充电站编码,必填字段,具有唯一性约束
|
||||
- **longitude/latitude**: 地理位置坐标,用于地图展示和定位
|
||||
- **province/city/county/address**: 地址信息,分别表示省、市、区县和详细地址
|
||||
- **additionalInfo**: 附加信息,使用JSON格式存储扩展属性
|
||||
- **version**: 版本号,用于乐观锁控制,防止并发更新冲突
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [Station.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Station.java#L1-L65)
|
||||
- [schema-init.sql](file://jcpp-app/src/main/resources/sql/schema-init.sql#L34-L58)
|
||||
|
||||
## RESTful API接口
|
||||
|
||||
### API端点概览
|
||||
|
||||
`StationController`提供了完整的RESTful API端点,用于管理充电站资源。所有API均遵循REST设计原则,使用标准的HTTP方法和状态码。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as "客户端"
|
||||
participant Controller as "StationController"
|
||||
participant Service as "DefaultStationService"
|
||||
participant Mapper as "StationMapper"
|
||||
Client->>Controller : POST /api/stations
|
||||
Controller->>Service : createStation(request)
|
||||
Service->>Mapper : insert(station)
|
||||
Mapper-->>Service : 返回结果
|
||||
Service-->>Controller : 返回充电站
|
||||
Controller-->>Client : 200 OK {station}
|
||||
Client->>Controller : GET /api/stations
|
||||
Controller->>Service : getStations(request)
|
||||
Service->>Mapper : selectPage(wrapper)
|
||||
Mapper-->>Service : 返回分页结果
|
||||
Service-->>Controller : 返回PageResponse
|
||||
Controller-->>Client : 200 OK {PageResponse}
|
||||
Client->>Controller : PUT /api/stations/{id}
|
||||
Controller->>Service : updateStation(id, request)
|
||||
Service->>Mapper : selectById(id)
|
||||
Mapper-->>Service : 返回充电站
|
||||
Service->>Mapper : updateById(station)
|
||||
Mapper-->>Service : 返回结果
|
||||
Service-->>Controller : 返回充电站
|
||||
Controller-->>Client : 200 OK {station}
|
||||
Client->>Controller : DELETE /api/stations/{id}
|
||||
Controller->>Service : deleteStation(id)
|
||||
Service->>Mapper : selectById(id)
|
||||
Mapper-->>Service : 返回充电站
|
||||
Service->>Mapper : countByStationId(id)
|
||||
Mapper-->>Service : 返回数量
|
||||
Service->>Mapper : deleteById(id)
|
||||
Mapper-->>Service : 返回结果
|
||||
Service-->>Controller : 返回成功
|
||||
Controller-->>Client : 200 OK {success}
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L1-L107)
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L1-L247)
|
||||
|
||||
### 详细API说明
|
||||
|
||||
#### 创建充电站 (POST /api/stations)
|
||||
|
||||
创建新的充电站资源。
|
||||
|
||||
- **请求参数**: `StationCreateRequest`对象
|
||||
- **请求体示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"stationName": "三丙家专属充电站",
|
||||
"stationCode": "S20241001001",
|
||||
"longitude": 120.107933,
|
||||
"latitude": 30.267013,
|
||||
"province": "浙江省",
|
||||
"city": "杭州市",
|
||||
"county": "西湖区",
|
||||
"address": "西溪路552-1号"
|
||||
}
|
||||
```
|
||||
|
||||
- **响应格式**: `ApiResponse<Station>`
|
||||
- **权限要求**: `AuthorityEnum.STATION_MANAGE`
|
||||
|
||||
#### 分页查询充电站 (GET /api/stations)
|
||||
|
||||
分页查询充电站列表,支持多种查询条件。
|
||||
|
||||
- **请求参数**:
|
||||
- `page`: 页码(默认0)
|
||||
- `size`: 每页大小(默认10)
|
||||
- `stationName`: 充电站名称(模糊查询)
|
||||
- `stationCode`: 充电站编码(模糊查询)
|
||||
- `province`: 省份(精确查询)
|
||||
- `city`: 城市(精确查询)
|
||||
- `sortField`: 排序字段
|
||||
- `sortOrder`: 排序顺序(asc/desc)
|
||||
- **响应格式**: `ApiResponse<PageResponse<Station>>`
|
||||
- **权限要求**: `AuthorityEnum.STATION_MANAGE`
|
||||
|
||||
#### 更新充电站 (PUT /api/stations/{id})
|
||||
|
||||
更新指定ID的充电站信息。
|
||||
|
||||
- **路径参数**: `id` - 充电站UUID
|
||||
- **请求参数**: `StationUpdateRequest`对象
|
||||
- **请求体示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"stationName": "三丙家专属充电站(更新)",
|
||||
"longitude": 120.108000,
|
||||
"latitude": 30.267100,
|
||||
"province": "浙江省",
|
||||
"city": "杭州市",
|
||||
"county": "西湖区",
|
||||
"address": "西溪路552-1号(更新)"
|
||||
}
|
||||
```
|
||||
|
||||
- **响应格式**: `ApiResponse<Station>`
|
||||
- **权限要求**: `AuthorityEnum.STATION_MANAGE`
|
||||
|
||||
#### 删除充电站 (DELETE /api/stations/{id})
|
||||
|
||||
删除指定ID的充电站。
|
||||
|
||||
- **路径参数**: `id` - 充电站UUID
|
||||
- **响应格式**: `ApiResponse<Void>`
|
||||
- **权限要求**: `AuthorityEnum.STATION_MANAGE`
|
||||
- **业务逻辑**: 删除前会检查该充电站下是否存在充电桩,如果存在则不允许删除
|
||||
|
||||
#### 获取充电站选项 (GET /api/stations/options)
|
||||
|
||||
获取充电站选项列表,用于下拉选择组件。
|
||||
|
||||
- **响应格式**: `ApiResponse<List<StationOption>>`
|
||||
- **权限要求**: `AuthorityEnum.STATION_MANAGE`
|
||||
|
||||
#### 搜索充电站选项 (GET /api/stations/search)
|
||||
|
||||
搜索充电站选项,支持关键字搜索和分页。
|
||||
|
||||
- **请求参数**:
|
||||
- `keyword`: 搜索关键字
|
||||
- `page`: 页码
|
||||
- `size`: 每页大小
|
||||
- **响应格式**: `ApiResponse<List<StationOption>>`
|
||||
- **权限要求**: `AuthorityEnum.STATION_MANAGE`
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L1-L107)
|
||||
- [StationCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/StationCreateRequest.java#L1-L44)
|
||||
- [StationUpdateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/StationUpdateRequest.java#L1-L40)
|
||||
- [StationQueryRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/StationQueryRequest.java#L1-L29)
|
||||
|
||||
## 服务层实现
|
||||
|
||||
### DefaultStationService
|
||||
|
||||
`DefaultStationService`是充电站管理的核心服务实现类,协调`StationMapper`和`PileMapper`进行数据库操作,并处理业务逻辑。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[API请求] --> B{操作类型}
|
||||
B --> |创建| C[createStation]
|
||||
B --> |查询| D[getStations]
|
||||
B --> |更新| E[updateStation]
|
||||
B --> |删除| F[deleteStation]
|
||||
C --> G[构建Station实体]
|
||||
G --> H[设置默认值]
|
||||
H --> I[调用stationMapper.insert]
|
||||
D --> J[构建QueryWrapper]
|
||||
J --> K[添加查询条件]
|
||||
K --> L[调用stationMapper.selectPage]
|
||||
L --> M[构建PageResponse]
|
||||
E --> N[查询现有Station]
|
||||
N --> O[更新字段]
|
||||
O --> P[调用stationMapper.updateById]
|
||||
F --> Q[检查Station存在]
|
||||
Q --> R[检查充电桩数量]
|
||||
R --> |有充电桩| S[抛出异常]
|
||||
R --> |无充电桩| T[调用stationMapper.deleteById]
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L1-L247)
|
||||
|
||||
#### 核心方法说明
|
||||
|
||||
- **getStations**: 实现分页查询功能,根据`StationQueryRequest`中的条件构建查询条件,支持按名称、编码、省份、城市等字段进行查询,并支持排序功能
|
||||
- **getStationById**: 根据ID查询单个充电站信息
|
||||
- **createStation**: 创建新的充电站,自动生成UUID和创建时间,初始化版本号为1
|
||||
- **updateStation**: 更新充电站信息,更新时会自动设置`updatedTime`字段
|
||||
- **deleteStation**: 删除充电站前会进行完整性检查,确保该充电站下没有关联的充电桩
|
||||
- **getStationOptions**: 获取充电站选项列表,用于前端下拉选择
|
||||
- **searchStationOptions**: 支持关键字搜索的充电站选项查询
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L1-L247)
|
||||
- [StationMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/StationMapper.java#L1-L15)
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 创建充电站完整流程
|
||||
|
||||
以下是一个通过API创建新充电站并验证其存在的完整示例:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as "用户"
|
||||
participant Frontend as "前端应用"
|
||||
participant Backend as "后端服务"
|
||||
participant Database as "数据库"
|
||||
User->>Frontend : 填写充电站信息并提交
|
||||
Frontend->>Backend : POST /api/stations
|
||||
Backend->>Backend : 验证请求参数
|
||||
Backend->>Backend : 调用DefaultStationService.createStation
|
||||
Backend->>Backend : 构建Station实体
|
||||
Backend->>Database : 执行INSERT语句
|
||||
Database-->>Backend : 返回插入结果
|
||||
Backend-->>Frontend : 返回创建的充电站信息
|
||||
Frontend-->>User : 显示创建成功消息
|
||||
User->>Frontend : 查询充电站列表
|
||||
Frontend->>Backend : GET /api/stations
|
||||
Backend->>Backend : 调用DefaultStationService.getStations
|
||||
Backend->>Database : 执行SELECT查询
|
||||
Database-->>Backend : 返回查询结果
|
||||
Backend-->>Frontend : 返回分页响应
|
||||
Frontend-->>User : 显示包含新充电站的列表
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L1-L107)
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L1-L247)
|
||||
|
||||
#### 示例代码
|
||||
|
||||
```java
|
||||
// 创建充电站请求
|
||||
StationCreateRequest request = new StationCreateRequest();
|
||||
request.setStationName("新充电站");
|
||||
request.setStationCode("NEW001");
|
||||
request.setLongitude(120.123456f);
|
||||
request.setLatitude(30.654321f);
|
||||
request.setProvince("浙江省");
|
||||
request.setCity("杭州市");
|
||||
request.setCounty("西湖区");
|
||||
request.setAddress("文三路168号");
|
||||
|
||||
// 调用API创建充电站
|
||||
ResponseEntity<ApiResponse<Station>> response = restTemplate.postForEntity(
|
||||
"/api/stations",
|
||||
request,
|
||||
new ParameterizedTypeReference<ApiResponse<Station>>() {}
|
||||
);
|
||||
|
||||
// 验证创建结果
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
Station createdStation = response.getBody().getData();
|
||||
assertThat(createdStation.getStationName()).isEqualTo("新充电站");
|
||||
|
||||
// 查询验证
|
||||
ResponseEntity<ApiResponse<PageResponse<Station>>> queryResponse = restTemplate.getForEntity(
|
||||
"/api/stations?stationName=新充电站",
|
||||
new ParameterizedTypeReference<ApiResponse<PageResponse<Station>>>() {}
|
||||
);
|
||||
|
||||
assertThat(queryResponse.getBody().getData().getTotal()).isGreaterThan(0);
|
||||
```
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L1-L107)
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L1-L247)
|
||||
- [InstallInitializingBean.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/initializing/InstallInitializingBean.java#L218-L233)
|
||||
|
||||
## 分页查询机制
|
||||
|
||||
### 分页实现原理
|
||||
|
||||
系统采用MyBatis Plus的分页插件实现分页查询功能,通过`Page`对象和`IPage`接口提供分页支持。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[客户端请求] --> B[StationController]
|
||||
B --> C[DefaultStationService]
|
||||
C --> D[构建QueryWrapper]
|
||||
D --> E[创建Page对象]
|
||||
E --> F[调用stationMapper.selectPage]
|
||||
F --> G[数据库执行分页查询]
|
||||
G --> H[返回IPage结果]
|
||||
H --> I[构建PageResponse]
|
||||
I --> J[返回客户端]
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L65-L99)
|
||||
- [PageResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PageResponse.java#L1-L43)
|
||||
|
||||
#### PageResponse结构
|
||||
|
||||
`PageResponse`类封装了分页查询的响应数据,包含以下字段:
|
||||
|
||||
- **records**: 当前页的数据记录列表
|
||||
- **total**: 总记录数
|
||||
- **page**: 当前页码
|
||||
- **size**: 每页大小
|
||||
- **totalPages**: 总页数
|
||||
|
||||
分页计算公式:`totalPages = ceil(total / size)`
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [PageResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PageResponse.java#L1-L43)
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L65-L99)
|
||||
|
||||
## 级联删除逻辑
|
||||
|
||||
### 删除业务流程
|
||||
|
||||
系统在删除充电站时实现了严格的级联检查机制,确保数据完整性。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[删除请求] --> B{充电站存在?}
|
||||
B --> |否| C[抛出ITEM_NOT_FOUND异常]
|
||||
B --> |是| D{有充电桩?}
|
||||
D --> |是| E[抛出VERSION_CONFLICT异常]
|
||||
D --> |否| F[执行删除操作]
|
||||
F --> G{删除成功?}
|
||||
G --> |否| H[抛出VERSION_CONFLICT异常]
|
||||
G --> |是| I[返回成功]
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L150-L185)
|
||||
|
||||
#### 详细逻辑说明
|
||||
|
||||
1. **存在性检查**: 首先通过`stationMapper.selectById(id)`检查充电站是否存在,如果不存在则抛出`ITEM_NOT_FOUND`异常
|
||||
2. **关联检查**: 调用`pileMapper.countByStationId(id)`统计该充电站下的充电桩数量,如果数量大于0,则抛出`VERSION_CONFLICT`
|
||||
异常,提示用户先删除所有充电桩
|
||||
3. **执行删除**: 通过`stationMapper.deleteById(id)`执行删除操作
|
||||
4. **结果验证**: 检查受影响的行数,如果为0则说明删除失败,可能是被其他操作删除,抛出`VERSION_CONFLICT`异常
|
||||
|
||||
这种设计确保了数据的一致性和完整性,防止意外删除包含充电桩的充电站。
|
||||
|
||||
**Section sources**
|
||||
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L150-L185)
|
||||
- [PileMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/PileMapper.java#L60-L65)
|
||||
658
docs/核心模块详解/设备管理模块/设备管理模块.md
Normal file
658
docs/核心模块详解/设备管理模块/设备管理模块.md
Normal file
@@ -0,0 +1,658 @@
|
||||
# 设备管理模块
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java)
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java)
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java)
|
||||
- [Station.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Station.java)
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java)
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java)
|
||||
- [StationCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/StationCreateRequest.java)
|
||||
- [PileCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/PileCreateRequest.java)
|
||||
- [GunCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/GunCreateRequest.java)
|
||||
- [PageResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PageResponse.java)
|
||||
- [StationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/StationService.java)
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java)
|
||||
- [StationMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/StationMapper.java)
|
||||
- [StationRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/station/StationRedisCache.java)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
|
||||
1. [引言](#引言)
|
||||
2. [核心数据模型](#核心数据模型)
|
||||
3. [RESTful API 接口](#restful-api-接口)
|
||||
4. [业务服务层设计](#业务服务层设计)
|
||||
5. [完整使用示例](#完整使用示例)
|
||||
6. [复杂业务逻辑实现](#复杂业务逻辑实现)
|
||||
|
||||
## 引言
|
||||
|
||||
设备管理模块是充电站管理系统的核心组成部分,负责管理充电站(Station)、充电桩(Pile)和充电枪(Gun)三个关键实体。本模块提供了完整的CRUD操作,支持分页查询、级联选择和状态管理等功能。系统采用分层架构设计,包括控制器层、服务层、数据访问层和缓存层,确保了系统的可维护性和高性能。
|
||||
|
||||
## 核心数据模型
|
||||
|
||||
### 实体层次关系
|
||||
|
||||
设备管理模块中的三个核心实体构成了一个清晰的层次结构:一个充电站(Station)可以包含多个充电桩(Pile),而每个充电桩又可以连接多个充电枪(Gun)。这种层级关系通过外键关联实现,确保了数据的一致性和完整性。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Station {
|
||||
+UUID id
|
||||
+String stationName
|
||||
+String stationCode
|
||||
+Float longitude
|
||||
+Float latitude
|
||||
+String province
|
||||
+String city
|
||||
+String county
|
||||
+String address
|
||||
+LocalDateTime createdTime
|
||||
+LocalDateTime updatedTime
|
||||
+JsonNode additionalInfo
|
||||
+Integer version
|
||||
}
|
||||
class Pile {
|
||||
+UUID id
|
||||
+String pileName
|
||||
+String pileCode
|
||||
+String protocol
|
||||
+UUID stationId
|
||||
+String brand
|
||||
+String model
|
||||
+String manufacturer
|
||||
+PileTypeEnum type
|
||||
+LocalDateTime createdTime
|
||||
+LocalDateTime updatedTime
|
||||
+JsonNode additionalInfo
|
||||
+Integer version
|
||||
}
|
||||
class Gun {
|
||||
+UUID id
|
||||
+String gunNo
|
||||
+String gunName
|
||||
+String gunCode
|
||||
+UUID stationId
|
||||
+UUID pileId
|
||||
+LocalDateTime createdTime
|
||||
+LocalDateTime updatedTime
|
||||
+JsonNode additionalInfo
|
||||
+Integer version
|
||||
}
|
||||
Station "1" *-- "0..*" Pile : 包含
|
||||
Pile "1" *-- "0..*" Gun : 包含
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [Station.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Station.java#L1-L65)
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java#L1-L64)
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L56)
|
||||
|
||||
### 数据模型详细说明
|
||||
|
||||
#### 充电站(Station)
|
||||
|
||||
充电站实体代表一个物理的充电站点,包含站点的基本信息和地理位置数据。每个充电站都有唯一的ID标识,通过`stationCode`
|
||||
字段保证编码的唯一性。实体还包含了省份、城市、区县和详细地址等完整的地理位置信息,便于进行区域管理和查询。
|
||||
|
||||
**核心字段说明**
|
||||
|
||||
- `id`: 充电站唯一标识符,使用UUID类型
|
||||
- `stationName`: 充电站名称,必填字段,用于显示
|
||||
- `stationCode`: 充电站编码,必填字段,用于系统识别
|
||||
- `longitude`/`latitude`: 经纬度坐标,用于地图定位
|
||||
- `province`/`city`/`county`/`address`: 完整的地址信息
|
||||
- `version`: 版本号,用于乐观锁控制
|
||||
|
||||
**实体来源**
|
||||
|
||||
- [Station.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Station.java#L1-L65)
|
||||
|
||||
#### 充电桩(Pile)
|
||||
|
||||
充电桩实体代表安装在充电站内的具体充电设备。每个充电桩都归属于一个特定的充电站,通过`stationId`
|
||||
外键进行关联。充电桩包含了设备的品牌、型号、制造商等信息,并指定了通信协议类型,以便系统能够正确处理不同厂商设备的通信需求。
|
||||
|
||||
**核心字段说明**
|
||||
|
||||
- `id`: 充电桩唯一标识符
|
||||
- `pileName`: 充电桩名称
|
||||
- `pileCode`: 充电桩编码
|
||||
- `protocol`: 通信协议类型,决定设备的通信方式
|
||||
- `stationId`: 所属充电站ID,建立与Station的关联
|
||||
- `type`: 充电桩类型(直流/交流)
|
||||
- `version`: 版本号,用于并发控制
|
||||
|
||||
**实体来源**
|
||||
|
||||
- [Pile.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Pile.java#L1-L64)
|
||||
|
||||
#### 充电枪(Gun)
|
||||
|
||||
充电枪实体代表充电桩上的具体充电接口。每个充电枪都归属于一个特定的充电桩,通过`pileId`
|
||||
外键进行关联。充电枪包含了枪号(gunNo)和编码(gunCode)等识别信息,这些信息通常与物理设备上的标签对应,便于现场管理和维护。
|
||||
|
||||
**核心字段说明**
|
||||
|
||||
- `id`: 充电枪唯一标识符
|
||||
- `gunNo`: 充电枪编号,通常为物理标识
|
||||
- `gunName`: 充电枪名称
|
||||
- `gunCode`: 充电枪编码,系统唯一标识
|
||||
- `stationId`: 所属充电站ID(冗余字段,便于查询)
|
||||
- `pileId`: 所属充电桩ID,建立与Pile的关联
|
||||
- `version`: 版本号,支持并发更新
|
||||
|
||||
**实体来源**
|
||||
|
||||
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L56)
|
||||
|
||||
## RESTful API 接口
|
||||
|
||||
### 控制器概览
|
||||
|
||||
设备管理模块提供了三个主要的REST控制器:`StationController`、`PileController`和`GunController`
|
||||
,分别对应三个核心实体的管理操作。这些控制器遵循RESTful设计原则,使用标准的HTTP方法(GET、POST、PUT、DELETE)来执行相应的CRUD操作。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[客户端] --> B[StationController]
|
||||
A --> C[PileController]
|
||||
A --> D[GunController]
|
||||
B --> E[StationService]
|
||||
C --> F[PileService]
|
||||
D --> G[GunService]
|
||||
E --> H[StationMapper]
|
||||
F --> I[PileMapper]
|
||||
G --> J[GunMapper]
|
||||
E --> K[StationRedisCache]
|
||||
F --> L[PileRedisCache]
|
||||
G --> M[GunRedisCache]
|
||||
style A fill:#f9f,stroke:#333
|
||||
style B fill:#bbf,stroke:#333
|
||||
style C fill:#bbf,stroke:#333
|
||||
style D fill:#bbf,stroke:#333
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L1-L107)
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L1-L111)
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L1-L115)
|
||||
|
||||
### StationController API
|
||||
|
||||
#### 创建充电站
|
||||
|
||||
创建新的充电站实体。
|
||||
|
||||
- **端点**: `POST /api/stations`
|
||||
- **请求体**: `StationCreateRequest`
|
||||
- **响应**: `ApiResponse<Station>`
|
||||
- **权限控制**: 需要管理员权限
|
||||
|
||||
**请求DTO结构**
|
||||
|
||||
```json
|
||||
{
|
||||
"stationName": "string",
|
||||
"stationCode": "string",
|
||||
"longitude": 0,
|
||||
"latitude": 0,
|
||||
"province": "string",
|
||||
"city": "string",
|
||||
"county": "string",
|
||||
"address": "string"
|
||||
}
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L50-L57)
|
||||
- [StationCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/StationCreateRequest.java#L1-L44)
|
||||
|
||||
#### 查询充电站
|
||||
|
||||
支持分页查询和条件筛选。
|
||||
|
||||
- **端点**: `GET /api/stations`
|
||||
- **请求参数**: `StationQueryRequest`
|
||||
- **响应**: `ApiResponse<PageResponse<Station>>`
|
||||
|
||||
**分页响应结构**
|
||||
|
||||
```json
|
||||
{
|
||||
"records": [...],
|
||||
"total": 100,
|
||||
"page": 1,
|
||||
"size": 20,
|
||||
"totalPages": 5
|
||||
}
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L30-L37)
|
||||
- [PageResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PageResponse.java#L1-L43)
|
||||
|
||||
#### 更新充电站
|
||||
|
||||
根据ID更新充电站信息。
|
||||
|
||||
- **端点**: `PUT /api/stations/{id}`
|
||||
- **请求体**: `StationUpdateRequest`
|
||||
- **响应**: `ApiResponse<Station>`
|
||||
|
||||
**来源**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L60-L68)
|
||||
|
||||
#### 删除充电站
|
||||
|
||||
删除指定ID的充电站。
|
||||
|
||||
- **端点**: `DELETE /api/stations/{id}`
|
||||
- **响应**: `ApiResponse<Void>`
|
||||
|
||||
**来源**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L71-L77)
|
||||
|
||||
#### 获取选项列表
|
||||
|
||||
为前端下拉组件提供数据。
|
||||
|
||||
- **端点**: `GET /api/stations/options`
|
||||
- **响应**: `ApiResponse<List<StationOption>>`
|
||||
|
||||
**选项响应结构**
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "uuid",
|
||||
"label": "名称 (编码)",
|
||||
"stationName": "名称",
|
||||
"stationCode": "编码"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L80-L88)
|
||||
- [StationOption.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/StationOption.java#L1-L39)
|
||||
|
||||
### PileController API
|
||||
|
||||
#### 创建充电桩
|
||||
|
||||
创建新的充电桩实体。
|
||||
|
||||
- **端点**: `POST /api/piles`
|
||||
- **请求体**: `PileCreateRequest`
|
||||
- **响应**: `ApiResponse<Pile>`
|
||||
|
||||
**来源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L35-L42)
|
||||
|
||||
#### 查询充电桩状态
|
||||
|
||||
获取充电桩的实时运行状态。
|
||||
|
||||
- **端点**: `GET /api/piles/status/{pileCode}`
|
||||
- **响应**: `ApiResponse<String>`
|
||||
|
||||
**来源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L90-L111)
|
||||
|
||||
### GunController API
|
||||
|
||||
#### 创建充电枪
|
||||
|
||||
创建新的充电枪实体。
|
||||
|
||||
- **端点**: `POST /api/guns`
|
||||
- **请求体**: `GunCreateRequest`
|
||||
- **响应**: `ApiResponse<Gun>`
|
||||
|
||||
**来源**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L35-L42)
|
||||
|
||||
#### 查询充电枪状态
|
||||
|
||||
根据枪编码获取充电枪的运行状态。
|
||||
|
||||
- **端点**: `GET /api/guns/status/{gunCode}`
|
||||
- **响应**: `ApiResponse<String>`
|
||||
|
||||
**来源**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L80-L100)
|
||||
|
||||
#### 按编码查询充电枪
|
||||
|
||||
根据枪编码获取充电枪的详细信息。
|
||||
|
||||
- **端点**: `GET /api/guns/code/{gunCode}`
|
||||
- **响应**: `ApiResponse<GunWithStatusResponse>`
|
||||
|
||||
**来源**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L103-L115)
|
||||
|
||||
## 业务服务层设计
|
||||
|
||||
### 服务层架构
|
||||
|
||||
业务服务层是设备管理模块的核心,负责协调数据访问层和缓存层的操作。`DefaultStationService`、`DefaultPileService`和
|
||||
`DefaultGunService`分别实现了对应的接口,提供了具体的业务逻辑处理。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class StationService {
|
||||
<<interface>>
|
||||
+getStations(StationQueryRequest) PageResponse~Station~
|
||||
+getStationById(UUID) Station
|
||||
+createStation(StationCreateRequest) Station
|
||||
+updateStation(UUID, StationUpdateRequest) Station
|
||||
+deleteStation(UUID) void
|
||||
+getStationOptions() StationOption[]
|
||||
+searchStationOptions(String, int, int) StationOption[]
|
||||
}
|
||||
class DefaultStationService {
|
||||
-stationMapper StationMapper
|
||||
-stationRedisCache StationRedisCache
|
||||
+getStations(StationQueryRequest) PageResponse~Station~
|
||||
+getStationById(UUID) Station
|
||||
+createStation(StationCreateRequest) Station
|
||||
+updateStation(UUID, StationUpdateRequest) Station
|
||||
+deleteStation(UUID) void
|
||||
+getStationOptions() StationOption[]
|
||||
+searchStationOptions(String, int, int) StationOption[]
|
||||
}
|
||||
class StationMapper {
|
||||
<<interface>>
|
||||
+selectPage(StationQueryRequest) Page~Station~
|
||||
+selectById(UUID) Station
|
||||
+insert(Station) int
|
||||
+updateById(Station) int
|
||||
+deleteById(UUID) int
|
||||
+selectOptions() StationOption[]
|
||||
+searchOptions(String, int, int) StationOption[]
|
||||
}
|
||||
class StationRedisCache {
|
||||
-redisTemplate RedisTemplate
|
||||
+get(UUID) Station
|
||||
+put(Station) void
|
||||
+evict(UUID) void
|
||||
+evictAll() void
|
||||
}
|
||||
StationService <|.. DefaultStationService : 实现
|
||||
DefaultStationService --> StationMapper : 使用
|
||||
DefaultStationService --> StationRedisCache : 使用
|
||||
```
|
||||
|
||||
**图示来源**
|
||||
|
||||
- [StationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/StationService.java#L1-L67)
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java)
|
||||
- [StationMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/StationMapper.java)
|
||||
- [StationRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/station/StationRedisCache.java)
|
||||
|
||||
### DefaultStationService 实现细节
|
||||
|
||||
#### 创建充电站流程
|
||||
|
||||
`DefaultStationService.createStation()`方法负责创建新的充电站实体。该方法首先验证输入数据的有效性,然后生成新的UUID作为实体ID,设置创建和更新时间戳,最后将实体保存到数据库。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始]) --> ValidateInput["验证输入数据"]
|
||||
ValidateInput --> GenerateId["生成UUID"]
|
||||
GenerateId --> SetTimestamps["设置创建/更新时间"]
|
||||
SetTimestamps --> SaveToDB["保存到数据库"]
|
||||
SaveToDB --> UpdateCache["更新Redis缓存"]
|
||||
UpdateCache --> ReturnResult["返回结果"]
|
||||
ReturnResult --> End([结束])
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L50-L70)
|
||||
|
||||
#### 查询充电站流程
|
||||
|
||||
`DefaultStationService.getStations()`方法实现了分页查询功能。该方法首先尝试从Redis缓存中获取数据,如果缓存未命中,则从数据库查询并将结果存入缓存,以提高后续查询的性能。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始]) --> CheckCache["检查Redis缓存"]
|
||||
CheckCache --> CacheHit{"缓存命中?"}
|
||||
CacheHit --> |是| ReturnFromCache["从缓存返回"]
|
||||
CacheHit --> |否| QueryDB["查询数据库"]
|
||||
QueryDB --> SaveToCache["保存到缓存"]
|
||||
SaveToCache --> ReturnFromDB["从数据库返回"]
|
||||
ReturnFromCache --> End([结束])
|
||||
ReturnFromDB --> End
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L30-L45)
|
||||
|
||||
#### 删除充电站流程
|
||||
|
||||
`DefaultStationService.deleteStation()`方法实现了充电站的删除操作。该方法不仅删除充电站实体本身,还会级联删除其下属的所有充电桩和充电枪,确保数据的一致性。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始]) --> ValidateExistence["验证充电站存在"]
|
||||
ValidateExistence --> DeleteGuns["删除所有充电枪"]
|
||||
DeleteGuns --> DeletePiles["删除所有充电桩"]
|
||||
DeletePiles --> DeleteStation["删除充电站"]
|
||||
DeleteStation --> EvictCache["清除缓存"]
|
||||
EvictCache --> End([结束])
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L120-L150)
|
||||
|
||||
## 完整使用示例
|
||||
|
||||
### 创建包含多个充电桩的充电站
|
||||
|
||||
以下示例展示了如何通过API创建一个包含多个充电桩的充电站。
|
||||
|
||||
#### 步骤1: 创建充电站
|
||||
|
||||
```http
|
||||
POST /api/stations
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"stationName": "高新科技园充电站",
|
||||
"stationCode": "ST001",
|
||||
"longitude": 116.397026,
|
||||
"latitude": 39.909026,
|
||||
"province": "北京市",
|
||||
"city": "北京市",
|
||||
"county": "海淀区",
|
||||
"address": "中关村大街1号"
|
||||
}
|
||||
```
|
||||
|
||||
**响应**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "创建成功",
|
||||
"data": {
|
||||
"id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
|
||||
"stationName": "高新科技园充电站",
|
||||
"stationCode": "ST001",
|
||||
// 其他字段...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L50-L57)
|
||||
|
||||
#### 步骤2: 创建充电桩
|
||||
|
||||
使用上一步返回的充电站ID创建两个充电桩。
|
||||
|
||||
```http
|
||||
POST /api/piles
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"pileName": "快充桩A",
|
||||
"pileCode": "PL001",
|
||||
"protocol": "LVNENG_V340",
|
||||
"stationId": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
|
||||
"brand": "绿能",
|
||||
"model": "GN-800",
|
||||
"manufacturer": "绿能科技有限公司",
|
||||
"type": "DC"
|
||||
}
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L35-L42)
|
||||
|
||||
#### 步骤3: 创建充电枪
|
||||
|
||||
为每个充电桩创建两个充电枪。
|
||||
|
||||
```http
|
||||
POST /api/guns
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"gunName": "快充枪A1",
|
||||
"gunNo": "A1",
|
||||
"gunCode": "GN001",
|
||||
"stationId": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
|
||||
"pileId": "b2c3d4e5-f678-9012-3456-7890abcdef12"
|
||||
}
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L35-L42)
|
||||
|
||||
#### 步骤4: 验证创建结果
|
||||
|
||||
通过查询接口验证整个层级结构是否正确创建。
|
||||
|
||||
```http
|
||||
GET /api/stations/a1b2c3d4-e5f6-7890-1234-567890abcdef
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L40-L47)
|
||||
|
||||
## 复杂业务逻辑实现
|
||||
|
||||
### 分页查询实现
|
||||
|
||||
分页查询功能通过`PageResponse`类和MyBatis Plus的分页插件实现。`StationService.getStations()`方法接收`StationQueryRequest`
|
||||
参数,该参数包含了分页信息(页码和每页大小)以及可能的查询条件。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as 客户端
|
||||
participant Controller as StationController
|
||||
participant Service as DefaultStationService
|
||||
participant Mapper as StationMapper
|
||||
participant DB as 数据库
|
||||
Client->>Controller : GET /api/stations?page=1&size=20
|
||||
Controller->>Service : getStations(request)
|
||||
Service->>Service : 从缓存获取或生成缓存键
|
||||
Service->>Service : 检查缓存是否存在
|
||||
alt 缓存命中
|
||||
Service-->>Controller : 返回缓存数据
|
||||
else 缓存未命中
|
||||
Service->>Mapper : selectPage(request)
|
||||
Mapper->>DB : 执行SQL查询
|
||||
DB-->>Mapper : 返回分页结果
|
||||
Mapper-->>Service : Page<Station>
|
||||
Service->>Service : 转换为PageResponse
|
||||
Service->>Service : 存入缓存
|
||||
Service-->>Controller : PageResponse<Station>
|
||||
end
|
||||
Controller->>Controller : 包装为ApiResponse
|
||||
Controller-->>Client : 返回JSON响应
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L30-L37)
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L30-L45)
|
||||
- [PageResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PageResponse.java#L1-L43)
|
||||
|
||||
### 级联删除实现
|
||||
|
||||
级联删除是设备管理模块中的一个重要功能,确保在删除充电站时,其下属的所有充电桩和充电枪也被正确删除。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始]) --> ValidateId["验证ID有效性"]
|
||||
ValidateId --> CheckExistence["检查充电站是否存在"]
|
||||
CheckExistence --> |不存在| ReturnError["返回404错误"]
|
||||
CheckExistence --> |存在| BeginTransaction["开始数据库事务"]
|
||||
BeginTransaction --> DeleteGuns["删除所有充电枪"]
|
||||
DeleteGuns --> DeletePiles["删除所有充电桩"]
|
||||
DeletePiles --> DeleteStation["删除充电站"]
|
||||
DeleteStation --> ClearCache["清除相关缓存"]
|
||||
ClearCache --> CommitTransaction["提交事务"]
|
||||
CommitTransaction --> ReturnSuccess["返回成功"]
|
||||
ReturnError --> End([结束])
|
||||
ReturnSuccess --> End
|
||||
Exception --> RollbackTransaction["回滚事务"]
|
||||
RollbackTransaction --> ThrowException["抛出异常"]
|
||||
ThrowException --> End
|
||||
```
|
||||
|
||||
**来源**
|
||||
|
||||
- [DefaultStationService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultStationService.java#L120-L150)
|
||||
|
||||
### 缓存管理策略
|
||||
|
||||
系统采用了多级缓存策略,结合了Redis和本地缓存(Caffeine),以提高数据访问性能。
|
||||
|
||||
#### 缓存键设计
|
||||
|
||||
缓存键遵循统一的命名规范,便于管理和监控:
|
||||
|
||||
- 充电站缓存键:`station:{id}`
|
||||
- 充电桩缓存键:`pile:{id}`
|
||||
- 充电枪缓存键:`gun:{id}`
|
||||
|
||||
#### 缓存失效策略
|
||||
|
||||
当实体被创建、更新或删除时,相关的缓存会被自动清除:
|
||||
|
||||
- 创建:新实体存入缓存
|
||||
- 更新:更新缓存中的实体
|
||||
- 删除:从缓存中移除实体
|
||||
|
||||
**来源**
|
||||
|
||||
- [StationRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/station/StationRedisCache.java)
|
||||
- [PileRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/pile/PileRedisCache.java)
|
||||
- [GunRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/gun/GunRedisCache.java)
|
||||
Reference in New Issue
Block a user