mirror of
https://codeup.aliyun.com/67c68d4e484ca2f0a13ac3c1/ydc/jsowell-charger-web.git
synced 2026-04-20 11:05:18 +08:00
10 KiB
10 KiB
JCPP 项目充电桩数据同步接口实现 Prompt
请将以下内容复制给 JCPP 项目的 Claude Code 执行
任务概述
需要在 JCPP 项目中实现充电桩数据同步接口,用于接收来自 Web 项目的充电桩和充电枪数据。
背景说明
Web 项目(MySQL)中维护了充电桩的主数据,现在需要将这些数据同步到 JCPP 项目(PostgreSQL)中,用于登录鉴权等操作。
数据流向
Web 项目 (MySQL) → HTTP API → JCPP 项目 (PostgreSQL)
关键差异
- 主键类型:Web 使用 int,JCPP 使用 uuid
- station_id 类型:Web 是 int,JCPP 是 uuid(需要映射)
- 字段名称:sn → pile_code, name → pile_name
需要实现的功能
1. 充电桩同步接口
接口路径:POST /api/sync/piles
重要说明:
- ✅ 所有充电桩的
station_id统一使用固定值:88bca8da-cdbf-6587-aecc-75784838c501 - Web 项目的原始 station_id 保存在
additionalInfo.webStationId中便于追溯
请求格式:
{
"piles": [
{
"pileCode": "20231212000010",
"pileName": "1号充电桩",
"protocol": "yunkuaichongV150",
"brand": "特来电",
"model": "AC-7KW",
"manufacturer": "特来电",
"type": "OPERATION",
"additionalInfo": {
"webPileId": 6844,
"webStationId": 123,
"businessType": "1",
"secretKey": "abc123",
"longitude": "116.404",
"latitude": "39.915",
"iccid": "89860123456789012345"
}
}
]
}
字段说明:
pileCode:充电桩编码(对应 Web 的 sn),唯一标识pileName:充电桩名称(对应 Web 的 name)protocol:软件协议(对应 Web 的 software_protocol)brand:品牌(可为空)model:型号(可为空)manufacturer:制造商(可为空)type:类型,枚举值:OPERATION:运营桩(对应 Web 的 business_type = "1")PERSONAL:个人桩(对应 Web 的 business_type = "2")
additionalInfo:附加信息(JSON 格式),包含:webPileId:Web 项目的充电桩 IDwebStationId:Web 项目的充电站 ID(原始 int 值)- 其他 Web 项目的字段
响应格式:
{
"success": true,
"message": "同步成功",
"results": [
{
"pileCode": "20231212000010",
"pileId": "550e8400-e29b-41d4-a716-446655440000",
"success": true,
"message": "创建成功"
}
]
}
处理逻辑:
- 遍历
piles数组 - 对于每个充电桩:
- 根据
pileCode查询t_pile表,判断是否已存在 - station_id 统一使用固定值:
88bca8da-cdbf-6587-aecc-75784838c501 - 如果充电桩已存在,执行 UPDATE 操作
- 如果充电桩不存在,执行 INSERT 操作(生成新的 uuid)
- 将
additionalInfo存储为 jsonb 类型
- 根据
- 返回每个充电桩的处理结果
注意事项:
- 使用事务保证数据一致性
- pile_code 必须唯一(已有唯一索引)
- 所有充电桩的 station_id 都使用固定值
88bca8da-cdbf-6587-aecc-75784838c501
2. 充电枪同步接口
接口路径:POST /api/sync/guns
重要说明:
- ✅ 所有充电枪的
station_id统一使用固定值:88bca8da-cdbf-6587-aecc-75784838c501
请求格式:
{
"guns": [
{
"gunCode": "2023121200001001",
"gunName": "1号枪",
"gunNo": "01",
"pileCode": "20231212000010",
"additionalInfo": {
"webGunId": 30060,
"status": "1",
"parkNo": "A01"
}
}
]
}
字段说明:
gunCode:充电枪编码(对应 Web 的 pile_connector_code),唯一标识gunName:充电枪名称(对应 Web 的 name)gunNo:枪号(从 gunCode 提取最后 2 位)pileCode:所属充电桩编码(对应 Web 的 pile_sn)additionalInfo:附加信息(JSON 格式),包含 Web 项目的其他字段
响应格式:
{
"success": true,
"message": "同步成功",
"results": [
{
"gunCode": "2023121200001001",
"gunId": "660e8400-e29b-41d4-a716-446655440000",
"success": true,
"message": "创建成功"
}
]
}
处理逻辑:
- 遍历
guns数组 - 对于每个充电枪:
- 根据
gunCode查询t_gun表,判断是否已存在 - 根据
pileCode查询t_pile表,获取pile_id(uuid) - 如果充电桩不存在,记录错误并跳过该充电枪
- station_id 统一使用固定值:
88bca8da-cdbf-6587-aecc-75784838c501 - 如果充电枪已存在,执行 UPDATE 操作
- 如果充电枪不存在,执行 INSERT 操作(生成新的 uuid)
- 根据
- 返回每个充电枪的处理结果
注意事项:
- 充电桩必须先于充电枪同步
- gun_code 必须唯一(已有唯一索引)
- (pile_id, gun_no) 组合必须唯一(已有唯一索引)
- 所有充电枪的 station_id 都使用固定值
88bca8da-cdbf-6587-aecc-75784838c501
实现建议
技术栈
- 框架:Spring Boot
- 数据库:PostgreSQL 17
- ORM:JPA / MyBatis
- JSON 处理:Jackson / Gson
代码结构建议
src/main/java/com/jcpp/
├── controller/
│ └── SyncController.java # 同步接口 Controller
├── service/
│ ├── PileSyncService.java # 充电桩同步服务接口
│ └── GunSyncService.java # 充电枪同步服务接口
├── service/impl/
│ ├── PileSyncServiceImpl.java
│ └── GunSyncServiceImpl.java
├── entity/
│ ├── Pile.java # t_pile 实体
│ └── Gun.java # t_gun 实体
├── repository/
│ ├── PileRepository.java
│ └── GunRepository.java
└── dto/
├── PileSyncDTO.java # 充电桩同步 DTO
├── GunSyncDTO.java # 充电枪同步 DTO
├── SyncRequest.java # 同步请求
└── SyncResponse.java # 同步响应
关键代码示例
PileSyncService 接口:
public interface PileSyncService {
/**
* 同步充电桩数据
* @param piles 充电桩列表
* @return 同步结果
*/
SyncResponse syncPiles(List<PileSyncDTO> piles);
}
处理逻辑伪代码:
@Transactional
public SyncResponse syncPiles(List<PileSyncDTO> piles) {
List<SyncResult> results = new ArrayList<>();
// 固定的 station_id
UUID FIXED_STATION_ID = UUID.fromString("88bca8da-cdbf-6587-aecc-75784838c501");
for (PileSyncDTO dto : piles) {
try {
// 1. 查询充电桩是否存在
Pile existingPile = pileRepository.findByPileCode(dto.getPileCode());
if (existingPile != null) {
// 更新
existingPile.setPileName(dto.getPileName());
existingPile.setProtocol(dto.getProtocol());
existingPile.setStationId(FIXED_STATION_ID); // 使用固定值
existingPile.setBrand(dto.getBrand());
existingPile.setModel(dto.getModel());
existingPile.setManufacturer(dto.getManufacturer());
existingPile.setType(dto.getType());
existingPile.setAdditionalInfo(dto.getAdditionalInfo());
existingPile.setUpdatedTime(new Date());
pileRepository.save(existingPile);
results.add(SyncResult.success(dto.getPileCode(), existingPile.getId(), "更新成功"));
} else {
// 创建
Pile newPile = new Pile();
newPile.setId(UUID.randomUUID());
newPile.setPileCode(dto.getPileCode());
newPile.setPileName(dto.getPileName());
newPile.setProtocol(dto.getProtocol());
newPile.setStationId(FIXED_STATION_ID); // 使用固定值
newPile.setBrand(dto.getBrand());
newPile.setModel(dto.getModel());
newPile.setManufacturer(dto.getManufacturer());
newPile.setType(dto.getType());
newPile.setAdditionalInfo(dto.getAdditionalInfo());
newPile.setCreatedTime(new Date());
pileRepository.save(newPile);
results.add(SyncResult.success(dto.getPileCode(), newPile.getId(), "创建成功"));
}
} catch (Exception e) {
results.add(SyncResult.fail(dto.getPileCode(), e.getMessage()));
}
}
return SyncResponse.build(results);
}
测试建议
1. 单元测试
- 测试 station_id 映射查询
- 测试充电桩创建
- 测试充电桩更新
- 测试充电枪创建
- 测试充电枪更新
2. 集成测试
- 测试完整的同步流程
- 测试异常场景(映射不存在、充电桩不存在等)
- 测试并发同步
3. 性能测试
- 测试批量同步性能(100、500、1000 条数据)
- 测试数据库连接池配置
注意事项
-
事务处理
- 每批数据使用一个事务
- 单个充电桩失败不影响其他充电桩
-
错误处理
- 记录详细的错误信息
- 返回明确的错误原因
-
日志记录
- 记录同步开始和结束时间
- 记录成功和失败的数量
- 记录详细的错误日志
-
性能优化
- 使用批量查询减少数据库访问
- 合理设置数据库连接池大小
- 考虑使用缓存优化映射查询
-
安全性
- 添加接口鉴权
- 验证请求数据的合法性
- 防止 SQL 注入
交付物
-
代码
- Controller、Service、Repository、Entity、DTO 等完整代码
- 单元测试代码
-
接口文档
- Swagger / OpenAPI 文档
- 接口调用示例
-
部署说明
- 配置项说明
- 部署步骤
联调准备
完成实现后,请提供:
- 接口地址(如:http://jcpp-server:8080/api/sync)
- 测试账号(如果需要鉴权)
- 测试数据示例
重要提醒:
- 确保 JCPP 数据库中已存在 station_id 为
88bca8da-cdbf-6587-aecc-75784838c501的充电站记录 - 如果不存在,需要先创建该充电站记录
问题反馈
如有任何问题或需要澄清的地方,请及时反馈。