# 充电站管理
**本文档引用的文件**
- [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)
## 目录
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`
- **权限要求**: `AuthorityEnum.STATION_MANAGE`
#### 分页查询充电站 (GET /api/stations)
分页查询充电站列表,支持多种查询条件。
- **请求参数**:
- `page`: 页码(默认0)
- `size`: 每页大小(默认10)
- `stationName`: 充电站名称(模糊查询)
- `stationCode`: 充电站编码(模糊查询)
- `province`: 省份(精确查询)
- `city`: 城市(精确查询)
- `sortField`: 排序字段
- `sortOrder`: 排序顺序(asc/desc)
- **响应格式**: `ApiResponse>`
- **权限要求**: `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`
- **权限要求**: `AuthorityEnum.STATION_MANAGE`
#### 删除充电站 (DELETE /api/stations/{id})
删除指定ID的充电站。
- **路径参数**: `id` - 充电站UUID
- **响应格式**: `ApiResponse`
- **权限要求**: `AuthorityEnum.STATION_MANAGE`
- **业务逻辑**: 删除前会检查该充电站下是否存在充电桩,如果存在则不允许删除
#### 获取充电站选项 (GET /api/stations/options)
获取充电站选项列表,用于下拉选择组件。
- **响应格式**: `ApiResponse>`
- **权限要求**: `AuthorityEnum.STATION_MANAGE`
#### 搜索充电站选项 (GET /api/stations/search)
搜索充电站选项,支持关键字搜索和分页。
- **请求参数**:
- `keyword`: 搜索关键字
- `page`: 页码
- `size`: 每页大小
- **响应格式**: `ApiResponse>`
- **权限要求**: `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> response = restTemplate.postForEntity(
"/api/stations",
request,
new ParameterizedTypeReference>() {}
);
// 验证创建结果
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
Station createdStation = response.getBody().getData();
assertThat(createdStation.getStationName()).isEqualTo("新充电站");
// 查询验证
ResponseEntity>> queryResponse = restTemplate.getForEntity(
"/api/stations?stationName=新充电站",
new ParameterizedTypeReference>>() {}
);
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)