diff --git a/jsowell-admin/src/main/java/com/jsowell/web/controller/thirdparty/dianxing/DianXingPlatformController.java b/jsowell-admin/src/main/java/com/jsowell/web/controller/thirdparty/dianxing/DianXingPlatformController.java new file mode 100644 index 000000000..a53b3a28a --- /dev/null +++ b/jsowell-admin/src/main/java/com/jsowell/web/controller/thirdparty/dianxing/DianXingPlatformController.java @@ -0,0 +1,47 @@ +package com.jsowell.web.controller.thirdparty.dianxing; + +import com.jsowell.common.annotation.Anonymous; +import com.jsowell.common.core.controller.BaseController; +import com.jsowell.common.exception.BusinessException; +import com.jsowell.common.response.RestApiResponse; +import com.jsowell.thirdparty.platform.ThirdPartyPlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.web.bind.annotation.*; + +/** + * 宁波电刑平台 + * + * @author Lemon + * @Date 2024/5/10 9:21:59 + */ +@Anonymous +@RestController +@RequestMapping("/dianxing") +public class DianXingPlatformController extends BaseController { + @Autowired + @Qualifier("dianXingPlatformServiceImpl") + private ThirdPartyPlatformService dianXingService; + + + /** + * 推送充电记录 + * @param orderCode + * @return + */ + @GetMapping("/pushChargeRecord/{orderCode}") + public RestApiResponse pushChargeRecordInfo(@PathVariable("orderCode") String orderCode) { + RestApiResponse response = null; + try { + String result = dianXingService.notificationChargeOrderInfo(orderCode); + response = new RestApiResponse<>(result); + } catch (BusinessException e) { + logger.error("点行平台推送充电记录 error:{}, {}", e.getCode(), e.getMessage()); + response = new RestApiResponse<>(e); + } catch (Exception e) { + logger.error("点行平台推送充电记录 error", e); + } + logger.info("点行平台推送充电记录 result:{}", response); + return response; + } +} diff --git a/jsowell-common/src/main/java/com/jsowell/common/enums/thirdparty/ThirdPlatformTypeEnum.java b/jsowell-common/src/main/java/com/jsowell/common/enums/thirdparty/ThirdPlatformTypeEnum.java index 654f82a5f..08830269b 100644 --- a/jsowell-common/src/main/java/com/jsowell/common/enums/thirdparty/ThirdPlatformTypeEnum.java +++ b/jsowell-common/src/main/java/com/jsowell/common/enums/thirdparty/ThirdPlatformTypeEnum.java @@ -20,6 +20,7 @@ public enum ThirdPlatformTypeEnum { HUA_WEI("9", "华为平台", "MA5GTQ528"), NEI_MENG_GU_PLATFORM("10", "内蒙古平台", ""), QING_HAI_PLATFORM("11", "青海平台", "630000000"), + DIAN_XING_PLATFORM("12", "宁波点行停车平台", ""), ; private String typeCode; diff --git a/jsowell-common/src/main/java/com/jsowell/common/util/Sm2Util.java b/jsowell-common/src/main/java/com/jsowell/common/util/Sm2Util.java index 61e0608df..6a9e64878 100644 --- a/jsowell-common/src/main/java/com/jsowell/common/util/Sm2Util.java +++ b/jsowell-common/src/main/java/com/jsowell/common/util/Sm2Util.java @@ -28,12 +28,13 @@ import java.util.TreeMap; */ public class Sm2Util { - static{ + static { Security.addProvider(new BouncyCastleProvider()); } /** * 随机生成sm2的公钥私钥对 + * * @return 公钥私钥对 */ public static KeyPair generateSm2KeyPair() { @@ -54,9 +55,8 @@ public class Sm2Util { } /** - * - * @param data 加密前的json数据 - * @param platformPublicKeyStr 点行平台的国密二公钥 + * @param data 加密前的json数据 + * @param platformPublicKeyStr 点行平台的国密二公钥 * @param thirdPartyPrivateKeyStr 第三方平台生成的国密二私钥 * @return 用于http发送请求的数据 * @throws NoSuchAlgorithmException @@ -67,14 +67,13 @@ public class Sm2Util { public static String generateEncryptedRequestInfo(JSONObject data, String platformPublicKeyStr, String thirdPartyPrivateKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException, CryptoException { String sign = sign(thirdPartyPrivateKeyStr, data); - data.put("sign",sign); + data.put("sign", sign); return encrypt(platformPublicKeyStr, data.toString()); } /** - * * @param publicKeyStr 以BASE64表示的sm2公钥 - * @param data 待加密字符串, UTF-8编码 + * @param data 待加密字符串, UTF-8编码 * @return 以BASE64表示的加密结果 * @throws NoSuchAlgorithmException * @throws NoSuchProviderException @@ -106,9 +105,8 @@ public class Sm2Util { } /** - * * @param privateKeyStr 以BASE64表示的sm2私钥 - * @param cipherData 以BASE64表示的加密结果 + * @param cipherData 以BASE64表示的加密结果 * @return 解密后字符串, UTF-8编码 * @throws NoSuchAlgorithmException * @throws NoSuchProviderException @@ -140,9 +138,8 @@ public class Sm2Util { } /** - * * @param privateKeyStr 以BASE64表示的sm2私钥 - * @param dataJson 待签名json数据 + * @param dataJson 待签名json数据 * @throws NoSuchAlgorithmException * @throws NoSuchProviderException * @throws InvalidKeySpecException @@ -175,9 +172,8 @@ public class Sm2Util { } /** - * * @param publicKeyStr 以BASE64表示的sm2公钥 - * @param dataJson 含有签名的待验签json数据 + * @param dataJson 含有签名的待验签json数据 * @return * @throws NoSuchAlgorithmException * @throws NoSuchProviderException @@ -202,22 +198,22 @@ public class Sm2Util { return sm2Signer.verifySignature(Base64.decode(sign)); } - private static String getSignContent(JSONObject rawData){ + private static String getSignContent(JSONObject rawData) { JSONObject data = new JSONObject(new TreeMap<>()); - rawData.forEach((k,v) -> data.put(k,v)); + rawData.forEach((k, v) -> data.put(k, v)); StringBuffer sb = new StringBuffer(); - data.forEach((k,v)->{ + data.forEach((k, v) -> { if (v != null && !"".equals(v)) { sb.append(k + "=" + v + "&"); } }); String stringData = sb.toString(); - return stringData == null || stringData.isEmpty() ? "" : stringData.substring(0,stringData.length()-1); + return stringData == null || stringData.isEmpty() ? "" : stringData.substring(0, stringData.length() - 1); } private static BCECPrivateKey getPrivateKey(byte[] privateBytes) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException { PKCS8EncodedKeySpec eks2 = new PKCS8EncodedKeySpec(privateBytes); - KeyFactory kf= KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME); + KeyFactory kf = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME); return (BCECPrivateKey) kf.generatePrivate(eks2); } @@ -228,9 +224,9 @@ public class Sm2Util { } public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException, CryptoException { -// KeyPair keyPair = generateSm2KeyPair(); -// System.out.println(Base64.toBase64String(keyPair.getPublic().getEncoded())); -// System.out.println(Base64.toBase64String(keyPair.getPrivate().getEncoded())); + // KeyPair keyPair = generateSm2KeyPair(); + // System.out.println(Base64.toBase64String(keyPair.getPublic().getEncoded())); + // System.out.println(Base64.toBase64String(keyPair.getPrivate().getEncoded())); String platformPublicKeyStr = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEYPOlKmr/XY+na8KxiNvRui1esFugt4tT2AVk+eRlH4KCYLabDZDordal3kcn4UNM7t6J+dyhcfLstNWXpf4lQA=="; String thirdPartyPrivateKeyStr = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgCMref1FGlPZ9RfeJw/cnU5uEvFZNhHt7OvF4sgXnBjWgCgYIKoEcz1UBgi2hRANCAARj6kqkCaeNJSxWExQFsot1OuSCFrQOblhKx0U/y8GhgSND2MOAM08yXzl308waLqLt+jcsLF2UTW6XfrZNS5pk"; JSONObject data = new JSONObject(); diff --git a/jsowell-common/src/main/java/com/jsowell/common/util/http/HttpUtils.java b/jsowell-common/src/main/java/com/jsowell/common/util/http/HttpUtils.java index 1d9292447..1b9b28f75 100644 --- a/jsowell-common/src/main/java/com/jsowell/common/util/http/HttpUtils.java +++ b/jsowell-common/src/main/java/com/jsowell/common/util/http/HttpUtils.java @@ -269,6 +269,61 @@ public class HttpUtils { } } + /** + * + * @param url + * @param param + * @param tpToken + * @return + */ + public static String sendPostTpToken(String url, String param, String tpToken) { + PrintWriter out = null; + BufferedReader in = null; + StringBuilder result = new StringBuilder(); + try { + // log.info("sendPost - {}", url); + URL realUrl = new URL(url); + URLConnection conn = realUrl.openConnection(); + conn.setRequestProperty("accept", "*/*"); + conn.setRequestProperty("connection", "Keep-Alive"); + conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + conn.setRequestProperty("Accept-Charset", "utf-8"); + // conn.setRequestProperty("Authorization", "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI0MjUwMTA3NjUiLCJpYXQiOjE2ODU0MjM3ODMsInN1YiI6IjNEU0JUV0hWSUM2S1ZDS0kiLCJleHAiOjY4Njk0MjM3ODN9.nU-6QNNBp0dcz65_lT-yVAoESZFUHmOwZpoqsKVNspQ"); + conn.setRequestProperty("tpToken", tpToken); + conn.setDoOutput(true); + conn.setDoInput(true); + out = new PrintWriter(conn.getOutputStream()); + out.print(param); + out.flush(); + in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8)); + String line; + while ((line = in.readLine()) != null) { + result.append(line); + } + // log.info("recv - {}", result); + } catch (ConnectException e) { + log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e); + } catch (SocketTimeoutException e) { + log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e); + } catch (IOException e) { + log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e); + } catch (Exception e) { + log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e); + } finally { + try { + if (out != null) { + out.close(); + } + if (in != null) { + in.close(); + } + } catch (IOException ex) { + log.error("调用in.close Exception, url=" + url + ",param=" + param, ex); + } + } + return result.toString(); + } + private static class TrustAnyHostnameVerifier implements HostnameVerifier { @Override public boolean verify(String hostname, SSLSession session) { 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 57c8c2b21..d3ee4c79d 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 @@ -252,10 +252,11 @@ public class LianLianServiceImpl implements LianLianService { public static void main(String[] args) throws UnsupportedEncodingException { - String dataSecret = "1234567890abcdef"; // SPBNJ1Z5EQNmpK08 VTAEKDPVN9CUS7WO huawei: zd4NrLWJ38XCTaqP E6gnWuz0QzBW75CR 正式:NHsBDtTanA60vTIu pJahbxk8wG79CMDB - String dataSecretIV = "1234567890abcdef"; // peRoTcb2C7zqKeII 83UZFFRRZDYNF5CR huawei: RJJecvNTJ48SGMG7 SXejaSUx5yud8UHm 正式:2uyE2Cgu4nVf6egc y259VRq7h8RyFXmT + String dataSecret = "vj3RWNsWIxT5MC2K"; // SPBNJ1Z5EQNmpK08 VTAEKDPVN9CUS7WO huawei: zd4NrLWJ38XCTaqP E6gnWuz0QzBW75CR 正式:NHsBDtTanA60vTIu pJahbxk8wG79CMDB + String dataSecretIV = "jjkySnGlM3pbOUki"; // peRoTcb2C7zqKeII 83UZFFRRZDYNF5CR huawei: RJJecvNTJ48SGMG7 SXejaSUx5yud8UHm 正式:2uyE2Cgu4nVf6egc y259VRq7h8RyFXmT String signSecret = "sRjCDeokckFGpYpA"; // sRjCDeokckFGpYpA - String dataString = "P1/F/NR6fTmwF0jBZ5zzSsuMBwkBgCaVRX1wnGuAtVDmbCJq5P4dAqw6hBh3l/c/nhYb+G32jZKwiWrfvAjY875/1wiGnygxHtUOniX9kXPwXmzRLVGVMAZ+YVnZOJmxX7TBN6Aq2rO6bKqRlRO+9brn0jXiFP7gtpKaaWjE14d/vc9xJoK2TP1rWTESLXyJvViIx5peI60c16c/93l7QZgAOZ5gUYeoL56UvQ9keiufBFHrgFmlTfDQdamlxD6S8QguDw7yV5/UoFvM3zMNcrIz68NdsagMaiKSU+jqGyfdLWa/iokmogbRqm12Cfi4CQClhv6rYii5o1fVyc0+TD3Fl2MDAESDJAUdzV9xr4M="; + String dataString = "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"; // 解密data byte[] plainText = Cryptos.aesDecrypt(Encodes.decodeBase64(dataString), dataSecret.getBytes(), dataSecretIV.getBytes()); diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/platform/ThirdPartyPlatformService.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/platform/ThirdPartyPlatformService.java index d98d8c3fc..664f23c09 100644 --- a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/platform/ThirdPartyPlatformService.java +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/platform/ThirdPartyPlatformService.java @@ -16,9 +16,13 @@ import com.jsowell.thirdparty.lianlian.vo.LianLianResultVO; import com.jsowell.thirdparty.platform.util.Cryptos; import com.jsowell.thirdparty.platform.util.Encodes; import com.jsowell.thirdparty.platform.util.GBSignUtils; +import org.bouncycastle.crypto.CryptoException; import org.springframework.beans.factory.InitializingBean; import java.nio.charset.StandardCharsets; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.spec.InvalidKeySpecException; import java.util.*; /** @@ -275,7 +279,7 @@ public interface ThirdPartyPlatformService extends InitializingBean { * @param orderCode 订单编号 * @throws UnsupportedOperationException 未实现异常 */ - default String notificationChargeOrderInfo(String orderCode) { + default String notificationChargeOrderInfo(String orderCode) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException, CryptoException { throw new UnsupportedOperationException("This method is not yet implemented"); } diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/platform/ningbodianxing/service/DianXingPlatformServiceImpl.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/platform/ningbodianxing/service/DianXingPlatformServiceImpl.java new file mode 100644 index 000000000..d796e235f --- /dev/null +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/platform/ningbodianxing/service/DianXingPlatformServiceImpl.java @@ -0,0 +1,92 @@ +package com.jsowell.thirdparty.platform.ningbodianxing.service; + +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson2.JSONObject; +import com.jsowell.common.enums.thirdparty.BusinessInformationExchangeEnum; +import com.jsowell.common.enums.thirdparty.ThirdPlatformTypeEnum; +import com.jsowell.common.exception.BusinessException; +import com.jsowell.common.util.DateUtils; +import com.jsowell.common.util.Sm2Util; +import com.jsowell.common.util.http.HttpUtils; +import com.jsowell.pile.domain.OrderBasicInfo; +import com.jsowell.pile.service.OrderBasicInfoService; +import com.jsowell.pile.vo.ThirdPartySecretInfoVO; +import com.jsowell.thirdparty.platform.ThirdPartyPlatformService; +import com.jsowell.thirdparty.platform.factory.ThirdPartyPlatformFactory; +import com.jsowell.thirdparty.service.ThirdpartySecretInfoService; +import org.bouncycastle.crypto.CryptoException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.spec.InvalidKeySpecException; + +/** + * 宁波点行平台 + * + * @author Lemon + * @Date 2024/5/9 10:18:12 + */ +@Service +public class DianXingPlatformServiceImpl implements ThirdPartyPlatformService { + @Autowired + private OrderBasicInfoService orderBasicInfoService; + + @Autowired + private ThirdpartySecretInfoService thirdpartySecretInfoService; + + Logger logger = LoggerFactory.getLogger(this.getClass()); + + // 平台类型 + private final String thirdPlatformType = ThirdPlatformTypeEnum.DIAN_XING_PLATFORM.getTypeCode(); + + @Override + public void afterPropertiesSet() throws Exception { + ThirdPartyPlatformFactory.register(thirdPlatformType, this); + } + + /** + * 推送订单接口 + * @param orderCode 订单编号 + * @return + */ + @Override + public String notificationChargeOrderInfo(String orderCode) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException, CryptoException { + // 通过订单编号查询订单信息 + OrderBasicInfo orderBasicInfo = orderBasicInfoService.getOrderInfoByOrderCode(orderCode); + if (orderBasicInfo == null) { + throw new BusinessException("", "未查询到该订单信息"); + } + String plateNum = orderBasicInfo.getPlateNumber() == null ? "无" : orderBasicInfo.getPlateNumber(); + // 拼装订单信息 JSON 参数 + JSONObject jsonObject = new JSONObject(); + jsonObject.put("outTradeId", orderBasicInfo.getOrderCode()); // 充电桩平台订单号 + jsonObject.put("plateNum", plateNum); // 车牌号 + jsonObject.put("startTime", orderBasicInfo.getChargeStartTime()); // 充电开始时间,格式 yyyy-MM-dd HH:mm:ss + jsonObject.put("endTime", orderBasicInfo.getChargeEndTime()); // 充电结束时间, + jsonObject.put("payAmount", orderBasicInfo.getPayAmount()); // 支付金额,格式为小数点后保留 2 位 + jsonObject.put("recordTime", DateUtils.getDateTime()); // 记录上报时间 + + // 查询出该平台的配置参数 + ThirdPartySecretInfoVO thirdPartySecretInfoVO = thirdpartySecretInfoService.queryByThirdPlatformType(thirdPlatformType); + if (thirdPartySecretInfoVO == null) { + throw new BusinessException("", "无此平台配置信息"); + } + // 加密参数(方法中已将 sign 放入参数中并返回) + String recordInfoStr = Sm2Util.generateEncryptedRequestInfo(jsonObject, thirdPartySecretInfoVO.getTheirPublicSecret(), thirdPartySecretInfoVO.getOurPrivateSecret()); + String tpToken = "4121d1c9121a41d894ed5082d264db30"; + + // 发送请求 + String url = thirdPartySecretInfoVO.getTheirUrlPrefix(); + JSONObject postParam = new JSONObject(); + postParam.put("recordInfo", recordInfoStr); + + String result = HttpUtils.sendPostTpToken(url, postParam.toJSONString(), tpToken); + return result; + } + + +}