Browse Source

feat(charging): 实现充电业务互联互通接口对接

- 删除废弃的充电订单状态详情VO类
- 重命名停止充电响应VO为通用充电响应VO
- 修改充电业务控制器请求路径从/dev/v1/linkData到/dev/v1/business
- 新增充电接收服务接口及实现类用于处理平台推送数据
- 新增充电状态响应VO和启动充电响应VO
- 扩展充电工具类支持数据加解密功能
- 新增互联互通响应状态常量定义
- 修复电桩工具类中加密秘钥和签名秘钥使用错误的问题
- 新增HMAC签名生成工具方法支持出参签名
- 新建联动数据控制器处理平台推送的启动充电结果通知
SheepHy 3 weeks ago
parent
commit
c1de90c2cc

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

@@ -21,7 +21,7 @@ import java.util.List;
 @RestController
 @RequiredArgsConstructor
 @Tag(name = "充电业务相关接口")
-@RequestMapping("/dev/v1/linkData")
+@RequestMapping("/dev/v1/business")
 public class ChargingBusinessController {
 
     private final ChargingBusinessService chargingBusinessService;

+ 37 - 0
src/main/java/com/zsElectric/boot/charging/controller/LinkDataController.java

@@ -0,0 +1,37 @@
+package com.zsElectric.boot.charging.controller;
+
+import com.zsElectric.boot.charging.service.ChargingReceptionService;
+import com.zsElectric.boot.common.util.electric.RequestParmsEntity;
+import com.zsElectric.boot.common.util.electric.ResponseParmsEntity;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@Slf4j
+@RestController
+@RequiredArgsConstructor
+@Tag(name = "充电业务相关接口")
+@RequestMapping("/dev/v1/linkData")
+public class LinkDataController {
+
+    private final ChargingReceptionService chargingReceptionService;
+
+    /**
+     * <p>2.4 推送启动充电结果</p>
+     * @author SheepHy
+     * @param requestDTO,参数为类则包含{@link RequestParmsEntity}
+     * @return 停推送启动充电结果VO
+     */
+    @Operation(summary = "推送启动充电结果")
+    @GetMapping("/notification_start_charge_result")
+    public ResponseParmsEntity chargeResponse(@RequestBody RequestParmsEntity requestDTO){
+        return chargingReceptionService.chargeResponse(requestDTO);
+    }
+
+
+}

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

@@ -1,9 +1,6 @@
 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 com.zsElectric.boot.charging.vo.*;
 
 import java.util.List;
 
@@ -48,4 +45,15 @@ public interface ChargingBusinessService {
      *
      */
     QueryStationStatusVO queryStationStatus(List<String> stationIDs) throws Exception;
+
+//    /**
+//     * <p>请求启动充电</p>
+//     * @author SheepHy
+//     * @param requestDTO,参数为类则包含{@link StartChargingRequestDTO}
+//     * @return 返回值描述,如无返回值则为void 返回值为类则包含{@link StartChargingResponseVO}
+//     */
+//    StartChargingResponseVO startCharging(StartChargingRequestDTO requestDTO) throws Exception;
+
+
+
 }

+ 34 - 0
src/main/java/com/zsElectric/boot/charging/service/ChargingReceptionService.java

@@ -0,0 +1,34 @@
+package com.zsElectric.boot.charging.service;
+
+
+import com.zsElectric.boot.common.util.electric.RequestParmsEntity;
+import com.zsElectric.boot.common.util.electric.ResponseParmsEntity;
+
+/**
+ * 接收互联互通(平台)推送数据接口
+ * */
+public interface ChargingReceptionService {
+
+    /**
+     * <p>2.4 推送启动充电结果</p>
+     * @author SheepHy
+     * @param requestDTO,参数为类则包含{@link RequestParmsEntity}
+     * @return 停推送启动充电结果VO
+     */
+    ResponseParmsEntity chargeResponse(RequestParmsEntity requestDTO);
+
+    /**
+     * 2.6 推送充电状态
+     * */
+    ResponseParmsEntity chargeStatusResponse(RequestParmsEntity requestDTO);
+
+    /**
+     * 2.8 推送停止充电结果
+     * */
+    ResponseParmsEntity stopChargeResponse(RequestParmsEntity requestDTO);
+
+    /**
+     * 2.9 推送充电订单信息
+     * */
+    ResponseParmsEntity chargeOrderResponse(RequestParmsEntity requestDTO);
+}

+ 77 - 0
src/main/java/com/zsElectric/boot/charging/service/impl/ChargingReceptionServiceImpl.java

@@ -0,0 +1,77 @@
+package com.zsElectric.boot.charging.service.impl;
+
+import com.google.gson.Gson;
+import com.zsElectric.boot.charging.service.ChargingReceptionService;
+import com.zsElectric.boot.charging.vo.ChargeResponseVO;
+import com.zsElectric.boot.charging.vo.ChargingStatusResponseVO;
+import com.zsElectric.boot.common.constant.ConnectivityConstants;
+import com.zsElectric.boot.common.util.AESCryptoUtils;
+import com.zsElectric.boot.common.util.electric.ChargingUtil;
+import com.zsElectric.boot.common.util.electric.RequestParmsEntity;
+import com.zsElectric.boot.common.util.electric.ResponseParmsEntity;
+import com.zsElectric.boot.core.exception.BusinessException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import static com.zsElectric.boot.common.constant.ConnectivityConstants.FAIL_REASON_NONE;
+import static com.zsElectric.boot.common.constant.ConnectivityConstants.STATUS_OK;
+import static com.zsElectric.boot.common.util.HmacMD5Util.genSign;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class ChargingReceptionServiceImpl implements ChargingReceptionService {
+
+    private final ChargingUtil chargingUtil;
+
+    @Override
+    public ResponseParmsEntity chargeResponse(RequestParmsEntity requestDTO) {
+        log.info("接收推送启动充电结果请求参数:{}", requestDTO);
+        ChargingStatusResponseVO chargingStatusResponseVO;
+        // 响应参数 答复处理
+        ChargeResponseVO chargeResponseVO = new ChargeResponseVO();
+        String encryptData;
+        String genSign;
+        try {
+            String decryptData = chargingUtil.decryptData(requestDTO.getData());
+            log.info("解密后的数据:{}", decryptData);
+            chargingStatusResponseVO = new Gson().fromJson(decryptData, ChargingStatusResponseVO.class);
+            //todo 业务代码待处理
+
+
+            chargeResponseVO.setStartChargeSeq(chargingStatusResponseVO.getStartChargeSeq());
+            chargeResponseVO.setSuccStat(STATUS_OK);
+            chargeResponseVO.setFailReason(FAIL_REASON_NONE);
+            encryptData = chargingUtil.encryptData(new Gson().toJson(chargeResponseVO));
+            genSign = genSign(STATUS_OK, "请求成功", encryptData, ConnectivityConstants.SIG_SECRET);
+        }catch (Exception e){
+            log.error("数据解密失败:{}", e.getMessage());
+            throw new BusinessException("数据解密失败:" + e.getMessage(), e);
+        }
+        return new ResponseParmsEntity()
+                .setRet(STATUS_OK)
+                .setMsg("请求成功")
+                .setData(encryptData)
+                .setSig(genSign);
+    }
+
+    @Override
+    public ResponseParmsEntity chargeStatusResponse(RequestParmsEntity requestDTO) {
+        log.info("接收推送充电状态请求参数:{}", requestDTO);
+        return null;
+    }
+
+    @Override
+    public ResponseParmsEntity stopChargeResponse(RequestParmsEntity requestDTO) {
+        log.info("接收推送停止充电结果请求参数:{}", requestDTO);
+        return null;
+    }
+
+    @Override
+    public ResponseParmsEntity chargeOrderResponse(RequestParmsEntity requestDTO) {
+        log.info("接收推送充电订单信息请求参数:{}", requestDTO);
+        return null;
+    }
+
+}

+ 0 - 104
src/main/java/com/zsElectric/boot/charging/vo/ChargeOrderDetailVO.java

@@ -1,104 +0,0 @@
-package com.zsElectric.boot.charging.vo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.experimental.Accessors;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-@Data
-@Accessors(chain = true)
-@Schema(description = "充电订单状态详情响应VO")
-public class ChargeOrderDetailVO {
-
-    @Schema(description = "订单状态(1-启动中,2-启动成功,3-启动失败,4-结束)",
-            example = "2")
-    private Integer StartChargeSeqStat;
-
-    @Schema(description = "充电订单号(格式:运营商ID+唯一编号)",
-            example = "123456789201712121131011234")
-    private String StartChargeSeq;
-
-    @Schema(description = "充电设备接口编码",
-            example = "3702120244401_1")
-    private String ConnectorID;
-
-    @Schema(description = "设备接口状态(0-离网,1-空闲,2-占用(未充电),3-占用(充电中),4-占用(预约锁定),255-故障)",
-            example = "3")
-    private Integer ConnectorStatus;
-
-    @Schema(description = "A相电流", example = "78.1")
-    private BigDecimal CurrentA;
-
-    @Schema(description = "B相电流", example = "0.0")
-    private BigDecimal CurrentB;
-
-    @Schema(description = "C相电流", example = "0.0")
-    private BigDecimal CurrentC;
-
-    @Schema(description = "A相电压", example = "575.3")
-    private BigDecimal VoltageA;
-
-    @Schema(description = "B相电压", example = "0.0")
-    private BigDecimal VoltageB;
-
-    @Schema(description = "C相电压", example = "0.0")
-    private BigDecimal VoltageC;
-
-    @Schema(description = "电池SOC(剩余电量百分比)", example = "5.0")
-    private BigDecimal Soc;
-
-    @Schema(description = "充电开始时间", example = "2018-02-06 16:54:38")
-    private String StartTime;
-
-    @Schema(description = "充电结束时间", example = "2018-02-06 17:25:00")
-    private String EndTime;
-
-    @Schema(description = "累计充电电量(单位:kWh)", example = "3.5438")
-    private BigDecimal TotalPower;
-
-    @Schema(description = "电费(单位:元)", example = "4.956")
-    private BigDecimal ElecMoney;
-
-    @Schema(description = "服务费(单位:元)", example = "0.0")
-    private BigDecimal ServiceMoney;
-
-    @Schema(description = "总金额(单位:元)", example = "4.956")
-    private BigDecimal TotalMoney;
-
-    @Schema(description = "总时段数", example = "1")
-    private Integer SumPeriod;
-
-    @Schema(description = "充电明细列表")
-    private List<ChargeDetail> ChargeDetails;
-
-    @Data
-    @Accessors(chain = true)
-    @Schema(description = "充电明细信息")
-    public static class ChargeDetail {
-
-        @Schema(description = "开始时间(yyyy-MM-dd HH:mm:ss格式)",
-                example = "2018-02-06 16:54:38")
-        private String DetailStartTime;
-
-        @Schema(description = "结束时间(yyyy-MM-dd HH:mm:ss格式)",
-                example = "2018-02-06 17:25:00")
-        private String DetailEndTime;
-
-        @Schema(description = "时段电价(小数点后2位)", example = "0.70")
-        private BigDecimal ElecPrice;
-
-        @Schema(description = "时段服务费价格(小数点后2位)", example = "0.30")
-        private BigDecimal ServicePrice;
-
-        @Schema(description = "时段充电量(单位:度,小数点后2位)", example = "3.54")
-        private BigDecimal DetailPower;
-
-        @Schema(description = "时段电费(小数点后2位)", example = "2.48")
-        private BigDecimal DetailElecMoney;
-
-        @Schema(description = "时段服务费(小数点后2位)", example = "1.06")
-        private BigDecimal DetailServiceMoney;
-    }
-}

+ 2 - 2
src/main/java/com/zsElectric/boot/charging/vo/StopChargeResponseVO.java → src/main/java/com/zsElectric/boot/charging/vo/ChargeResponseVO.java

@@ -7,8 +7,8 @@ import lombok.experimental.Accessors;
 
 @Data
 @Accessors(chain = true)
-@Schema(description = "充电订单停止响应VO")
-public class StopChargeResponseVO {
+@Schema(description = "响应VO")
+public class ChargeResponseVO {
 
     @Schema(description = "充电订单号(格式:运营商ID+唯一编号)",
             example = "123456789201805141125123456")

+ 40 - 0
src/main/java/com/zsElectric/boot/charging/vo/ChargingStatusResponseVO.java

@@ -0,0 +1,40 @@
+package com.zsElectric.boot.charging.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+@Data
+@Accessors(chain = true)
+@Schema(description = "充电状态查询响应VO")
+public class ChargingStatusResponseVO {
+
+    @Schema(description = "充电订单号(格式:运营商ID+唯一编号)",
+            example = "123456789201805141125123456",
+            required = true)
+    private String StartChargeSeq;
+
+    @Schema(description = "充电订单状态(1:启动中;2:充电中;3:停止中;4:已结束;5:未知)",
+            example = "2",
+            allowableValues = {"1", "2", "3", "4", "5"},
+            required = true)
+    private Integer StartChargeSeqStat;
+
+    @Schema(description = "充电设备接口编码",
+            example = "3702120244403_1",
+            required = true)
+    private String ConnectorID;
+
+    @Schema(description = "充电启动时间(格式:yyyy-MM-dd HH:mm:ss)",
+            example = "2018-05-17 09:08:00",
+            required = true)
+    private String StartTime;
+
+    @Schema(description = "停止充电验证码",
+            example = "886543")
+    private String IdentCode;
+
+    @Schema(description = "失败原因描述",
+            example = "设备离线")
+    private String FailReasonMsg;
+}

+ 15 - 9
src/main/java/com/zsElectric/boot/charging/vo/ChargeOrderStatusVO.java → src/main/java/com/zsElectric/boot/charging/vo/StartChargingResponseVO.java

@@ -1,4 +1,3 @@
-
 package com.zsElectric.boot.charging.vo;
 
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -7,32 +6,39 @@ import lombok.experimental.Accessors;
 
 @Data
 @Accessors(chain = true)
-@Schema(description = "充电订单状态响应VO")
-public class ChargeOrderStatusVO {
+@Schema(description = "充电启动响应VO")
+public class StartChargingResponseVO {
 
     @Schema(description = "充电订单号(格式:运营商ID+唯一编号)",
-            example = "123456789201805141125123456")
+            example = "123456789201805071630123456",
+            required = true)
     private String StartChargeSeq;
 
     @Schema(description = "充电订单状态(1-启动中,2-充电中,3-停止中,4-已结束,5-未知)",
             example = "1",
-            allowableValues = {"1", "2", "3", "4", "5"})
+            allowableValues = {"1", "2", "3", "4", "5"},
+            required = true)
     private Integer StartChargeSeqStat;
 
     @Schema(description = "充电设备接口编码",
-            example = "3702120244402_1")
+            example = "3702120244102_1",
+            required = true)
     private String ConnectorID;
 
     @Schema(description = "操作结果(0-成功,1-失败)",
             example = "0",
-            allowableValues = {"0", "1"})
+            allowableValues = {"0", "1"},
+            required = true)
     private Integer SuccStat;
 
     @Schema(description = "失败原因(0-无,1-此设备不存在,2-此设备离线,其它-自定义)",
-            example = "0")
+            example = "0",
+            allowableValues = {"0", "1", "2"},
+            required = true)
     private Integer FailReason;
 
     @Schema(description = "失败原因描述",
-            example = "无错误")
+            example = "无错误",
+            required = true)
     private String FailReasonMsg;
 }

+ 21 - 1
src/main/java/com/zsElectric/boot/common/constant/ConnectivityConstants.java

@@ -132,5 +132,25 @@ public interface ConnectivityConstants {
 
 
 
-    /*------------------------------------------请求URL-----------------------------------------------*/
+    /*------------------------------------------请求URL_END-----------------------------------------------*/
+
+    /*------------------------------------------响应状态-----------------------------------------------*/
+    /**
+     * 操作结果成功
+     * */
+    int STATUS_OK = 0;
+    /**
+     * 操作结果失败
+     * */
+    int STATUS_ERROR = 1;
+    /**
+     * 失败原因无
+     * */
+    int FAIL_REASON_NONE = 0;
+    /**
+     * 失败原因接收失败
+     * */
+    int FAIL_REASON_RECEIVE_FAIL = 1;
+
+    /*------------------------------------------响应状态_END-----------------------------------------------*/
 }

+ 14 - 0
src/main/java/com/zsElectric/boot/common/util/HmacMD5Util.java

@@ -36,6 +36,20 @@ public class HmacMD5Util {
         String content = (operatorId + data + timeStamp + seq).toUpperCase();
         return hmacMD5Hex(content, sigSecret);
     }
+
+
+    /**
+     * 出参
+     * */
+    public static String genSign(
+            int Ret,
+            String Msg,
+            String Data,
+            String sigSecret) throws NoSuchAlgorithmException {
+
+        String content = (Ret + Msg + Data).toUpperCase();
+        return hmacMD5Hex(content, sigSecret);
+    }
     
     /**
      * HMAC-MD5签名生成

+ 15 - 0
src/main/java/com/zsElectric/boot/common/util/electric/ChargingUtil.java

@@ -110,4 +110,19 @@ public class ChargingUtil {
             throw new RuntimeException("第三方接口响应发生异常", e);
         }
     }
+
+
+    /**
+     * 统一解密接口数据-己方响应
+     * */
+    public String decryptData(String data) throws Exception {
+        return AESCryptoUtils.decrypt(data, ConnectivityConstants.DATA_SECRET, ConnectivityConstants.DATA_SECRET_IV);
+    }
+
+    /**
+     * 统一加密接口数据-己方响应
+     * */
+    public String encryptData(String data) throws Exception {
+        return AESCryptoUtils.encrypt(data, ConnectivityConstants.DATA_SECRET, ConnectivityConstants.DATA_SECRET_IV);
+    }
 }

+ 3 - 3
src/main/java/com/zsElectric/boot/common/util/electric/ElectricTokenManager.java

@@ -161,11 +161,11 @@ public class ElectricTokenManager {
 
             requestParms
                     .setOperatorID(ConnectivityConstants.OPERATOR_ID)
-                    .setData(AESCryptoUtils.encrypt(queryTokenParms.toString(), ConnectivityConstants.DATA_SECRET,
-                            ConnectivityConstants.DATA_SECRET_IV))
+                    .setData(AESCryptoUtils.encrypt(new Gson().toJson(queryTokenParms), ConnectivityConstants.PLATFORM_DATA_SECRET,
+                            ConnectivityConstants.PLATFORM_DATA_SECRET_IV))
                     .setTimeStamp(result.getTimestamp())
                     .setSeq(result.getSequence())
-                    .setSig(HmacMD5Util.genSign(requestParms.getOperatorID(), requestParms.getData(), requestParms.getTimeStamp(), requestParms.getSeq(), ConnectivityConstants.SIG_SECRET));
+                    .setSig(HmacMD5Util.genSign(requestParms.getOperatorID(), requestParms.getData(), requestParms.getTimeStamp(), requestParms.getSeq(), ConnectivityConstants.PLATFORM_SIG_SECRET));
 
             JsonObject response = okHttpUtil.doPostForm(ConnectivityConstants.TEST_DOMAIN + ConnectivityConstants.QUERY_TOKEN, BeanUtil.beanToMap(requestParms), null);