16 KiB
充电站管理
**本文档引用的文件** - [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)目录
引言
充电站管理功能是本系统的核心模块之一,负责充电站的全生命周期管理。该功能提供了完整的CRUD操作,支持通过RESTful API对充电站进行创建、查询、更新和删除。系统采用分层架构设计,包含控制器层、服务层和数据访问层,确保了代码的可维护性和扩展性。充电站实体与充电桩实体之间存在一对多的关系,系统在删除充电站时会进行级联检查,确保数据完整性。
数据模型
Station实体
Station实体是充电站管理的核心数据模型,定义了充电站的基本属性和元数据。该实体映射到数据库中的t_station表,使用MyBatis
Plus框架进行ORM映射。
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
核心属性说明
- id: 充电站唯一标识符,使用UUID类型,作为主键
- createdTime: 创建时间,记录充电站创建的精确时间戳
- updatedTime: 更新时间,每次更新时自动更新
- stationName: 充电站名称,必填字段,用于标识充电站
- stationCode: 充电站编码,必填字段,具有唯一性约束
- longitude/latitude: 地理位置坐标,用于地图展示和定位
- province/city/county/address: 地址信息,分别表示省、市、区县和详细地址
- additionalInfo: 附加信息,使用JSON格式存储扩展属性
- version: 版本号,用于乐观锁控制,防止并发更新冲突
Section sources
RESTful API接口
API端点概览
StationController提供了完整的RESTful API端点,用于管理充电站资源。所有API均遵循REST设计原则,使用标准的HTTP方法和状态码。
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
详细API说明
创建充电站 (POST /api/stations)
创建新的充电站资源。
- 请求参数:
StationCreateRequest对象 - 请求体示例:
{
"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对象 - 请求体示例:
{
"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
服务层实现
DefaultStationService
DefaultStationService是充电站管理的核心服务实现类,协调StationMapper和PileMapper进行数据库操作,并处理业务逻辑。
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
核心方法说明
- getStations: 实现分页查询功能,根据
StationQueryRequest中的条件构建查询条件,支持按名称、编码、省份、城市等字段进行查询,并支持排序功能 - getStationById: 根据ID查询单个充电站信息
- createStation: 创建新的充电站,自动生成UUID和创建时间,初始化版本号为1
- updateStation: 更新充电站信息,更新时会自动设置
updatedTime字段 - deleteStation: 删除充电站前会进行完整性检查,确保该充电站下没有关联的充电桩
- getStationOptions: 获取充电站选项列表,用于前端下拉选择
- searchStationOptions: 支持关键字搜索的充电站选项查询
Section sources
使用示例
创建充电站完整流程
以下是一个通过API创建新充电站并验证其存在的完整示例:
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
示例代码
// 创建充电站请求
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
分页查询机制
分页实现原理
系统采用MyBatis Plus的分页插件实现分页查询功能,通过Page对象和IPage接口提供分页支持。
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
PageResponse结构
PageResponse类封装了分页查询的响应数据,包含以下字段:
- records: 当前页的数据记录列表
- total: 总记录数
- page: 当前页码
- size: 每页大小
- totalPages: 总页数
分页计算公式:totalPages = ceil(total / size)
Section sources
级联删除逻辑
删除业务流程
系统在删除充电站时实现了严格的级联检查机制,确保数据完整性。
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
详细逻辑说明
- 存在性检查: 首先通过
stationMapper.selectById(id)检查充电站是否存在,如果不存在则抛出ITEM_NOT_FOUND异常 - 关联检查: 调用
pileMapper.countByStationId(id)统计该充电站下的充电桩数量,如果数量大于0,则抛出VERSION_CONFLICT异常,提示用户先删除所有充电桩 - 执行删除: 通过
stationMapper.deleteById(id)执行删除操作 - 结果验证: 检查受影响的行数,如果为0则说明删除失败,可能是被其他操作删除,抛出
VERSION_CONFLICT异常
这种设计确保了数据的一致性和完整性,防止意外删除包含充电桩的充电站。
Section sources