diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/dto/nanrui/PushAlarmInfoDTO.java b/jsowell-pile/src/main/java/com/jsowell/pile/dto/nanrui/PushAlarmInfoDTO.java new file mode 100644 index 000000000..412e4dba2 --- /dev/null +++ b/jsowell-pile/src/main/java/com/jsowell/pile/dto/nanrui/PushAlarmInfoDTO.java @@ -0,0 +1,23 @@ +package com.jsowell.pile.dto.nanrui; + +import com.jsowell.pile.dto.PushStationInfoDTO; +import lombok.Data; + +/** + * 推送告警信息DTO + * + * @author Lemon + * @Date 2023/10/12 15:33 + */ +@Data +public class PushAlarmInfoDTO extends PushStationInfoDTO { + /** + * 枪口号 + */ + private String pileConnectorCode; + + /** + * 枪口状态 + */ + private String connectorStatus; +} diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/mapper/OrderBasicInfoMapper.java b/jsowell-pile/src/main/java/com/jsowell/pile/mapper/OrderBasicInfoMapper.java index 3228cbfe7..ee66087fc 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/mapper/OrderBasicInfoMapper.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/mapper/OrderBasicInfoMapper.java @@ -7,6 +7,7 @@ import com.jsowell.pile.dto.*; import com.jsowell.pile.dto.nanrui.NRQueryOrderDTO; import com.jsowell.pile.vo.base.MerchantOrderInfoVO; import com.jsowell.pile.vo.lianlian.AccumulativeInfoVO; +import com.jsowell.pile.vo.nanrui.NROrderInfoVO; import com.jsowell.pile.vo.uniapp.OrderVO; import com.jsowell.pile.vo.uniapp.PersonPileConnectorSumInfoVO; import com.jsowell.pile.vo.uniapp.SendMessageVO; @@ -254,5 +255,5 @@ public interface OrderBasicInfoMapper { * @param dto * @return */ - List getNROrderInfoByOrderCode(@Param("dto") NRQueryOrderDTO dto); + List getNROrderInfoByOrderCode(@Param("dto") NRQueryOrderDTO dto); } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/IOrderBasicInfoService.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/IOrderBasicInfoService.java index 9a74a8138..620a7d9c9 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/IOrderBasicInfoService.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/IOrderBasicInfoService.java @@ -14,6 +14,7 @@ import com.jsowell.pile.vo.base.MerchantOrderInfoVO; import com.jsowell.pile.vo.base.OrderAmountDetailVO; import com.jsowell.pile.vo.base.OrderPeriodAmountVO; import com.jsowell.pile.vo.lianlian.AccumulativeInfoVO; +import com.jsowell.pile.vo.nanrui.NROrderInfoVO; import com.jsowell.pile.vo.uniapp.OrderVO; import com.jsowell.pile.vo.uniapp.PersonPileConnectorSumInfoVO; import com.jsowell.pile.vo.uniapp.SendMessageVO; @@ -361,12 +362,12 @@ public interface IOrderBasicInfoService { * @param orderCode * @return */ - NROrderInfo getNROrderInfoByOrderCode(String orderCode); + NROrderInfoVO getNROrderInfoByOrderCode(String orderCode); /** * 通过充电结束时间批量查询 * @param dto * @return */ - List getNROrderInfos(NRQueryOrderDTO dto); + List getNROrderInfos(NRQueryOrderDTO dto); } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java index af73ae897..bc6e23dbe 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java @@ -49,6 +49,7 @@ import com.jsowell.pile.transaction.service.TransactionService; import com.jsowell.pile.vo.base.PileInfoVO; import com.jsowell.pile.vo.base.*; import com.jsowell.pile.vo.lianlian.AccumulativeInfoVO; +import com.jsowell.pile.vo.nanrui.NROrderInfoVO; import com.jsowell.pile.vo.uniapp.*; import com.jsowell.pile.vo.web.*; import com.jsowell.wxpay.common.WeChatPayParameter; @@ -1000,31 +1001,30 @@ public class OrderBasicInfoServiceImpl implements IOrderBasicInfoService { * @return */ @Override - public NROrderInfo getNROrderInfoByOrderCode(String orderCode) { + public NROrderInfoVO getNROrderInfoByOrderCode(String orderCode) { NRQueryOrderDTO dto = new NRQueryOrderDTO(); dto.setOrderCode(orderCode); - List nrOrderInfos = orderBasicInfoMapper.getNROrderInfoByOrderCode(dto); + List nrOrderInfos = orderBasicInfoMapper.getNROrderInfoByOrderCode(dto); if (CollectionUtils.isEmpty(nrOrderInfos)) { return null; } // 此方法仅通过订单编号查,因此只有一条数据 - NROrderInfo nrOrderInfo = nrOrderInfos.get(0); - // 将组织机构代码截取后九位 - String organizationCode = nrOrderInfo.getOperatorId(); - String operatorId = StringUtils.substring(organizationCode, organizationCode.length() - 9); - nrOrderInfo.setOperatorId(operatorId); - nrOrderInfo.setUserChargeType(1); - // TODO 获取电表总起、止值 - // pileMsgRecordService.getPileFeedList() - - nrOrderInfo.setMeterValueStart(BigDecimal.ZERO); - nrOrderInfo.setMeterValueEnd(BigDecimal.ZERO); - return nrOrderInfo; + NROrderInfoVO nrOrderInfoVO = nrOrderInfos.get(0); + return nrOrderInfoVO; } + /** + * 通过充电结束时间批量查询 + * @param dto + * @return + */ @Override - public List getNROrderInfos(NRQueryOrderDTO dto) { - return orderBasicInfoMapper.getNROrderInfoByOrderCode(dto); + public List getNROrderInfos(NRQueryOrderDTO dto) { + List nrOrderInfoVOList = orderBasicInfoMapper.getNROrderInfoByOrderCode(dto); + if (CollectionUtils.isEmpty(nrOrderInfoVOList)) { + return new ArrayList<>(); + } + return nrOrderInfoVOList; } /** diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/vo/nanrui/NROrderInfoVO.java b/jsowell-pile/src/main/java/com/jsowell/pile/vo/nanrui/NROrderInfoVO.java new file mode 100644 index 000000000..be65332f9 --- /dev/null +++ b/jsowell-pile/src/main/java/com/jsowell/pile/vo/nanrui/NROrderInfoVO.java @@ -0,0 +1,15 @@ +package com.jsowell.pile.vo.nanrui; + +import com.jsowell.pile.domain.nanrui.NROrderInfo; +import lombok.Data; + +/** + * TODO + * + * @author Lemon + * @Date 2023/10/12 15:57 + */ +@Data +public class NROrderInfoVO extends NROrderInfo { + private String stationId; +} diff --git a/jsowell-pile/src/main/resources/mapper/pile/OrderBasicInfoMapper.xml b/jsowell-pile/src/main/resources/mapper/pile/OrderBasicInfoMapper.xml index 64fb104f6..198e48d0e 100644 --- a/jsowell-pile/src/main/resources/mapper/pile/OrderBasicInfoMapper.xml +++ b/jsowell-pile/src/main/resources/mapper/pile/OrderBasicInfoMapper.xml @@ -1167,7 +1167,7 @@ station_id = #{stationId,jdbcType=BIGINT} - SELECT t1.merchant_id, t3.organization_code AS operatorId, diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/lianlian/service/LianLianService.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/lianlian/service/LianLianService.java index 07e78548b..876f17c70 100644 --- a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/lianlian/service/LianLianService.java +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/lianlian/service/LianLianService.java @@ -79,7 +79,8 @@ public interface LianLianService { * @param operatorSecret * @return */ - String getToken(String urlAddress, String operatorId, String operatorSecret, String dataSecretIv, String signSecret, String dataSecret); + String getToken(String urlAddress, String operatorId, String operatorSecret, + String dataSecretIv, String signSecret, String dataSecret); /** * 推送联联平台 设备状态变化推送 diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/lianlian/service/impl/LianLianServiceImpl.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/lianlian/service/impl/LianLianServiceImpl.java index 663fb3bda..99ce3acd9 100644 --- a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/lianlian/service/impl/LianLianServiceImpl.java +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/lianlian/service/impl/LianLianServiceImpl.java @@ -744,12 +744,13 @@ public class LianLianServiceImpl implements LianLianService { * @return */ @Override - public String getToken(String urlAddress, String operatorId, String operatorSecret, String dataSecretIv, String signSecret, String dataSecret) { + public String getToken(String urlAddress, String operatorId, String operatorSecret, + String dataSecretIv, String signSecret, String dataSecret) { // String operatorId = dto.getOperatorId(); // String operatorSecret = dto.getOperatorSecret(); String token = ""; try { - // 测试用请求地址 + // 请求地址 String requestUrl = urlAddress + "query_token"; // 请求data diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/lianlian/util/HttpRequestUtil.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/lianlian/util/HttpRequestUtil.java index 52bd9a4e1..d7df212e6 100644 --- a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/lianlian/util/HttpRequestUtil.java +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/lianlian/util/HttpRequestUtil.java @@ -155,4 +155,71 @@ public class HttpRequestUtil { // System.out.println("解密数据:" + plainData); return resultMsg; } + + /** + * 南瑞平台发送请求 + * + * TODO(和联联平台一样的方法,若测试通过,则统一更换成上面的方法) + * + * @param token 南瑞平台令牌 + * @param data 要传输的JsonString格式数据 + * @param url 请求地址 + * @param dataSecret 消息密钥 + * @param dataSecretIV 消息密钥初始化向量 + * @param operatorId 运营商id + * @param sigSecret 签名密钥 + * @return + */ + public static String nrSendPost(String token, String data, String url, String dataSecret, + String dataSecretIV, String operatorId, String sigSecret){ + log.info("南瑞平台发送请求 data:{}", data); + //加密 + byte[] encryptText = Cryptos.aesEncrypt(data.getBytes(), + dataSecret.getBytes(), dataSecretIV.getBytes()); + String encryptData = Encodes.encodeBase64(encryptText); + System.out.println("加密数据:" + encryptData); + + Map params = Maps.newLinkedHashMap(); + params.put("OperatorID", operatorId); + params.put("Data", encryptData); + params.put("TimeStamp", DateUtils.parseDateToStr(DateUtils.YYYYMMDDHHMMSS, new Date())); + params.put("Seq", "001"); + String sign = GBSignUtils.sign(params, sigSecret); + params.put("Sig", sign); + + String postData = JSON.toJSONString(params); + log.info("南瑞平台发送请求 最终提交数据:{}", postData); + // System.out.println("最终提交数据:" + postData); + + String hutoolRequest = HttpRequest.post(url).header("Authorization", "Bearer " + token).body(postData).execute().body(); + + log.info("南瑞平台发送请求 接收到返回数据:{}", hutoolRequest); + // System.out.println("接收到返回数据:" + hutoolRequest); + + Map map = (Map) JSON.parse(hutoolRequest); + + log.info("南瑞平台发送请求 返回数据map:{}", JSON.toJSONString(map)); + + int ret = (int) map.get("Ret"); + String resultMsg = (String) map.get("Msg"); + if (ret != 0) { + // 表示请求有异常 + log.error("南瑞平台发送请求 error:{}, 源数据:{}", resultMsg, data); + return resultMsg; + } + String rData = (String) map.get("Data"); + + byte[] plainText = Cryptos.aesDecrypt(Encodes.decodeBase64(rData), + dataSecret.getBytes(), dataSecretIV.getBytes()); + String plainData = ""; + try { + plainData = new String(plainText, "UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + } + + log.info("南瑞平台发送请求 解密数据:{}", plainData); + // System.out.println("解密数据:" + plainData); + return resultMsg; + } } diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/nanrui/service/NRService.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/nanrui/service/NRService.java index 83a6d524b..9a6e0a8cb 100644 --- a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/nanrui/service/NRService.java +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/nanrui/service/NRService.java @@ -2,11 +2,15 @@ package com.jsowell.thirdparty.nanrui.service; import com.jsowell.common.core.domain.ykc.RealTimeMonitorData; import com.jsowell.pile.domain.nanrui.NROrderInfo; +import com.jsowell.pile.dto.PushStationInfoDTO; import com.jsowell.pile.dto.QueryOrderDTO; import com.jsowell.pile.dto.QueryStationInfoDTO; import com.jsowell.pile.dto.nanrui.NRQueryOrderDTO; +import com.jsowell.pile.dto.nanrui.PushAlarmInfoDTO; +import com.jsowell.thirdparty.lianlian.dto.CommonParamsDTO; import com.jsowell.thirdparty.nanrui.domain.NRStationStatusInfo; +import java.io.UnsupportedEncodingException; import java.text.ParseException; import java.util.List; import java.util.Map; @@ -19,13 +23,35 @@ import java.util.Map; */ public interface NRService { + /** + * 从南瑞平台获取令牌 + * @param + * @return + */ + public String getToken(String urlAddress, String operatorId, String operatorSecret, + String dataSecretIv, String signSecret, String dataSecret); + + /** + * 生成令牌 + * @param dto + * @return + * @throws UnsupportedEncodingException + */ + Map generateToken(CommonParamsDTO dto) throws UnsupportedEncodingException; + + /** + * 校验签名 + * @param dto + */ + Map checkoutSign(CommonParamsDTO dto); + /** * 推送充电站信息 - * @param stationId + * @param dto * @return * @throws ParseException */ - public String notification_stationInfo(String stationId) throws ParseException; + public String pushStationInfo(PushStationInfoDTO dto) throws ParseException; /** @@ -38,11 +64,10 @@ public interface NRService { /** * 推送告警信息 * 当充电接口发生异常告警或故障时,运营商企业平台应立即主动推送信息到省、市两级监管平台 - * @param pileConnectorCode - * @param connectorStatus + * @param dto * @return */ - String notification_alarmInfo(String pileConnectorCode, String connectorStatus); + String pushAlarmInfo(PushAlarmInfoDTO dto); /** @@ -50,7 +75,7 @@ public interface NRService { * 当充电枪由 闲置 转为 充电 等状态发生变化时,运营商平台应立即推送当前状态到省、市两级监管平台。 * 充电过程中运营商平台应 每分钟 上报充电包含电流、电压在内的监测数据。 */ - String notification_stationStatus(RealTimeMonitorData realTimeMonitorData); + String pushPileStatus(RealTimeMonitorData realTimeMonitorData); /** @@ -69,7 +94,7 @@ public interface NRService { * @param orderCode * @return */ - String notification_orderInfo(String orderCode); + String pushOrderInfo(String orderCode); /** * 查询充电电量信息 diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/nanrui/service/impl/NRServiceImpl.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/nanrui/service/impl/NRServiceImpl.java index 30d2a35f0..33dd990af 100644 --- a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/nanrui/service/impl/NRServiceImpl.java +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/nanrui/service/impl/NRServiceImpl.java @@ -1,5 +1,9 @@ package com.jsowell.thirdparty.nanrui.service.impl; +import cn.hutool.http.HttpUtil; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; import com.github.pagehelper.PageInfo; import com.google.common.collect.Lists; import com.jsowell.common.constant.CacheConstants; @@ -12,23 +16,37 @@ import com.jsowell.common.util.PageUtils; import com.jsowell.common.util.StringUtils; import com.jsowell.pile.domain.*; import com.jsowell.pile.domain.nanrui.NROrderInfo; +import com.jsowell.pile.dto.PushStationInfoDTO; import com.jsowell.pile.dto.QueryConnectorListDTO; import com.jsowell.pile.dto.QueryStationInfoDTO; import com.jsowell.pile.dto.nanrui.NRQueryOrderDTO; +import com.jsowell.pile.dto.nanrui.PushAlarmInfoDTO; import com.jsowell.pile.service.*; +import com.jsowell.pile.vo.base.ThirdPartyStationRelationVO; +import com.jsowell.pile.vo.nanrui.NROrderInfoVO; import com.jsowell.pile.vo.uniapp.CurrentTimePriceDetails; import com.jsowell.pile.vo.web.PileConnectorInfoVO; import com.jsowell.pile.vo.web.PileModelInfoVO; import com.jsowell.pile.vo.web.PileStationVO; +import com.jsowell.thirdparty.lianlian.dto.CommonParamsDTO; +import com.jsowell.thirdparty.lianlian.service.LianLianService; +import com.jsowell.thirdparty.lianlian.util.Cryptos; +import com.jsowell.thirdparty.lianlian.util.Encodes; +import com.jsowell.thirdparty.lianlian.util.GBSignUtils; +import com.jsowell.thirdparty.lianlian.util.HttpRequestUtil; +import com.jsowell.thirdparty.lianlian.vo.LianLianResultVO; import com.jsowell.thirdparty.nanrui.domain.*; import com.jsowell.thirdparty.nanrui.service.NRService; +import com.jsowell.thirdparty.nanrui.util.QEncodeUtil; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.text.ParseException; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** @@ -58,20 +76,73 @@ public class NRServiceImpl implements NRService { @Autowired private IOrderBasicInfoService orderBasicInfoService; + @Autowired + private IThirdPartyStationRelationService thirdPartyStationRelationService; + + @Autowired + private LianLianService lianLianService; + @Autowired private RedisCache redisCache; + /** - * 充电站信息变化推送 - * @param stationId + * 从南瑞平台获取令牌 + * @param urlAddress + * @param operatorId + * @param operatorSecret + * @param dataSecretIv + * @param signSecret + * @param dataSecret * @return */ @Override - public String notification_stationInfo(String stationId) throws ParseException { - PileStationVO stationInfoVO = pileStationInfoService.getStationInfo(stationId); + public String getToken(String urlAddress, String operatorId, String operatorSecret, + String dataSecretIv, String signSecret, String dataSecret) { + return lianLianService.getToken(urlAddress, operatorId, operatorSecret, + dataSecretIv, signSecret, dataSecret); + } + + @Override + public Map generateToken(CommonParamsDTO dto) throws UnsupportedEncodingException { + return lianLianService.generateToken(dto); + } + + @Override + public Map checkoutSign(CommonParamsDTO dto) { + return lianLianService.checkoutSign(dto); + } + + /** + * 推送充电站信息 + * @param dto + * @return + */ + @Override + public String pushStationInfo(PushStationInfoDTO dto) throws ParseException { + PileStationVO stationInfoVO = pileStationInfoService.getStationInfo(String.valueOf(dto.getStationId())); if (stationInfoVO == null) { return null; } + // 通过站点id查询相关配置信息 + ThirdPartyStationRelation relation = new ThirdPartyStationRelation(); + relation.setStationId(dto.getStationId()); + ThirdPartyStationRelationVO relationInfo = thirdPartyStationRelationService.selectRelationInfo(relation); + // ThirdPartySettingInfo settingInfo = thirdPartySettingInfoService.getInfoByStationId(dto.getStationId()); + if (relationInfo == null) { + // 新增 + relation.setThirdPartyType(dto.getThirdPartyType()); + thirdPartyStationRelationService.insertThirdPartyStationRelation(relation); + + relationInfo = thirdPartyStationRelationService.selectRelationInfo(relation); + } + String operatorId = relationInfo.getOperatorId(); + String operatorSecret = relationInfo.getOperatorSecret(); + String signSecret = relationInfo.getSignSecret(); + String dataSecret = relationInfo.getDataSecret(); + String dataSecretIv = relationInfo.getDataSecretIv(); + String urlAddress = relationInfo.getUrlAddress(); + // 拼装南瑞平台所需参数 NRStationInfo nrStationInfo = NRStationInfo.builder() .stationId("NR" + stationInfoVO.getId()) @@ -103,25 +174,39 @@ public class NRServiceImpl implements NRService { nrStationInfo.setStationType(Integer.parseInt(stationType)); nrStationInfo.setConstruction(255); - List nrEquipmentInfos = getEquipmentInfo(stationId); + List nrEquipmentInfos = getEquipmentInfo(String.valueOf(dto.getStationId())); nrStationInfo.setEquipmentInfos(nrEquipmentInfos); - // TODO 推送到平台 + // 推送到平台 + String url = urlAddress + "notification_stationInfo"; - return null; + String jsonStr = JSONObject.toJSONString(nrStationInfo); + JSONObject data = new JSONObject(); + data.put("StationInfo", jsonStr); + + String jsonString = JSONObject.toJSONString(data); + System.out.println("jsonString : " + jsonString); + + // 获取令牌 + String token = getToken(urlAddress, operatorId, operatorSecret, dataSecretIv, signSecret, dataSecret); + String result = HttpRequestUtil.nrSendPost(token, jsonString, url, dataSecret + , dataSecretIv, operatorId, signSecret); + + // System.out.println(result); + return result; } + /** + * 获取充电站信息 + * @param dto + * @return + */ @Override public Map query_stations_info(QueryStationInfoDTO dto) { List resultList = new ArrayList<>(); int pageNo = dto.getPageNo() == null ? 1 : dto.getPageNo(); int pageSize = dto.getPageSize() == null ? 10 : dto.getPageSize(); - // 查询密钥等配置 - // ThirdPartyPlatformConfig configInfo = thirdPartyPlatformConfigService.getInfoByOperatorId(dto.getOperatorId()); - // if (configInfo == null) { - // return null; - // } PageUtils.startPage(pageNo, pageSize); List stationInfos = pileStationInfoService.getStationInfosByThirdParty(); if (CollectionUtils.isEmpty(stationInfos)) { @@ -194,24 +279,38 @@ public class NRServiceImpl implements NRService { /** * 推送告警信息 - * @param pileConnectorCode - * @param connectorStatus + * @param dto * @return */ @Override - public String notification_alarmInfo(String pileConnectorCode, String connectorStatus) { + public String pushAlarmInfo(PushAlarmInfoDTO dto) { List nrAlarmInfos = new ArrayList<>(); + + // 通过站点id查询相关配置信息 + ThirdPartyStationRelation relation = new ThirdPartyStationRelation(); + relation.setStationId(dto.getStationId()); + ThirdPartyStationRelationVO relationInfo = thirdPartyStationRelationService.selectRelationInfo(relation); + if (relationInfo == null) { + return null; + } + String operatorId = relationInfo.getOperatorId(); + String operatorSecret = relationInfo.getOperatorSecret(); + String signSecret = relationInfo.getSignSecret(); + String dataSecret = relationInfo.getDataSecret(); + String dataSecretIv = relationInfo.getDataSecretIv(); + String urlAddress = relationInfo.getUrlAddress(); + // 从缓存中获取故障原因 - String redisKey = CacheConstants.PILE_HARDWARE_FAULT + pileConnectorCode; + String redisKey = CacheConstants.PILE_HARDWARE_FAULT + dto.getPileConnectorCode(); String faultReason = redisCache.getCacheObject(redisKey); int status = 0; - if (StringUtils.equals(connectorStatus, "01")) { + if (StringUtils.equals(dto.getConnectorStatus(), "01")) { // 故障 status = 1; } // 封装对象 NRAlarmInfo alarmInfo = NRAlarmInfo.builder() - .connectorId(pileConnectorCode) + .connectorId(dto.getPileConnectorCode()) .alertTime(DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD_HH_MM_SS)) .alertCode(120) // 120-预留 .describe(faultReason) @@ -219,13 +318,24 @@ public class NRServiceImpl implements NRService { .build(); nrAlarmInfos.add(alarmInfo); - Map map = new LinkedHashMap<>(); - map.put("AlarmInfos", nrAlarmInfos); - // TODO 发送请求 + // 发送请求 + String url = urlAddress + "notification_alarmInfo"; + String jsonStr = JSONObject.toJSONString(nrAlarmInfos); + JSONObject data = new JSONObject(); + data.put("AlarmInfos", jsonStr); - return null; + String jsonString = JSONObject.toJSONString(data); + System.out.println("jsonString : " + jsonString); + + // 获取令牌 + String token = getToken(urlAddress, operatorId, operatorSecret, + dataSecretIv, signSecret, dataSecret); + String result = HttpRequestUtil.nrSendPost(token, jsonString, url, dataSecret + , dataSecretIv, operatorId, signSecret); + + return result; } /** @@ -234,10 +344,35 @@ public class NRServiceImpl implements NRService { * @return */ @Override - public String notification_stationStatus(RealTimeMonitorData realTimeMonitorData) { + public String pushPileStatus(RealTimeMonitorData realTimeMonitorData) { String pileConnectorCode = realTimeMonitorData.getPileSn() + realTimeMonitorData.getConnectorCode(); String connectorStatus = realTimeMonitorData.getConnectorStatus(); String transactionCode = realTimeMonitorData.getTransactionCode(); + + // 查出该桩所属哪个站点 + String pileSn = StringUtils.substring(pileConnectorCode, 0, 14); + PileStationVO stationVO = pileStationInfoService.getStationInfoByPileSn(pileSn); + // 通过站点id查询相关配置信息 + ThirdPartyStationRelation relation = new ThirdPartyStationRelation(); + relation.setStationId(Long.parseLong(stationVO.getId())); + ThirdPartyStationRelationVO relationInfo = thirdPartyStationRelationService.selectRelationInfo(relation); + if (relationInfo == null) { + return null; + } + String operatorId = relationInfo.getOperatorId(); + String operatorSecret = relationInfo.getOperatorSecret(); + String signSecret = relationInfo.getSignSecret(); + String dataSecret = relationInfo.getDataSecret(); + String dataSecretIv = relationInfo.getDataSecretIv(); + String urlAddress = relationInfo.getUrlAddress(); + + String url = urlAddress + "notification_stationStatus"; + + // 获取令牌 + String token = getToken(urlAddress, operatorId, operatorSecret, dataSecretIv, signSecret, dataSecret); + if (StringUtils.isBlank(token)) { + return null; + } // 根据交易流水号查询订单信息 OrderBasicInfo orderBasicInfo = orderBasicInfoService.getOrderInfoByTransactionCode(transactionCode); // 封装对象 @@ -256,14 +391,22 @@ public class NRServiceImpl implements NRService { nrConnectorStatusInfo.setSoc(new BigDecimal(realTimeMonitorData.getSOC()).setScale(1, BigDecimal.ROUND_HALF_UP)); } - Map map = new LinkedHashMap<>(); - map.put("ConnectorStatusInfo", nrConnectorStatusInfo); + // 发送请求 + JSONObject json = new JSONObject(); + json.put("ConnectorStatusInfo", nrConnectorStatusInfo); + String jsonString = JSONObject.toJSONString(json); - // TODO 发送请求 - - return null; + String result = HttpRequestUtil.nrSendPost(token, jsonString, url, dataSecret, dataSecretIv, operatorId, signSecret); + return result; } + /** + * 查询设备接口状态 + * 此接口用于批量查询设备实时状态 + * 由充电运营商方实现此接口,省、市两级监管平台调用。 + * @param stationIds + * @return + */ @Override public Map query_station_status(List stationIds) { List resultList = new ArrayList<>(); @@ -329,31 +472,97 @@ public class NRServiceImpl implements NRService { return map; } + /** + * 充电电量信息推送 + * 当运营商平台完成一次充电时,将充电电量信息推送至省、市两级监管平台 + * @param orderCode + * @return + */ @Override - public String notification_orderInfo(String orderCode) { + public String pushOrderInfo(String orderCode) { // 根据订单号查询订单信息 - NROrderInfo nrOrderInfo = orderBasicInfoService.getNROrderInfoByOrderCode(orderCode); - // TODO 发送请求 - Map map = new LinkedHashMap<>(); - map.put("OrderInfo", nrOrderInfo); + NROrderInfoVO nrOrderInfoVO = orderBasicInfoService.getNROrderInfoByOrderCode(orderCode); + NROrderInfo nrOrderInfo = formatNROrderInfo((nrOrderInfoVO)); - return null; + // 通过站点id查询相关配置信息 + ThirdPartyStationRelation relation = new ThirdPartyStationRelation(); + relation.setStationId(Long.parseLong(nrOrderInfoVO.getStationId())); + ThirdPartyStationRelationVO relationInfo = thirdPartyStationRelationService.selectRelationInfo(relation); + if (relationInfo == null) { + return null; + } + String operatorId = relationInfo.getOperatorId(); + String operatorSecret = relationInfo.getOperatorSecret(); + String signSecret = relationInfo.getSignSecret(); + String dataSecret = relationInfo.getDataSecret(); + String dataSecretIv = relationInfo.getDataSecretIv(); + String urlAddress = relationInfo.getUrlAddress(); + + String url = urlAddress + "notification_orderInfo"; + + // 获取令牌 + String token = getToken(urlAddress, operatorId, operatorSecret, dataSecretIv, signSecret, dataSecret); + if (StringUtils.isBlank(token)) { + return null; + } + + // 发送请求 + JSONObject jsonObject = new JSONObject(); + jsonObject.put("OrderInfo", nrOrderInfo); + + String jsonString = JSONObject.toJSONString(jsonObject); + + String result = HttpRequestUtil.nrSendPost(token, jsonString, url, dataSecret, dataSecretIv, operatorId, signSecret); + return result; } @Override public List query_order_info(NRQueryOrderDTO dto) { - List nrOrderInfos = orderBasicInfoService.getNROrderInfos(dto); + List resultList = new ArrayList<>(); + List nrOrderInfos = orderBasicInfoService.getNROrderInfos(dto); if (CollectionUtils.isEmpty(nrOrderInfos)) { return new ArrayList<>(); } - // 将组织机构代码只取后9位数 - for (NROrderInfo nrOrderInfo : nrOrderInfos) { - String operatorId = nrOrderInfo.getOperatorId(); - if (StringUtils.isNotBlank(operatorId)) { - nrOrderInfo.setOperatorId(StringUtils.substring(operatorId, operatorId.length() - 9)); - } + for (NROrderInfoVO nrOrderInfoVO : nrOrderInfos) { + NROrderInfo nrOrderInfo = formatNROrderInfo(nrOrderInfoVO); + resultList.add(nrOrderInfo); } - return nrOrderInfos; + return resultList; + } + + /** + * 格式化南瑞平台订单对象 + * @param nrOrderInfoVO + * @return + */ + private NROrderInfo formatNROrderInfo(NROrderInfoVO nrOrderInfoVO) { + // 将组织机构代码截取后九位 + String organizationCode = nrOrderInfoVO.getOperatorId(); + if (StringUtils.isBlank(organizationCode)) { + return null; + } + String operatorId = StringUtils.substring(organizationCode, organizationCode.length() - 9); + + NROrderInfo nrOrderInfo = NROrderInfo.builder() + .operatorId(operatorId) + .connectorId(nrOrderInfoVO.getConnectorId()) + .startChargeSeq(nrOrderInfoVO.getStartChargeSeq()) + .userChargeType(1) + .elect(nrOrderInfoVO.getElect()) + .cuspElect(nrOrderInfoVO.getCuspElect()) + .peakElect(nrOrderInfoVO.getPeakElect()) + .flatElect(nrOrderInfoVO.getFlatElect()) + .valleyElect(nrOrderInfoVO.getValleyElect()) + .startTime(nrOrderInfoVO.getStartTime()) + .endTime(nrOrderInfoVO.getEndTime()) + + .build(); + // TODO 获取电表总起、止值 + // pileMsgRecordService.getPileFeedList() + + nrOrderInfo.setMeterValueStart(BigDecimal.ZERO); + nrOrderInfo.setMeterValueEnd(BigDecimal.ZERO); + return nrOrderInfo; } public static void main(String[] args) { diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/nanrui/util/NRMD5Util.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/nanrui/util/NRMD5Util.java new file mode 100644 index 000000000..ca00be888 --- /dev/null +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/nanrui/util/NRMD5Util.java @@ -0,0 +1,98 @@ +package com.jsowell.thirdparty.nanrui.util; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * TODO + * + * @author Lemon + * @Date 2023/10/12 13:42 + */ +public class NRMD5Util { + public static void main(String[] args) { + String sigSecret = "yyyyyyyyyyyyyyyy"; + String dataSecret = "DDDDDDD"; + String dataSecretIv = "XXXXXXXX"; + String operatorId = "MA002TMQX"; + String data = "{'EquipAuthSeq':'MA002TMQX202004090925368255','ConnectorID':'MA01H3BQ1_1306060015204'}"; + String retData = QEncodeUtil.encrypt(data, dataSecret, dataSecretIv); + String timeStamp = "20200409000000"; + String seq = "0001"; + String sig = getHmacMd5Str(sigSecret, operatorId + retData + timeStamp + seq); + } + + public static String getHmacMd5Str(String key, String data) { + String result = ""; + try { + byte[] keyByte = key.getBytes("UTF-8"); + byte[] dataByte = data.getBytes("UTF-8"); + byte[] hmacMd5Byte = getHmacMd5Bytes(keyByte, dataByte); + StringBuffer md5StrBuff = new StringBuffer(); + for (byte b : hmacMd5Byte) { + if (Integer.toHexString(0xFF & b).length() == 1) + md5StrBuff.append("0").append(Integer.toHexString(0xFF & b)); + else md5StrBuff.append(Integer.toHexString(0xFF & b)); + } + result = md5StrBuff.toString().toUpperCase(); + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } + + public static byte[] getHmacMd5Bytes(byte[] key, byte[] data) throws NoSuchAlgorithmException { + /** + * HmacMd5 calculation formula: H(K XOR opad, H(K XOR ipad, text)) + * HmacMd5 计算公式:H(K XOR opad, H(K XOR ipad, text)) + * H 代表 hash 算法,本类中使用 MD5 算法,K 代表密钥,text 代表要加密的数据 ipad 为 0x36,opad 为 0x5C。 + */ + int length = 64; + byte[] ipad = new byte[length]; + byte[] opad = new byte[length]; + for (int i = 0; i < 64; i++) { + ipad[i] = 0x36; + opad[i] = 0x5C; + } + byte[] actualKey = key; + // Actual key. + byte[] keyArr = new byte[length]; + // 如果密钥长度,大于 64 字节,就使用哈希算法,计算其摘要,作为真正的密钥。 + if (key.length > length) { + actualKey = md5(key); + } + // append zeros to K 如果密钥长度不足 64 字节,就使用 0x00 补齐到 64 字节。 + System.arraycopy(actualKey, 0, keyArr, 0, actualKey.length); + if (actualKey.length < length) { + for (int i = actualKey.length; i < keyArr.length; i++) keyArr[i] = 0x00; + } + // calc K XOR ipad 使用密钥和 ipad 进行异或运算。 + byte[] kIpadXorResult = new byte[length]; + for (int i = 0; i < length; i++) { + kIpadXorResult[i] = (byte) (keyArr[i] ^ ipad[i]); + } + // append "text" to the end of "K XOR ipad" 将待加密数据追加到 K XOR ipad 计算结果后面。 + byte[] firstAppendResult = new byte[kIpadXorResult.length + data.length]; + System.arraycopy(kIpadXorResult, 0, firstAppendResult, 0, kIpadXorResult.length); + // calc H(K XOR ipad, text) 使用哈希算法计算上面结果的摘要 + System.arraycopy(data, 0, firstAppendResult, keyArr.length, data.length); + // calc K XOR opad 使用密钥和 opad 进行异或运算。 + byte[] firstHashResult = md5(firstAppendResult); + byte[] kOpadXorResult = new byte[length]; + for (int i = 0; i < length; i++) { + kOpadXorResult[i] = (byte) (keyArr[i] ^ opad[i]); + } + // 将 H(K XOR * ipad, text)结果追加到 K XOR opad 结果后面 + byte[] secondAppendResult = new byte[kOpadXorResult.length + firstHashResult.length]; // + System.arraycopy(kOpadXorResult, 0, secondAppendResult, 0, kOpadXorResult.length); + // 对上面的数据进行哈希运算。 + System.arraycopy(firstHashResult, 0, secondAppendResult, keyArr.length, firstHashResult.length); + return md5(secondAppendResult); + } + + private static byte[] md5(byte[] str) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(str); + return md.digest(); + } +} diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/nanrui/util/QEncodeUtil.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/nanrui/util/QEncodeUtil.java new file mode 100644 index 000000000..28ed833fc --- /dev/null +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/nanrui/util/QEncodeUtil.java @@ -0,0 +1,73 @@ +package com.jsowell.thirdparty.nanrui.util; + +import sun.misc.BASE64Decoder; +import sun.misc.BASE64Encoder; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +/** + * TODO + * + * @author Lemon + * @Date 2023/10/12 13:54 + */ +public class QEncodeUtil { + public static String encrypt(String sSrc, String sKey, String datasecretiv) { + try { + if (sKey == null) { + return null; + } + // 判断 Key 是否为 16 位 + if (sKey.length() != 16) { + return null; + } + byte[] raw = sKey.getBytes("UTF-8"); + SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//"算法/模式/补码方式" + IvParameterSpec iv = new IvParameterSpec(datasecretiv.getBytes());//使用 CBC 模式,需要一个向量 iv,可增加加密算法的强度 1234567890123456 + cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); + byte[] encrypted = cipher.doFinal(sSrc.getBytes()); + String str = new BASE64Encoder().encode(encrypted); // 此处使用 BASE64 做转码功能,同时能起到 2 次加密的作用。 + str = str.replaceAll("\r", ""); + str = str.replaceAll("\n", ""); + return str; + } catch (Exception ex) { + return null; + } + } + + // 解密 + public static String decrypt(String sSrc, String sKey, String datasecretiv) { + try { + // 判断 Key 是否正确 + if (sKey == null) { + System.out.print("Key 为空 null"); + return null; + } + // 判断 Key 是否为 16 位 + if (sKey.length() != 16) { + System.out.print("Key 长度不是 16 位"); + return null; + } + byte[] raw = sKey.getBytes("UTF-8"); + SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + IvParameterSpec iv = new IvParameterSpec(datasecretiv.getBytes()); + cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); + byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc); + //先用 base64 解密 + try { + byte[] original = cipher.doFinal(encrypted1); + return new String(original, "UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + System.out.println(e.toString()); + return null; + } + } catch (Exception ex) { + return null; + } + } +} diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/zhongdianlian/service/impl/ZDLServiceImpl.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/zhongdianlian/service/impl/ZDLServiceImpl.java index 8d09018f4..eab47181e 100644 --- a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/zhongdianlian/service/impl/ZDLServiceImpl.java +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/zhongdianlian/service/impl/ZDLServiceImpl.java @@ -2,13 +2,8 @@ package com.jsowell.thirdparty.zhongdianlian.service.impl; import com.alibaba.fastjson2.JSONObject; import com.github.pagehelper.PageInfo; -import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.jsowell.common.constant.Constants; -import com.jsowell.common.enums.lianlian.LianLianPileStatusEnum; -import com.jsowell.common.enums.lianlian.StationPaymentEnum; -import com.jsowell.common.enums.ykc.PileStatusEnum; -import com.jsowell.common.util.DateUtils; import com.jsowell.common.util.PageUtils; import com.jsowell.common.util.StringUtils; import com.jsowell.pile.domain.*; @@ -17,9 +12,6 @@ import com.jsowell.pile.dto.QueryStationInfoDTO; import com.jsowell.pile.service.*; import com.jsowell.pile.vo.base.ThirdPartyStationRelationVO; import com.jsowell.pile.vo.web.PileModelInfoVO; -import com.jsowell.thirdparty.lianlian.domain.ConnectorInfo; -import com.jsowell.thirdparty.lianlian.domain.EquipmentInfo; -import com.jsowell.thirdparty.lianlian.domain.StationInfo; import com.jsowell.thirdparty.lianlian.dto.CommonParamsDTO; import com.jsowell.thirdparty.lianlian.service.LianLianService; import com.jsowell.thirdparty.lianlian.util.Cryptos;