Procházet zdrojové kódy

feat(charging): 新增设备接口状态查询功能

- 新增查询设备认证接口,路径为 /queryEquipAuth
- 新增查询充电站接口状态功能,支持传入充电站 ID 列表- 新增相关 VO 和实体类:QueryStationStatusVO、StationStatusInfo、ConnectorStatusInfo- 实现 ChargingBusinessService 接口中的 queryStationStatus 方法
- 完成控制器中 queryStationStatus 接口的定义与实现
-优化 TokenManager 中的请求逻辑,使用 OkHttpUtil 替代原工具类
- 增强 Token 请求参数加密及响应数据签名验证逻辑
- 补充详细的日志记录以便于调试和问题追踪
wzq před 1 měsícem
rodič
revize
4cb04d3c2b

+ 17 - 1
src/main/java/com/zsElectric/boot/charging/controller/ChargingBusinessController.java

@@ -3,6 +3,7 @@ package com.zsElectric.boot.charging.controller;
 import com.zsElectric.boot.charging.service.ChargingBusinessService;
 import com.zsElectric.boot.charging.vo.ChargingPricePolicyVO;
 import com.zsElectric.boot.charging.vo.EquipmentAuthResponseVO;
+import com.zsElectric.boot.charging.vo.QueryStationStatusVO;
 import com.zsElectric.boot.charging.vo.QueryStationsInfoVO;
 import com.zsElectric.boot.core.web.Result;
 import io.swagger.v3.oas.annotations.Operation;
@@ -15,6 +16,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.List;
+
 @Tag(name = "充电业务相关接口")
 @RestController
 @RequestMapping("/dev/v1/linkData")
@@ -48,7 +51,7 @@ public class ChargingBusinessController {
      *
      */
     @Operation(summary = "查询业务策略信息")
-    @GetMapping("/queryEquipBusinessPolicy")
+    @GetMapping("/queryEquipAuth")
     public Result<EquipmentAuthResponseVO> queryEquipAuth(String EquipAuthSeq, String ConnectorID){
         return Result.success(chargingBusinessService.queryEquipAuth(EquipAuthSeq, ConnectorID));
     }
@@ -69,4 +72,17 @@ public class ChargingBusinessController {
                                                          @RequestParam(value = "PageSize", defaultValue = "10") @Schema(description = "页大小") Integer PageSize){
         return Result.success(chargingBusinessService.queryStationsInfo(LastQueryTime, PageNo, PageSize));
     }
+
+    /**
+     * <p>设备接口状态查询</p>
+     * @author wzq
+     * @param stationIDs 充电站ID列表
+     * @return 设备接口状态
+     *
+     */
+    @Operation(summary = "设备接口状态查询")
+    @GetMapping("/queryStationStatus")
+     public Result<QueryStationStatusVO> queryStationStatus(List<String> stationIDs){
+        return Result.success(chargingBusinessService.queryStationStatus(stationIDs));
+     }
 }

+ 11 - 0
src/main/java/com/zsElectric/boot/charging/entity/ConnectorStatusInfo.java

@@ -0,0 +1,11 @@
+package com.zsElectric.boot.charging.entity;
+
+import lombok.Data;
+
+@Data
+public class ConnectorStatusInfo {
+
+    private String ConnectorID;
+
+    private Integer Status;
+}

+ 13 - 0
src/main/java/com/zsElectric/boot/charging/entity/StationStatusInfo.java

@@ -0,0 +1,13 @@
+package com.zsElectric.boot.charging.entity;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class StationStatusInfo {
+
+    private String StationID;
+
+    private List<ConnectorStatusInfo> ConnectorStatusInfos;
+}

+ 12 - 0
src/main/java/com/zsElectric/boot/charging/service/ChargingBusinessService.java

@@ -2,8 +2,11 @@ package com.zsElectric.boot.charging.service;
 
 import com.zsElectric.boot.charging.vo.ChargingPricePolicyVO;
 import com.zsElectric.boot.charging.vo.EquipmentAuthResponseVO;
+import com.zsElectric.boot.charging.vo.QueryStationStatusVO;
 import com.zsElectric.boot.charging.vo.QueryStationsInfoVO;
 
+import java.util.List;
+
 public interface ChargingBusinessService {
 
     /**
@@ -36,4 +39,13 @@ public interface ChargingBusinessService {
      *
      */
     QueryStationsInfoVO queryStationsInfo(String LastQueryTime, Integer PageNo, Integer PageSize);
+
+    /**
+     * <p>设备接口状态查询</p>
+     * @author wzq
+     * @param stationIDs 充电站ID列表
+     * @return 充电站状态列表
+     *
+     */
+    QueryStationStatusVO queryStationStatus(List<String> stationIDs);
 }

+ 14 - 0
src/main/java/com/zsElectric/boot/charging/service/impl/ChargingBusinessServiceImpl.java

@@ -6,6 +6,7 @@ import com.google.gson.JsonObject;
 import com.zsElectric.boot.charging.service.ChargingBusinessService;
 import com.zsElectric.boot.charging.vo.ChargingPricePolicyVO;
 import com.zsElectric.boot.charging.vo.EquipmentAuthResponseVO;
+import com.zsElectric.boot.charging.vo.QueryStationStatusVO;
 import com.zsElectric.boot.charging.vo.QueryStationsInfoVO;
 import com.zsElectric.boot.common.constant.ConnectivityConstants;
 import com.zsElectric.boot.common.util.electric.ChargingUtil;
@@ -14,6 +15,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 
@@ -63,4 +65,16 @@ public class ChargingBusinessServiceImpl implements ChargingBusinessService {
         log.info("查询充电站信息返回结果解密后:{}", responseDecode);
         return new Gson().fromJson(responseDecode, QueryStationsInfoVO.class);
     }
+
+    @Override
+    public QueryStationStatusVO queryStationStatus(List<String> stationIDs) {
+        Map<String, Object> queryParms = new HashMap<>();
+        queryParms.put("StationIDs", stationIDs);
+        log.info("设备接口状态查询请求参数:{}", queryParms);
+        JsonObject jsonObject = chargingUtil.chargingRequest(ConnectivityConstants.QUERY_STATION_STATUS, queryParms, true);
+        log.info("设备接口状态查询返回结果:{}", jsonObject);
+        JsonObject responseDecode = chargingUtil.responseDecode(jsonObject);
+        log.info("设备接口状态查询返回结果解密后:{}", responseDecode);
+        return new Gson().fromJson(responseDecode, QueryStationStatusVO.class);
+    }
 }

+ 19 - 0
src/main/java/com/zsElectric/boot/charging/vo/QueryStationStatusVO.java

@@ -0,0 +1,19 @@
+package com.zsElectric.boot.charging.vo;
+
+import com.zsElectric.boot.charging.entity.StationStatusInfo;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class QueryStationStatusVO implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    List<StationStatusInfo> StationStatusInfos;
+
+    private Integer Total;
+}

+ 56 - 13
src/main/java/com/zsElectric/boot/common/util/electric/TokenManager.java

@@ -15,6 +15,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.checkerframework.checker.units.qual.A;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
+
 import java.time.Duration;
 import java.time.LocalDateTime;
 import java.util.Objects;
@@ -30,32 +31,32 @@ import java.util.concurrent.locks.ReentrantLock;
 public class TokenManager {
 
     @Resource
-    private ChargingUtil chargingUtil;
-    
+    private OkHttpUtil okHttpUtil;
+
     private static final String TOKEN_KEY = "api:local:accessToken";
     private static final String TOKEN_REFRESH_LOCK_KEY = "api:token:refresh:lock";
     private static final int DEFAULT_TOKEN_EXPIRE_HOURS = 24;
-    
+
     private final RedisTemplate<String, Object> redisTemplate;
 
     // 本地锁,防止单JVM内重复刷新Token[2](@ref)
     private final ReentrantLock localLock = new ReentrantLock();
-    
+
     /**
      * 获取有效的访问令牌(主入口方法)
      */
     public String getValidAccessToken() {
         // 尝试从Redis获取已存储的Token[1](@ref)
         ApiToken apiToken = getStoredToken();
-        
+
         // 如果Token不存在或已过期,则刷新Token[1,3](@ref)
         if (Objects.isNull(apiToken) || !apiToken.isValid()) {
             apiToken = refreshAccessToken();
         }
-        
+
         return apiToken.getAccessToken();
     }
-    
+
     /**
      * 从Redis获取存储的Token
      */
@@ -157,23 +158,65 @@ public class TokenManager {
                     .setOperatorID(ConnectivityConstants.OPERATOR_ID)
                     .setOperatorSecret(ConnectivityConstants.OPERATOR_SECRET);
 
-            JsonObject response = chargingUtil.chargingRequest(ConnectivityConstants.QUERY_TOKEN, BeanUtil.beanToMap(queryTokenParms), false);
+            RequestParmsEntity requestParms = new RequestParmsEntity();
+            SequenceGenUtil.SequenceResult result = SequenceGenUtil.generate();
+
+            requestParms
+                    .setOperatorID(ConnectivityConstants.OPERATOR_ID)
+                    .setData(AESCryptoUtil.decrypt(queryTokenParms.toString(), ConnectivityConstants.DATA_SECRET, ConnectivityConstants.DATA_SECRET_IV))
+                    .setTimeStamp(result.getTimestamp())
+                    .setSeq(result.getSequence())
+                    .setSig(HmacMD5Util.genSign(requestParms.getOperatorID(), requestParms.getData(), requestParms.getTimeStamp(), requestParms.getSeq(), ConnectivityConstants.SIG_SECRET));
+
+            JsonObject response = okHttpUtil.doPostForm(ConnectivityConstants.QUERY_TOKEN, BeanUtil.beanToMap(requestParms), null);
 
             if (Objects.isNull(response)) {
                 log.error("调用第三方接口获取Token失败");
                 return null;
             }
-            JsonObject decode = chargingUtil.responseDecode(response);
+
+
             Gson gson = new Gson();
-            QueryTokenResponseData responseData = gson.fromJson(decode, QueryTokenResponseData.class);
+            ResponseParmsEntity responseParms = gson.fromJson(response, ResponseParmsEntity.class);
+            String data = responseParms.getRet() + responseParms.getMsg() + responseParms.getData();
+            boolean verify = HmacMD5Util.verify(data, ConnectivityConstants.PLATFORM_SIG_SECRET, responseParms.getSig());
+            if (!verify) {
+                log.error("第三方接口响应数据签名验证失败");
+                return null;
+            }
+            if (responseParms.getRet() != 0) {
+                switch (responseParms.getRet()) {
+                    case -1:
+                        log.error("系统繁忙,此时请求方稍后重试");
+                        break;
+                    case 4001:
+                        log.error("签名错误");
+                        break;
+                    case 4002:
+                        log.error("Token错误");
+                        break;
+                    case 4003:
+                        log.error("参数不合法,缺少必需的示例:OperatorID、Sig、TimeStamp、Data、Seq五个参数");
+                        break;
+                    case 4004:
+                        log.error("请求的业务参数不合法,各接口定义自己的必须参数");
+                        break;
+                    case 500:
+                        log.error("系统错误");
+                        break;
+                }
+            }
+            String decodeData = AESCryptoUtil.decrypt(responseParms.getData(), ConnectivityConstants.PLATFORM_DATA_SECRET,
+                    ConnectivityConstants.PLATFORM_DATA_SECRET_IV);
+            QueryTokenResponseData responseData = gson.fromJson(decodeData, QueryTokenResponseData.class);
 
-            if (responseData.getSuccStat() == 1){
+            if (responseData.getSuccStat() == 1) {
                 //0-无,1-OperatorID无效
                 String failReason = "";
-                if (responseData.getFailReason() == 0){
+                if (responseData.getFailReason() == 0) {
                     failReason = "无";
                 }
-                if(responseData.getFailReason() == 1){
+                if (responseData.getFailReason() == 1) {
                     failReason = "OperatorID无效";
                 }
                 log.error("调用第三方接口获取Token失败,失败原因: {}", failReason);