南岐GPS三方接口对接

This commit is contained in:
秦鸿展
2026-08-27 13:58:10 +08:00
parent f1dec2298d
commit e4b29858a4
5 changed files with 478 additions and 0 deletions
@@ -0,0 +1,214 @@
package com.linke.thirdParty.application.server;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.linke.thirdParty.domain.departInterfaceInfo.repository.todo.SysDepartInterfaceInfoDo;
import com.linke.thirdParty.infrastructure.dict.NanqiGpsConstant;
import com.linke.thirdParty.interfaces.vo.gps.NanqiGpsLocationVO;
import com.mhd.common.core.domain.po.thirdparty.SysDepartInterfaceInfoPo;
import com.mhd.common.core.exception.ServiceException;
import com.mhd.common.core.utils.HttpClientUtil;
import com.mhd.common.redis.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 南岐车联网GPS平台 对接应用服务
*
* <p>提供两个接口:</p>
* <ol>
* <li>login:登录获取 sessionId,并缓存到 Redis</li>
* <li>queryByPlate:根据车牌号+sessionId 查询车辆实时定位</li>
* </ol>
*
* @author mhd
*/
@Slf4j
@Service
public class NanqiGpsApplicationService {
@Autowired
private SysDepartInterfaceInfoApplicationService interfaceInfoApplicationService;
@Autowired
private RedisService redisService;
/**
* 南岐登录账号
*/
private String userId = NanqiGpsConstant.DEFAULT_USER_ID;
/**
* 南岐登录密码(明文)
*/
private String password = NanqiGpsConstant.DEFAULT_PASSWORD;
/**
* 从三方接口配置表读取南岐配置(interfaceType = nanqi_gps),未配置则使用默认值
*/
private void getBaseInfo() {
SysDepartInterfaceInfoDo sysDepartInterfaceInfoDo = new SysDepartInterfaceInfoDo();
sysDepartInterfaceInfoDo.setInterfaceType(NanqiGpsConstant.INTERFACE_TYPE);
List<SysDepartInterfaceInfoPo> sysDepartInterfaceInfoPos = interfaceInfoApplicationService.queryList1(sysDepartInterfaceInfoDo);
if (sysDepartInterfaceInfoPos == null || sysDepartInterfaceInfoPos.isEmpty()) {
return;
}
for (SysDepartInterfaceInfoPo info : sysDepartInterfaceInfoPos) {
String key = info.getInterfaceTypeKey();
String value = info.getInterfaceTypeValue();
if ("userId".equals(key)) {
userId = value;
} else if ("password".equals(key)) {
password = value;
}
}
}
/**
* 登录获取 sessionId(若 Redis 已有有效 sessionId 则直接复用)
*
* @return sessionId
*/
public String login() {
return getSessionId();
}
/**
* 获取有效 sessionId:优先从 Redis 取,取不到则调用登录接口重新获取
*
* @return sessionId
*/
public String getSessionId() {
String cacheKey = NanqiGpsConstant.SESSION_ID_KEY;
String sessionId = redisService.getCacheObject(cacheKey);
if (sessionId != null && !sessionId.isEmpty()) {
return sessionId;
}
// 重新登录
getBaseInfo();
sessionId = doLogin(userId, password, NanqiGpsConstant.LOGIN_TYPE_USER);
if (sessionId != null && !sessionId.isEmpty()) {
redisService.setCacheObject(cacheKey, sessionId, NanqiGpsConstant.SESSION_ID_EXPIRE_SECONDS, TimeUnit.SECONDS);
}
return sessionId;
}
/**
* 手动刷新 sessionId(强制重新登录,忽略缓存)
*
* @return sessionId
*/
public String refreshSessionId() {
redisService.deleteObject(NanqiGpsConstant.SESSION_ID_KEY);
return getSessionId();
}
/**
* 执行南岐登录接口
*
* @param loginUserId 登录账号
* @param loginPassword 登录密码(明文)
* @param loginType user-用户 car-车辆/人员
* @return sessionId
*/
private String doLogin(String loginUserId, String loginPassword, String loginType) {
Map<String, String> params = new HashMap<>();
params.put("userId", loginUserId);
// 密码需要 MD5 32 位小写加密
String md5Pwd = DigestUtils.md5DigestAsHex(loginPassword.getBytes()).toLowerCase();
params.put("password", md5Pwd);
params.put("loginType", loginType == null ? NanqiGpsConstant.LOGIN_TYPE_USER : loginType);
params.put("loginWay", NanqiGpsConstant.DEFAULT_LOGIN_WAY);
params.put("loginLang", NanqiGpsConstant.DEFAULT_LOGIN_LANG);
String result = HttpClientUtil.doGet(NanqiGpsConstant.LOGIN_URL, params);
log.info("南岐GPS登录返回: {}", result);
JSONObject json = JSON.parseObject(result);
if (json == null) {
throw new ServiceException("南岐GPS登录接口无响应");
}
Integer rspCode = json.getInteger("rspCode");
if (rspCode == null || rspCode != 1) {
throw new ServiceException("南岐GPS登录失败:" + json.getString("rspDesc"));
}
return json.getString("sessionId");
}
/**
* 根据车牌号查询车辆实时定位
*
* @param carPlate 车牌号
* @return 车辆定位信息
*/
public NanqiGpsLocationVO queryByPlate(String carPlate) {
if (carPlate == null || carPlate.trim().isEmpty()) {
throw new ServiceException("车牌号不能为空");
}
String sessionId = getSessionId();
if (sessionId == null || sessionId.isEmpty()) {
throw new ServiceException("获取南岐GPS sessionId失败");
}
Map<String, String> params = new HashMap<>();
params.put("carPlate", carPlate.trim());
params.put("sessionId", sessionId);
String result = HttpClientUtil.doGet(NanqiGpsConstant.GET_GPS_URL, params);
log.info("南岐GPS查询车辆[{}]返回: {}", carPlate, result);
JSONObject json = JSON.parseObject(result);
if (json == null) {
throw new ServiceException("南岐GPS查询接口无响应");
}
Integer rspCode = json.getInteger("rspCode");
if (rspCode == null || rspCode != 1) {
// 可能是 sessionId 失效,尝试刷新后重试一次
String newSessionId = refreshSessionId();
params.put("sessionId", newSessionId);
result = HttpClientUtil.doGet(NanqiGpsConstant.GET_GPS_URL, params);
json = JSON.parseObject(result);
if (json == null || !Integer.valueOf(1).equals(json.getInteger("rspCode"))) {
throw new ServiceException("南岐GPS查询失败:" + (json == null ? "" : json.getString("rspDesc")));
}
}
NanqiGpsLocationVO vo = new NanqiGpsLocationVO();
vo.setRspCode(json.getInteger("rspCode"));
vo.setRspDesc(json.getString("rspDesc"));
JSONArray list = json.getJSONArray("list");
if (list != null && !list.isEmpty()) {
JSONObject loc = list.getJSONObject(0);
vo.setCarId(loc.getString("carId"));
vo.setCarPlate(loc.getString("carPlate"));
vo.setCarName(loc.getString("carName"));
vo.setTeamId(loc.getString("teamId"));
vo.setTeamName(loc.getString("teamName"));
vo.setTime(loc.getString("time"));
vo.setLng(loc.getBigDecimal("lng"));
vo.setLat(loc.getBigDecimal("lat"));
vo.setSpeed(loc.getBigDecimal("speed"));
vo.setDrct(loc.getString("drct"));
vo.setMile(loc.getString("mile"));
vo.setPreMile(loc.getString("preMile"));
vo.setSatl(loc.getString("satl"));
vo.setSgn(loc.getString("sgn"));
vo.setAddr(loc.getString("addr"));
vo.setState(loc.getString("state"));
vo.setStateCn(loc.getString("stateCn"));
vo.setDrvName(loc.getString("drvName"));
vo.setDrvPhone(loc.getString("drvPhone"));
vo.setCarType(loc.getString("carType"));
vo.setExpState(loc.getString("expState"));
vo.setExpTime(loc.getString("expTime"));
}
return vo;
}
}
@@ -0,0 +1,64 @@
package com.linke.thirdParty.infrastructure.dict;
/**
* 南岐车联网GPS平台 接口常量
*
* @author mhd
*/
public class NanqiGpsConstant {
/**
* 三方接口配置表 interfaceType(对应 sys_depart_interface_info 表)
*/
public static final String INTERFACE_TYPE = "nanqi_gps";
/**
* 登录接口地址(第一接口)
*/
public static final String LOGIN_URL = "http://iov.yotugo.com/gps-web/api/login.jsp";
/**
* 车辆定位查询接口地址(第二接口)
*/
public static final String GET_GPS_URL = "http://iov.yotugo.com/gps-web/api/get_gps_r_plate.jsp";
/**
* 登录账号(默认值,可被 sys_depart_interface_info 配置覆盖,key 为 userId
*/
public static final String DEFAULT_USER_ID = "zhnanqi";
/**
* 登录密码(默认值,明文,可被配置覆盖,key 为 password
*/
public static final String DEFAULT_PASSWORD = "nq123456";
/**
* 登录方式:默认 interface
*/
public static final String DEFAULT_LOGIN_WAY = "interface";
/**
* 登录语言:默认中文
*/
public static final String DEFAULT_LOGIN_LANG = "zh_CN";
/**
* 登录类型:car 表示按车辆/人员登录
*/
public static final String LOGIN_TYPE_CAR = "car";
/**
* 登录类型:user 表示按用户登录
*/
public static final String LOGIN_TYPE_USER = "user";
/**
* sessionId 缓存 key 前缀
*/
public static final String SESSION_ID_KEY = "nanqi_gps:sessionId:";
/**
* sessionId 缓存时长(秒),默认 12 小时
*/
public static final long SESSION_ID_EXPIRE_SECONDS = 12 * 60 * 60L;
}
@@ -0,0 +1,28 @@
package com.linke.thirdParty.interfaces.dto.gps;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* 南岐GPS 登录入参
*
* @author mhd
*/
@Data
@ApiModel("南岐GPS 登录入参")
public class NanqiGpsLoginDTO implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "登录用户/车牌号(loginType=user填用户IDloginType=car填车牌号),为空时使用平台配置的账号", required = false)
private String userId;
@ApiModelProperty(value = "登录密码(明文,内部会MD5小写加密),为空时使用平台配置的密码", required = false)
private String password;
@ApiModelProperty(value = "登录类型:user-用户 car-车辆/人员,默认car", required = false)
private String loginType;
}
@@ -0,0 +1,80 @@
package com.linke.thirdParty.interfaces.facade;
import com.linke.thirdParty.application.server.NanqiGpsApplicationService;
import com.linke.thirdParty.interfaces.vo.gps.NanqiGpsLocationVO;
import com.mhd.common.core.exception.ServiceException;
import com.mhd.common.core.web.domain.AjaxResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* 南岐车联网GPS平台 接口
*
* @author mhd
*/
@RestController
@RequestMapping("/nanqiGps")
@Api(tags = "南岐车联网GPS")
@Slf4j
public class NanqiGpsApi {
@Autowired
private NanqiGpsApplicationService nanqiGpsApplicationService;
/**
* 登录获取 sessionId
*/
@ApiOperation(value = "登录获取sessionId", notes = "登录获取南岐GPS平台sessionIdRedis缓存复用)")
@GetMapping(value = "/login")
public AjaxResult login() {
try {
String sessionId = nanqiGpsApplicationService.login();
return AjaxResult.success("操作成功", sessionId);
} catch (ServiceException e) {
return AjaxResult.error(500, e.getMessage());
} catch (Exception e) {
log.error("南岐GPS登录失败", e);
return AjaxResult.error(500, "操作失败" + e.getMessage());
}
}
/**
* 手动刷新 sessionId
*/
@ApiOperation(value = "手动刷新sessionId", notes = "强制重新登录南岐GPS平台,忽略缓存")
@GetMapping(value = "/refreshSessionId")
public AjaxResult refreshSessionId() {
try {
String sessionId = nanqiGpsApplicationService.refreshSessionId();
return AjaxResult.success("操作成功", sessionId);
} catch (ServiceException e) {
return AjaxResult.error(500, e.getMessage());
} catch (Exception e) {
log.error("南岐GPS刷新sessionId失败", e);
return AjaxResult.error(500, "操作失败" + e.getMessage());
}
}
/**
* 根据车牌号查询车辆实时定位
*/
@ApiOperation(value = "根据车牌号查询车辆实时定位", notes = "通过车牌号查询南岐GPS车辆实时定位")
@GetMapping(value = "/queryByPlate")
public AjaxResult queryByPlate(@RequestParam(value = "carPlate") String carPlate) {
try {
NanqiGpsLocationVO vo = nanqiGpsApplicationService.queryByPlate(carPlate);
return AjaxResult.success("操作成功", vo);
} catch (ServiceException e) {
return AjaxResult.error(500, e.getMessage());
} catch (Exception e) {
log.error("南岐GPS查询车辆[{}]定位失败", carPlate, e);
return AjaxResult.error(500, "操作失败" + e.getMessage());
}
}
}
@@ -0,0 +1,92 @@
package com.linke.thirdParty.interfaces.vo.gps;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* 南岐GPS 车辆定位信息 VO(对应文档 表1 常用字段)
*
* @author mhd
*/
@Data
@ApiModel("南岐GPS 车辆定位信息")
public class NanqiGpsLocationVO implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("应答结果:1成功 0失败")
private Integer rspCode;
@ApiModelProperty("应答描述")
private String rspDesc;
@ApiModelProperty("车辆id")
private String carId;
@ApiModelProperty("车牌号")
private String carPlate;
@ApiModelProperty("车辆名")
private String carName;
@ApiModelProperty("车队id")
private String teamId;
@ApiModelProperty("车队名称")
private String teamName;
@ApiModelProperty("定位时间")
private String time;
@ApiModelProperty("经度(WGS84")
private BigDecimal lng;
@ApiModelProperty("纬度(WGS84")
private BigDecimal lat;
@ApiModelProperty("速度(千米/小时)")
private BigDecimal speed;
@ApiModelProperty("方向 0~360")
private String drct;
@ApiModelProperty("平台总里程(千米)")
private String mile;
@ApiModelProperty("今日里程(千米)")
private String preMile;
@ApiModelProperty("定位信号:0无 弱<=3 中<=6 强>6")
private String satl;
@ApiModelProperty("通讯信号:0无 弱<=10 中<=20 强>20")
private String sgn;
@ApiModelProperty("地理描述")
private String addr;
@ApiModelProperty("车辆定位状态")
private String state;
@ApiModelProperty("车辆状态文字")
private String stateCn;
@ApiModelProperty("驾驶员")
private String drvName;
@ApiModelProperty("驾驶员电话")
private String drvPhone;
@ApiModelProperty("车辆类型")
private String carType;
@ApiModelProperty("服务到期状态:1已到期 0未到期")
private String expState;
@ApiModelProperty("服务期限")
private String expTime;
}