From 6d6a400dca8b6eb1f0a6868d5ecc8b3b81b595e2 Mon Sep 17 00:00:00 2001 From: fengyarnom Date: Fri, 21 Feb 2025 10:07:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AF=B9=20SIM=20=E5=8D=A1?= =?UTF-8?q?=E5=95=86=E7=9A=84=20HTTP=20=E7=8A=B6=E6=80=81=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E5=92=8C=E6=B5=81=E9=87=8F=E6=9F=A5=E8=AF=A2=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/SimCardQueryService.java | 20 ++ .../service/SimCardQueryServiceImpl.java | 179 ++++++++++++++++++ .../sideslope/simcard/BaseResponse.java | 10 + .../sideslope/simcard/CardDetailData.java | 38 ++++ .../sideslope/simcard/CardInfoData.java | 10 + .../sideslope/simcard/CardStatusData.java | 10 + .../imdroid/sideslope/simcard/GprsData.java | 41 ++++ 7 files changed, 308 insertions(+) create mode 100644 sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/SimCardQueryService.java create mode 100644 sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/SimCardQueryServiceImpl.java create mode 100644 sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/BaseResponse.java create mode 100644 sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/CardDetailData.java create mode 100644 sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/CardInfoData.java create mode 100644 sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/CardStatusData.java create mode 100644 sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/GprsData.java diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/SimCardQueryService.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/SimCardQueryService.java new file mode 100644 index 00000000..f2d12878 --- /dev/null +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/SimCardQueryService.java @@ -0,0 +1,20 @@ +package com.imdroid.sideslope.service; + +import com.imdroid.sideslope.sal.Device; +import com.imdroid.sideslope.simcard.*; + +public interface SimCardQueryService { + + // 查询卡基本信息 + BaseResponse queryCardInfo(Device device); + + // 查询卡状态 + BaseResponse queryCardStatus(Device device); + + // 查询流量信息 + BaseResponse queryGprs(Device device); + + // 查询卡详细信息 + BaseResponse queryCardDetail(Device device); + +} diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/SimCardQueryServiceImpl.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/SimCardQueryServiceImpl.java new file mode 100644 index 00000000..15bcf6cf --- /dev/null +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/service/SimCardQueryServiceImpl.java @@ -0,0 +1,179 @@ +package com.imdroid.sideslope.service; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.imdroid.secapi.dto.GnssStatusJoin; +import com.imdroid.secapi.dto.SimCard; +import com.imdroid.secapi.dto.SimCardsMapper; +import com.imdroid.sideslope.sal.Device; +import com.imdroid.sideslope.sal.DeviceService; +import com.imdroid.sideslope.simcard.*; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.security.MessageDigest; +import java.util.*; + +@Service +public class SimCardQueryServiceImpl implements SimCardQueryService{ + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private static final String BASE_URL = "http://120.78.169.220:8089"; + private static final String USERNAME = "gzyzdz"; + private static final String KEY = "632629d1269a202c9d49a574623e4e4c"; + + @Resource(name = "local") + private DeviceService deviceService; + + @Autowired + SimCardsMapper simCardsMapper; + + @Override + public BaseResponse queryCardInfo(Device device) { + return executeQuery(device, "/api/Service/Cardinfo", CardInfoData.class); + } + + @Override + public BaseResponse queryCardStatus(Device device) { + return executeQuery(device, "/api/Service/QueryCardStatus", CardStatusData.class); + } + + @Override + public BaseResponse queryGprs(Device device) { + return executeQuery(device, "/api/Service/QueryGprs", GprsData.class); + } + + @Override + public BaseResponse queryCardDetail(Device device) { + return executeQuery(device, "/api/Service/QueryCard", CardDetailData.class); + } + + private BaseResponse executeQuery(Device device, String path, Class responseType) { + try { + Map params = new HashMap<>(); + params.put("username", USERNAME); + params.put("key", KEY); + params.put("card", device.getIccid()); + params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000)); + + String signature = calculateSignature(params); + params.put("signature", signature); + + logger.info("Request params: {}", params); + String response = sendHttpPost(path, params); + logger.info("查询响应: 设备={}, ICCID={}, 响应={}", + device.getDeviceId(), device.getIccid(), response); + + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true); + + // 特殊处理CardStatus的数组响应 + if (responseType == CardStatusData.class) { + JsonNode root = mapper.readTree(response); + if (root.get("Status").asInt() == 1 && root.get("Data").isArray()) { + CardStatusData statusData = new CardStatusData(); + statusData.setStatusCode(root.get("Data").get(0).asInt()); + statusData.setStatusDesc(root.get("Data").get(1).asText()); + BaseResponse baseResponse = new BaseResponse<>(); + baseResponse.setStatus(1); + baseResponse.setMessage("Success"); + baseResponse.setData(statusData); + return (BaseResponse) baseResponse; + } + } + + JavaType type = mapper.getTypeFactory().constructParametricType(BaseResponse.class, responseType); + return mapper.readValue(response, type); + + } catch (Exception e) { + logger.error("查询失败: 设备={}, 错误={}", device.getDeviceId(), e.getMessage()); + return null; + } + } + + private String calculateSignature(Map params) { + try { + List paramList = new ArrayList<>(); + for (Map.Entry entry : params.entrySet()) { + paramList.add(entry.getKey() + "=" + entry.getValue()); + } + Collections.sort(paramList); + + String paramString = String.join("&", paramList); + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] digest = md.digest(paramString.getBytes()); + StringBuilder sb = new StringBuilder(); + for (byte b : digest) { + sb.append(String.format("%02x", b)); + } + String signature = sb.toString(); + logger.debug("Signature: {}", signature); + return signature; + + } catch (Exception e) { + logger.error("签名计算失败: {}", e.getMessage()); + return null; + } + } + + private String sendHttpPost(String path, Map params) throws Exception { + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpPost httpPost = new HttpPost(BASE_URL + path); + + List pairs = new ArrayList<>(); + for (Map.Entry entry : params.entrySet()) { + pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); + } + + httpPost.setEntity(new UrlEncodedFormEntity(pairs)); + httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded"); + + try (CloseableHttpResponse response = httpClient.execute(httpPost)) { + return EntityUtils.toString(response.getEntity()); + } + } + } + + public boolean hasValidIccid(Device device) { + return device.getIccid() != null && !device.getIccid().trim().isEmpty(); + } + + public SimCard CreateOrUpdateSimCard(Device device) { + SimCard simCard = simCardsMapper.queryByDeviceId(device.getDeviceId()); + if (simCard == null) { + simCard = createNewSimCard(device); + } + return simCard; + } + + public SimCard createNewSimCard(Device device) { + SimCard newCard = new SimCard(); + newCard.setDeviceid(device.getDeviceId()); + newCard.setUpdatetime(new Date()); + newCard.setIccid(device.getIccid()); + newCard.setStatus(-1); + newCard.setMsisdn(""); + newCard.setRemaining(BigDecimal.ZERO); + newCard.setUsed(BigDecimal.ZERO); + newCard.setTotal(BigDecimal.ZERO); + + simCardsMapper.insert(newCard); + return newCard; + } + + public boolean isValidResponse(BaseResponse response) { + return response != null && response.getStatus() == 1; + } +} diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/BaseResponse.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/BaseResponse.java new file mode 100644 index 00000000..6f6e42a9 --- /dev/null +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/BaseResponse.java @@ -0,0 +1,10 @@ +package com.imdroid.sideslope.simcard; + +import lombok.Data; + +@Data +public class BaseResponse { + private Integer status; + private String message; + private T data; +} diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/CardDetailData.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/CardDetailData.java new file mode 100644 index 00000000..5f1a5b14 --- /dev/null +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/CardDetailData.java @@ -0,0 +1,38 @@ +package com.imdroid.sideslope.simcard; + +import lombok.Data; + +@Data +public class CardDetailData { + private Integer operatortype; + private String activetime; + private String starttime; + private String stoptime; + private String silentdate; + private Integer status; + private String msisdn; + private String iccid; + private String imsi; + private Integer packageid; + private String packagename; + private String net; + + private GprsInfo gprs; + private ApnInfo apn; + + @Data + public static class GprsInfo { + private Double total; + private Double used; + private Double left; + } + + @Data + public static class ApnInfo { + private String apnid; + private String status; + private String ip; + private String rat; + private String onoffstatus; + } +} diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/CardInfoData.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/CardInfoData.java new file mode 100644 index 00000000..80db3d36 --- /dev/null +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/CardInfoData.java @@ -0,0 +1,10 @@ +package com.imdroid.sideslope.simcard; + +import lombok.Data; + +@Data +public class CardInfoData { + private String imsi; + private String msisdn; + private String iccid; +} diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/CardStatusData.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/CardStatusData.java new file mode 100644 index 00000000..43f8ec9f --- /dev/null +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/CardStatusData.java @@ -0,0 +1,10 @@ +package com.imdroid.sideslope.simcard; + +import lombok.Data; + + +@Data +public class CardStatusData { + private Integer statusCode; + private String statusDesc; +} diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/GprsData.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/GprsData.java new file mode 100644 index 00000000..caeb4041 --- /dev/null +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/simcard/GprsData.java @@ -0,0 +1,41 @@ +package com.imdroid.sideslope.simcard; + +import lombok.Data; + +import java.util.List; + +@Data +public class GprsData { + private Integer operatortype; + private List gps; + + @Data + public static class GprsUsage { + private Double left; + private Double total; + private Double used; + } + + // 返回数据格式 + // { + // "Status": 1, + // "Message": "Success", + // "Data": { + // "operatortype": 1, + // "GPS": [ + // { + // "Left": "2023", + // "Total": "2.0", + // "Used": "25" + // } + // ] + // } + // } + + public GprsUsage getFirstGprsUsage() { + if (gps != null && !gps.isEmpty()) { + return gps.get(0); + } + return null; + } +}