新增对 SIM 卡商的 HTTP 状态查询和流量查询接口

This commit is contained in:
fengyarnom 2025-02-21 10:07:21 +08:00
parent aa0ef8625d
commit 6d6a400dca
7 changed files with 308 additions and 0 deletions

View File

@ -0,0 +1,20 @@
package com.imdroid.sideslope.service;
import com.imdroid.sideslope.sal.Device;
import com.imdroid.sideslope.simcard.*;
public interface SimCardQueryService {
// 查询卡基本信息
BaseResponse<CardInfoData> queryCardInfo(Device device);
// 查询卡状态
BaseResponse<CardStatusData> queryCardStatus(Device device);
// 查询流量信息
BaseResponse<GprsData> queryGprs(Device device);
// 查询卡详细信息
BaseResponse<CardDetailData> queryCardDetail(Device device);
}

View File

@ -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<CardInfoData> queryCardInfo(Device device) {
return executeQuery(device, "/api/Service/Cardinfo", CardInfoData.class);
}
@Override
public BaseResponse<CardStatusData> queryCardStatus(Device device) {
return executeQuery(device, "/api/Service/QueryCardStatus", CardStatusData.class);
}
@Override
public BaseResponse<GprsData> queryGprs(Device device) {
return executeQuery(device, "/api/Service/QueryGprs", GprsData.class);
}
@Override
public BaseResponse<CardDetailData> queryCardDetail(Device device) {
return executeQuery(device, "/api/Service/QueryCard", CardDetailData.class);
}
private <T> BaseResponse<T> executeQuery(Device device, String path, Class<T> responseType) {
try {
Map<String, String> 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<CardStatusData> baseResponse = new BaseResponse<>();
baseResponse.setStatus(1);
baseResponse.setMessage("Success");
baseResponse.setData(statusData);
return (BaseResponse<T>) 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<String, String> params) {
try {
List<String> paramList = new ArrayList<>();
for (Map.Entry<String, String> 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<String, String> params) throws Exception {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost httpPost = new HttpPost(BASE_URL + path);
List<BasicNameValuePair> pairs = new ArrayList<>();
for (Map.Entry<String, String> 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;
}
}

View File

@ -0,0 +1,10 @@
package com.imdroid.sideslope.simcard;
import lombok.Data;
@Data
public class BaseResponse<T> {
private Integer status;
private String message;
private T data;
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -0,0 +1,10 @@
package com.imdroid.sideslope.simcard;
import lombok.Data;
@Data
public class CardStatusData {
private Integer statusCode;
private String statusDesc;
}

View File

@ -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<GprsUsage> 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;
}
}