package com.zsElectric.boot.thirdParty.service.impl; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.fasterxml.jackson.databind.ObjectMapper; import com.zsElectric.boot.business.mapper.RechargeLevelMapper; import com.zsElectric.boot.business.mapper.ThirdPartyEquipmentInfoMapper; import com.zsElectric.boot.business.mapper.ThirdPartyInfoMapper; import com.zsElectric.boot.business.mapper.ThirdPartyStationInfoMapper; import com.zsElectric.boot.business.model.vo.applet.AppletConnectorDetailVO; import com.zsElectric.boot.charging.mapper.ThirdPartyConnectorInfoMapper; import com.zsElectric.boot.business.mapper.UserAccountMapper; import com.zsElectric.boot.business.mapper.UserOrderInfoMapper; import com.zsElectric.boot.business.model.entity.RechargeLevel; import com.zsElectric.boot.business.model.entity.ThirdPartyInfo; import com.zsElectric.boot.business.model.entity.UserAccount; import com.zsElectric.boot.business.model.entity.UserInfo; import com.zsElectric.boot.business.model.entity.UserOrderInfo; import com.zsElectric.boot.business.model.query.StationInfoQuery; import com.zsElectric.boot.business.model.vo.AppletStationDetailVO; import com.zsElectric.boot.business.model.vo.StationInfoVO; import com.zsElectric.boot.charging.entity.ThirdPartyConnectorInfo; import com.zsElectric.boot.charging.entity.ThirdPartyEquipmentInfo; import com.zsElectric.boot.charging.entity.ThirdPartyStationInfo; import com.zsElectric.boot.business.service.UserInfoService; import com.zsElectric.boot.business.service.UserAccountService; import com.zsElectric.boot.business.service.ChargeOrderInfoService; import com.zsElectric.boot.business.model.form.applet.AppInvokeChargeForm; import com.zsElectric.boot.business.model.form.applet.AppStopChargeForm; import com.zsElectric.boot.business.model.vo.applet.AppChargeVO; import com.zsElectric.boot.common.constant.SystemConstants; import com.zsElectric.boot.common.util.AESCryptoUtils; import com.zsElectric.boot.common.util.HmacMD5Util; import com.zsElectric.boot.thirdParty.model.*; import com.zsElectric.boot.thirdParty.service.ThirdPartyTokenService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** * 第三方Token服务实现类 * * @author wzq */ @Slf4j @Service @RequiredArgsConstructor public class ThirdPartyTokenServiceImpl implements ThirdPartyTokenService { private final ThirdPartyInfoMapper thirdPartyInfoMapper; private final RechargeLevelMapper rechargeLevelMapper; private final RedisTemplate redisTemplate; private final UserInfoService userInfoService; private final UserAccountMapper userAccountMapper; private final UserAccountService userAccountService; private final UserOrderInfoMapper userOrderInfoMapper; private final ThirdPartyStationInfoMapper thirdPartyStationInfoMapper; private final ThirdPartyEquipmentInfoMapper thirdPartyEquipmentInfoMapper; private final ThirdPartyConnectorInfoMapper thirdPartyConnectorInfoMapper; private final ChargeOrderInfoService chargeOrderInfoService; private final ObjectMapper objectMapper = new ObjectMapper(); /** * Redis Token Key 前缀 */ private static final String TOKEN_KEY_PREFIX = "third_party_access:token:"; /** * Redis OperatorId Token映射 Key 前缀 */ private static final String OPERATOR_TOKEN_KEY_PREFIX = "third_party_access:operator:"; /** * 默认Token有效期(秒) */ private static final int DEFAULT_TOKEN_EXPIRE_SECONDS = 7200; @Override public ThirdPartyResponse queryToken(ThirdPartyRequest request) { try { // 1. 参数校验 if (!validateRequestParams(request)) { return buildErrorResponse(4003, "参数不合法,缺少必需的参数", null); } // 2. 通过operatorId查询第三方配置信息 ThirdPartyInfo thirdPartyInfo = getThirdPartyInfoByOperatorId(request.getOperatorId()); if (thirdPartyInfo == null) { log.warn("运营商不存在, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4004, "运营商不存在", null); } // 3. 验证签名 String signContent = request.getOperatorId() + request.getData() + request.getTimeStamp() + request.getSeq(); if (!HmacMD5Util.verify(signContent, thirdPartyInfo.getSigSecret(), request.getSig())) { log.warn("签名验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4001, "签名错误", thirdPartyInfo); } // 4. 解密并解析业务参数 String decryptedData = AESCryptoUtils.decrypt( request.getData(), thirdPartyInfo.getDataSecret(), thirdPartyInfo.getDataSecretIV() ); log.info("解密后的请求数据: {}", decryptedData); QueryTokenRequestData tokenRequest = objectMapper.readValue(decryptedData, QueryTokenRequestData.class); if (tokenRequest == null || StrUtil.isBlank(tokenRequest.getOperatorId()) || StrUtil.isBlank(tokenRequest.getOperatorSecret())) { return buildErrorResponse(4004, "请求的业务参数不合法", thirdPartyInfo); } // 5. 验证运营商ID和密钥 if (!thirdPartyInfo.getOperatorId().equals(tokenRequest.getOperatorId()) || !thirdPartyInfo.getOperatorSecret().equals(tokenRequest.getOperatorSecret())) { log.warn("运营商ID或密钥错误, operatorId: {}", tokenRequest.getOperatorId()); // 返回失败响应数据 QueryTokenResponseData failData = QueryTokenResponseData.fail(tokenRequest.getOperatorId(), 1); return buildSuccessResponse(failData, thirdPartyInfo); } // 6. 生成或获取已有Token String accessToken = getOrGenerateToken(tokenRequest.getOperatorId()); Integer remainingTTL = getRemainingTTL(accessToken); // 7. 构建成功响应 QueryTokenResponseData responseData = QueryTokenResponseData.success( tokenRequest.getOperatorId(), accessToken, remainingTTL ); log.info("生成Token成功, operatorId: {}, token有效期: {}秒", tokenRequest.getOperatorId(), remainingTTL); return buildSuccessResponse(responseData, thirdPartyInfo); } catch (Exception e) { log.error("处理query_token请求异常", e); return buildErrorResponse(500, "系统错误", null); } } @Override public ThirdPartyResponse queryRechargeLevelPage(ThirdPartyRequest request, String authorization) { try { // 1. 参数校验 if (!validateRequestParams(request)) { return buildErrorResponse(4003, "参数不合法,缺少必需的参数", null); } // 2. 通过operatorId查询第三方配置信息 ThirdPartyInfo thirdPartyInfo = getThirdPartyInfoByOperatorId(request.getOperatorId()); if (thirdPartyInfo == null) { log.warn("运营商不存在, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4004, "运营商不存在", null); } // 3. 验证签名 String signContent = request.getOperatorId() + request.getData() + request.getTimeStamp() + request.getSeq(); if (!HmacMD5Util.verify(signContent, thirdPartyInfo.getSigSecret(), request.getSig())) { log.warn("签名验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4001, "签名错误", thirdPartyInfo); } // 4. 从Header中解析并验证Token String accessToken = parseAccessToken(authorization); if (StrUtil.isBlank(accessToken)) { log.warn("Token为空或格式错误, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } if (!validateAccessToken(accessToken, request.getOperatorId())) { log.warn("Token验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } // 5. 解密并解析业务参数 String decryptedData = AESCryptoUtils.decrypt( request.getData(), thirdPartyInfo.getDataSecret(), thirdPartyInfo.getDataSecretIV() ); log.info("解密后的请求数据: {}", decryptedData); RechargeLevelPageRequestData pageRequest = objectMapper.readValue(decryptedData, RechargeLevelPageRequestData.class); if (pageRequest == null) { pageRequest = new RechargeLevelPageRequestData(); } // 6. 查询充值档位分页数据 IPage pageResult = queryRechargeLevelFromDb(pageRequest); // 7. 转换为响应数据 List records = pageResult.getRecords().stream() .map(this::convertToItem) .collect(Collectors.toList()); RechargeLevelPageResponseData responseData = RechargeLevelPageResponseData.of( pageResult.getTotal(), pageResult.getCurrent(), pageResult.getSize(), pageResult.getPages(), records ); log.info("查询充值档位成功, operatorId: {}, total: {}", request.getOperatorId(), pageResult.getTotal()); return buildSuccessResponse(responseData, thirdPartyInfo); } catch (Exception e) { log.error("处理query_recharge_level_page请求异常", e); return buildErrorResponse(500, "系统错误", null); } } @Override public ThirdPartyResponse queryUserInfo(ThirdPartyRequest request, String authorization) { try { // 1. 参数校验 if (!validateRequestParams(request)) { return buildErrorResponse(4003, "参数不合法,缺少必需的参数", null); } // 2. 通过operatorId查询第三方配置信息 ThirdPartyInfo thirdPartyInfo = getThirdPartyInfoByOperatorId(request.getOperatorId()); if (thirdPartyInfo == null) { log.warn("运营商不存在, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4004, "运营商不存在", null); } // 3. 验证签名 String signContent = request.getOperatorId() + request.getData() + request.getTimeStamp() + request.getSeq(); if (!HmacMD5Util.verify(signContent, thirdPartyInfo.getSigSecret(), request.getSig())) { log.warn("签名验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4001, "签名错误", thirdPartyInfo); } // 4. 从Header中解析并验证Token String accessToken = parseAccessToken(authorization); if (StrUtil.isBlank(accessToken)) { log.warn("Token为空或格式错误, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } if (!validateAccessToken(accessToken, request.getOperatorId())) { log.warn("Token验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } // 5. 解密并解析业务参数 String decryptedData = AESCryptoUtils.decrypt( request.getData(), thirdPartyInfo.getDataSecret(), thirdPartyInfo.getDataSecretIV() ); log.info("解密后的请求数据: {}", decryptedData); QueryUserInfoRequestData userInfoRequest = objectMapper.readValue(decryptedData, QueryUserInfoRequestData.class); if (userInfoRequest == null || StrUtil.isBlank(userInfoRequest.getPhone())) { log.warn("手机号为空, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4004, "请求的业务参数不合法,手机号不能为空", thirdPartyInfo); } String phone = userInfoRequest.getPhone(); // 6. 根据手机号查询用户信息 UserInfo userInfo = userInfoService.getUserInfoByPhone(phone); Integer isNewUser = 0; if (userInfo == null) { // 用户不存在,注册新用户 log.info("用户不存在,注册新用户, phone: {}", phone); userInfo = userInfoService.registerOrUpdateUserByPhone(phone, null); if (userInfo == null) { log.error("注册用户失败, phone: {}", phone); return buildErrorResponse(500, "注册用户失败", thirdPartyInfo); } isNewUser = 1; } // 7. 查询用户账户信息 UserAccount userAccount = userAccountMapper.selectOne( Wrappers.lambdaQuery() .eq(UserAccount::getUserId, userInfo.getId()) .eq(UserAccount::getIsDeleted, 0) ); // 如果账户不存在,创建账户 if (userAccount == null) { log.info("用户账户不存在,创建账户, userId: {}", userInfo.getId()); userAccount = new UserAccount(); userAccount.setUserId(userInfo.getId()); userAccount.setBalance(BigDecimal.ZERO); userAccount.setRedeemBalance(BigDecimal.ZERO); userAccount.setIntegral(BigDecimal.ZERO); userAccountMapper.insert(userAccount); } // 8. 构建响应数据 QueryUserInfoResponseData.UserInfoItem userInfoItem = new QueryUserInfoResponseData.UserInfoItem(); userInfoItem.setUserId(userInfo.getId()); userInfoItem.setNickName(userInfo.getNickName()); userInfoItem.setPhone(userInfo.getPhone()); userInfoItem.setOpenid(userInfo.getOpenid()); QueryUserInfoResponseData.AccountInfoItem accountInfoItem = new QueryUserInfoResponseData.AccountInfoItem(); accountInfoItem.setAccountId(userAccount.getId()); accountInfoItem.setBalance(userAccount.getBalance() != null ? userAccount.getBalance() : BigDecimal.ZERO); accountInfoItem.setRedeemBalance(userAccount.getRedeemBalance() != null ? userAccount.getRedeemBalance() : BigDecimal.ZERO); accountInfoItem.setIntegral(userAccount.getIntegral() != null ? userAccount.getIntegral() : BigDecimal.ZERO); QueryUserInfoResponseData responseData = QueryUserInfoResponseData.of(isNewUser, userInfoItem, accountInfoItem); log.info("根据手机号查询用户信息成功, operatorId: {}, phone: {}, isNewUser: {}", request.getOperatorId(), phone, isNewUser); return buildSuccessResponse(responseData, thirdPartyInfo); } catch (Exception e) { log.error("处理query_user_info请求异常", e); return buildErrorResponse(500, "系统错误", null); } } @Override public ThirdPartyResponse chargeOrderPay(ThirdPartyRequest request, String authorization) { try { // 1. 参数校验 if (!validateRequestParams(request)) { return buildErrorResponse(4003, "参数不合法,缺少必需的参数", null); } // 2. 通过operatorId查询第三方配置信息 ThirdPartyInfo thirdPartyInfo = getThirdPartyInfoByOperatorId(request.getOperatorId()); if (thirdPartyInfo == null) { log.warn("运营商不存在, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4004, "运营商不存在", null); } // 3. 验证签名 String signContent = request.getOperatorId() + request.getData() + request.getTimeStamp() + request.getSeq(); if (!HmacMD5Util.verify(signContent, thirdPartyInfo.getSigSecret(), request.getSig())) { log.warn("签名验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4001, "签名错误", thirdPartyInfo); } // 4. 从Header中解析并验证Token String accessToken = parseAccessToken(authorization); if (StrUtil.isBlank(accessToken)) { log.warn("Token为空或格式错误, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } if (!validateAccessToken(accessToken, request.getOperatorId())) { log.warn("Token验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } // 5. 解密并解析业务参数 String decryptedData = AESCryptoUtils.decrypt( request.getData(), thirdPartyInfo.getDataSecret(), thirdPartyInfo.getDataSecretIV() ); log.info("解密后的请求数据: {}", decryptedData); ChangeOrderPayRequestData payRequest = objectMapper.readValue(decryptedData, ChangeOrderPayRequestData.class); if (payRequest == null || StrUtil.isBlank(payRequest.getPhone()) || StrUtil.isBlank(payRequest.getOrderNo())) { log.warn("请求参数不完整, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4004, "请求的业务参数不合法,手机号和订单号不能为空", thirdPartyInfo); } Long userId = payRequest.getUserId(); String phone = payRequest.getPhone(); //根据userId和phone校验用户 UserInfo userInfo = userInfoService.getOne(Wrappers.lambdaQuery(UserInfo.class).eq(UserInfo::getPhone, phone).eq(UserInfo::getId, userId).last("limit 1")); if (ObjectUtil.isNull(userInfo)) { log.warn("用户不存在, userId: {}, phone: {}", userId, phone); ChargeOrderPayResponseData failData = ChargeOrderPayResponseData.fail("用户不存在"); return buildSuccessResponse(failData, thirdPartyInfo); } String orderNo = payRequest.getOrderNo(); UserAccount userAccount = userAccountService.getOne(Wrappers.lambdaQuery(UserAccount.class).eq(UserAccount::getUserId, userId).last("limit 1")); // 如果账户不存在,创建账户 if (ObjectUtil.isNull(userAccount)) { log.info("用户账户不存在,创建账户, userId: {}", userInfo.getId()); userAccount = new UserAccount(); userAccount.setUserId(userInfo.getId()); userAccount.setBalance(BigDecimal.ZERO); userAccount.setRedeemBalance(BigDecimal.ZERO); userAccount.setIntegral(BigDecimal.ZERO); userAccountMapper.insert(userAccount); } // 6. 幂等性检查 - 通过Redis检查订单是否已处理 String orderKey = "third_party_pay:order:" + orderNo; Boolean isProcessed = redisTemplate.hasKey(orderKey); if (Boolean.TRUE.equals(isProcessed)) { log.warn("订单已处理,请勿重复提交, orderNo: {}", orderNo); ChargeOrderPayResponseData failData = ChargeOrderPayResponseData.fail("订单已处理,请勿重复提交"); return buildSuccessResponse(failData, thirdPartyInfo); } // 7. 查询充值档位信息(如果有levelId) BigDecimal rechargeMoney; if (payRequest.getLevelId() != null) { RechargeLevel rechargeLevel = rechargeLevelMapper.selectById(payRequest.getLevelId()); if (rechargeLevel == null) { log.warn("充值档位不存在, levelId: {}", payRequest.getLevelId()); ChargeOrderPayResponseData failData = ChargeOrderPayResponseData.fail("充值档位不存在"); return buildSuccessResponse(failData, thirdPartyInfo); } rechargeMoney = rechargeLevel.getMoney(); } else if (StrUtil.isNotBlank(payRequest.getTotalMoney())) { // 使用传入的金额 rechargeMoney = new BigDecimal(payRequest.getTotalMoney()); } else { log.warn("充值金额未指定, operatorId: {}", request.getOperatorId()); ChargeOrderPayResponseData failData = ChargeOrderPayResponseData.fail("充值金额未指定"); return buildSuccessResponse(failData, thirdPartyInfo); } // 8. 增加充值订单记录到c_user_order_info表 UserOrderInfo orderInfo = new UserOrderInfo(); orderInfo.setUserId(userId); orderInfo.setOrderNo(orderNo); orderInfo.setOrderMoney(rechargeMoney); orderInfo.setPayMoney(rechargeMoney); orderInfo.setLastMoney(rechargeMoney); // 解析支付时间 if (StrUtil.isNotBlank(payRequest.getPayTime())) { try { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); orderInfo.setPayTime(LocalDateTime.parse(payRequest.getPayTime(), formatter)); } catch (Exception e) { orderInfo.setPayTime(LocalDateTime.now()); } } else { orderInfo.setPayTime(LocalDateTime.now()); } orderInfo.setLevelId(payRequest.getLevelId()); orderInfo.setOutTradeNo(orderNo); // 第三方订单号 orderInfo.setOrderStatus(2); // 已支付 orderInfo.setOrderType(3); // 渠道方 orderInfo.setRemark("第三方渠道充值-" + request.getOperatorId()); userOrderInfoMapper.insert(orderInfo); log.info("创建充值订单记录成功, orderNo: {}, userId: {}", orderNo, userId); // 9. 充值账户余额并记录日志 // 使用订单号的Id值作为变更记录ID Long changeId = orderInfo.getId(); UserAccount updatedAccount = userAccountService.updateAccountBalanceAndLog( userId, rechargeMoney, SystemConstants.CHANGE_TYPE_ADD, SystemConstants.ACCOUNT_LOG_THIRD_PARTY_PAY_NOTE + "-" + orderNo, changeId ); BigDecimal balanceAfter = updatedAccount != null ? updatedAccount.getBalance() : userAccount.getBalance().add(rechargeMoney); // 10. 构建成功响应 ChargeOrderPayResponseData responseData = ChargeOrderPayResponseData.success( userId, rechargeMoney, balanceAfter, orderNo ); log.info("充电券购买成功, operatorId: {}, phone: {}, orderNo: {}, rechargeMoney: {}, balanceAfter: {}", request.getOperatorId(), phone, orderNo, rechargeMoney, balanceAfter); return buildSuccessResponse(responseData, thirdPartyInfo); } catch (Exception e) { log.error("处理charge_order_pay请求异常", e); return buildErrorResponse(500, "系统错误", null); } } /** * 从Authorization Header中解析Token * 支持格式: "Bearer {token}" 或直接传 "{token}" */ private String parseAccessToken(String authorization) { if (StrUtil.isBlank(authorization)) { return null; } // 支持 Bearer Token 格式 if (authorization.startsWith("Bearer ")) { return authorization.substring(7).trim(); } // 直接返回Token return authorization.trim(); } /** * 验证访问Token */ private boolean validateAccessToken(String accessToken, String operatorId) { String tokenKey = TOKEN_KEY_PREFIX + accessToken; String storedOperatorId = (String) redisTemplate.opsForValue().get(tokenKey); return operatorId.equals(storedOperatorId); } /** * 从数据库查询充值档位分页数据 */ private IPage queryRechargeLevelFromDb(RechargeLevelPageRequestData pageRequest) { Page page = new Page<>(pageRequest.getPageNum(), pageRequest.getPageSize()); LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); // 按ID排序 queryWrapper.eq(RechargeLevel::getStatus, SystemConstants.STATUS_ONE); queryWrapper.orderByAsc(RechargeLevel::getId); return rechargeLevelMapper.selectPage(page, queryWrapper); } /** * 转换为响应项 */ private RechargeLevelPageResponseData.RechargeLevelItem convertToItem(RechargeLevel entity) { RechargeLevelPageResponseData.RechargeLevelItem item = new RechargeLevelPageResponseData.RechargeLevelItem(); item.setId(entity.getId()); item.setName(entity.getName()); item.setMoney(entity.getMoney()); item.setStatus(entity.getStatus()); item.setTips(entity.getTips()); return item; } /** * 通过operatorId查询第三方配置信息 */ private ThirdPartyInfo getThirdPartyInfoByOperatorId(String operatorId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(ThirdPartyInfo::getOperatorId, operatorId) .eq(ThirdPartyInfo::getStatus, 0) // 状态正常 .last("LIMIT 1"); return thirdPartyInfoMapper.selectOne(queryWrapper); } /** * 校验请求参数完整性 */ private boolean validateRequestParams(ThirdPartyRequest request) { return request != null && StrUtil.isNotBlank(request.getOperatorId()) && StrUtil.isNotBlank(request.getData()) && StrUtil.isNotBlank(request.getTimeStamp()) && StrUtil.isNotBlank(request.getSeq()) && StrUtil.isNotBlank(request.getSig()); } /** * 获取或生成Token * 如果Redis中存在有效Token则返回,否则生成新Token */ private String getOrGenerateToken(String operatorId) { // 检查是否有已存在的有效Token String operatorTokenKey = OPERATOR_TOKEN_KEY_PREFIX + operatorId; String existingToken = (String) redisTemplate.opsForValue().get(operatorTokenKey); if (StrUtil.isNotBlank(existingToken)) { // 验证Token是否仍然有效 String tokenKey = TOKEN_KEY_PREFIX + existingToken; Boolean hasKey = redisTemplate.hasKey(tokenKey); if (Boolean.TRUE.equals(hasKey)) { log.info("返回已存在的有效Token, operatorId: {}", operatorId); return existingToken; } } // 生成新Token String newToken = IdUtil.fastSimpleUUID() + IdUtil.fastSimpleUUID(); // 存储Token String tokenKey = TOKEN_KEY_PREFIX + newToken; redisTemplate.opsForValue().set(tokenKey, operatorId, DEFAULT_TOKEN_EXPIRE_SECONDS, TimeUnit.SECONDS); // 存储OperatorId与Token的映射关系 redisTemplate.opsForValue().set(operatorTokenKey, newToken, DEFAULT_TOKEN_EXPIRE_SECONDS, TimeUnit.SECONDS); log.info("生成新Token, operatorId: {}, expireSeconds: {}", operatorId, DEFAULT_TOKEN_EXPIRE_SECONDS); return newToken; } /** * 获取Token剩余有效时间(秒) */ private Integer getRemainingTTL(String token) { String tokenKey = TOKEN_KEY_PREFIX + token; Long ttl = redisTemplate.getExpire(tokenKey, TimeUnit.SECONDS); return ttl != null && ttl > 0 ? ttl.intValue() : 0; } /** * 构建成功响应(通用) */ private ThirdPartyResponse buildSuccessResponse(Object responseData, ThirdPartyInfo thirdPartyInfo) throws Exception { String jsonData = objectMapper.writeValueAsString(responseData); String encryptedData = AESCryptoUtils.encrypt( jsonData, thirdPartyInfo.getDataSecret(), thirdPartyInfo.getDataSecretIV() ); String sig = HmacMD5Util.genSign(0, "", encryptedData, thirdPartyInfo.getSigSecret()); return ThirdPartyResponse.success(encryptedData, sig); } /** * 构建错误响应 */ private ThirdPartyResponse buildErrorResponse(Integer ret, String msg, ThirdPartyInfo thirdPartyInfo) { try { String sigSecret = thirdPartyInfo != null ? thirdPartyInfo.getSigSecret() : ""; String sig = StrUtil.isNotBlank(sigSecret) ? HmacMD5Util.genSign(ret, msg, "", sigSecret) : ""; return ThirdPartyResponse.error(ret, msg, sig); } catch (Exception e) { log.error("生成错误响应签名失败", e); ThirdPartyResponse response = new ThirdPartyResponse(); response.setRet(ret); response.setMsg(msg); response.setData(""); response.setSig(""); return response; } } // ==================== 充电站与设备查询接口 ==================== /** * 时间格式化器 HHmmss */ private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HHmmss"); @Override public ThirdPartyResponse queryChargeStationList(ThirdPartyRequest request, String authorization) { try { // 1. 参数校验 if (!validateRequestParams(request)) { return buildErrorResponse(4003, "参数不合法,缺少必需的参数", null); } // 2. 通过operatorId查询第三方配置信息 ThirdPartyInfo thirdPartyInfo = getThirdPartyInfoByOperatorId(request.getOperatorId()); if (thirdPartyInfo == null) { log.warn("运营商不存在, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4004, "运营商不存在", null); } // 3. 验证签名 String signContent = request.getOperatorId() + request.getData() + request.getTimeStamp() + request.getSeq(); if (!HmacMD5Util.verify(signContent, thirdPartyInfo.getSigSecret(), request.getSig())) { log.warn("签名验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4001, "签名错误", thirdPartyInfo); } // 4. 从Header中解析并验证Token String accessToken = parseAccessToken(authorization); if (StrUtil.isBlank(accessToken)) { log.warn("Token为空或格式错误, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } if (!validateAccessToken(accessToken, request.getOperatorId())) { log.warn("Token验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } // 5. 解密并解析业务参数 String decryptedData = AESCryptoUtils.decrypt( request.getData(), thirdPartyInfo.getDataSecret(), thirdPartyInfo.getDataSecretIV() ); log.info("解密后的请求数据: {}", decryptedData); ChargeStationListRequestData listRequest = objectMapper.readValue(decryptedData, ChargeStationListRequestData.class); if (listRequest == null) { listRequest = new ChargeStationListRequestData(); } // 6. 查询充电站分页数据 // 获取当前时间(HHmmss格式) String currentTime = LocalTime.now().format(TIME_FORMATTER); // 构建分页对象 Page page = new Page<>(listRequest.getPageNum(), listRequest.getPageSize()); StationInfoQuery stationInfoQuery = new StationInfoQuery().setLatitude(listRequest.getLatitude()).setLongitude(listRequest.getLongitude()).setSortType(listRequest.getSortType()); // 执行查询 IPage pageResult = thirdPartyStationInfoMapper.selectAppletStationInfoPage( page, stationInfoQuery, currentTime, null ); // 7. 转换为响应数据 List records = pageResult.getRecords().stream() .map(this::convertToStationItem) .collect(Collectors.toList()); ChargeStationListResponseData responseData = ChargeStationListResponseData.of( pageResult.getTotal(), pageResult.getCurrent(), pageResult.getSize(), pageResult.getPages(), records ); log.info("查询充电站列表成功, operatorId: {}, total: {}", request.getOperatorId(), pageResult.getTotal()); return buildSuccessResponse(responseData, thirdPartyInfo); } catch (Exception e) { log.error("处理query_charge_station_list请求异常", e); return buildErrorResponse(500, "系统错误", null); } } @Override public ThirdPartyResponse queryChargeStationDetail(ThirdPartyRequest request, String authorization) { try { // 1. 参数校验 if (!validateRequestParams(request)) { return buildErrorResponse(4003, "参数不合法,缺少必需的参数", null); } // 2. 通过operatorId查询第三方配置信息 ThirdPartyInfo thirdPartyInfo = getThirdPartyInfoByOperatorId(request.getOperatorId()); if (thirdPartyInfo == null) { log.warn("运营商不存在, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4004, "运营商不存在", null); } // 3. 验证签名 String signContent = request.getOperatorId() + request.getData() + request.getTimeStamp() + request.getSeq(); if (!HmacMD5Util.verify(signContent, thirdPartyInfo.getSigSecret(), request.getSig())) { log.warn("签名验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4001, "签名错误", thirdPartyInfo); } // 4. 从Header中解析并验证Token String accessToken = parseAccessToken(authorization); if (StrUtil.isBlank(accessToken)) { log.warn("Token为空或格式错误, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } if (!validateAccessToken(accessToken, request.getOperatorId())) { log.warn("Token验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } // 5. 解密并解析业务参数 String decryptedData = AESCryptoUtils.decrypt( request.getData(), thirdPartyInfo.getDataSecret(), thirdPartyInfo.getDataSecretIV() ); log.info("解密后的请求数据: {}", decryptedData); ChargeStationDetailRequestData detailRequest = objectMapper.readValue(decryptedData, ChargeStationDetailRequestData.class); if (detailRequest == null || (detailRequest.getStationId() == null )) { return buildErrorResponse(4003, "请求的业务参数不合法", thirdPartyInfo); } // 6. 查询充电站详情 // 获取当前时间(HHmmss格式) String currentTime = LocalTime.now().format(TIME_FORMATTER); // 查询站点详情基本信息 AppletStationDetailVO result = thirdPartyStationInfoMapper.selectStationDetail( detailRequest.getStationId(), detailRequest.getLongitude(), detailRequest.getLatitude(), currentTime, null ); if (result == null) { return buildErrorResponse(4004, "充电站不存在", thirdPartyInfo); } // 查询站点对应的stationId ThirdPartyStationInfo stationInfo = thirdPartyStationInfoMapper.selectById(detailRequest.getStationId()); if (stationInfo == null) { return buildErrorResponse(4004, "充电站不存在", thirdPartyInfo); } // 根据站点stationId查询设备列表(third_party_equipment_info) List equipmentList = thirdPartyEquipmentInfoMapper.selectList( new LambdaQueryWrapper() .eq(ThirdPartyEquipmentInfo::getStationId, stationInfo.getStationId()) ); // 构建设备ID到设备类型的映射 Map equipmentTypeMap = equipmentList.stream() .collect(Collectors.toMap( ThirdPartyEquipmentInfo::getEquipmentId, e -> e.getEquipmentType() != null ? e.getEquipmentType() : 0, (v1, v2) -> v1 )); // 根据设备列表的equipmentId查询充电接口信息(third_party_connector_info) List connectorList = new ArrayList<>(); if (!equipmentList.isEmpty()) { List equipmentIds = equipmentList.stream() .map(ThirdPartyEquipmentInfo::getEquipmentId) .collect(Collectors.toList()); connectorList = thirdPartyConnectorInfoMapper.selectList( new LambdaQueryWrapper() .in(ThirdPartyConnectorInfo::getEquipmentId, equipmentIds) ); } // 统计终端状态 int idleCount = 0; int occupiedCount = 0; int offlineCount = 0; List connectorVOList = new ArrayList<>(); for (ThirdPartyConnectorInfo connector : connectorList) { AppletStationDetailVO.ConnectorInfoVO vo = new AppletStationDetailVO.ConnectorInfoVO(); vo.setConnectorId(connector.getId()); vo.setConnectorName(connector.getConnectorName()); vo.setConnectorCode(connector.getConnectorId()); // 设备分类:从设备表获取设备类型(1-直流设备,2-交流设备,3-交直流一体设备,4-无线设备,5-其他) Integer equipmentType = equipmentTypeMap.get(connector.getEquipmentId()); if (equipmentType != null) { switch (equipmentType) { case 1: vo.setEquipmentType("直流设备"); break; case 2: vo.setEquipmentType("交流设备"); break; case 3: vo.setEquipmentType("交直流一体设备"); break; case 4: vo.setEquipmentType("无线设备"); break; case 5: vo.setEquipmentType("其他"); break; default: vo.setEquipmentType("未知"); } } // 从充电接口表获取实际状态 // 0-离网,1-空闲,2-占用(未充电),3-占用(充电中),4-占用(预约锁定),255-故障 Integer connectorStatus = connector.getStatus(); if (connectorStatus == null) { // 默认为离网 connectorStatus = 0; } vo.setStatus(connectorStatus); // 设置状态名称并统计 switch (connectorStatus) { case 0: vo.setStatusName("离网"); offlineCount++; break; case 1: vo.setStatusName("空闲"); idleCount++; break; case 2: vo.setStatusName("占用(未充电)"); occupiedCount++; break; case 3: vo.setStatusName("占用(充电中)"); occupiedCount++; break; case 4: vo.setStatusName("占用(预约锁定)"); occupiedCount++; break; case 255: vo.setStatusName("故障"); offlineCount++; break; default: vo.setStatusName("未知"); offlineCount++; } connectorVOList.add(vo); } result.setConnectorList(connectorVOList); result.setIdleCount(idleCount); result.setOccupiedCount(occupiedCount); result.setOfflineCount(offlineCount); // 7. 转换为响应数据 ChargeStationDetailResponseData responseData = convertToStationDetail(result); log.info("查询充电站详情成功, operatorId: {}, stationId: {}", request.getOperatorId(), stationInfo.getStationId()); return buildSuccessResponse(responseData, thirdPartyInfo); } catch (Exception e) { log.error("处理query_charge_station_detail请求异常", e); return buildErrorResponse(500, "系统错误", null); } } @Override public ThirdPartyResponse queryChargeDeviceDetail(ThirdPartyRequest request, String authorization) { try { // 1. 参数校验 if (!validateRequestParams(request)) { return buildErrorResponse(4003, "参数不合法,缺少必需的参数", null); } // 2. 通过operatorId查询第三方配置信息 ThirdPartyInfo thirdPartyInfo = getThirdPartyInfoByOperatorId(request.getOperatorId()); if (thirdPartyInfo == null) { log.warn("运营商不存在, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4004, "运营商不存在", null); } // 3. 验证签名 String signContent = request.getOperatorId() + request.getData() + request.getTimeStamp() + request.getSeq(); if (!HmacMD5Util.verify(signContent, thirdPartyInfo.getSigSecret(), request.getSig())) { log.warn("签名验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4001, "签名错误", thirdPartyInfo); } // 4. 从Header中解析并验证Token String accessToken = parseAccessToken(authorization); if (StrUtil.isBlank(accessToken)) { log.warn("Token为空或格式错误, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } if (!validateAccessToken(accessToken, request.getOperatorId())) { log.warn("Token验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } // 5. 解密并解析业务参数 String decryptedData = AESCryptoUtils.decrypt( request.getData(), thirdPartyInfo.getDataSecret(), thirdPartyInfo.getDataSecretIV() ); log.info("解密后的请求数据: {}", decryptedData); ChargeDeviceDetailRequestData detailRequest = objectMapper.readValue(decryptedData, ChargeDeviceDetailRequestData.class); if (detailRequest == null || (detailRequest.getId() == null && StrUtil.isBlank(detailRequest.getEquipmentId()))) { return buildErrorResponse(4003, "请求的业务参数不合法", thirdPartyInfo); } // 6. 查询充电设备详情 // 获取当前时间(HHmmss格式) String currentTime = LocalTime.now().format(TIME_FORMATTER); AppletConnectorDetailVO result = thirdPartyConnectorInfoMapper.selectConnectorDetailById( detailRequest.getEquipmentId(), null, currentTime, null, null ); // 8. 转换为响应数据 ChargeDeviceDetailResponseData responseData = convertToDeviceDetail(result); log.info("查询充电终端详情成功, operatorId: {}, equipmentId: {}", request.getOperatorId(), result.getConnectorId()); return buildSuccessResponse(responseData, thirdPartyInfo); } catch (Exception e) { log.error("处理query_charge_device_detail请求异常", e); return buildErrorResponse(500, "系统错误", null); } } /** * 转换充电站信息为详情响应(从AppletStationDetailVO转换) */ private ChargeStationDetailResponseData convertToStationDetail(AppletStationDetailVO result) { ChargeStationDetailResponseData detail = new ChargeStationDetailResponseData(); detail.setStationId(result.getStationId()); detail.setStationName(result.getStationName()); detail.setTips(result.getTips()); detail.setDistance(result.getDistance()); detail.setAddress(result.getAddress()); detail.setLongitude(result.getLongitude()); detail.setLatitude(result.getLatitude()); detail.setPictures(result.getPictures()); detail.setCurrentPrice(result.getCurrentPrice()); detail.setCurrentPeriod(result.getCurrentPeriod()); detail.setOriginalPrice(result.getOriginalPrice()); detail.setPeriodFlag(result.getPeriodFlag()); detail.setIdleCount(result.getIdleCount()); detail.setOccupiedCount(result.getOccupiedCount()); detail.setOfflineCount(result.getOfflineCount()); detail.setBusinessHours(result.getBusinessHours()); detail.setServiceProvider(result.getServiceProvider()); detail.setInvoiceProvider(result.getInvoiceProvider()); detail.setCustomerServiceHotline(result.getCustomerServiceHotline()); // 转换充电终端列表 if (result.getConnectorList() != null) { List connectorVOList = result.getConnectorList().stream() .map(connector -> { ChargeStationDetailResponseData.ConnectorInfoVO vo = new ChargeStationDetailResponseData.ConnectorInfoVO(); vo.setConnectorId(connector.getConnectorId()); vo.setConnectorName(connector.getConnectorName()); vo.setEquipmentType(connector.getEquipmentType()); vo.setConnectorCode(connector.getConnectorCode()); vo.setStatus(connector.getStatus()); vo.setStatusName(connector.getStatusName()); return vo; }) .collect(Collectors.toList()); detail.setConnectorList(connectorVOList); } return detail; } /** * 转换充电站信息为列表项 */ private ChargeStationListResponseData.StationItem convertToStationItem(StationInfoVO stationInfoVO) { ChargeStationListResponseData.StationItem item = new ChargeStationListResponseData.StationItem(); item.setStationId(stationInfoVO.getStationId()); item.setStationName(stationInfoVO.getStationName()); item.setTips(stationInfoVO.getTips()); item.setDistance(stationInfoVO.getDistance()); item.setFastCharging(stationInfoVO.getFastCharging()); item.setSlowCharging(stationInfoVO.getSlowCharging()); item.setPeakValue(stationInfoVO.getPeakValue()); item.setPeakTime(stationInfoVO.getPeakTime()); item.setPeriodFlag(stationInfoVO.getPeriodFlag()); item.setPlatformPrice(stationInfoVO.getPlatformPrice()); return item; } /** * 转换充电设备信息为详情响应(从AppletConnectorDetailVO转换) */ private ChargeDeviceDetailResponseData convertToDeviceDetail(AppletConnectorDetailVO connectorDetail) { ChargeDeviceDetailResponseData detail = new ChargeDeviceDetailResponseData(); detail.setConnectorId(connectorDetail.getConnectorId()); detail.setConnectorCode(connectorDetail.getConnectorCode()); detail.setConnectorName(connectorDetail.getConnectorName()); detail.setStationId(connectorDetail.getStationId()); detail.setStationName(connectorDetail.getStationName()); detail.setStationAddress(connectorDetail.getStationAddress()); detail.setEquipmentId(connectorDetail.getEquipmentId()); detail.setEquipmentCode(connectorDetail.getEquipmentCode()); detail.setEquipmentName(connectorDetail.getEquipmentName()); detail.setEquipmentType(connectorDetail.getEquipmentType()); detail.setEquipmentTypeName(connectorDetail.getEquipmentTypeName()); detail.setParkNo(connectorDetail.getParkNo()); detail.setStatus(connectorDetail.getStatus()); detail.setStatusName(connectorDetail.getStatusName()); detail.setConnectorType(connectorDetail.getConnectorType()); detail.setConnectorTypeName(connectorDetail.getConnectorTypeName()); detail.setVoltageUpperLimits(connectorDetail.getVoltageUpperLimits()); detail.setVoltageLowerLimits(connectorDetail.getVoltageLowerLimits()); detail.setCurrent(connectorDetail.getCurrent()); detail.setPower(connectorDetail.getPower()); detail.setNationalStandard(connectorDetail.getNationalStandard()); detail.setNationalStandardName(connectorDetail.getNationalStandardName()); detail.setCurrentPrice(connectorDetail.getCurrentPrice()); detail.setPeriodFlag(connectorDetail.getPeriodFlag()); detail.setCurrentPeriodDesc(connectorDetail.getCurrentPeriodDesc()); detail.setParkingTips(connectorDetail.getParkingTips()); return detail; } @Override public ThirdPartyResponse invokeCharge(ThirdPartyRequest request, String authorization) { try { // 1. 参数校验 if (!validateRequestParams(request)) { return buildErrorResponse(4003, "参数不合法,缺少必需的参数", null); } // 2. 通过operatorId查询第三方配置信息 ThirdPartyInfo thirdPartyInfo = getThirdPartyInfoByOperatorId(request.getOperatorId()); if (thirdPartyInfo == null) { log.warn("运营商不存在, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4004, "运营商不存在", null); } // 3. 验证签名 String signContent = request.getOperatorId() + request.getData() + request.getTimeStamp() + request.getSeq(); if (!HmacMD5Util.verify(signContent, thirdPartyInfo.getSigSecret(), request.getSig())) { log.warn("签名验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4001, "签名错误", thirdPartyInfo); } // 4. 从Header中解析并验证Token String accessToken = parseAccessToken(authorization); if (StrUtil.isBlank(accessToken)) { log.warn("Token为空或格式错误, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } if (!validateAccessToken(accessToken, request.getOperatorId())) { log.warn("Token验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } // 5. 解密并解析业务参数 String decryptedData = AESCryptoUtils.decrypt( request.getData(), thirdPartyInfo.getDataSecret(), thirdPartyInfo.getDataSecretIV() ); log.info("启动充电-解密后的请求数据: {}", decryptedData); InvokeChargeRequestData invokeRequest = objectMapper.readValue(decryptedData, InvokeChargeRequestData.class); if (invokeRequest == null || StrUtil.isBlank(invokeRequest.getEquipmentId()) || StrUtil.isBlank(invokeRequest.getStationId()) || StrUtil.isBlank(invokeRequest.getConnectorId())) { return buildErrorResponse(4003, "请求的业务参数不合法", thirdPartyInfo); } // 6. 构建启动充电表单 AppInvokeChargeForm formData = new AppInvokeChargeForm(); formData.setOrderType(2); // 渠道方订单 formData.setEquipmentId(invokeRequest.getEquipmentId()); formData.setStationId(invokeRequest.getStationId()); formData.setConnectorId(invokeRequest.getConnectorId()); formData.setChannelOrderNo(invokeRequest.getChannelOrderNo()); formData.setChannelUserPhone(invokeRequest.getChannelUserPhone()); formData.setChannelPreAmt(invokeRequest.getChannelPreAmt()); // 7. 调用启动充电服务 AppChargeVO chargeVO = chargeOrderInfoService.invokeCharge(formData); // 8. 构建响应数据 InvokeChargeResponseData responseData = InvokeChargeResponseData.success( chargeVO.getChargeOrderId(), chargeVO.getChargeOrderNo(), chargeVO.getStatus() ); log.info("启动充电成功, chargeOrderNo: {}", chargeVO.getChargeOrderNo()); return buildSuccessResponse(responseData, thirdPartyInfo); } catch (Exception e) { log.error("处理invoke_charge请求异常", e); return buildErrorResponse(500, "系统错误: " + e.getMessage(), null); } } @Override public ThirdPartyResponse stopCharge(ThirdPartyRequest request, String authorization) { try { // 1. 参数校验 if (!validateRequestParams(request)) { return buildErrorResponse(4003, "参数不合法,缺少必需的参数", null); } // 2. 通过operatorId查询第三方配置信息 ThirdPartyInfo thirdPartyInfo = getThirdPartyInfoByOperatorId(request.getOperatorId()); if (thirdPartyInfo == null) { log.warn("运营商不存在, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4004, "运营商不存在", null); } // 3. 验证签名 String signContent = request.getOperatorId() + request.getData() + request.getTimeStamp() + request.getSeq(); if (!HmacMD5Util.verify(signContent, thirdPartyInfo.getSigSecret(), request.getSig())) { log.warn("签名验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4001, "签名错误", thirdPartyInfo); } // 4. 从Header中解析并验证Token String accessToken = parseAccessToken(authorization); if (StrUtil.isBlank(accessToken)) { log.warn("Token为空或格式错误, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } if (!validateAccessToken(accessToken, request.getOperatorId())) { log.warn("Token验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } // 5. 解密并解析业务参数 String decryptedData = AESCryptoUtils.decrypt( request.getData(), thirdPartyInfo.getDataSecret(), thirdPartyInfo.getDataSecretIV() ); log.info("停止充电-解密后的请求数据: {}", decryptedData); StopChargeRequestData stopRequest = objectMapper.readValue(decryptedData, StopChargeRequestData.class); if (stopRequest == null || StrUtil.isBlank(stopRequest.getChargeOrderNo())) { return buildErrorResponse(4003, "请求的业务参数不合法", thirdPartyInfo); } // 6. 构建停止充电表单 AppStopChargeForm formData = new AppStopChargeForm(); formData.setChargeOrderNo(stopRequest.getChargeOrderNo()); // 7. 调用停止充电服务 AppChargeVO chargeVO = chargeOrderInfoService.stopCharge(formData); // 8. 构建响应数据 StopChargeResponseData responseData = StopChargeResponseData.success( chargeVO.getChargeOrderId(), chargeVO.getChargeOrderNo(), chargeVO.getStatus() ); log.info("停止充电成功, chargeOrderNo: {}", chargeVO.getChargeOrderNo()); return buildSuccessResponse(responseData, thirdPartyInfo); } catch (Exception e) { log.error("处理stop_charge请求异常", e); return buildErrorResponse(500, "系统错误: " + e.getMessage(), null); } } @Override public ThirdPartyResponse queryChargeOrderList(ThirdPartyRequest request, String authorization) { try { // 1. 参数校验 if (!validateRequestParams(request)) { return buildErrorResponse(4003, "参数不合法,缺少必需的参数", null); } // 2. 通过operatorId查询第三方配置信息 ThirdPartyInfo thirdPartyInfo = getThirdPartyInfoByOperatorId(request.getOperatorId()); if (thirdPartyInfo == null) { log.warn("运营商不存在, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4004, "运营商不存在", null); } // 3. 验证签名 String signContent = request.getOperatorId() + request.getData() + request.getTimeStamp() + request.getSeq(); if (!HmacMD5Util.verify(signContent, thirdPartyInfo.getSigSecret(), request.getSig())) { log.warn("签名验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4001, "签名错误", thirdPartyInfo); } // 4. 从Header中解析并验证Token String accessToken = parseAccessToken(authorization); if (StrUtil.isBlank(accessToken)) { log.warn("Token为空或格式错误, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } if (!validateAccessToken(accessToken, request.getOperatorId())) { log.warn("Token验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } // 5. 解密并解析业务参数 String decryptedData = AESCryptoUtils.decrypt( request.getData(), thirdPartyInfo.getDataSecret(), thirdPartyInfo.getDataSecretIV() ); log.info("查询充电订单列表-解密后的请求数据: {}", decryptedData); ChargeOrderListRequestData listRequest = objectMapper.readValue(decryptedData, ChargeOrderListRequestData.class); if (listRequest == null) { listRequest = new ChargeOrderListRequestData(); } // 6. 构建查询条件(只查询渠道类型订单 order_type=2) LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); queryWrapper.eq(com.zsElectric.boot.business.model.entity.ChargeOrderInfo::getOrderType, SystemConstants.CHARGE_ORDER_TYPE_CHANNEL); queryWrapper.eq(com.zsElectric.boot.business.model.entity.ChargeOrderInfo::getOperatorId, listRequest.getOperatorId()); queryWrapper.eq(com.zsElectric.boot.business.model.entity.ChargeOrderInfo::getIsDeleted, 0); // 可选条件:userId if (listRequest.getUserId() != null) { queryWrapper.eq(com.zsElectric.boot.business.model.entity.ChargeOrderInfo::getUserId, listRequest.getUserId()); } // 可选条件:chargeOrderNo if (StrUtil.isNotBlank(listRequest.getChargeOrderNo())) { queryWrapper.like(com.zsElectric.boot.business.model.entity.ChargeOrderInfo::getChargeOrderNo, listRequest.getChargeOrderNo()); } // 按创建时间倒序 queryWrapper.orderByDesc(com.zsElectric.boot.business.model.entity.ChargeOrderInfo::getCreateTime); // 7. 分页查询 long pageNo = listRequest.getPageNo() != null && listRequest.getPageNo() > 0 ? listRequest.getPageNo() : 1L; long pageSize = listRequest.getPageSize() != null && listRequest.getPageSize() > 0 ? listRequest.getPageSize() : 10L; Page page = new Page<>(pageNo, pageSize); IPage pageResult = chargeOrderInfoService.page(page, queryWrapper); // 8. 转换为响应数据 List records = pageResult.getRecords().stream() .map(this::convertToChargeOrderItem) .collect(Collectors.toList()); ChargeOrderListResponseData responseData = ChargeOrderListResponseData.of( pageResult.getTotal(), pageResult.getCurrent(), pageResult.getSize(), pageResult.getPages(), records ); log.info("查询充电订单列表成功, operatorId: {}, total: {}", request.getOperatorId(), pageResult.getTotal()); return buildSuccessResponse(responseData, thirdPartyInfo); } catch (Exception e) { log.error("处理query_charge_order_list请求异常", e); return buildErrorResponse(500, "系统错误: " + e.getMessage(), null); } } /** * 将ChargeOrderInfo转换为ChargeOrderItem */ private ChargeOrderListResponseData.ChargeOrderItem convertToChargeOrderItem(com.zsElectric.boot.business.model.entity.ChargeOrderInfo order) { ChargeOrderListResponseData.ChargeOrderItem item = new ChargeOrderListResponseData.ChargeOrderItem(); item.setId(order.getId()); item.setUserId(order.getUserId()); item.setChargeOrderNo(order.getChargeOrderNo()); item.setEquipmentId(order.getEquipmentId()); item.setConnectorId(order.getConnectorId()); item.setStartTime(order.getStartTime()); item.setEndTime(order.getEndTime()); item.setChargeTime(order.getChargeTime()); item.setTotalCharge(order.getTotalCharge()); item.setStatus(order.getStatus()); item.setPreAmt(order.getPreAmt()); item.setPhoneNum(order.getPhoneNum()); item.setPlateNum(order.getPlateNum()); item.setStopType(order.getStopType()); item.setStopReason(order.getStopReason()); item.setCreateTime(order.getCreateTime() != null ? order.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : null); // 查询充电站名称 if (order.getThirdPartyStationId() != null) { ThirdPartyStationInfo stationInfo = thirdPartyStationInfoMapper.selectById(order.getThirdPartyStationId()); if (stationInfo != null) { item.setStationName(stationInfo.getStationName()); } } // 查询充电设备接口名称 if (StrUtil.isNotBlank(order.getConnectorId())) { ThirdPartyConnectorInfo connectorInfo = thirdPartyConnectorInfoMapper.selectOne( Wrappers.lambdaQuery() .eq(ThirdPartyConnectorInfo::getConnectorId, order.getConnectorId()) .last("LIMIT 1") ); if (connectorInfo != null) { item.setConnectorName(connectorInfo.getConnectorName()); } } return item; } @Override public ThirdPartyResponse queryChargeOrderInfo(ThirdPartyRequest request, String authorization) { try { // 1. 参数校验 if (!validateRequestParams(request)) { return buildErrorResponse(4003, "参数不合法,缺少必需的参数", null); } // 2. 通过operatorId查询第三方配置信息 ThirdPartyInfo thirdPartyInfo = getThirdPartyInfoByOperatorId(request.getOperatorId()); if (thirdPartyInfo == null) { log.warn("运营商不存在, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4004, "运营商不存在", null); } // 3. 验证签名 String signContent = request.getOperatorId() + request.getData() + request.getTimeStamp() + request.getSeq(); if (!HmacMD5Util.verify(signContent, thirdPartyInfo.getSigSecret(), request.getSig())) { log.warn("签名验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4001, "签名错误", thirdPartyInfo); } // 4. 从Header中解析并验证Token String accessToken = parseAccessToken(authorization); if (StrUtil.isBlank(accessToken)) { log.warn("Token为空或格式错误, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } if (!validateAccessToken(accessToken, request.getOperatorId())) { log.warn("Token验证失败, operatorId: {}", request.getOperatorId()); return buildErrorResponse(4002, "token错误", thirdPartyInfo); } // 5. 解密并解析业务参数 String decryptedData = AESCryptoUtils.decrypt( request.getData(), thirdPartyInfo.getDataSecret(), thirdPartyInfo.getDataSecretIV() ); log.info("查询充电订单详情-解密后的请求数据: {}", decryptedData); ChargeOrderDetailRequestData detailRequest = objectMapper.readValue(decryptedData, ChargeOrderDetailRequestData.class); if (detailRequest == null || StrUtil.isBlank(detailRequest.getChargeOrderNo())) { return buildErrorResponse(4003, "请求的业务参数不合法,chargeOrderNo不能为空", thirdPartyInfo); } // 6. 查询订单(只查询渠道类型订单 order_type=2) com.zsElectric.boot.business.model.entity.ChargeOrderInfo order = chargeOrderInfoService.getOne( Wrappers.lambdaQuery() .eq(com.zsElectric.boot.business.model.entity.ChargeOrderInfo::getChargeOrderNo, detailRequest.getChargeOrderNo()) .eq(com.zsElectric.boot.business.model.entity.ChargeOrderInfo::getOrderType, SystemConstants.CHARGE_ORDER_TYPE_CHANNEL) .eq(com.zsElectric.boot.business.model.entity.ChargeOrderInfo::getIsDeleted, 0) .last("LIMIT 1") ); if (order == null) { log.warn("充电订单不存在或不是渠道订单, chargeOrderNo: {}", detailRequest.getChargeOrderNo()); ChargeOrderDetailResponseData failData = ChargeOrderDetailResponseData.fail("充电订单不存在或不是渠道订单"); return buildSuccessResponse(failData, thirdPartyInfo); } // 7. 构建响应数据 ChargeOrderDetailResponseData responseData = ChargeOrderDetailResponseData.success(); responseData.setId(order.getId()); responseData.setUserId(order.getUserId()); responseData.setChargeOrderNo(order.getChargeOrderNo()); responseData.setEquipmentId(order.getEquipmentId()); responseData.setConnectorId(order.getConnectorId()); responseData.setStartTime(order.getStartTime()); responseData.setEndTime(order.getEndTime()); responseData.setChargeTime(order.getChargeTime()); responseData.setTotalCharge(order.getTotalCharge()); responseData.setStatus(order.getStatus()); responseData.setPreAmt(order.getPreAmt()); responseData.setPhoneNum(order.getPhoneNum()); responseData.setPlateNum(order.getPlateNum()); responseData.setStopType(order.getStopType()); responseData.setStopReason(order.getStopReason()); responseData.setCreateTime(order.getCreateTime() != null ? order.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : null); // 查询充电站名称 if (order.getThirdPartyStationId() != null) { ThirdPartyStationInfo stationInfo = thirdPartyStationInfoMapper.selectById(order.getThirdPartyStationId()); if (stationInfo != null) { responseData.setStationName(stationInfo.getStationName()); } } // 查询充电设备接口名称 if (StrUtil.isNotBlank(order.getConnectorId())) { ThirdPartyConnectorInfo connectorInfo = thirdPartyConnectorInfoMapper.selectOne( Wrappers.lambdaQuery() .eq(ThirdPartyConnectorInfo::getConnectorId, order.getConnectorId()) .last("LIMIT 1") ); if (connectorInfo != null) { responseData.setConnectorName(connectorInfo.getConnectorName()); } } log.info("查询充电订单详情成功, chargeOrderNo: {}", detailRequest.getChargeOrderNo()); return buildSuccessResponse(responseData, thirdPartyInfo); } catch (Exception e) { log.error("处理query_charge_order_info请求异常", e); return buildErrorResponse(500, "系统错误: " + e.getMessage(), null); } } }