|
|
@@ -0,0 +1,338 @@
|
|
|
+package com.zsElectric.openapi.business.service.impl;
|
|
|
+
|
|
|
+import com.fasterxml.jackson.databind.JsonNode;
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
+import com.zsElectric.openapi.business.entity.ChargeResponseVO;
|
|
|
+import com.zsElectric.openapi.business.entity.QueryTokenRequestParms;
|
|
|
+import com.zsElectric.openapi.business.entity.QueryTokenResponseData;
|
|
|
+import com.zsElectric.openapi.business.entity.RequestParmsEntity;
|
|
|
+import com.zsElectric.openapi.business.entity.ResponseParmsEntity;
|
|
|
+import com.zsElectric.openapi.business.service.ChargingReceptionService;
|
|
|
+import com.zsElectric.openapi.common.ChargingUtil;
|
|
|
+import com.zsElectric.openapi.common.ConnectivityConstants;
|
|
|
+import com.zsElectric.openapi.common.HmacMD5Util;
|
|
|
+import com.zsElectric.openapi.common.JwtTokenUtil;
|
|
|
+import com.zsElectric.openapi.common.exception.BusinessException;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.function.Consumer;
|
|
|
+
|
|
|
+import static com.zsElectric.openapi.common.ConnectivityConstants.FAIL_REASON_NONE;
|
|
|
+import static com.zsElectric.openapi.common.ConnectivityConstants.STATUS_OK;
|
|
|
+import static com.zsElectric.openapi.common.HmacMD5Util.genSign;
|
|
|
+import static com.zsElectric.openapi.common.HmacMD5Util.verify;
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * 第三方充电推送接收服务实现
|
|
|
+ *
|
|
|
+ * @author system
|
|
|
+ * @since 2025-12-11
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class ChargingReceptionServiceImpl implements ChargingReceptionService {
|
|
|
+
|
|
|
+ private final ChargingUtil chargingUtil;
|
|
|
+ private final ObjectMapper objectMapper;
|
|
|
+ private final JwtTokenUtil jwtTokenUtil;
|
|
|
+ // ==================== 接口实现 ====================
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ResponseParmsEntity chargeResponse(RequestParmsEntity requestDTO) {
|
|
|
+ log.info("接收推送启动充电结果请求参数:{}", requestDTO);
|
|
|
+ return processStartChargeResultRequest(requestDTO);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ResponseParmsEntity chargeStatusResponse(RequestParmsEntity requestDTO) {
|
|
|
+ log.info("接收推送充电状态请求参数:{}", requestDTO);
|
|
|
+ return processChargeStatusRequest(requestDTO);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ResponseParmsEntity stopChargeResponse(RequestParmsEntity requestDTO) {
|
|
|
+ log.info("接收推送停止充电结果请求参数:{}", requestDTO);
|
|
|
+ return processStopChargeResultRequest(requestDTO);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ResponseParmsEntity chargeOrderResponse(RequestParmsEntity requestDTO) throws Exception {
|
|
|
+ log.info("接收推送充电订单信息请求参数:{}", requestDTO);
|
|
|
+ return processChargeRequest(requestDTO, jsonNode -> {
|
|
|
+ log.debug("充电订单信息 - StartChargeSeq: {}", getTextValue(jsonNode, "StartChargeSeq"));
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ResponseParmsEntity stationStatus(RequestParmsEntity requestDTO) {
|
|
|
+ log.info("接收设备状态变化推送请求参数:{}", requestDTO);
|
|
|
+ return processStationStatusRequest(requestDTO);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ResponseParmsEntity getToken(RequestParmsEntity request) throws Exception {
|
|
|
+ log.info("接收获取Token请求参数:{}", request);
|
|
|
+ return processGetTokenRequest(request);
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== 公共处理方法 ====================
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 通用充电请求处理模板
|
|
|
+ */
|
|
|
+ private ResponseParmsEntity processChargeRequest(RequestParmsEntity requestDTO, Consumer<JsonNode> businessHandler) {
|
|
|
+ try {
|
|
|
+ JsonNode jsonNode = verifyAndDecrypt(requestDTO);
|
|
|
+ // 执行业务处理
|
|
|
+ businessHandler.accept(jsonNode);
|
|
|
+
|
|
|
+ // 构建响应
|
|
|
+ return buildChargeResponse(getTextValue(jsonNode, "StartChargeSeq"));
|
|
|
+ } catch (BusinessException e) {
|
|
|
+ throw e;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("处理请求失败:{}", e.getMessage());
|
|
|
+ throw new BusinessException("处理请求失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理启动充电结果推送请求
|
|
|
+ * 数据格式:{"ConnectorID":"xxx","StartChargeSeq":"xxx","StartChargeSeqStat":2,"StartTime":"xxx"}
|
|
|
+ */
|
|
|
+ private ResponseParmsEntity processStartChargeResultRequest(RequestParmsEntity requestDTO) {
|
|
|
+ try {
|
|
|
+ JsonNode jsonNode = verifyAndDecrypt(requestDTO);
|
|
|
+
|
|
|
+ // 启动充电结果业务处理
|
|
|
+ String startChargeSeq = getTextValue(jsonNode, "StartChargeSeq");
|
|
|
+ return buildChargeResponse(startChargeSeq);
|
|
|
+ } catch (BusinessException e) {
|
|
|
+ throw e;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("处理启动充电结果推送失败:{}", e.getMessage(), e);
|
|
|
+ throw new BusinessException("处理启动充电结果推送失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理停止充电结果推送请求
|
|
|
+ * 数据格式:{"ConnectorID":"xxx","FailReason":0,"StartChargeSeq":"xxx","StartChargeSeqStat":4,"SuccStat":0}
|
|
|
+ */
|
|
|
+ private ResponseParmsEntity processStopChargeResultRequest(RequestParmsEntity requestDTO) {
|
|
|
+ try {
|
|
|
+ JsonNode jsonNode = verifyAndDecrypt(requestDTO);
|
|
|
+
|
|
|
+ // 停止充电结果业务处理
|
|
|
+ String startChargeSeq = getTextValue(jsonNode, "StartChargeSeq");
|
|
|
+ Integer startChargeSeqStat = getIntValue(jsonNode, "StartChargeSeqStat");
|
|
|
+ Integer succStat = getIntValue(jsonNode, "SuccStat");
|
|
|
+ Integer failReason = getIntValue(jsonNode, "FailReason");
|
|
|
+
|
|
|
+ log.info("停止充电结果 - StartChargeSeq: {}, Stat: {}, SuccStat: {}, FailReason: {}",
|
|
|
+ startChargeSeq, startChargeSeqStat, succStat, failReason);
|
|
|
+
|
|
|
+
|
|
|
+ // 构建响应
|
|
|
+ return buildChargeResponse(startChargeSeq);
|
|
|
+ } catch (BusinessException e) {
|
|
|
+ throw e;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("处理停止充电结果推送失败:{}", e.getMessage(), e);
|
|
|
+ throw new BusinessException("处理停止充电结果推送失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理实时充电状态推送请求
|
|
|
+ * 数据格式:{"ConnectorID":"xxx","ConnectorStatus":3,"TotalPower":1.95,"ElecMoney":1.89,...}
|
|
|
+ */
|
|
|
+ private ResponseParmsEntity processChargeStatusRequest(RequestParmsEntity requestDTO) {
|
|
|
+ try {
|
|
|
+ JsonNode jsonNode = verifyAndDecrypt(requestDTO);
|
|
|
+
|
|
|
+ // 构建响应
|
|
|
+ return buildChargeResponse(getTextValue(jsonNode, "StartChargeSeq"));
|
|
|
+ } catch (BusinessException e) {
|
|
|
+ throw e;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("处理充电状态推送失败:{}", e.getMessage(), e);
|
|
|
+ throw new BusinessException("处理充电状态推送失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理设备状态变化推送请求
|
|
|
+ */
|
|
|
+ private ResponseParmsEntity processStationStatusRequest(RequestParmsEntity requestDTO) {
|
|
|
+ try {
|
|
|
+ String decryptData = verifyAndDecryptRaw(requestDTO);
|
|
|
+
|
|
|
+ // 构建响应
|
|
|
+ return buildStatusResponse();
|
|
|
+ } catch (BusinessException e) {
|
|
|
+ throw e;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("处理设备状态推送失败:{}", e.getMessage());
|
|
|
+ throw new BusinessException("处理设备状态推送失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理获取Token请求
|
|
|
+ */
|
|
|
+ private ResponseParmsEntity processGetTokenRequest(RequestParmsEntity request) throws Exception {
|
|
|
+ ResponseParmsEntity responseParmsEntity = new ResponseParmsEntity();
|
|
|
+ try {
|
|
|
+ // 验证签名
|
|
|
+ if (!HmacMD5Util.verify(request.getOperatorID() + request.getData() + request.getTimeStamp() + request.getSeq(),
|
|
|
+ ConnectivityConstants.SIG_SECRET, request.getSig())) {
|
|
|
+ responseParmsEntity.setRet(4001);
|
|
|
+ responseParmsEntity.setMsg("签名验证失败");
|
|
|
+ responseParmsEntity.setData("");
|
|
|
+ responseParmsEntity.setSig(HmacMD5Util.genSign(responseParmsEntity.getRet(), responseParmsEntity.getMsg(), responseParmsEntity.getData(),
|
|
|
+ ConnectivityConstants.SIG_SECRET));
|
|
|
+ return responseParmsEntity;
|
|
|
+ }
|
|
|
+
|
|
|
+ String data = request.getData();
|
|
|
+ String string = chargingUtil.decryptData(data);
|
|
|
+ QueryTokenRequestParms queryTokenRequestParms = objectMapper.readValue(string, QueryTokenRequestParms.class);
|
|
|
+ if (queryTokenRequestParms == null || queryTokenRequestParms.getOperatorID() == null || queryTokenRequestParms.getOperatorSecret() == null) {
|
|
|
+
|
|
|
+ responseParmsEntity.setRet(4003);
|
|
|
+ responseParmsEntity.setMsg("参数错误");
|
|
|
+ responseParmsEntity.setData("");
|
|
|
+ responseParmsEntity.setSig(HmacMD5Util.genSign(responseParmsEntity.getRet(), responseParmsEntity.getMsg(), responseParmsEntity.getData(),
|
|
|
+ ConnectivityConstants.SIG_SECRET));
|
|
|
+ return responseParmsEntity;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 判断运营商ID与密钥是否正确
|
|
|
+ if (!queryTokenRequestParms.getOperatorID().equals(ConnectivityConstants.PLATFORM_OPERATOR_ID) && !queryTokenRequestParms.getOperatorSecret().equals(ConnectivityConstants.PLATFORM_OPERATOR_SECRET)) {
|
|
|
+ responseParmsEntity.setRet(4004);
|
|
|
+ responseParmsEntity.setMsg("OperatorID或OperatorSecret错误!");
|
|
|
+ responseParmsEntity.setData("");
|
|
|
+ responseParmsEntity.setSig(HmacMD5Util.genSign(responseParmsEntity.getRet(), responseParmsEntity.getMsg(), responseParmsEntity.getData(),
|
|
|
+ ConnectivityConstants.SIG_SECRET));
|
|
|
+ return responseParmsEntity;
|
|
|
+ }
|
|
|
+
|
|
|
+ // redis获取token,不存在则创建
|
|
|
+ String accessToken = jwtTokenUtil.generateToken(queryTokenRequestParms.getOperatorID());
|
|
|
+ Integer remainingTTL = jwtTokenUtil.getRemainingTTL(accessToken).intValue();
|
|
|
+ // 构建Data(token信息)
|
|
|
+ QueryTokenResponseData queryTokenResponseData = new QueryTokenResponseData();
|
|
|
+ queryTokenResponseData.setOperatorID(queryTokenRequestParms.getOperatorID());
|
|
|
+ queryTokenResponseData.setAccessToken(accessToken);
|
|
|
+ queryTokenResponseData.setTokenAvailableTime(remainingTTL);
|
|
|
+ queryTokenResponseData.setSuccStat(0);
|
|
|
+ queryTokenResponseData.setFailReason(0);
|
|
|
+
|
|
|
+ log.info("生成token信息:{}", objectMapper.writeValueAsString(queryTokenResponseData));
|
|
|
+
|
|
|
+ String encodeData = chargingUtil.encryptData(objectMapper.writeValueAsString(queryTokenResponseData));
|
|
|
+
|
|
|
+ responseParmsEntity.setRet(0);
|
|
|
+ responseParmsEntity.setMsg("成功");
|
|
|
+ responseParmsEntity.setData(encodeData);
|
|
|
+ responseParmsEntity.setSig(HmacMD5Util.genSign(responseParmsEntity.getRet(), responseParmsEntity.getMsg(), responseParmsEntity.getData(),
|
|
|
+ ConnectivityConstants.SIG_SECRET));
|
|
|
+ return responseParmsEntity;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("系统错误:{}", e.getMessage());
|
|
|
+ responseParmsEntity.setRet(500);
|
|
|
+ responseParmsEntity.setMsg("系统错误");
|
|
|
+ responseParmsEntity.setData("");
|
|
|
+ responseParmsEntity.setSig(HmacMD5Util.genSign(responseParmsEntity.getRet(), responseParmsEntity.getMsg(), responseParmsEntity.getData(),
|
|
|
+ ConnectivityConstants.SIG_SECRET));
|
|
|
+ return responseParmsEntity;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 验签并解密请求数据
|
|
|
+ */
|
|
|
+ private JsonNode verifyAndDecrypt(RequestParmsEntity requestDTO) throws Exception {
|
|
|
+ String decryptData = verifyAndDecryptRaw(requestDTO);
|
|
|
+ return objectMapper.readTree(decryptData);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 验签并解密请求数据(返回原始字符串)
|
|
|
+ */
|
|
|
+ private String verifyAndDecryptRaw(RequestParmsEntity requestDTO) throws Exception {
|
|
|
+ String signData = requestDTO.getOperatorID() + requestDTO.getData() + requestDTO.getTimeStamp() + requestDTO.getSeq();
|
|
|
+ if (!verify(signData, ConnectivityConstants.SIG_SECRET, requestDTO.getSig())) {
|
|
|
+ log.error("数据验签失败");
|
|
|
+ throw new BusinessException("数据验签失败");
|
|
|
+ }
|
|
|
+ String decryptData = chargingUtil.decryptData(requestDTO.getData());
|
|
|
+ log.info("==================== 解密数据开始 ====================");
|
|
|
+ log.info("操作员ID: {}", requestDTO.getOperatorID());
|
|
|
+ log.info("解密后的数据:{}", decryptData);
|
|
|
+ log.info("==================== 解密数据结束 ====================");
|
|
|
+ return decryptData;
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== 响应构建 ====================
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建充电响应
|
|
|
+ */
|
|
|
+ private ResponseParmsEntity buildChargeResponse(String startChargeSeq) throws Exception {
|
|
|
+ ChargeResponseVO chargeResponseVO = new ChargeResponseVO();
|
|
|
+ chargeResponseVO.setStartChargeSeq(startChargeSeq);
|
|
|
+ chargeResponseVO.setSuccStat(STATUS_OK);
|
|
|
+ chargeResponseVO.setFailReason(FAIL_REASON_NONE);
|
|
|
+
|
|
|
+ String encryptData = chargingUtil.encryptData(objectMapper.writeValueAsString(chargeResponseVO));
|
|
|
+ String sign = genSign(STATUS_OK, "请求成功", encryptData, ConnectivityConstants.SIG_SECRET);
|
|
|
+
|
|
|
+ ResponseParmsEntity response = new ResponseParmsEntity();
|
|
|
+ response.setRet(STATUS_OK);
|
|
|
+ response.setMsg("请求成功");
|
|
|
+ response.setData(encryptData);
|
|
|
+ response.setSig(sign);
|
|
|
+ return response;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建设备状态响应
|
|
|
+ */
|
|
|
+ private ResponseParmsEntity buildStatusResponse() throws Exception {
|
|
|
+ Map<String, Integer> statusMap = new HashMap<>();
|
|
|
+ statusMap.put("Status", 0);
|
|
|
+
|
|
|
+ String encryptData = chargingUtil.encryptData(objectMapper.writeValueAsString(statusMap));
|
|
|
+ String sign = genSign(STATUS_OK, "", encryptData, ConnectivityConstants.SIG_SECRET);
|
|
|
+
|
|
|
+ ResponseParmsEntity response = new ResponseParmsEntity();
|
|
|
+ response.setRet(STATUS_OK);
|
|
|
+ response.setMsg("");
|
|
|
+ response.setData(encryptData);
|
|
|
+ response.setSig(sign);
|
|
|
+ return response;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // ==================== JSON解析工具方法 ====================
|
|
|
+
|
|
|
+ private String getTextValue(JsonNode node, String fieldName) {
|
|
|
+ JsonNode field = node.get(fieldName);
|
|
|
+ return (field != null && !field.isNull()) ? field.asText() : null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Integer getIntValue(JsonNode node, String fieldName) {
|
|
|
+ JsonNode field = node.get(fieldName);
|
|
|
+ return (field != null && !field.isNull()) ? field.asInt() : null;
|
|
|
+ }
|
|
|
+}
|