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.

248 lines
10KB

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