Files
jsowell-charger-web/doc/充电桩数据同步实现计划.md
2025-12-30 15:59:34 +08:00

465 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 充电桩数据同步实现计划
> 创建时间2025-12-30
> 任务状态:规划中
---
## 一、需求概述
将 Web 项目MySQL中的充电桩数据同步到 JCPP 项目PostgreSQL用于登录鉴权等操作。
### 1.1 数据流向
```
Web 项目 (MySQL) → JCPP 项目 (PostgreSQL)
```
### 1.2 同步方式
- **全量同步**:同步所有充电桩和充电枪数据
- **增量同步**:只同步新增或修改的数据(基于 update_time
---
## 二、表结构映射分析
### 2.1 充电桩表映射
| Web 字段 (pile_basic_info) | JCPP 字段 (t_pile) | 映射说明 |
|---------------------------|-------------------|---------|
| id (int) | - | Web 主键,不同步 |
| sn (varchar(20)) | pile_code (varchar(255)) | 充电桩编码,唯一标识 |
| name (varchar(32)) | pile_name (varchar(255)) | 充电桩名称 |
| software_protocol (varchar(20)) | protocol (varchar(255)) | 软件协议 |
| station_id (int) | station_id (uuid) | ✅ 统一使用固定值 '88bca8da-cdbf-6587-aecc-75784838c501' |
| model_id (int) | model (varchar(255)) | 型号,需要查询转换 |
| - | brand (varchar(255)) | 品牌,可为空 |
| - | manufacturer (varchar(255)) | 制造商,可为空 |
| business_type (char(5)) | type (varchar(16)) | 经营类型映射 |
| 其他字段 | additional_info (jsonb) | 存储为 JSON |
### 2.2 充电枪表映射
| Web 字段 (pile_connector_info) | JCPP 字段 (t_gun) | 映射说明 |
|-------------------------------|------------------|---------|
| id (int) | - | Web 主键,不同步 |
| pile_connector_code (varchar(20)) | gun_code (varchar(255)) | 充电枪编码,唯一标识 |
| name (varchar(20)) | gun_name (varchar(255)) | 充电枪名称 |
| pile_sn (varchar(20)) | pile_id (uuid) | ⚠️ 需要通过 pile_code 查询 pile_id |
| - | gun_no (varchar(255)) | 枪号,从 pile_connector_code 提取 |
| - | station_id (uuid) | ✅ 统一使用固定值 '88bca8da-cdbf-6587-aecc-75784838c501' |
### 2.3 关键问题
#### 问题1station_id 类型映射int → uuid
**解决方案**
- ✅ 统一使用固定的 UUID 值:`88bca8da-cdbf-6587-aecc-75784838c501`
- 所有充电桩都使用这个固定的 station_id
- Web 的原始 station_id 保存在 additional_info 中便于追溯
#### 问题2pile_id 获取
**解决方案**
- 先同步充电桩,获取返回的 pile_id
- 再同步充电枪时,通过 pile_code 查询 pile_id
#### 问题3gun_no 提取
**解决方案**
- pile_connector_code 格式为 "桩号+枪号"20231212000010**01**
- 提取最后 2 位作为 gun_no
---
## 三、实现方案
### 3.1 Web 项目实现(本项目)
#### 3.1.1 数据传输对象DTO
**文件位置**`jsowell-pile/src/main/java/com/jsowell/pile/jcpp/dto/sync/`
1. **JcppPileSyncDTO** - 充电桩同步数据
```java
{
"pileCode": "20231212000010",
"pileName": "1号充电桩",
"protocol": "yunkuaichongV150",
"brand": "特来电",
"model": "AC-7KW",
"manufacturer": "特来电",
"type": "OPERATION", // OPERATION-运营桩, PERSONAL-个人桩
"additionalInfo": {
"webPileId": 6844,
"webStationId": 123, // 保存 Web 的原始 station_id
"businessType": "1",
"secretKey": "abc123",
"longitude": "116.404",
"latitude": "39.915",
"iccid": "89860123456789012345"
}
}
```
**注意**:所有充电桩的 station_id 统一使用固定值 `88bca8da-cdbf-6587-aecc-75784838c501`
2. **JcppGunSyncDTO** - 充电枪同步数据
```java
{
"gunCode": "2023121200001001",
"gunName": "1号枪",
"gunNo": "01",
"pileCode": "20231212000010",
"additionalInfo": {
"webGunId": 30060,
"status": "1",
"parkNo": "A01"
}
}
```
3. **JcppSyncRequest** - 同步请求
```java
{
"syncType": "FULL", // FULL-全量, INCREMENTAL-增量
"lastSyncTime": "2025-12-30 10:00:00", // 增量同步时使用
"piles": [...],
"guns": [...]
}
```
4. **JcppSyncResponse** - 同步响应
```java
{
"success": true,
"message": "同步成功",
"totalPiles": 100,
"successPiles": 98,
"failedPiles": 2,
"totalGuns": 200,
"successGuns": 195,
"failedGuns": 5,
"errors": [...]
}
```
#### 3.1.2 服务接口
**文件位置**`jsowell-pile/src/main/java/com/jsowell/pile/jcpp/service/`
1. **IJcppPileSyncService** - 充电桩同步服务接口
```java
public interface IJcppPileSyncService {
/**
* 全量同步充电桩数据到 JCPP
*/
JcppSyncResponse syncAllPiles();
/**
* 增量同步充电桩数据到 JCPP
* @param lastSyncTime 上次同步时间
*/
JcppSyncResponse syncIncrementalPiles(Date lastSyncTime);
/**
* 同步单个充电桩
*/
boolean syncSinglePile(String pileSn);
}
```
2. **JcppPileSyncServiceImpl** - 实现类
- 查询 Web 数据库
- 转换数据格式
- 调用 JCPP 接口发送数据
- 处理同步结果
#### 3.1.3 Controller 接口
**文件位置**`jsowell-admin/src/main/java/com/jsowell/web/controller/jcpp/`
**JcppPileSyncController**
```java
@RestController
@RequestMapping("/jcpp/sync")
public class JcppPileSyncController {
/**
* 全量同步充电桩数据
* POST /jcpp/sync/full
*/
@PostMapping("/full")
public AjaxResult syncFull();
/**
* 增量同步充电桩数据
* POST /jcpp/sync/incremental
* @param lastSyncTime 上次同步时间(可选,默认取上次记录)
*/
@PostMapping("/incremental")
public AjaxResult syncIncremental(@RequestParam(required = false) Date lastSyncTime);
/**
* 同步单个充电桩
* POST /jcpp/sync/pile/{pileSn}
*/
@PostMapping("/pile/{pileSn}")
public AjaxResult syncSinglePile(@PathVariable String pileSn);
/**
* 查询同步记录
* GET /jcpp/sync/records
*/
@GetMapping("/records")
public TableDataInfo getSyncRecords();
}
```
#### 3.1.4 同步记录表
**表名**`jcpp_sync_record`
```sql
CREATE TABLE `jcpp_sync_record` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`sync_type` varchar(20) NOT NULL COMMENT '同步类型FULL-全量INCREMENTAL-增量)',
`sync_status` varchar(20) NOT NULL COMMENT '同步状态RUNNING-进行中SUCCESS-成功FAILED-失败)',
`start_time` datetime NOT NULL COMMENT '开始时间',
`end_time` datetime DEFAULT NULL COMMENT '结束时间',
`total_piles` int(11) DEFAULT 0 COMMENT '总充电桩数',
`success_piles` int(11) DEFAULT 0 COMMENT '成功充电桩数',
`failed_piles` int(11) DEFAULT 0 COMMENT '失败充电桩数',
`total_guns` int(11) DEFAULT 0 COMMENT '总充电枪数',
`success_guns` int(11) DEFAULT 0 COMMENT '成功充电枪数',
`failed_guns` int(11) DEFAULT 0 COMMENT '失败充电枪数',
`error_message` text COMMENT '错误信息',
`create_by` varchar(20) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_sync_type` (`sync_type`),
KEY `idx_start_time` (`start_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='JCPP 充电桩同步记录表';
```
#### 3.1.5 配置项
**配置文件**`application-{env}.yml`
```yaml
jcpp:
sync:
# JCPP 同步接口地址
api-url: http://jcpp-server:8080/api/sync
# 批量同步大小
batch-size: 100
# 超时时间(秒)
timeout: 60
# 是否启用自动增量同步
auto-sync-enabled: false
# 自动同步间隔(分钟)
auto-sync-interval: 30
```
---
### 3.2 JCPP 项目实现(需要配合)
#### 3.2.1 需要实现的接口
**接口1接收充电桩同步数据**
```
POST /api/sync/piles
Content-Type: application/json
Request Body:
{
"piles": [
{
"pileCode": "20231212000010",
"pileName": "1号充电桩",
"protocol": "yunkuaichongV150",
"brand": "特来电",
"model": "AC-7KW",
"manufacturer": "特来电",
"type": "OPERATION",
"additionalInfo": {
"webStationId": 123 // Web 的原始 station_id
}
}
]
}
Response:
{
"success": true,
"message": "同步成功",
"results": [
{
"pileCode": "20231212000010",
"pileId": "uuid",
"success": true,
"message": "创建成功"
}
]
}
```
**注意**:所有充电桩的 station_id 统一使用固定值 `88bca8da-cdbf-6587-aecc-75784838c501`
**接口2接收充电枪同步数据**
```
POST /api/sync/guns
Content-Type: application/json
Request Body:
{
"guns": [
{
"gunCode": "2023121200001001",
"gunName": "1号枪",
"gunNo": "01",
"pileCode": "20231212000010",
"additionalInfo": {...}
}
]
}
Response:
{
"success": true,
"message": "同步成功",
"results": [...]
}
```
#### 3.2.2 数据处理逻辑
1. **充电桩同步逻辑**
- 根据 pile_code 判断是否已存在
- 存在则更新,不存在则创建
- station_id 统一使用固定值 `88bca8da-cdbf-6587-aecc-75784838c501`
- 返回 pile_id (uuid)
2. **充电枪同步逻辑**
- 根据 gun_code 判断是否已存在
- 通过 pile_code 查询 pile_id
- station_id 统一使用固定值 `88bca8da-cdbf-6587-aecc-75784838c501`
- 存在则更新,不存在则创建
---
## 四、实现步骤
### 阶段一Web 项目基础实现 ✅
- [x] 1. 创建 DTO 类JcppPileSyncDTO、JcppGunSyncDTO、JcppSyncRequest、JcppSyncResponse、JcppSyncResult
- [x] 2. 创建同步记录表jcpp_sync_record及 Mapper
- [x] 3. 创建 Service 接口和实现类IJcppPileSyncService、JcppPileSyncServiceImpl
- [x] 4. 创建 Controller 接口JcppPileSyncController
- [x] 5. 添加配置项application-sit.yml
**已完成文件**
- DTO: `JcppPileSyncDTO.java`, `JcppGunSyncDTO.java`, `JcppSyncRequest.java`, `JcppSyncResponse.java`, `JcppSyncResult.java`
- Domain: `JcppSyncRecord.java`
- Mapper: `JcppSyncRecordMapper.java`, `JcppSyncRecordMapper.xml`
- Service: `IJcppPileSyncService.java`, `JcppPileSyncServiceImpl.java`
- Controller: `JcppPileSyncController.java`
- SQL: `sql/jcpp_sync_record.sql`
- Config: `application-sit.yml` (已添加 jcpp.sync 配置)
### 阶段二JCPP 项目配合实现 ⏳
- [ ] 1. 实现充电桩同步接口(使用固定 station_id
- [ ] 2. 实现充电枪同步接口(使用固定 station_id
### 阶段三:联调测试 ⏳
- [ ] 1. 测试全量同步
- [ ] 2. 测试增量同步
- [ ] 3. 测试单个充电桩同步
- [ ] 4. 测试异常场景
- [ ] 5. 性能测试
### 阶段四:优化完善 ⏳
- [ ] 1. 添加重试机制
- [ ] 2. 添加同步进度查询
- [ ] 3. 添加定时自动同步
- [ ] 4. 完善错误处理和日志
---
## 五、技术要点
### 5.1 数据转换
1. **business_type 映射**
- Web: "1"-运营桩, "2"-个人桩
- JCPP: "OPERATION"-运营桩, "PERSONAL"-个人桩
2. **gun_no 提取**
- pile_connector_code: "2023121200001001"
- gun_no: "01" (最后2位)
3. **additional_info 构建**
- 将 Web 的其他字段存储为 JSON
- 保留原始 ID 便于追溯
### 5.2 性能优化
1. **批量同步**
- 每批 100 条数据
- 避免一次性加载所有数据
2. **异步处理**
- 全量同步使用异步任务
- 返回任务 ID可查询进度
3. **增量同步**
- 基于 update_time 字段
- 记录上次同步时间
### 5.3 异常处理
1. **网络异常**
- 重试机制最多3次
- 指数退避策略
2. **数据异常**
- 记录失败数据
- 继续处理其他数据
3. **事务处理**
- JCPP 端保证事务一致性
- Web 端记录同步状态
---
## 六、注意事项
1. **数据一致性**
- 充电桩必须先于充电枪同步
- 确保 pile_code 唯一性
2. **性能考虑**
- 全量同步可能耗时较长
- 建议在业务低峰期执行
3. **安全性**
- 同步接口需要鉴权
- 敏感数据加密传输
4. **监控告警**
- 同步失败告警
- 同步耗时监控
---
## 七、变更记录
| 日期 | 版本 | 修改人 | 修改内容 |
|------|------|--------|----------|
| 2025-12-30 | v1.0 | Claude | 创建文档,制定实现计划 |
---
## 八、相关文档
- [充电桩数据同步需求.md](./充电桩数据同步需求.md)
- [JCPP对接进度文档.md](./JCPP对接进度文档.md)