同步充电桩数据

This commit is contained in:
Guoqs
2025-12-31 16:38:27 +08:00
parent ee7a3425d0
commit 193470ffb4
5 changed files with 253 additions and 43 deletions

View File

@@ -2,11 +2,13 @@ package com.jsowell.pile.jcpp.service.impl;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;
import com.jsowell.common.util.StringUtils;
import com.jsowell.pile.domain.JcppSyncRecord;
import com.jsowell.pile.domain.PileBasicInfo;
import com.jsowell.pile.domain.PileConnectorInfo;
import com.jsowell.pile.jcpp.dto.sync.*;
import com.jsowell.pile.jcpp.service.IJcppAuthService;
import com.jsowell.pile.jcpp.service.IJcppPileSyncService;
import com.jsowell.pile.mapper.JcppSyncRecordMapper;
import com.jsowell.pile.service.PileBasicInfoService;
@@ -40,10 +42,13 @@ public class JcppPileSyncServiceImpl implements IJcppPileSyncService {
@Autowired
private JcppSyncRecordMapper jcppSyncRecordMapper;
@Autowired
private IJcppAuthService jcppAuthService;
@Autowired
private RestTemplate restTemplate;
@Value("${jcpp.sync.api-url:http://localhost:8080/api/sync}")
@Value("${jcpp.sync.api-url:http://localhost:8180/api/sync}")
private String jcppApiUrl;
@Value("${jcpp.sync.batch-size:100}")
@@ -196,7 +201,7 @@ public class JcppPileSyncServiceImpl implements IJcppPileSyncService {
List<PileConnectorInfo> gunList = pileConnectorInfoService.selectPileConnectorInfoList(queryGun);
// 3. 转换数据格式
List<JcppPileSyncDTO> pileDTOs = convertPilesToDTO(List.of(pile));
List<JcppPileSyncDTO> pileDTOs = convertPilesToDTO(Lists.newArrayList(pile));
List<JcppGunSyncDTO> gunDTOs = convertGunsToDTO(gunList);
// 4. 调用 JCPP 同步接口
@@ -227,9 +232,9 @@ public class JcppPileSyncServiceImpl implements IJcppPileSyncService {
dto.setProtocol(pile.getSoftwareProtocol());
// 品牌、型号、制造商(可为空)
dto.setBrand(null); // Web 项目中没有这些字段
dto.setBrand("jsowell"); // Web 项目中没有这些字段
dto.setModel(null);
dto.setManufacturer(null);
dto.setManufacturer("jsowell");
// 类型映射1-运营桩 → OPERATION, 2-个人桩 → PERSONAL
String type = "OPERATION"; // 默认运营桩
@@ -244,11 +249,11 @@ public class JcppPileSyncServiceImpl implements IJcppPileSyncService {
additionalInfo.put("webStationId", pile.getStationId());
additionalInfo.put("businessType", pile.getBusinessType());
additionalInfo.put("secretKey", pile.getSecretKey());
additionalInfo.put("longitude", pile.getLongitude());
additionalInfo.put("latitude", pile.getLatitude());
additionalInfo.put("iccid", pile.getIccid());
// additionalInfo.put("longitude", pile.getLongitude());
// additionalInfo.put("latitude", pile.getLatitude());
additionalInfo.put("iccid", pile.getIccId());
additionalInfo.put("merchantId", pile.getMerchantId());
additionalInfo.put("vinFlag", pile.getVinFlag());
// additionalInfo.put("vinFlag", pile.get());
dto.setAdditionalInfo(additionalInfo);
@@ -333,17 +338,30 @@ public class JcppPileSyncServiceImpl implements IJcppPileSyncService {
private List<JcppSyncResult> syncPilesToJcpp(List<JcppPileSyncDTO> pileDTOs) {
String url = jcppApiUrl + "/piles";
// 构建请求体
JSONObject requestBody = new JSONObject();
requestBody.put("piles", pileDTOs);
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(requestBody.toJSONString(), headers);
try {
// 获取访问令牌
String token = jcppAuthService.getAccessToken();
if (token == null || token.isEmpty()) {
log.error("无法获取 JCPP 访问令牌");
// 返回失败结果
List<JcppSyncResult> results = new ArrayList<>();
for (JcppPileSyncDTO dto : pileDTOs) {
results.add(JcppSyncResult.fail(dto.getPileCode(), "无法获取访问令牌"));
}
return results;
}
// 构建请求体
JSONObject requestBody = new JSONObject();
requestBody.put("piles", pileDTOs);
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + token);
HttpEntity<String> entity = new HttpEntity<>(requestBody.toJSONString(), headers);
// 发送请求
ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
@@ -352,6 +370,12 @@ public class JcppPileSyncServiceImpl implements IJcppPileSyncService {
JSONObject responseBody = JSON.parseObject(response.getBody());
List<JcppSyncResult> results = responseBody.getList("results", JcppSyncResult.class);
return results != null ? results : new ArrayList<>();
} else if (response.getStatusCode() == HttpStatus.UNAUTHORIZED) {
// token 过期,清除缓存并重试一次
log.warn("JCPP 访问令牌已过期,清除缓存并重试");
jcppAuthService.clearToken();
// 递归调用重试(只重试一次)
return retrySyncPilesToJcpp(pileDTOs);
} else {
log.error("JCPP 充电桩同步接口返回错误: {}", response.getStatusCode());
// 返回失败结果
@@ -372,23 +396,158 @@ public class JcppPileSyncServiceImpl implements IJcppPileSyncService {
}
}
/**
* 重试同步充电桩token 过期时使用)
*/
private List<JcppSyncResult> retrySyncPilesToJcpp(List<JcppPileSyncDTO> pileDTOs) {
String url = jcppApiUrl + "/piles";
try {
// 重新获取访问令牌
String token = jcppAuthService.getAccessToken();
if (token == null || token.isEmpty()) {
log.error("重试时仍无法获取 JCPP 访问令牌");
// 返回失败结果
List<JcppSyncResult> results = new ArrayList<>();
for (JcppPileSyncDTO dto : pileDTOs) {
results.add(JcppSyncResult.fail(dto.getPileCode(), "无法获取访问令牌"));
}
return results;
}
// 构建请求体
JSONObject requestBody = new JSONObject();
requestBody.put("piles", pileDTOs);
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + token);
HttpEntity<String> entity = new HttpEntity<>(requestBody.toJSONString(), headers);
// 发送请求
ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
if (response.getStatusCode() == HttpStatus.OK) {
// 解析响应
JSONObject responseBody = JSON.parseObject(response.getBody());
List<JcppSyncResult> results = responseBody.getList("results", JcppSyncResult.class);
return results != null ? results : new ArrayList<>();
} else {
log.error("JCPP 充电桩同步接口返回错误: {}", response.getStatusCode());
// 返回失败结果
List<JcppSyncResult> results = new ArrayList<>();
for (JcppPileSyncDTO dto : pileDTOs) {
results.add(JcppSyncResult.fail(dto.getPileCode(), "接口返回错误: " + response.getStatusCode()));
}
return results;
}
} catch (Exception e) {
log.error("重试调用 JCPP 充电桩同步接口异常", e);
// 返回失败结果
List<JcppSyncResult> results = new ArrayList<>();
for (JcppPileSyncDTO dto : pileDTOs) {
results.add(JcppSyncResult.fail(dto.getPileCode(), "接口调用异常: " + e.getMessage()));
}
return results;
}
}
/**
* 同步充电枪到 JCPP
*/
private List<JcppSyncResult> syncGunsToJcpp(List<JcppGunSyncDTO> gunDTOs) {
String url = jcppApiUrl + "/guns";
// 构建请求体
JSONObject requestBody = new JSONObject();
requestBody.put("guns", gunDTOs);
try {
// 获取访问令牌
String token = jcppAuthService.getAccessToken();
if (token == null || token.isEmpty()) {
log.error("无法获取 JCPP 访问令牌");
// 返回失败结果
List<JcppSyncResult> results = new ArrayList<>();
for (JcppGunSyncDTO dto : gunDTOs) {
results.add(JcppSyncResult.fail(dto.getGunCode(), "无法获取访问令牌"));
}
return results;
}
// 设置请求
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 构建请求
JSONObject requestBody = new JSONObject();
requestBody.put("guns", gunDTOs);
HttpEntity<String> entity = new HttpEntity<>(requestBody.toJSONString(), headers);
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + token);
HttpEntity<String> entity = new HttpEntity<>(requestBody.toJSONString(), headers);
// 发送请求
ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
if (response.getStatusCode() == HttpStatus.OK) {
// 解析响应
JSONObject responseBody = JSON.parseObject(response.getBody());
List<JcppSyncResult> results = responseBody.getList("results", JcppSyncResult.class);
return results != null ? results : new ArrayList<>();
} else if (response.getStatusCode() == HttpStatus.UNAUTHORIZED) {
// token 过期,清除缓存并重试一次
log.warn("JCPP 访问令牌已过期,清除缓存并重试");
jcppAuthService.clearToken();
// 递归调用重试(只重试一次)
return retrySyncGunsToJcpp(gunDTOs);
} else {
log.error("JCPP 充电枪同步接口返回错误: {}", response.getStatusCode());
// 返回失败结果
List<JcppSyncResult> results = new ArrayList<>();
for (JcppGunSyncDTO dto : gunDTOs) {
results.add(JcppSyncResult.fail(dto.getGunCode(), "接口返回错误: " + response.getStatusCode()));
}
return results;
}
} catch (Exception e) {
log.error("调用 JCPP 充电枪同步接口异常", e);
// 返回失败结果
List<JcppSyncResult> results = new ArrayList<>();
for (JcppGunSyncDTO dto : gunDTOs) {
results.add(JcppSyncResult.fail(dto.getGunCode(), "接口调用异常: " + e.getMessage()));
}
return results;
}
}
/**
* 重试同步充电枪token 过期时使用)
*/
private List<JcppSyncResult> retrySyncGunsToJcpp(List<JcppGunSyncDTO> gunDTOs) {
String url = jcppApiUrl + "/guns";
try {
// 重新获取访问令牌
String token = jcppAuthService.getAccessToken();
if (token == null || token.isEmpty()) {
log.error("重试时仍无法获取 JCPP 访问令牌");
// 返回失败结果
List<JcppSyncResult> results = new ArrayList<>();
for (JcppGunSyncDTO dto : gunDTOs) {
results.add(JcppSyncResult.fail(dto.getGunCode(), "无法获取访问令牌"));
}
return results;
}
// 构建请求体
JSONObject requestBody = new JSONObject();
requestBody.put("guns", gunDTOs);
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + token);
HttpEntity<String> entity = new HttpEntity<>(requestBody.toJSONString(), headers);
// 发送请求
ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
@@ -407,7 +566,7 @@ public class JcppPileSyncServiceImpl implements IJcppPileSyncService {
return results;
}
} catch (Exception e) {
log.error("调用 JCPP 充电枪同步接口异常", e);
log.error("重试调用 JCPP 充电枪同步接口异常", e);
// 返回失败结果
List<JcppSyncResult> results = new ArrayList<>();
for (JcppGunSyncDTO dto : gunDTOs) {

View File

@@ -1,6 +1,7 @@
package com.jsowell.pile.mapper;
import com.jsowell.pile.domain.JcppSyncRecord;
import org.springframework.stereotype.Repository;
import java.util.List;
@@ -9,6 +10,7 @@ import java.util.List;
*
* @author jsowell
*/
@Repository
public interface JcppSyncRecordMapper {
/**