mirror of
https://codeup.aliyun.com/67c68d4e484ca2f0a13ac3c1/ydc/jsowell-charger-web.git
synced 2026-04-20 11:05:18 +08:00
465 lines
12 KiB
Markdown
465 lines
12 KiB
Markdown
|
|
# 充电桩数据同步实现计划
|
|||
|
|
|
|||
|
|
> 创建时间: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 关键问题
|
|||
|
|
|
|||
|
|
#### 问题1:station_id 类型映射(int → uuid)
|
|||
|
|
**解决方案**:
|
|||
|
|
- ✅ 统一使用固定的 UUID 值:`88bca8da-cdbf-6587-aecc-75784838c501`
|
|||
|
|
- 所有充电桩都使用这个固定的 station_id
|
|||
|
|
- Web 的原始 station_id 保存在 additional_info 中便于追溯
|
|||
|
|
|
|||
|
|
#### 问题2:pile_id 获取
|
|||
|
|
**解决方案**:
|
|||
|
|
- 先同步充电桩,获取返回的 pile_id
|
|||
|
|
- 再同步充电枪时,通过 pile_code 查询 pile_id
|
|||
|
|
|
|||
|
|
#### 问题3:gun_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)
|