|
|
@@ -0,0 +1,220 @@
|
|
|
+package com.sckw.core.service;
|
|
|
+
|
|
|
+
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
+import com.sckw.core.reponse.CollectZjxlResponse;
|
|
|
+import jakarta.annotation.Resource;
|
|
|
+
|
|
|
+import javax.crypto.Mac;
|
|
|
+import javax.crypto.spec.SecretKeySpec;
|
|
|
+import javax.net.ssl.*;
|
|
|
+import java.io.BufferedReader;
|
|
|
+import java.io.InputStreamReader;
|
|
|
+import java.io.OutputStreamWriter;
|
|
|
+import java.io.PrintWriter;
|
|
|
+import java.net.URL;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.security.SecureRandom;
|
|
|
+import java.security.cert.X509Certificate;
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * Author: donglang
|
|
|
+ * Time: 2025-10-19
|
|
|
+ * Des: 中交接口
|
|
|
+ * Version: 1.0
|
|
|
+ */
|
|
|
+
|
|
|
+public class VehicleCollectService {
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private ObjectMapper objectMapper;
|
|
|
+
|
|
|
+ public static final String HMAC_SHA1 = "HmacSHA1";
|
|
|
+ public static final char[] DIGITAL = "0123456789ABCDEF".toCharArray();
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <pre>
|
|
|
+ * 请求流程:
|
|
|
+ * 1、其他 API,cid + 私钥生成的签名 + 业务参数
|
|
|
+ * </pre>
|
|
|
+ */
|
|
|
+ public CollectZjxlResponse transTimeManage(String carNo) throws Exception {
|
|
|
+ // URL 前缀
|
|
|
+ String baseUrl = "https://openapi-test.sinoiov.cn/save/apis/";
|
|
|
+ // 检索最新节点
|
|
|
+ String vLastLocationV3Url = baseUrl + "transTimeManageV3";
|
|
|
+ Map<String, String> vLastLocationParam = new HashMap<>();
|
|
|
+ // 客户端 ID
|
|
|
+ vLastLocationParam.put("cid", "7598ca30-000e-4930-953d-39e6756b6ee5");
|
|
|
+ // 私钥
|
|
|
+ vLastLocationParam.put("srt", "2b15bfd6-3546-4e25-bc9b-7cf88d4d2c3c");
|
|
|
+ // 业务参数
|
|
|
+ vLastLocationParam.put("vclN", carNo);
|
|
|
+ vLastLocationParam.put("timeNearby", "24");
|
|
|
+ String vLastLocationV3Result = httpsCall(vLastLocationV3Url, vLastLocationParam, false);
|
|
|
+
|
|
|
+ //反序列化
|
|
|
+ CollectZjxlResponse response = objectMapper.readValue(vLastLocationV3Result, CollectZjxlResponse.class);
|
|
|
+ return response;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * https 调用,1、处理参数:①移除srt,②计算签名,③增加sign;2、将 map参数拼接成string格式;3、发起调用;4、处理结果
|
|
|
+ *
|
|
|
+ * @param url url
|
|
|
+ * @param param 请求参数
|
|
|
+ * @param strict 严格模式 true 校验证书等;false 不校验
|
|
|
+ */
|
|
|
+ public static String httpsCall(String url, Map<String, String> param, boolean strict) throws Exception {
|
|
|
+ // 1、处理参数
|
|
|
+ processParam(param);
|
|
|
+ // 2、将 map 参数拼接成 string 格式
|
|
|
+ String reqBody = convertMapToString(param);
|
|
|
+ System.out.printf("Request - url: %s, reqBody: %s\n", url, reqBody);
|
|
|
+ if (!strict) {
|
|
|
+ // 信任证书
|
|
|
+ trustAllCerts();
|
|
|
+ // 信任域名
|
|
|
+ trustAllHosts();
|
|
|
+ }
|
|
|
+ // 3、发起调用;
|
|
|
+ HttpsURLConnection conn = (HttpsURLConnection) new URL(url).openConnection();
|
|
|
+ conn.setDoInput(true);
|
|
|
+ conn.setDoOutput(true);
|
|
|
+
|
|
|
+ conn.setUseCaches(false);
|
|
|
+ conn.setRequestMethod("POST");
|
|
|
+ conn.setRequestProperty("Content-Length", String.valueOf(reqBody.getBytes(StandardCharsets.UTF_8).length));
|
|
|
+ conn.setRequestProperty("charset", "UTF-8");
|
|
|
+ conn.connect();
|
|
|
+ PrintWriter writer = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(), StandardCharsets.UTF_8));
|
|
|
+ // 注意这里不能有换行
|
|
|
+ writer.print(reqBody);
|
|
|
+ writer.flush();
|
|
|
+ writer.close();
|
|
|
+ BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
|
|
|
+ String line;
|
|
|
+ StringBuilder result = new StringBuilder();
|
|
|
+ while ((line = reader.readLine()) != null) {
|
|
|
+ result.append(line);
|
|
|
+ }
|
|
|
+
|
|
|
+ reader.close();
|
|
|
+ System.out.printf("Response - code: %s, message: %s, respBody: %s\n", conn.getResponseCode(), conn.getResponseMessage(), result);
|
|
|
+ // 4、处理结果
|
|
|
+ return result.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理参数:①移除 srt,②计算签名,③增加 sign;
|
|
|
+ *
|
|
|
+ * @param param 原始参数
|
|
|
+ */
|
|
|
+ private static void processParam(Map<String, String> param) throws Exception {
|
|
|
+ if (!param.containsKey("srt")) {
|
|
|
+ throw new NullPointerException();
|
|
|
+ }
|
|
|
+ String srt = param.remove("srt");
|
|
|
+ List<String> paramValueList = new ArrayList<>();
|
|
|
+ for (Map.Entry<String, String> entry : param.entrySet()) {
|
|
|
+ paramValueList.add(entry.getKey() + entry.getValue());
|
|
|
+ }
|
|
|
+ Collections.sort(paramValueList);
|
|
|
+ String[] data = new String[paramValueList.size()];
|
|
|
+ paramValueList.toArray(data);
|
|
|
+ byte[] signature = hmacSha1(data, srt.getBytes(StandardCharsets.UTF_8));
|
|
|
+ String sign = encodeHexStr(signature);
|
|
|
+ param.put("sign", sign);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将参数转换为字符串
|
|
|
+ *
|
|
|
+ * @param param 请求参数
|
|
|
+ */
|
|
|
+ private static String convertMapToString(Map<String, String> param) {
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ if (param != null && !param.isEmpty()) {
|
|
|
+ for (Map.Entry<String, String> entry : param.entrySet()) {
|
|
|
+ sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
|
|
|
+ }
|
|
|
+ sb.deleteCharAt(sb.length() - 1);
|
|
|
+ }
|
|
|
+ return sb.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 信任所有证书
|
|
|
+ */
|
|
|
+ private static void trustAllCerts() throws Exception {
|
|
|
+ TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
|
|
|
+ public X509Certificate[] getAcceptedIssuers() {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void checkClientTrusted(X509Certificate[] certs, String authType) {
|
|
|
+ }
|
|
|
+
|
|
|
+ public void checkServerTrusted(X509Certificate[] certs, String authType) {
|
|
|
+ }
|
|
|
+ }};
|
|
|
+ SSLContext sc = SSLContext.getInstance("SSL");
|
|
|
+ sc.init(null, trustAllCerts, new SecureRandom());
|
|
|
+ HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 信任所有域名
|
|
|
+ */
|
|
|
+ private static void trustAllHosts() {
|
|
|
+ HostnameVerifier trustAllHosts = (hostname, session) -> true;
|
|
|
+ HttpsURLConnection.setDefaultHostnameVerifier(trustAllHosts);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * HmacSha1 定制算法
|
|
|
+ *
|
|
|
+ * @param strings 内容
|
|
|
+ * @param key key
|
|
|
+ * @return 签名
|
|
|
+ */
|
|
|
+ private static byte[] hmacSha1(String[] strings, byte[] key) throws Exception {
|
|
|
+ SecretKeySpec signingKey = new SecretKeySpec(key, HMAC_SHA1);
|
|
|
+ Mac mac = Mac.getInstance(HMAC_SHA1);
|
|
|
+ mac.init(signingKey);
|
|
|
+ for (String data : strings) {
|
|
|
+ mac.update(data.getBytes(StandardCharsets.UTF_8));
|
|
|
+ }
|
|
|
+ return mac.doFinal();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 字节转为 Hex 字符串
|
|
|
+ *
|
|
|
+ * @param bytes 字节数组
|
|
|
+ * @return Hex 字符串
|
|
|
+ */
|
|
|
+ private static String encodeHexStr(final byte[] bytes) {
|
|
|
+ if (bytes == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ char[] result = new char[bytes.length * 2];
|
|
|
+ for (int i = 0; i < bytes.length; i++) {
|
|
|
+ result[i * 2] = DIGITAL[(bytes[i] & 0xf0) >> 4];
|
|
|
+ result[i * 2 + 1] = DIGITAL[bytes[i] & 0x0f];
|
|
|
+ }
|
|
|
+ return new String(result);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|