You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

241 lines
9.7KB

  1. package com.telpo.beidouast.service.impl;
  2. import com.alibaba.fastjson.JSONObject;
  3. import com.telpo.beidouast.common.*;
  4. import com.telpo.beidouast.entity.mongo.IPProvinceEntity;
  5. import com.telpo.beidouast.service.IDipperAstPosAsyncTaskService;
  6. import com.telpo.beidouast.service.IPProvinceService;
  7. import lombok.extern.slf4j.Slf4j;
  8. import org.apache.commons.lang3.ObjectUtils;
  9. import org.springframework.beans.factory.annotation.Autowired;
  10. import org.springframework.scheduling.annotation.Async;
  11. import org.springframework.stereotype.Service;
  12. import java.io.UnsupportedEncodingException;
  13. import java.util.List;
  14. /**
  15. * @program: DipperAstPosAsyncTaskServiceImpl
  16. * @description: 系统预先基于省份的省会城市的经纬度作为辅助信息,
  17. * * 根据设备请求的IP地址,从高德IP定位服务获取相关的省份,再匹配相应的位置信息作为辅助位置信息。
  18. * * 如果匹配不到省份,则以武汉中心作为辅助为位置信息。
  19. * * 关于IP与省份的关系保存到缓存中,用于下次使用时,先在缓存中获取匹配信息,匹配不到,再请求高德IP定位服务。
  20. * * 高德IP定位服务:https://lbs.amap.com/api/webservice/guide/api/ipconfig。
  21. * @author: king
  22. * @create: 2021-01-10 14:01
  23. */
  24. @Service
  25. @Slf4j
  26. public class DipperAstPosAsyncTaskServiceImpl implements IDipperAstPosAsyncTaskService {
  27. @Autowired
  28. private RedisUtil redisUtil;
  29. @Autowired
  30. private OkHttpUtil okHttpUtil;
  31. @Autowired
  32. private IPProvinceService iPProvinceService;
  33. private String centerProvince;
  34. private String centerProvinceFilePath;
  35. private String ipPositionRequestPath;
  36. private String ipPositionRequestKey;
  37. // private String getAstPos(String ipAddress) throws UnsupportedEncodingException {
  38. //
  39. // String centerAddress = getIpPositionProvince(ipAddress);
  40. // if (ObjectUtils.isEmpty(centerAddress) || centerAddress.equals("0")) {
  41. // log.warn("IP地址非法,无法获取辅助位置信息!");
  42. // // 返回武汉的定位数据
  43. // centerAddress = centerProvince;
  44. // } else {
  45. // // 保存到mongoDB
  46. // createIPProvince(ipAddress, centerAddress);
  47. // }
  48. //
  49. // String lonAndAlt;
  50. // if (redisUtil.hasKey(centerAddress)) {
  51. // // 获取省会城市定位信息
  52. // lonAndAlt= (String) redisUtil.get(centerAddress);
  53. // } else {
  54. // // 请求高德IP定位服务
  55. // this.getPosFromFile(centerAddress);
  56. // lonAndAlt = (String) redisUtil.get(centerAddress);
  57. // }
  58. //
  59. // return lonAndAlt;
  60. // }
  61. // 从CSV文件读取省会城市中心点位置信息
  62. private void getPosFromFile(String centerAddress) {
  63. // 不存在说明token是已过期了
  64. String centerProvinceName = "";
  65. String centerProvinceLonAndAlt = "";
  66. List<String> centerAddressSets = CSVUtil.readCSV(this.centerProvinceFilePath);
  67. for (String centerAddressSet:centerAddressSets) {
  68. String[] centerAddressSetArray = centerAddressSet.split(",");
  69. if (centerAddressSetArray.length < 3) {
  70. log.warn("CSV数据格式错误");
  71. } else {
  72. centerProvinceName = centerAddressSetArray[3];
  73. centerProvinceLonAndAlt = centerAddressSetArray[1]+","+centerAddressSetArray[2];
  74. redisUtil.set(centerProvinceName, centerProvinceLonAndAlt, 0);
  75. }
  76. }
  77. }
  78. // 根据IP获取省会信息
  79. private String getIpPositionProvince(String ipAddress) {
  80. // 关于IP与省份的关系保存到缓存中
  81. // 使用时,先在缓存中获取匹配信息
  82. // 用mongodb实现
  83. IPProvinceEntity ipProvinceEntity = iPProvinceService.getIPProvince(ipAddress);
  84. if (ipProvinceEntity == null) {
  85. // 匹配不到,再请求高德IP定位服务。
  86. JSONObject userObj = new JSONObject();
  87. userObj.put("ip", ipAddress);
  88. userObj.put("key", ipPositionRequestKey);
  89. JSONObject json = okHttpUtil.postRequestWithJson(ipPositionRequestPath, null, userObj);
  90. if (ObjectUtils.isNotEmpty(json)) {
  91. String province = (String) json.get("province");
  92. if (ObjectUtils.isEmpty(province)) {
  93. log.debug("json is :" + json.toString());
  94. return null;
  95. }
  96. return province;
  97. } else {
  98. // 意外错误
  99. log.debug("ip address is null");
  100. return null;
  101. }
  102. } else {
  103. return ipProvinceEntity.getProvince();
  104. }
  105. }
  106. // 将IP对应的省会保存到mongoDB
  107. @Async("asyncServiceExecutor")
  108. public void createIPProvince(String ipAddress, String province) {
  109. log.debug("异步创建推送失败任务记录!");
  110. try {
  111. IPProvinceEntity ipProvinceEntity = iPProvinceService.getIPProvince(ipAddress);
  112. if (ipProvinceEntity == null) {
  113. //DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
  114. ipProvinceEntity.setIp(ipAddress);
  115. ipProvinceEntity.setProvince(province);
  116. iPProvinceService.saveIPProvince(ipProvinceEntity);
  117. // } else {
  118. //
  119. // ipProvinceEntity.setProvince(province);
  120. // iPProvinceService.updateIPProvince(ipProvinceEntity, ipProvinceEntity);
  121. }
  122. } catch (Exception e) {
  123. log.error("创建推送失败记录异常:", e);
  124. }
  125. }
  126. /*
  127. * 获取定位辅助信息
  128. * @param ipAddress
  129. */
  130. @Override
  131. @Async("asyncServiceExecutor")
  132. public String pushAstPos(String ipAddress,
  133. String centerProvinceFilePath,
  134. String centerProvince,
  135. String ipPositionRequestPath,
  136. String ipPositionRequestKey) throws UnsupportedEncodingException {
  137. this.ipPositionRequestKey = ipPositionRequestKey;
  138. this.ipPositionRequestPath = ipPositionRequestPath;
  139. this.centerProvince = centerProvince;
  140. this.centerProvinceFilePath = centerProvinceFilePath;
  141. // (1) 获取省会城市信息
  142. String centerAddress = getIpPositionProvince(ipAddress);
  143. if (ObjectUtils.isEmpty(centerAddress) || centerAddress.equals("0")) {
  144. log.warn("IP地址非法,无法获取辅助位置信息!");
  145. // 返回武汉的定位数据
  146. centerAddress = this.centerProvince;
  147. } else {
  148. // 保存到mongoDB
  149. createIPProvince(ipAddress, centerAddress);
  150. }
  151. String lonAndAlt;
  152. if (redisUtil.hasKey(centerAddress)) {
  153. // 获取省会城市定位信息
  154. lonAndAlt= (String) redisUtil.get(centerAddress);
  155. } else {
  156. // 请求高德IP定位服务
  157. this.getPosFromFile(centerAddress);
  158. lonAndAlt = (String) redisUtil.get(centerAddress);
  159. }
  160. // (2) 处理返回结果
  161. if (lonAndAlt == null) {
  162. // null处理
  163. log.error("系统错误,请联系系统管理员。");
  164. return null;
  165. //return;
  166. }
  167. // push to GNNS Server
  168. String pushResult = getCmdOfPos(lonAndAlt);
  169. return pushResult;
  170. }
  171. // 组装命令发送给设备
  172. private String getCmdOfPos(String astPos) {
  173. // 创建Socket客户端实例;
  174. // SocketClient client = new SocketClient(astServer, posAstPort, astTimeout);
  175. // 时间和位置不是从服务器获取,而是本地生成
  176. String[] astPosArray = astPos.split(",");
  177. String lan = astPosArray[0].trim();
  178. String alt = astPosArray[1].trim();
  179. double lanValue = Double.parseDouble(lan) * 10000000;
  180. long lanLongValue = Double.doubleToLongBits(lanValue);
  181. if (lanLongValue < 0) {
  182. lanLongValue = lanLongValue + 4294967295L + 1;
  183. }
  184. double altValue = Double.parseDouble(alt) * 10000000;
  185. long altLongValue = Double.doubleToLongBits(altValue);
  186. if (altLongValue < 0) {
  187. altLongValue = altLongValue + 4294967295L + 1;
  188. }
  189. // 数值换算举例(以经度举例。纬度、高度、位置精度换算方法一致):
  190. // (1)经度数值为 113.431,则换算方法如下:
  191. // 113.431/比例因子 = 1134310000(十进制)
  192. //  439C3270(十六进制)
  193. //  经度数据填入 70 32 9C 43(小端模式)
  194. // (2)经度数值为-113.431,则换算方法如下:
  195. // 113.431/比例因子 = 1134310000(十进制)
  196. //  439C3270(十六进制)
  197. //  FFFFFFFF - 439C3270 + 1= BC63CD90(补码)
  198. // 经度数据填入 90 CD 63 BC(小端模式)
  199. // 指令(十六进制)
  200. // 举例: 23 3E 04 01 10 00 70 32 9C 43 D0 B2 CE 0D 70 17 00 00 40 0D 03 00 CA 95
  201. // 其中
  202. // 23 3E 为同步头
  203. // 04 01 为识别码
  204. // 10 00 表示长度为 16
  205. // 70 32 9C 43 表示注入的辅助经度为 113.431 度
  206. // D0 B2 CE 0D 表示注入的辅助纬度为 23.165 度
  207. // 00 2F 为校验和
  208. // astTimeCmd 组装
  209. String astTimeCmd = "233E0401";
  210. astTimeCmd += "1000";
  211. astTimeCmd += HexConvert.encodeHEX(lanLongValue);
  212. astTimeCmd += HexConvert.encodeHEX(altLongValue);
  213. String hexIn = HexConvert.convertStringToHex(astTimeCmd) + HexConvert.makeChecksum(astTimeCmd);
  214. //String sendResult = client.sendCmd(hexIn, ackAckCheckRef);
  215. //client.closeConnection();
  216. //return sendResult;
  217. return hexIn;
  218. }
  219. }