Quellcode durchsuchen

refactor(charging): 优化第三方充电推送接收服务实现

- 重构充电结果、充电状态、停止充电和充电订单响应处理逻辑为统一模板方法
- 实现接口数据验签解密和响应加密签名的公共方法,提升代码复用
- 新增充电状态数据实体ThirdPartyChargeStatus及对应Mapper,支持状态持久化
- 实现充电状态保存或更新及接口状态批量更新功能
- 添加分布式锁保护的熔断检查逻辑,防止重复并发处理订单状态
- 更新政策费用服务计算综合销售费逻辑,整合电价、服务费和字典配置
- 新增MyBatis查询方法优化电价和服务费获取,提升性能和准确性
- 删除冗余日志注解,简化控制层代码,提升调用链清晰度
SheepHy vor 1 Tag
Ursprung
Commit
4881e78f4d

+ 53 - 4
src/main/java/com/zsElectric/boot/business/service/impl/PolicyFeeServiceImpl.java

@@ -8,7 +8,9 @@ import com.zsElectric.boot.business.model.dto.AddPolicyFeeDTO;
 import com.zsElectric.boot.business.model.entity.PolicyFee;
 import com.zsElectric.boot.business.model.vo.TimePeriodPriceVO;
 import com.zsElectric.boot.business.service.PolicyFeeService;
+import com.zsElectric.boot.charging.entity.ThirdPartyPolicyInfo;
 import com.zsElectric.boot.charging.entity.ThirdPartyStationInfo;
+import com.zsElectric.boot.charging.mapper.ThirdPartyPolicyInfoMapper;
 import com.zsElectric.boot.system.mapper.DictItemMapper;
 import com.zsElectric.boot.system.model.entity.DictItem;
 import lombok.RequiredArgsConstructor;
@@ -32,6 +34,7 @@ public class PolicyFeeServiceImpl implements PolicyFeeService {
 
     private final PolicyFeeMapper policyFeeMapper;
     private final ThirdPartyStationInfoMapper stationInfoMapper;
+    private final ThirdPartyPolicyInfoMapper policyInfoMapper;
     private final DictItemMapper dictItemMapper;
     
     /**
@@ -60,7 +63,12 @@ public class PolicyFeeServiceImpl implements PolicyFeeService {
             // 已存在,执行更新
             existPolicyFee.setOpFee(addPolicyFeeDTO.getOperationServiceFee());
             // 计算并设置综合销售费
-            BigDecimal compSalesFee = getCompSalesFeeByPeriodFlag(addPolicyFeeDTO.getPeriodFlag());
+            BigDecimal compSalesFee = calculateCompSalesFee(
+                    addPolicyFeeDTO.getStationInfoId(),
+                    addPolicyFeeDTO.getTimePeriod(),
+                    addPolicyFeeDTO.getPeriodFlag(),
+                    addPolicyFeeDTO.getOperationServiceFee()
+            );
             existPolicyFee.setCompSalesFee(compSalesFee);
             return policyFeeMapper.updateById(existPolicyFee) > 0;
         } else {
@@ -70,7 +78,12 @@ public class PolicyFeeServiceImpl implements PolicyFeeService {
             policyFee.setStartTime(addPolicyFeeDTO.getTimePeriod());
             policyFee.setOpFee(addPolicyFeeDTO.getOperationServiceFee());
             // 计算并设置综合销售费
-            BigDecimal compSalesFee = getCompSalesFeeByPeriodFlag(addPolicyFeeDTO.getPeriodFlag());
+            BigDecimal compSalesFee = calculateCompSalesFee(
+                    addPolicyFeeDTO.getStationInfoId(),
+                    addPolicyFeeDTO.getTimePeriod(),
+                    addPolicyFeeDTO.getPeriodFlag(),
+                    addPolicyFeeDTO.getOperationServiceFee()
+            );
             policyFee.setCompSalesFee(compSalesFee);
             policyFee.setSalesType(addPolicyFeeDTO.getSalesType());
             // 根据销售类型设置对应的ID
@@ -92,12 +105,48 @@ public class PolicyFeeServiceImpl implements PolicyFeeService {
     }
     
     /**
-     * 根据时段标志获取综合销售费(从字典表查询)
+     * 计算综合销售费
+     * 公式:compSalesFee = elec_price + service_price + 字典表值 + op_fee
+     *
+     * @param stationInfoId 站点信息ID
+     * @param timePeriod    时间段(HHmmss格式)
+     * @param periodFlag    时段标志
+     * @param opFee         运营费
+     * @return 综合销售费
+     */
+    private BigDecimal calculateCompSalesFee(Long stationInfoId, String timePeriod, Integer periodFlag, BigDecimal opFee) {
+        BigDecimal elecPrice = BigDecimal.ZERO;
+        BigDecimal servicePrice = BigDecimal.ZERO;
+        
+        // 直接通过stationInfoId和timePeriod查询电价和服务费
+        ThirdPartyPolicyInfo policyInfo = policyInfoMapper.selectElecAndServicePriceByStation(stationInfoId, timePeriod);
+        log.info("计算compSalesFee - stationInfoId: {}, timePeriod: {}, policyInfo: {}", stationInfoId, timePeriod, policyInfo);
+        
+        if (policyInfo != null) {
+            elecPrice = policyInfo.getElecPrice() != null ? policyInfo.getElecPrice() : BigDecimal.ZERO;
+            servicePrice = policyInfo.getServicePrice() != null ? policyInfo.getServicePrice() : BigDecimal.ZERO;
+        }
+        
+        // 从字典表获取periodFlag对应的值
+        BigDecimal dictValue = getDictValueByPeriodFlag(periodFlag);
+        
+        // 计算综合销售费 = elec_price + service_price + 字典值 + op_fee
+        BigDecimal opFeeValue = opFee != null ? opFee : BigDecimal.ZERO;
+        BigDecimal compSalesFee = elecPrice.add(servicePrice).add(dictValue).add(opFeeValue);
+        
+        log.info("计算综合销售费 - stationInfoId: {}, timePeriod: {}, elecPrice: {}, servicePrice: {}, dictValue: {}, opFee: {}, compSalesFee: {}",
+                stationInfoId, timePeriod, elecPrice, servicePrice, dictValue, opFeeValue, compSalesFee);
+        
+        return compSalesFee;
+    }
+
+    /**
+     * 根据时段标志获取字典值
      *
      * @param periodFlag 时段标志(1-尖 2-峰 3-平 4-谷)
      * @return 综合销售费
      */
-    private BigDecimal getCompSalesFeeByPeriodFlag(Integer periodFlag) {
+    private BigDecimal getDictValueByPeriodFlag(Integer periodFlag) {
         if (periodFlag == null) {
             return BigDecimal.ZERO;
         }

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

@@ -130,7 +130,6 @@ public class LinkDataController {
      * */
     @Operation(summary = "推送充电状态")
     @PostMapping("/notification_equip_charge_status")
-    @Log(value = "推送充电状态", module = LogModuleEnum.PARKING, params = true, result = true)
     public ResponseParmsEntity chargeStatusResponse(@RequestBody RequestParmsEntity requestDTO){
         return chargingReceptionService.chargeStatusResponse(requestDTO);
     }

+ 111 - 0
src/main/java/com/zsElectric/boot/charging/entity/ThirdPartyChargeStatus.java

@@ -0,0 +1,111 @@
+package com.zsElectric.boot.charging.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 第三方充电状态推送记录实体类
+ *
+ * @author system
+ * @since 2025-12-18
+ */
+@Data
+@Accessors(chain = true)
+@TableName("third_party_charge_status")
+@Schema(description = "第三方充电状态推送记录")
+public class ThirdPartyChargeStatus {
+
+    @Schema(description = "主键ID")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @Schema(description = "充电订单号")
+    @TableField("start_charge_seq")
+    private String startChargeSeq;
+
+    @Schema(description = "充电接口ID")
+    @TableField("connector_id")
+    private String connectorId;
+
+    @Schema(description = "接口状态:0-离网,1-空闲,2-占用(未充电),3-占用(充电中),4-占用(预约锁定),255-故障")
+    @TableField("connector_status")
+    private Integer connectorStatus;
+
+    @Schema(description = "订单状态:1-启动中,2-充电中,3-停止中,4-已结束,5-未知")
+    @TableField("start_charge_seq_stat")
+    private Integer startChargeSeqStat;
+
+    @Schema(description = "开始充电时间")
+    @TableField("start_time")
+    private LocalDateTime startTime;
+
+    @Schema(description = "结束充电时间(实时推送为当前采样时间)")
+    @TableField("end_time")
+    private LocalDateTime endTime;
+
+    @Schema(description = "累计充电量(度)")
+    @TableField("total_power")
+    private BigDecimal totalPower;
+
+    @Schema(description = "累计总金额(元)")
+    @TableField("total_money")
+    private BigDecimal totalMoney;
+
+    @Schema(description = "累计电费(元)")
+    @TableField("elec_money")
+    private BigDecimal elecMoney;
+
+    @Schema(description = "累计服务费(元)")
+    @TableField("service_money")
+    private BigDecimal serviceMoney;
+
+    @Schema(description = "电池剩余电量SOC(%)")
+    @TableField("soc")
+    private Integer soc;
+
+    @Schema(description = "A相电压(V)")
+    @TableField("voltage_a")
+    private BigDecimal voltageA;
+
+    @Schema(description = "B相电压(V)")
+    @TableField("voltage_b")
+    private BigDecimal voltageB;
+
+    @Schema(description = "C相电压(V)")
+    @TableField("voltage_c")
+    private BigDecimal voltageC;
+
+    @Schema(description = "A相电流(A)")
+    @TableField("current_a")
+    private BigDecimal currentA;
+
+    @Schema(description = "B相电流(A)")
+    @TableField("current_b")
+    private BigDecimal currentB;
+
+    @Schema(description = "C相电流(A)")
+    @TableField("current_c")
+    private BigDecimal currentC;
+
+    @Schema(description = "创建时间")
+    @TableField("create_time")
+    private LocalDateTime createTime;
+
+    @Schema(description = "更新时间")
+    @TableField("update_time")
+    private LocalDateTime updateTime;
+
+    @Schema(description = "删除标识(0-未删除,1-已删除)")
+    @TableLogic
+    @TableField("deleted")
+    private Integer deleted;
+}

+ 15 - 0
src/main/java/com/zsElectric/boot/charging/mapper/ThirdPartyChargeStatusMapper.java

@@ -0,0 +1,15 @@
+package com.zsElectric.boot.charging.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zsElectric.boot.charging.entity.ThirdPartyChargeStatus;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 第三方充电状态推送记录Mapper接口
+ *
+ * @author system
+ * @since 2025-12-18
+ */
+@Mapper
+public interface ThirdPartyChargeStatusMapper extends BaseMapper<ThirdPartyChargeStatus> {
+}

+ 11 - 0
src/main/java/com/zsElectric/boot/charging/mapper/ThirdPartyPolicyInfoMapper.java

@@ -3,6 +3,7 @@ package com.zsElectric.boot.charging.mapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.zsElectric.boot.charging.entity.ThirdPartyPolicyInfo;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 /**
  * 第三方价格策略明细Mapper接口
@@ -12,4 +13,14 @@ import org.apache.ibatis.annotations.Mapper;
  */
 @Mapper
 public interface ThirdPartyPolicyInfoMapper extends BaseMapper<ThirdPartyPolicyInfo> {
+    
+    /**
+     * 根据stationInfoId和startTime查询电价和服务费
+     *
+     * @param stationInfoId 站点信息ID
+     * @param startTime     时段开始时间
+     * @return 价格策略明细(包含elec_price和service_price)
+     */
+    ThirdPartyPolicyInfo selectElecAndServicePriceByStation(@Param("stationInfoId") Long stationInfoId,
+                                                             @Param("startTime") String startTime);
 }

+ 308 - 185
src/main/java/com/zsElectric/boot/charging/service/impl/ChargingReceptionServiceImpl.java

@@ -1,33 +1,59 @@
 package com.zsElectric.boot.charging.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.zsElectric.boot.business.mapper.ChargeOrderInfoMapper;
+import com.zsElectric.boot.business.mapper.PolicyFeeMapper;
+import com.zsElectric.boot.business.mapper.UserAccountMapper;
+import com.zsElectric.boot.business.mapper.UserFirmMapper;
+import com.zsElectric.boot.business.model.entity.ChargeOrderInfo;
+import com.zsElectric.boot.business.model.entity.UserAccount;
+import com.zsElectric.boot.business.model.entity.UserFirm;
 import com.zsElectric.boot.charging.entity.ConnectorStatusInfo;
 import com.zsElectric.boot.charging.entity.StationStatusInfo;
+import com.zsElectric.boot.charging.entity.ThirdPartyChargeStatus;
 import com.zsElectric.boot.charging.entity.ThirdPartyConnectorInfo;
+import com.zsElectric.boot.charging.mapper.ThirdPartyChargeStatusMapper;
 import com.zsElectric.boot.charging.mapper.ThirdPartyConnectorInfoMapper;
 import com.zsElectric.boot.charging.service.ChargingReceptionService;
-import com.zsElectric.boot.charging.vo.*;
+import com.zsElectric.boot.charging.vo.ChargeResponseVO;
+import com.zsElectric.boot.charging.vo.QueryStationStatusVO;
 import com.zsElectric.boot.common.constant.ConnectivityConstants;
 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 com.zsElectric.boot.system.mapper.DictItemMapper;
+import com.zsElectric.boot.system.model.entity.DictItem;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
 
 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;
 import static com.zsElectric.boot.common.util.HmacMD5Util.verify;
 
+/**
+ * 第三方充电推送接收服务实现
+ *
+ * @author system
+ * @since 2025-12-11
+ */
 @Slf4j
 @Service
 @RequiredArgsConstructor
@@ -35,226 +61,323 @@ public class ChargingReceptionServiceImpl implements ChargingReceptionService {
 
     private final ChargingUtil chargingUtil;
     private final ThirdPartyConnectorInfoMapper connectorInfoMapper;
-
-    private final ObjectMapper objectMapper = new ObjectMapper();
+    private final ThirdPartyChargeStatusMapper chargeStatusMapper;
+    private final ObjectMapper objectMapper;
+    private final ChargeOrderInfoMapper chargeOrderInfoMapper;
+    private final RedissonClient redissonClient;
+    private final UserAccountMapper userAccountMapper;
+    private final UserFirmMapper userFirmMapper;
+    private final PolicyFeeMapper policyFeeMapper;
+    private final DictItemMapper dictItemMapper;
+
+    /** 熔断检查锁前缀 */
+    private static final String BREAK_CHECK_LOCK_KEY = "charging:break:check:";
+    /** 锁等待时间(秒) */
+    private static final long LOCK_WAIT_TIME = 3;
+    /** 锁持有时间(秒) */
+    private static final long LOCK_LEASE_TIME = 10;
+
+    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+    // ==================== 接口实现 ====================
 
     @Override
     public ResponseParmsEntity chargeResponse(RequestParmsEntity requestDTO) {
         log.info("接收推送启动充电结果请求参数:{}", requestDTO);
-        ChargingStatusResponseVO chargingStatusResponseVO;
-        // 响应参数 答复处理
-        ChargeResponseVO chargeResponseVO = new ChargeResponseVO();
-        String encryptData;
-        String genSign;
-        try {
-            String data = requestDTO.getOperatorID() + requestDTO.getData() + requestDTO.getTimeStamp() + requestDTO.getSeq();
-            if(verify(data, ConnectivityConstants.SIG_SECRET, requestDTO.getSig())){
-                String decryptData = chargingUtil.decryptData(requestDTO.getData());
-                log.info("解密后的数据:{}", decryptData);
-                JsonNode jsonNode = objectMapper.readTree(decryptData);
-//                equipChargeStatusResponseVO = objectMapper.readValue(decryptData, EquipChargeStatusResponseVO.class);
-                //todo 业务代码待处理
-
-
-
-                chargeResponseVO.setStartChargeSeq(jsonNode.get("StartChargeSeq").asText());
-//                chargeResponseVO.setStartChargeSeq(equipChargeStatusResponseVO.getStartChargeSeq());
-                chargeResponseVO.setSuccStat(STATUS_OK);
-                chargeResponseVO.setFailReason(FAIL_REASON_NONE);
-                encryptData = chargingUtil.encryptData(objectMapper.writeValueAsString(chargeResponseVO));
-                genSign = genSign(STATUS_OK, "请求成功", encryptData, ConnectivityConstants.SIG_SECRET);
-            }else {
-                log.error("数据验签失败");
-                throw new BusinessException("数据验签失败");
-            }
-        }catch (Exception e){
-            log.error("数据解密失败:{}", e.getMessage());
-            throw new BusinessException("数据解密失败:" + e.getMessage(), e);
-        }
-        ResponseParmsEntity responseParmsEntity = new ResponseParmsEntity();
-        responseParmsEntity.setRet(STATUS_OK);
-        responseParmsEntity.setMsg("请求成功");
-        responseParmsEntity.setData(encryptData);
-        responseParmsEntity.setSig(genSign);
-        return responseParmsEntity;
-
+        return processChargeRequest(requestDTO, jsonNode -> {
+            // TODO: 启动充电结果业务处理
+            log.debug("启动充电结果 - StartChargeSeq: {}", getTextValue(jsonNode, "StartChargeSeq"));
+        });
     }
 
     @Override
     public ResponseParmsEntity chargeStatusResponse(RequestParmsEntity requestDTO) {
         log.info("接收推送充电状态请求参数:{}", requestDTO);
-        EquipChargeStatusResponseVO equipChargeStatusResponseVO;
-        ChargeResponseVO chargeResponseVO = new ChargeResponseVO();
-        String encryptData;
-        String genSign;
+        return processChargeRequest(requestDTO, this::saveOrUpdateChargeStatus);
+    }
+
+    @Override
+    public ResponseParmsEntity stopChargeResponse(RequestParmsEntity requestDTO) {
+        log.info("接收推送停止充电结果请求参数:{}", requestDTO);
+        return processChargeRequest(requestDTO, jsonNode -> {
+            // TODO: 停止充电结果业务处理
+            log.debug("停止充电结果 - StartChargeSeq: {}", getTextValue(jsonNode, "StartChargeSeq"));
+        });
+    }
+
+    @Override
+    public ResponseParmsEntity chargeOrderResponse(RequestParmsEntity requestDTO) {
+        log.info("接收推送充电订单信息请求参数:{}", requestDTO);
+        return processChargeRequest(requestDTO, jsonNode -> {
+            // TODO: 充电订单信息业务处理
+            log.debug("充电订单信息 - StartChargeSeq: {}", getTextValue(jsonNode, "StartChargeSeq"));
+        });
+    }
+
+    @Override
+    public ResponseParmsEntity stationStatus(RequestParmsEntity requestDTO) {
+        log.info("接收设备状态变化推送请求参数:{}", requestDTO);
+        return processStationStatusRequest(requestDTO);
+    }
+
+    // ==================== 公共处理方法 ====================
+
+    /**
+     * 通用充电请求处理模板
+     */
+    private ResponseParmsEntity processChargeRequest(RequestParmsEntity requestDTO, Consumer<JsonNode> businessHandler) {
         try {
-            String data = requestDTO.getOperatorID() + requestDTO.getData() + requestDTO.getTimeStamp() + requestDTO.getSeq();
-            if(verify(data, ConnectivityConstants.SIG_SECRET, requestDTO.getSig())){
-                String decryptData = chargingUtil.decryptData(requestDTO.getData());
-                log.info("解密后的数据:{}", decryptData);
-                JsonNode jsonNode = objectMapper.readTree(decryptData);
-//                equipChargeStatusResponseVO = objectMapper.readValue(decryptData, EquipChargeStatusResponseVO.class);
-                //todo 业务代码待处理
-
-
-
-                chargeResponseVO.setStartChargeSeq(jsonNode.get("StartChargeSeq").asText());
-//                chargeResponseVO.setStartChargeSeq(equipChargeStatusResponseVO.getStartChargeSeq());
-                chargeResponseVO.setSuccStat(STATUS_OK);
-                chargeResponseVO.setFailReason(FAIL_REASON_NONE);
-                encryptData = chargingUtil.encryptData(objectMapper.writeValueAsString(chargeResponseVO));
-                genSign = genSign(STATUS_OK, "请求成功", encryptData, ConnectivityConstants.SIG_SECRET);
-            }else {
-                log.error("数据验签失败");
-                throw new BusinessException("数据验签失败");
-            }
+            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(), e);
+        }
+    }
+
+    /**
+     * 处理设备状态变化推送请求
+     */
+    private ResponseParmsEntity processStationStatusRequest(RequestParmsEntity requestDTO) {
+        try {
+            String decryptData = verifyAndDecryptRaw(requestDTO);
+            
+            // 解析并更新设备状态
+            QueryStationStatusVO stationStatusVO = objectMapper.readValue(decryptData, QueryStationStatusVO.class);
+            updateConnectorStatus(stationStatusVO);
+            
+            // 构建响应
+            return buildStatusResponse();
+        } catch (BusinessException e) {
+            throw e;
         } catch (Exception e) {
-            log.error("数据解密失败:{}", e.getMessage());
-            throw new BusinessException("数据解密失败:" + e.getMessage(), e);
+            log.error("处理设备状态推送失败:{}", e.getMessage());
+            throw new BusinessException("处理设备状态推送失败:" + e.getMessage(), e);
         }
+    }
 
-        ResponseParmsEntity responseParmsEntity = new ResponseParmsEntity();
-        responseParmsEntity.setRet(STATUS_OK);
-        responseParmsEntity.setMsg("请求成功");
-        responseParmsEntity.setData(encryptData);
-        responseParmsEntity.setSig(genSign);
-        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("解密后的数据:{}", decryptData);
+        return decryptData;
     }
 
-    @Override
-    public ResponseParmsEntity stopChargeResponse(RequestParmsEntity requestDTO) {
-        log.info("接收推送停止充电结果请求参数:{}", requestDTO);
-        StopChargingResponseVO stopChargingResponseVO;
+    // ==================== 响应构建 ====================
+
+    /**
+     * 构建充电响应
+     */
+    private ResponseParmsEntity buildChargeResponse(String startChargeSeq) throws Exception {
         ChargeResponseVO chargeResponseVO = new ChargeResponseVO();
-        String encryptData;
-        String genSign;
+        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;
+    }
+
+    // ==================== 状态更新 ====================
+
+    /**
+     * 更新充电接口状态
+     */
+    private void updateConnectorStatus(QueryStationStatusVO stationStatusVO) {
+        if (stationStatusVO == null || CollectionUtils.isEmpty(stationStatusVO.getStationStatusInfos())) {
+            return;
+        }
+        for (StationStatusInfo stationStatusInfo : stationStatusVO.getStationStatusInfos()) {
+            List<ConnectorStatusInfo> connectorStatusInfos = stationStatusInfo.getConnectorStatusInfos();
+            if (CollectionUtils.isEmpty(connectorStatusInfos)) {
+                continue;
+            }
+            for (ConnectorStatusInfo connectorStatus : connectorStatusInfos) {
+                connectorInfoMapper.update(null, Wrappers.<ThirdPartyConnectorInfo>lambdaUpdate()
+                        .eq(ThirdPartyConnectorInfo::getConnectorId, connectorStatus.getConnectorID())
+                        .set(ThirdPartyConnectorInfo::getStatus, connectorStatus.getStatus()));
+                log.debug("更新充电接口状态 - connectorId: {}, status: {}",
+                        connectorStatus.getConnectorID(), connectorStatus.getStatus());
+            }
+        }
+    }
+
+    /**
+     * 保存或更新充电状态数据
+     */
+    private void saveOrUpdateChargeStatus(JsonNode jsonNode) {
         try {
-            String data = requestDTO.getOperatorID() + requestDTO.getData() + requestDTO.getTimeStamp() + requestDTO.getSeq();
-            if(verify(data, ConnectivityConstants.SIG_SECRET, requestDTO.getSig())){
-                String decryptData = chargingUtil.decryptData(requestDTO.getData());
-                log.info("解密后的数据:{}", decryptData);
-                JsonNode jsonNode = objectMapper.readTree(decryptData);
-//                equipChargeStatusResponseVO = objectMapper.readValue(decryptData, EquipChargeStatusResponseVO.class);
-                //todo 业务代码待处理
-
-
-
-                chargeResponseVO.setStartChargeSeq(jsonNode.get("StartChargeSeq").asText());
-//                chargeResponseVO.setStartChargeSeq(equipChargeStatusResponseVO.getStartChargeSeq());
-                chargeResponseVO.setSuccStat(STATUS_OK);
-                chargeResponseVO.setFailReason(FAIL_REASON_NONE);
-                encryptData = chargingUtil.encryptData(objectMapper.writeValueAsString(chargeResponseVO));
-                genSign = genSign(STATUS_OK, "请求成功", encryptData, ConnectivityConstants.SIG_SECRET);
-            }else {
-                log.error("数据验签失败");
-                throw new BusinessException("数据验签失败");
+            String startChargeSeq = jsonNode.get("StartChargeSeq").asText();
+
+            // 查询是否已存在该订单
+            ThirdPartyChargeStatus existing = chargeStatusMapper.selectOne(
+                    Wrappers.<ThirdPartyChargeStatus>lambdaQuery()
+                            .eq(ThirdPartyChargeStatus::getStartChargeSeq, startChargeSeq)
+            );
+
+            ThirdPartyChargeStatus chargeStatus = (existing != null) ? existing : new ThirdPartyChargeStatus();
+
+            // 设置字段值
+            chargeStatus.setStartChargeSeq(startChargeSeq);
+            chargeStatus.setConnectorId(getTextValue(jsonNode, "ConnectorID"));
+            chargeStatus.setConnectorStatus(getIntValue(jsonNode, "ConnectorStatus"));
+            chargeStatus.setStartChargeSeqStat(getIntValue(jsonNode, "StartChargeSeqStat"));
+            chargeStatus.setStartTime(parseDateTime(getTextValue(jsonNode, "StartTime")));
+            chargeStatus.setEndTime(parseDateTime(getTextValue(jsonNode, "EndTime")));
+            chargeStatus.setTotalPower(getDecimalValue(jsonNode, "TotalPower"));
+            chargeStatus.setTotalMoney(getDecimalValue(jsonNode, "TotalMoney"));
+            chargeStatus.setElecMoney(getDecimalValue(jsonNode, "ElecMoney"));
+            chargeStatus.setServiceMoney(getDecimalValue(jsonNode, "SeviceMoney")); // 注意:第三方字段名SeviceMoney
+            chargeStatus.setSoc(getIntValue(jsonNode, "Soc"));
+            chargeStatus.setVoltageA(getDecimalValue(jsonNode, "VoltageA"));
+            chargeStatus.setVoltageB(getDecimalValue(jsonNode, "VoltageB"));
+            chargeStatus.setVoltageC(getDecimalValue(jsonNode, "VoltageC"));
+            chargeStatus.setCurrentA(getDecimalValue(jsonNode, "CurrentA"));
+            chargeStatus.setCurrentB(getDecimalValue(jsonNode, "CurrentB"));
+            chargeStatus.setCurrentC(getDecimalValue(jsonNode, "CurrentC"));
+
+            if (existing != null) {
+                chargeStatus.setUpdateTime(LocalDateTime.now());
+                chargeStatusMapper.updateById(chargeStatus);
+                log.info("更新充电状态成功 - startChargeSeq: {}", startChargeSeq);
+            } else {
+                chargeStatus.setCreateTime(LocalDateTime.now());
+                chargeStatusMapper.insert(chargeStatus);
+                log.info("新增充电状态成功 - startChargeSeq: {}", startChargeSeq);
             }
+            //熔断保护
+            isNeedBreak(startChargeSeq);
         } catch (Exception e) {
-            log.error("数据解密失败:{}", e.getMessage());
-            throw new BusinessException("数据解密失败:" + e.getMessage(), e);
+            log.error("保存充电状态数据失败", e);
         }
+    }
 
-        ResponseParmsEntity responseParmsEntity = new ResponseParmsEntity();
-        responseParmsEntity.setRet(STATUS_OK);
-        responseParmsEntity.setMsg("请求成功");
-        responseParmsEntity.setData(encryptData);
-        responseParmsEntity.setSig(genSign);
-        return responseParmsEntity;
+    // ==================== JSON解析工具方法 ====================
 
+    private String getTextValue(JsonNode node, String fieldName) {
+        JsonNode field = node.get(fieldName);
+        return (field != null && !field.isNull()) ? field.asText() : null;
     }
 
-    @Override
-    public ResponseParmsEntity chargeOrderResponse(RequestParmsEntity requestDTO) {
-        log.info("接收推送充电订单信息请求参数:{}", requestDTO);
-        ChargingOrderVO chargingOrderVO;
-        ChargeResponseVO chargeResponseVO = new ChargeResponseVO();
-        String encryptData;
-        String genSign;
+    private Integer getIntValue(JsonNode node, String fieldName) {
+        JsonNode field = node.get(fieldName);
+        return (field != null && !field.isNull()) ? field.asInt() : null;
+    }
+
+    private BigDecimal getDecimalValue(JsonNode node, String fieldName) {
+        JsonNode field = node.get(fieldName);
+        return (field != null && !field.isNull()) ? new BigDecimal(field.asText()) : null;
+    }
+
+    private LocalDateTime parseDateTime(String dateTimeStr) {
+        if (dateTimeStr == null || dateTimeStr.isEmpty()) {
+            return null;
+        }
         try {
-            String data = requestDTO.getOperatorID() + requestDTO.getData() + requestDTO.getTimeStamp() + requestDTO.getSeq();
-            if(verify(data, ConnectivityConstants.SIG_SECRET, requestDTO.getSig())){
-                String decryptData = chargingUtil.decryptData(requestDTO.getData());
-                log.info("解密后的数据:{}", decryptData);
-                JsonNode jsonNode = objectMapper.readTree(decryptData);
-//                equipChargeStatusResponseVO = objectMapper.readValue(decryptData, EquipChargeStatusResponseVO.class);
-                //todo 业务代码待处理
-
-
-
-                chargeResponseVO.setStartChargeSeq(jsonNode.get("StartChargeSeq").asText());
-//                chargeResponseVO.setStartChargeSeq(equipChargeStatusResponseVO.getStartChargeSeq());
-                chargeResponseVO.setSuccStat(STATUS_OK);
-                chargeResponseVO.setFailReason(FAIL_REASON_NONE);
-                encryptData = chargingUtil.encryptData(objectMapper.writeValueAsString(chargeResponseVO));
-                genSign = genSign(STATUS_OK, "请求成功", encryptData, ConnectivityConstants.SIG_SECRET);
-            }else {
-                log.error("数据验签失败");
-                throw new BusinessException("数据验签失败");
-            }
+            return LocalDateTime.parse(dateTimeStr, DATE_TIME_FORMATTER);
         } catch (Exception e) {
-            log.error("数据解密失败:{}", e.getMessage());
-            throw new BusinessException("数据解密失败:" + e.getMessage(), e);
+            log.warn("解析时间失败: {}", dateTimeStr);
+            return null;
         }
-        ResponseParmsEntity responseParmsEntity = new ResponseParmsEntity();
-        responseParmsEntity.setRet(STATUS_OK);
-        responseParmsEntity.setMsg("请求成功");
-        responseParmsEntity.setData(encryptData);
-        responseParmsEntity.setSig(genSign);
-        return responseParmsEntity;
     }
 
-    @Override
-    public ResponseParmsEntity stationStatus(RequestParmsEntity requestDTO) {
-        log.info("接收设备状态变化推送请求参数:{}", requestDTO);
-        String encryptData = "";
-        String genSign = "";
-        ResponseParmsEntity responseParmsEntity = new ResponseParmsEntity();
-
+    /**
+     * 根据充电订单号StartChargeSeq 获取订单信息判断是否需要熔断,提前跳枪
+     * 使用分布式锁防止并发重复检查
+     */
+    private void isNeedBreak(String startChargeSeq) {
+        String lockKey = BREAK_CHECK_LOCK_KEY + startChargeSeq;
+        RLock lock = redissonClient.getLock(lockKey);
         try {
-            String data = requestDTO.getOperatorID() + requestDTO.getData() + requestDTO.getTimeStamp() + requestDTO.getSeq();
-            if (verify(data, ConnectivityConstants.SIG_SECRET, requestDTO.getSig())) {
-                String decryptData = chargingUtil.decryptData(requestDTO.getData());
-                log.info("解密后的数据:{}", decryptData);
-
-                // 解析设备状态变化推送数据
-                QueryStationStatusVO stationStatusVO = objectMapper.readValue(decryptData, QueryStationStatusVO.class);
-                if (stationStatusVO != null && !CollectionUtils.isEmpty(stationStatusVO.getStationStatusInfos())) {
-                    for (StationStatusInfo stationStatusInfo : stationStatusVO.getStationStatusInfos()) {
-                        List<ConnectorStatusInfo> connectorStatusInfos = stationStatusInfo.getConnectorStatusInfos();
-                        if (!CollectionUtils.isEmpty(connectorStatusInfos)) {
-                            for (ConnectorStatusInfo connectorStatus : connectorStatusInfos) {
-                                // 根据连接器ID更新状态
-                                connectorInfoMapper.update(null, Wrappers.<ThirdPartyConnectorInfo>lambdaUpdate()
-                                        .eq(ThirdPartyConnectorInfo::getConnectorId, connectorStatus.getConnectorID())
-                                        .set(ThirdPartyConnectorInfo::getStatus, connectorStatus.getStatus()));
-                                log.debug("更新充电接口状态 - connectorId: {}, status: {}",
-                                        connectorStatus.getConnectorID(), connectorStatus.getStatus());
-                            }
+            // 尝试获取锁,最多等待3秒,持有锁最多10秒
+            if (lock.tryLock(LOCK_WAIT_TIME, LOCK_LEASE_TIME, TimeUnit.SECONDS)) {
+                try {
+                    ChargeOrderInfo chargeOrderInfo = chargeOrderInfoMapper.selectOne(
+                            Wrappers.<ChargeOrderInfo>lambdaQuery()
+                                    .eq(ChargeOrderInfo::getChargeOrderNo, startChargeSeq)
+                                    .eq(ChargeOrderInfo::getStatus, 1)
+                                    .eq(ChargeOrderInfo::getIsDeleted, 0)
+                    );
+                    if (null != chargeOrderInfo) {
+                        // TODO: 根据业务需求实现熔断条件判断(例如:余额不足、超时等)
+                        DictItem dictItem = dictItemMapper.selectOne(
+                                new LambdaQueryWrapper<DictItem>()
+                                        .eq(DictItem::getDictCode, "up_recharge")
+                                        .eq(DictItem::getStatus, 1)
+                                        .last("LIMIT 1"));
+                        //安全价
+                        BigDecimal upRecharge = new BigDecimal(dictItem.getValue());
+                        //获取用户余额
+                        BigDecimal balance = userAccountMapper.selectOne(Wrappers.<UserAccount>lambdaQuery()
+                                .eq(UserAccount::getUserId, chargeOrderInfo.getUserId())
+                                .eq(UserAccount::getIsDeleted, 0)).getBalance();
+                        //企业价
+                        BigDecimal firmPrice;
+                        //根据用户ID去查询当前用户是否有归属企业
+                        UserFirm userFirm = userFirmMapper.selectOne(Wrappers.<UserFirm>lambdaQuery()
+                                .eq(UserFirm::getUserId, chargeOrderInfo.getUserId())
+                                .eq(UserFirm::getIsDeleted, 0));
+                        if(null != userFirm){
+
                         }
+
                     }
+                } finally {
+                    lock.unlock();
                 }
-
-                Map<String, Integer> statusMap = new HashMap<>();
-                statusMap.put("Status", 0);
-                encryptData = chargingUtil.encryptData(objectMapper.writeValueAsString(statusMap));
-                genSign = genSign(STATUS_OK, "", encryptData, ConnectivityConstants.SIG_SECRET);
-
-                responseParmsEntity.setRet(STATUS_OK);
-                responseParmsEntity.setMsg("");
-                responseParmsEntity.setData(encryptData);
-                responseParmsEntity .setSig(genSign);
             } else {
-                log.error("数据验签失败");
-                throw new BusinessException("数据验签失败");
+                log.warn("获取熔断检查锁超时 - startChargeSeq: {}", startChargeSeq);
             }
-        } catch (Exception e) {
-            log.error("数据解密失败:{}", e.getMessage());
-            throw new BusinessException("数据解密失败:" + e.getMessage(), e);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            log.error("获取熔断检查锁被中断 - startChargeSeq: {}", startChargeSeq, e);
         }
-
-        return responseParmsEntity;
-
     }
-
 }

+ 25 - 0
src/main/resources/mapper/charging/ThirdPartyPolicyInfoMapper.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.zsElectric.boot.charging.mapper.ThirdPartyPolicyInfoMapper">
+
+    <!-- 根据stationInfoId和startTime查询电价和服务费 -->
+    <select id="selectElecAndServicePriceByStation" resultType="com.zsElectric.boot.charging.entity.ThirdPartyPolicyInfo">
+        SELECT 
+            tppi.id,
+            tppi.elec_price,
+            tppi.service_price,
+            tppi.period_flag
+        FROM third_party_station_info tpsi
+        INNER JOIN third_party_connector_info tpci 
+            ON tpci.station_id = tpsi.station_id AND tpci.is_deleted = 0
+        INNER JOIN third_party_equipment_price_policy tpepp 
+            ON tpepp.connector_id = tpci.connector_id AND tpepp.is_deleted = 0
+        INNER JOIN third_party_policy_info tppi 
+            ON tppi.price_policy_id = tpepp.id AND tppi.is_deleted = 0
+        WHERE tpsi.id = #{stationInfoId}
+            AND tpsi.is_deleted = 0
+            AND tppi.start_time = #{startTime}
+        LIMIT 1
+    </select>
+
+</mapper>