Files
jsowell-charger-web/doc/JCPP项目配合实现Prompt.md
2025-12-30 15:59:34 +08:00

10 KiB
Raw Blame History

JCPP 项目充电桩数据同步接口实现 Prompt

请将以下内容复制给 JCPP 项目的 Claude Code 执行


任务概述

需要在 JCPP 项目中实现充电桩数据同步接口,用于接收来自 Web 项目的充电桩和充电枪数据。

背景说明

Web 项目MySQL中维护了充电桩的主数据现在需要将这些数据同步到 JCPP 项目PostgreSQL用于登录鉴权等操作。

数据流向

Web 项目 (MySQL) → HTTP API → JCPP 项目 (PostgreSQL)

关键差异

  1. 主键类型Web 使用 intJCPP 使用 uuid
  2. station_id 类型Web 是 intJCPP 是 uuid需要映射
  3. 字段名称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 格式),包含:
    • webPileIdWeb 项目的充电桩 ID
    • webStationIdWeb 项目的充电站 ID原始 int 值)
    • 其他 Web 项目的字段

响应格式

{
  "success": true,
  "message": "同步成功",
  "results": [
    {
      "pileCode": "20231212000010",
      "pileId": "550e8400-e29b-41d4-a716-446655440000",
      "success": true,
      "message": "创建成功"
    }
  ]
}

处理逻辑

  1. 遍历 piles 数组
  2. 对于每个充电桩:
    • 根据 pileCode 查询 t_pile 表,判断是否已存在
    • station_id 统一使用固定值88bca8da-cdbf-6587-aecc-75784838c501
    • 如果充电桩已存在,执行 UPDATE 操作
    • 如果充电桩不存在,执行 INSERT 操作(生成新的 uuid
    • additionalInfo 存储为 jsonb 类型
  3. 返回每个充电桩的处理结果

注意事项

  • 使用事务保证数据一致性
  • 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": "创建成功"
    }
  ]
}

处理逻辑

  1. 遍历 guns 数组
  2. 对于每个充电枪:
    • 根据 gunCode 查询 t_gun 表,判断是否已存在
    • 根据 pileCode 查询 t_pile 表,获取 pile_id (uuid)
    • 如果充电桩不存在,记录错误并跳过该充电枪
    • station_id 统一使用固定值88bca8da-cdbf-6587-aecc-75784838c501
    • 如果充电枪已存在,执行 UPDATE 操作
    • 如果充电枪不存在,执行 INSERT 操作(生成新的 uuid
  3. 返回每个充电枪的处理结果

注意事项

  • 充电桩必须先于充电枪同步
  • gun_code 必须唯一(已有唯一索引)
  • (pile_id, gun_no) 组合必须唯一(已有唯一索引)
  • 所有充电枪的 station_id 都使用固定值 88bca8da-cdbf-6587-aecc-75784838c501

实现建议

技术栈

  • 框架Spring Boot
  • 数据库PostgreSQL 17
  • ORMJPA / 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 条数据)
  • 测试数据库连接池配置

注意事项

  1. 事务处理

    • 每批数据使用一个事务
    • 单个充电桩失败不影响其他充电桩
  2. 错误处理

    • 记录详细的错误信息
    • 返回明确的错误原因
  3. 日志记录

    • 记录同步开始和结束时间
    • 记录成功和失败的数量
    • 记录详细的错误日志
  4. 性能优化

    • 使用批量查询减少数据库访问
    • 合理设置数据库连接池大小
    • 考虑使用缓存优化映射查询
  5. 安全性

    • 添加接口鉴权
    • 验证请求数据的合法性
    • 防止 SQL 注入

交付物

  1. 代码

    • Controller、Service、Repository、Entity、DTO 等完整代码
    • 单元测试代码
  2. 接口文档

    • Swagger / OpenAPI 文档
    • 接口调用示例
  3. 部署说明

    • 配置项说明
    • 部署步骤

联调准备

完成实现后,请提供:

  1. 接口地址(如:http://jcpp-server:8080/api/sync
  2. 测试账号(如果需要鉴权)
  3. 测试数据示例

重要提醒

  • 确保 JCPP 数据库中已存在 station_id 为 88bca8da-cdbf-6587-aecc-75784838c501 的充电站记录
  • 如果不存在,需要先创建该充电站记录

问题反馈

如有任何问题或需要澄清的地方,请及时反馈。