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

444 lines
16 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>
**本文档引用的文件**
- [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)