新增对 SIM 卡商的 HTTP 状态查询和流量查询接口
This commit is contained in:
parent
aa0ef8625d
commit
6d6a400dca
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package com.imdroid.sideslope.simcard;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class CardStatusData {
|
||||||
|
private Integer statusCode;
|
||||||
|
private String statusDesc;
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user