# 设备管理模块 **本文档引用的文件** - [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) ## 目录 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` - **权限控制**: 需要管理员权限 **请求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>` **分页响应结构** ```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` **来源** - [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L60-L68) #### 删除充电站 删除指定ID的充电站。 - **端点**: `DELETE /api/stations/{id}` - **响应**: `ApiResponse` **来源** - [StationController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/StationController.java#L71-L77) #### 获取选项列表 为前端下拉组件提供数据。 - **端点**: `GET /api/stations/options` - **响应**: `ApiResponse>` **选项响应结构** ```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` **来源** - [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L35-L42) #### 查询充电桩状态 获取充电桩的实时运行状态。 - **端点**: `GET /api/piles/status/{pileCode}` - **响应**: `ApiResponse` **来源** - [PileController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/PileController.java#L90-L111) ### GunController API #### 创建充电枪 创建新的充电枪实体。 - **端点**: `POST /api/guns` - **请求体**: `GunCreateRequest` - **响应**: `ApiResponse` **来源** - [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L35-L42) #### 查询充电枪状态 根据枪编码获取充电枪的运行状态。 - **端点**: `GET /api/guns/status/{gunCode}` - **响应**: `ApiResponse` **来源** - [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L80-L100) #### 按编码查询充电枪 根据枪编码获取充电枪的详细信息。 - **端点**: `GET /api/guns/code/{gunCode}` - **响应**: `ApiResponse` **来源** - [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L103-L115) ## 业务服务层设计 ### 服务层架构 业务服务层是设备管理模块的核心,负责协调数据访问层和缓存层的操作。`DefaultStationService`、`DefaultPileService`和 `DefaultGunService`分别实现了对应的接口,提供了具体的业务逻辑处理。 ```mermaid classDiagram class StationService { <> +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 { <> +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 Service->>Service : 转换为PageResponse Service->>Service : 存入缓存 Service-->>Controller : PageResponse 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)