# 充电枪管理

<cite>
**本文档引用文件**   
- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java)
- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java)
- [GunMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/GunMapper.java)
- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java)
- [GunRepository.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/GunRepository.java)
- [GunRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/GunRepositoryImpl.java)
- [GunCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/GunCreateRequest.java)
- [GunUpdateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/GunUpdateRequest.java)
- [GunWithStatusResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/GunWithStatusResponse.java)
- [PageResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PageResponse.java)
- [AttrKeyEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/data/kv/AttrKeyEnum.java)
- [GunRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/gun/GunRedisCache.java)
- [GunRunStatusEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/GunRunStatusEnum.java)
</cite>

## 目录

1. [简介](#简介)
2. [数据模型](#数据模型)
3. [RESTful API](#restful-api)
4. [服务层实现](#服务层实现)
5. [缓存机制](#缓存机制)
6. [状态管理](#状态管理)
7. [使用示例](#使用示例)
8. [级联关系与状态同步](#级联关系与状态同步)

## 简介

本文档详细描述了充电枪管理功能的实现，包括数据模型、API接口、服务层逻辑、缓存机制和状态管理。系统通过Gun实体管理充电枪，支持创建、查询、更新和删除操作，并通过属性系统实时跟踪充电枪的运行状态。

## 数据模型

### Gun实体

`Gun`实体是充电枪的核心数据模型，定义了充电枪的基本属性和关系。

```mermaid
classDiagram
class Gun {
+UUID id
+LocalDateTime createdTime
+LocalDateTime updatedTime
+JsonNode additionalInfo
+String gunNo
+String gunName
+String gunCode
+UUID stationId
+UUID pileId
+Integer version
}
```

**图示来源**

- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L57)

**核心属性说明**

- **id**: 充电枪唯一标识符，UUID类型
- **gunNo**: 充电枪编号，如"01"、"02"
- **gunName**: 充电枪名称
- **gunCode**: 充电枪编码，全局唯一标识
- **stationId**: 所属充电站ID，与Station实体关联
- **pileId**: 所属充电桩ID，与Pile实体关联

**实体关系**

```mermaid
erDiagram
GUN {
uuid id PK
string gunNo
string gunName
string gunCode UK
uuid stationId FK
uuid pileId FK
timestamp createdTime
timestamp updatedTime
integer version
}
PILE {
uuid id PK
string pileCode UK
}
GUN ||--o{ PILE : "属于"
```

**图示来源**

- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L57)

**实体关系说明**

- **1对多关系**: 一个充电桩(Pile)可以有多个充电枪(Gun)，形成1对多关系
- **外键约束**: `pileId`字段作为外键关联到Pile实体
- **唯一性约束**: `gunCode`字段具有唯一性约束，确保全局唯一

**Section sources**

- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L57)

## RESTful API

### API概览

`GunController`提供了完整的RESTful API接口，支持对充电枪的CRUD操作。

```mermaid
graph TD
A[客户端] --> B[POST /api/guns]
A --> C[GET /api/guns/{id}]
A --> D[PUT /api/guns/{id}]
A --> E[DELETE /api/guns/{id}]
A --> F[GET /api/guns]
A --> G[GET /api/guns/status/{gunCode}]
A --> H[GET /api/guns/code/{gunCode}]
B --> I[创建充电枪]
C --> J[查询单个充电枪]
D --> K[更新充电枪]
E --> L[删除充电枪]
F --> M[分页查询充电枪]
G --> N[查询充电枪状态]
H --> O[查询充电枪详情]
```

**图示来源**

- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L1-L116)

### API详情

#### 创建充电枪 (POST /api/guns)

创建新的充电枪实体。

**请求参数**

- **HTTP方法**: POST
- **URL**: /api/guns
- **Content-Type**: application/json

**请求体 (GunCreateRequest)**

```json
{
  "gunName": "快充枪1",
  "gunNo": "01",
  "gunCode": "GUN001",
  "stationId": "uuid-string",
  "pileId": "uuid-string"
}
```

**响应格式**

```json
{
  "code": 200,
  "message": "创建成功",
  "data": {
    "id": "uuid-string",
    "createdTime": "2023-01-01T00:00:00",
    "gunName": "快充枪1",
    "gunNo": "01",
    "gunCode": "GUN001",
    "stationId": "uuid-string",
    "pileId": "uuid-string",
    "version": 0
  }
}
```

**验证规则**

- `gunName`: 必填，不允许XSS攻击
- `gunNo`: 必填
- `gunCode`: 必填，不允许重复
- `stationId`: 必填，有效UUID
- `pileId`: 必填，有效UUID

**Section sources**

- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L25-L32)
- [GunCreateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/GunCreateRequest.java#L1-L37)

#### 查询充电枪 (GET /api/guns)

分页查询充电枪列表，包含状态信息。

**请求参数**

- **HTTP方法**: GET
- **URL**: /api/guns
- **查询参数**:
    - `page`: 页码（默认1）
    - `size`: 每页大小（默认10）
    - `gunName`: 充电枪名称（可选）
    - `pileId`: 充电桩ID（可选）

**响应格式 (PageResponse<GunWithStatusResponse>)**

```json
{
  "records": [
    {
      "id": "uuid-string",
      "gunName": "快充枪1",
      "gunNo": "01",
      "gunCode": "GUN001",
      "stationId": "uuid-string",
      "pileId": "uuid-string",
      "stationName": "充电站A",
      "pileName": "充电桩1",
      "pileCode": "PILE001",
      "runStatus": "CHARGING"
    }
  ],
  "total": 1,
  "totalPages": 1,
  "page": 1,
  "size": 10
}
```

**分页参数**

- **records**: 当前页的数据列表
- **total**: 总记录数
- **totalPages**: 总页数
- **page**: 当前页码
- **size**: 每页大小

**Section sources**

- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L62-L68)
- [PageResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/PageResponse.java#L1-L44)
- [GunWithStatusResponse.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/response/GunWithStatusResponse.java#L1-L96)

#### 更新充电枪 (PUT /api/guns/{id})

更新指定ID的充电枪信息。

**请求参数**

- **HTTP方法**: PUT
- **URL**: /api/guns/{id}
- **路径参数**: id (充电枪UUID)
- **请求体**: GunUpdateRequest

**请求体 (GunUpdateRequest)**

```json
{
  "gunName": "快充枪1-更新",
  "gunNo": "01",
  "gunCode": "GUN001",
  "stationId": "uuid-string",
  "pileId": "uuid-string"
}
```

**响应格式**

```json
{
  "code": 200,
  "message": "更新成功",
  "data": {
    "id": "uuid-string",
    "updatedTime": "2023-01-01T00:00:00",
    "gunName": "快充枪1-更新",
    "gunNo": "01",
    "gunCode": "GUN001",
    "stationId": "uuid-string",
    "pileId": "uuid-string"
  }
}
```

**更新规则**

- 允许修改所有字段
- 更新时自动设置`updatedTime`字段
- 版本号保持不变

**Section sources**

- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L34-L43)
- [GunUpdateRequest.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/request/GunUpdateRequest.java#L1-L36)

#### 删除充电枪 (DELETE /api/guns/{id})

删除指定ID的充电枪。

**请求参数**

- **HTTP方法**: DELETE
- **URL**: /api/guns/{id}
- **路径参数**: id (充电枪UUID)

**响应格式**

```json
{
  "code": 200,
  "message": "删除成功",
  "data": null
}
```

**删除逻辑**

- 先检查充电枪是否存在
- 执行物理删除操作
- 返回成功或失败状态

**Section sources**

- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L45-L51)

#### 查询充电枪状态 (GET /api/guns/status/{gunCode})

根据充电枪编码查询其运行状态。

**请求参数**

- **HTTP方法**: GET
- **URL**: /api/guns/status/{gunCode}
- **路径参数**: gunCode (充电枪编码)

**响应格式**

```json
{
  "code": 200,
  "message": "查询成功",
  "data": "CHARGING"
}
```

**状态查询流程**

1. 根据`gunCode`查找充电枪实体
2. 通过`AttributeService`获取`gunRunStatus`属性
3. 返回状态值

**Section sources**

- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L69-L96)

#### 查询充电枪详情 (GET /api/guns/code/{gunCode})

根据充电枪编码查询其详细信息，包含状态。

**请求参数**

- **HTTP方法**: GET
- **URL**: /api/guns/code/{gunCode}
- **路径参数**: gunCode (充电枪编码)

**响应格式**

```json
{
  "code": 200,
  "message": "查询成功",
  "data": {
    "id": "uuid-string",
    "gunName": "快充枪1",
    "gunNo": "01",
    "gunCode": "GUN001",
    "stationId": "uuid-string",
    "pileId": "uuid-string",
    "stationName": "充电站A",
    "pileName": "充电桩1",
    "pileCode": "PILE001",
    "runStatus": "CHARGING"
  }
}
```

**详情查询特点**

- 返回完整的`GunWithStatusResponse`对象
- 包含关联的充电站和充电桩信息
- 包含当前运行状态

**Section sources**

- [GunController.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/GunController.java#L98-L115)

## 服务层实现

### DefaultGunService架构

`DefaultGunService`是充电枪业务逻辑的核心实现，协调数据访问和缓存操作。

```mermaid
classDiagram
class DefaultGunService {
-GunMapper gunMapper
-GunRepository gunRepository
-AttributeService attributeService
+createGun(GunCreateRequest) Gun
+findById(UUID) Gun
+updateGun(UUID, GunUpdateRequest) Gun
+deleteGun(UUID) void
+queryGunsWithStatus(GunQueryRequest) PageResponse
+findByPileCodeAndGunNo(String, String) Gun
+findByGunCode(String) Gun
+findGunWithStatusByCode(String) GunWithStatusResponse
+findGunStatus(UUID) String
+saveGunStatusChange(UUID, String, Long) void
+handleGunRunStatus(String, String, GunRunStatus, long) boolean
}
class GunService {
<<interface>>
+createGun(GunCreateRequest) Gun
+findById(UUID) Gun
+updateGun(UUID, GunUpdateRequest) Gun
+deleteGun(UUID) void
+queryGunsWithStatus(GunQueryRequest) PageResponse
+findByPileCodeAndGunNo(String, String) Gun
+findByGunCode(String) Gun
+findGunWithStatusByCode(String) GunWithStatusResponse
+findGunStatus(UUID) String
+saveGunStatusChange(UUID, String, Long) void
+handleGunRunStatus(String, String, GunRunStatus, long) boolean
}
DefaultGunService --|> GunService : 实现
DefaultGunService --> GunMapper : 使用
DefaultGunService --> GunRepository : 使用
DefaultGunService --> AttributeService : 使用
```

**图示来源**

- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L1-L246)

### 核心方法分析

#### 创建充电枪 (createGun)

实现充电枪的创建逻辑。

**处理流程**

1. 检查`gunCode`是否已存在
2. 构建新的`Gun`实体
3. 设置默认值（ID、创建时间、版本等）
4. 插入数据库

**验证逻辑**

- 使用`LambdaQueryWrapper`检查`gunCode`唯一性
- 抛出异常阻止重复创建

**Section sources**

- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L48-L75)

#### 查询充电枪状态 (findGunStatus)

从属性系统中查询充电枪的运行状态。

**实现细节**

- 使用`AttributeService.find()`异步获取属性
- 属性键为`AttrKeyEnum.GUN_RUN_STATUS.getCode()`
- 返回字符串格式的状态值

**异步处理**

- 使用`ListenableFuture`进行异步调用
- 通过`get()`方法阻塞等待结果
- 包含异常处理逻辑

**Section sources**

- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L178-L193)

#### 保存充电枪状态 (saveGunStatusChange)

将充电枪状态保存到属性系统。

**实现细节**

- 创建`BaseAttributeKvEntry`对象
- 使用`StringDataEntry`存储状态值
- 调用`attributeService.save()`持久化

**时间戳处理**

- 使用传入的`ts`参数或当前时间
- 支持精确到毫秒的时间戳

**Section sources**

- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L195-L208)

#### 处理充电枪运行状态 (handleGunRunStatus)

处理从协议层上报的充电枪状态。

**处理流程**

1. 将Proto状态转换为数据库枚举
2. 根据`pileCode`和`gunNo`查找充电枪
3. 检查状态是否发生变化
4. 保存新状态到属性系统
5. 判断是否需要更新充电桩状态

**状态转换**

- 实现Proto状态到数据库枚举的映射
- 支持多种状态类型（空闲、充电中、故障等）
- 未知状态返回null

**状态同步**

- 检查当前状态避免重复更新
- 记录状态变化日志
- 触发相关业务逻辑

**Section sources**

- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L210-L244)

## 缓存机制

### 缓存架构

系统采用多级缓存策略提升查询性能。

```mermaid
graph TD
A[应用层] --> B[GunService]
B --> C[GunRepository]
C --> D[GunRedisCache]
D --> E[Redis]
C --> F[GunMapper]
F --> G[数据库]
style D fill:#f9f,stroke:#333
style F fill:#bbf,stroke:#333
subgraph "缓存层"
D
E
end
subgraph "持久层"
F
G
end
```

**图示来源**

- [GunRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/GunRepositoryImpl.java#L1-L97)
- [GunRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/gun/GunRedisCache.java#L1-L36)

### GunRedisCache实现

`GunRedisCache`是基于Redis的充电枪缓存实现。

```mermaid
classDiagram
class GunRedisCache {
+String cacheName
+CacheSpecsMap cacheSpecsMap
+LettuceConnectionFactory connectionFactory
+JCPPRedisSerializer serializer
+serialize(Gun) byte[]
+deserialize(GunCacheKey, byte[]) Gun
}
class VersionedRedisCache {
<<abstract>>
+get(K, Callable<V>) V
+evict(K) void
+evict(Collection<K>) void
}
GunRedisCache --|> VersionedRedisCache : 继承
GunRedisCache --> Gun : 序列化/反序列化
GunRedisCache --> JacksonUtil : JSON转换
```

**图示来源**

- [GunRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/gun/GunRedisCache.java#L1-L36)

**核心特性**

- 使用`JCPPRedisSerializer`进行序列化
- 基于`JacksonUtil`实现JSON转换
- 支持版本化缓存
- 配置化缓存策略

**序列化实现**

- `serialize()`: 使用Jackson将Gun对象转换为字节数组
- `deserialize()`: 从字节数组反序列化为Gun对象

**Section sources**

- [GunRedisCache.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/cache/gun/GunRedisCache.java#L1-L36)

### 缓存键设计 (GunCacheKey)

缓存键设计支持多种查询场景。

```java
// 伪代码表示GunCacheKey的设计
public class GunCacheKey {
    private UUID gunId;           // 基于ID的缓存
    private String pileCode;      // 基于桩编码的缓存
    private String gunNo;         // 基于枪编号的缓存
    private String gunCode;       // 基于枪编码的缓存
    
    // 支持多种构造函数
    public GunCacheKey(UUID gunId)
    public GunCacheKey(String pileCode, String gunNo)
    public GunCacheKey(String gunCode)
}
```

**缓存键类型**

- **基于ID**: `new GunCacheKey(gunId)`
- **基于桩编码+枪编号**: `new GunCacheKey(pileCode, gunNo)`
- **基于枪编码**: `new GunCacheKey(gunCode)`

**Section sources**

- [GunRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/GunRepositoryImpl.java#L1-L97)

### 缓存事件处理

通过事件机制维护缓存一致性。

```mermaid
sequenceDiagram
participant Service as DefaultGunService
participant Repository as GunRepositoryImpl
participant Cache as GunRedisCache
participant Event as GunCacheEvictEvent
Service->>Repository : updateGun()
Repository->>Repository : handleEvictEvent()
Repository->>Cache : evict()
Cache->>Redis : 删除缓存
Repository->>Repository : 查询数据库
Repository-->>Service : 返回结果
```

**图示来源**

- [GunRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/GunRepositoryImpl.java#L1-L97)

**事件处理流程**

1. 服务层执行更新或删除操作
2. 触发`GunCacheEvictEvent`事件
3. `GunRepositoryImpl`监听并处理事件
4. 从Redis缓存中删除相关键
5. 后续查询将从数据库获取最新数据

**缓存失效策略**

- 写操作后立即失效缓存
- 支持批量失效多个缓存键
- 保证缓存与数据库的一致性

**Section sources**

- [GunRepositoryImpl.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/repository/impl/GunRepositoryImpl.java#L25-L45)

## 状态管理

### 运行状态枚举 (GunRunStatusEnum)

定义了充电枪的所有可能运行状态。

```mermaid
classDiagram
class GunRunStatusEnum {
+IDLE
+INSERTED
+CHARGING
+CHARGE_COMPLETE
+DISCHARGE_READY
+DISCHARGING
+DISCHARGE_COMPLETE
+RESERVED
+FAULT
}
```

**图示来源**

- [GunRunStatusEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/GunRunStatusEnum.java)

**状态说明**

- **IDLE**: 空闲状态，未连接车辆
- **INSERTED**: 已插枪，未开始充电
- **CHARGING**: 正在充电
- **CHARGE_COMPLETE**: 充电完成
- **DISCHARGE_READY**: 放电准备
- **DISCHARGING**: 正在放电
- **DISCHARGE_COMPLETE**: 放电完成
- **RESERVED**: 已预约
- **FAULT**: 故障状态

**状态转换**

- 通过`switch`语句实现Proto状态到枚举的转换
- 未知状态返回null，不进行更新

**Section sources**

- [GunRunStatusEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/GunRunStatusEnum.java)

### 状态获取流程

从协议会话中获取和更新充电枪状态。

```mermaid
sequenceDiagram
participant Protocol as 协议层
participant Service as DefaultGunService
participant Attribute as AttributeService
participant Redis as Redis
participant DB as 数据库
Protocol->>Service : handleGunRunStatus(pileCode, gunNo, protoStatus, ts)
Service->>Service : convertProtoStatusToDbStatus()
Service->>Repository : findByPileCodeAndGunNo(pileCode, gunNo)
Repository->>Redis : 查询缓存
Redis-->>Repository : 返回结果
Repository-->>Service : 返回Gun实体
Service->>Service : findGunStatus(gunId)
Service->>Attribute : find(gunId, GUN_RUN_STATUS)
Attribute->>Redis : 查询属性缓存
Redis-->>Attribute : 返回状态
Attribute-->>Service : 返回当前状态
alt 状态发生变化
Service->>Service : saveGunStatusChange(gunId, status, ts)
Service->>Attribute : save(gunId, attribute)
Attribute->>Redis : 保存属性
Redis-->>Attribute : 确认
Attribute-->>Service : 确认
Service-->>Protocol : 返回true
else 状态未变化
Service-->>Protocol : 返回false
end
```

**图示来源**

- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L210-L244)

**状态同步机制**

1. 协议层上报充电枪状态
2. 服务层转换状态格式
3. 查找对应的充电枪实体
4. 获取当前状态进行比较
5. 只有状态变化时才更新
6. 保存新状态到属性系统

**性能优化**

- 使用缓存减少数据库查询
- 状态比较避免不必要的更新
- 异步属性服务提高响应速度

**Section sources**

- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L210-L244)

## 使用示例

### 为充电桩配置两把充电枪

展示如何为一个充电桩配置两把充电枪的完整流程。

```mermaid
flowchart TD
Start([开始]) --> CreatePile["创建充电桩"]
CreatePile --> GetPileId["获取充电桩ID"]
GetPileId --> CreateGun1["创建第一把充电枪"]
CreateGun1 --> SetGun1Props["设置第一把枪属性"]
SetGun1Props --> CreateGun2["创建第二把充电枪"]
CreateGun2 --> SetGun2Props["设置第二把枪属性"]
SetGun2Props --> Verify["验证配置结果"]
Verify --> End([完成])
style CreatePile fill:#9f9,stroke:#333
style CreateGun1 fill:#9f9,stroke:#333
style CreateGun2 fill:#9f9,stroke:#333
```

**图示来源**

- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L48-L75)

**实现步骤**

#### 步骤1: 创建充电桩

首先创建一个充电桩实体。

```java
// 伪代码：创建充电桩
Pile pile = pileService.createPile(createRequest);
UUID pileId = pile.getId();
```

#### 步骤2: 创建第一把充电枪

为充电桩创建第一把充电枪。

```java
// 伪代码：创建第一把充电枪
GunCreateRequest gun1Request = GunCreateRequest.builder()
    .gunName("快充枪1")
    .gunNo("01")
    .gunCode("GUN001")
    .stationId(stationId)
    .pileId(pileId)
    .build();

Gun gun1 = gunService.createGun(gun1Request);
```

#### 步骤3: 创建第二把充电枪

为同一充电桩创建第二把充电枪。

```java
// 伪代码：创建第二把充电枪
GunCreateRequest gun2Request = GunCreateRequest.builder()
    .gunName("快充枪2")
    .gunNo("02")
    .gunCode("GUN002")
    .stationId(stationId)
    .pileId(pileId)
    .build();

Gun gun2 = gunService.createGun(gun2Request);
```

#### 步骤4: 验证配置结果

查询充电桩下的所有充电枪。

```java
// 伪代码：验证配置
List<Gun> guns = gunService.findByPileId(pileId);
assert guns.size() == 2;

GunWithStatusResponse gun1Status = gunService.findGunWithStatusByCode("GUN001");
GunWithStatusResponse gun2Status = gunService.findGunWithStatusByCode("GUN002");
```

**关键要点**

- 两把充电枪共享同一个`pileId`
- `gunNo`在同一充电桩下必须唯一
- `gunCode`在整个系统中必须唯一
- 可以独立管理每把充电枪的状态

**Section sources**

- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L48-L75)
- [GunMapper.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/mapper/GunMapper.java#L1-L132)

## 级联关系与状态同步

### 级联关系管理

充电枪与充电桩之间的级联关系管理。

```mermaid
erDiagram
STATION ||--o{ PILE : "拥有"
PILE ||--o{ GUN : "拥有"
STATION {
uuid id PK
string stationName
}
PILE {
uuid id PK
string pileCode UK
uuid stationId FK
}
GUN {
uuid id PK
string gunCode UK
uuid pileId FK
string gunNo
}
```

**图示来源**

- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L57)

**级联操作**

- **创建**: 充电枪必须关联到存在的充电桩
- **查询**: 支持通过充电桩查询所有充电枪
- **更新**: 可以修改充电枪所属的充电桩
- **删除**: 删除充电桩时级联删除所有充电枪

**外键约束**

- `pileId`字段确保充电枪必须属于某个充电桩
- 数据库层面保证引用完整性

**Section sources**

- [Gun.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/Gun.java#L1-L57)

### 状态同步机制

充电枪状态变化时与充电桩的状态同步。

```mermaid
flowchart TD
GunStatusChange["充电枪状态变化"] --> CheckStatus["检查新状态"]
CheckStatus --> |CHARGING| UpdatePile["更新充电桩状态"]
CheckStatus --> |DISCHARGING| UpdatePile["更新充电桩状态"]
CheckStatus --> |FAULT| UpdatePile["更新充电桩状态"]
CheckStatus --> |其他状态| NoUpdate["不更新"]
UpdatePile --> PileService["调用PileService"]
PileService --> UpdateStatus["更新充电桩状态"]
UpdateStatus --> Log["记录日志"]
Log --> End([完成])
style UpdatePile fill:#f96,stroke:#333
style NoUpdate fill:#69f,stroke:#333
```

**图示来源**

- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L233-L244)

**同步规则**

```java
private boolean shouldUpdatePileStatus(GunRunStatusEnum gunStatus) {
    return switch (gunStatus) {
        case CHARGING, DISCHARGING -> true; // 充电或放电时更新
        case FAULT -> true; // 故障时更新
        default -> false; // 其他状态不更新
    };
}
```

**触发条件**

- **充电开始**: 充电枪状态变为`CHARGING`
- **放电开始**: 充电枪状态变为`DISCHARGING`
- **故障发生**: 充电枪状态变为`FAULT`

**同步流程**

1. 充电枪状态发生变化
2. 调用`shouldUpdatePileStatus()`判断是否需要同步
3. 如果需要，通知`PileService`更新充电桩状态
4. 更新充电桩的在线状态和运行状态

**性能考虑**

- 只在必要时触发同步，减少不必要的操作
- 使用异步机制避免阻塞主流程
- 缓存充电桩状态减少数据库查询

**Section sources**

- [DefaultGunService.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultGunService.java#L233-L244)