# 充电站管理

<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)