Files
JChargePointProtocol/docs/核心模块详解/设备管理模块/设备管理模块.md
2025-10-28 14:39:06 +08:00

658 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 设备管理模块
<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)