package com.telpo.beidouast.service.impl; import com.alibaba.fastjson.JSONObject; import com.google.common.base.Joiner; import com.telpo.dipperposition.common.*; import com.telpo.beidouast.entity.mongo.IPProvinceEntity; import com.telpo.beidouast.mapper.IPProvinceMapper; import com.telpo.beidouast.service.IDipperAstPosAsyncTaskService; import com.telpo.beidouast.service.IPProvinceService; import com.telpo.beidouast.vo.IPProvinceVo; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.io.UnsupportedEncodingException; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; /** * @program: DipperAstPosAsyncTaskServiceImpl * @description: 系统预先基于省份的省会城市的经纬度作为辅助信息, * * 根据设备请求的IP地址,从高德IP定位服务获取相关的省份,再匹配相应的位置信息作为辅助位置信息。 * * 如果匹配不到省份,则以武汉中心作为辅助为位置信息。 * * 关于IP与省份的关系保存到缓存中,用于下次使用时,先在缓存中获取匹配信息,匹配不到,再请求高德IP定位服务。 * * 高德IP定位服务:https://lbs.amap.com/api/webservice/guide/api/ipconfig。 * @author: king * @create: 2021-01-10 14:01 */ @Service @Slf4j public class DipperAstPosAsyncTaskServiceImpl implements IDipperAstPosAsyncTaskService { @Autowired private RedisUtil redisUtil; @Autowired private OkHttpUtil okHttpUtil; @Autowired private IPProvinceService iPProvinceService; private String centerProvince; private String centerProvinceFilePath; private String ipPositionRequestPath; private String ipPositionRequestKey; // private String getAstPos(String ipAddress) throws UnsupportedEncodingException { // // String centerAddress = getIpPositionProvince(ipAddress); // if (ObjectUtils.isEmpty(centerAddress) || centerAddress.equals("0")) { // log.warn("IP地址非法,无法获取辅助位置信息!"); // // 返回武汉的定位数据 // centerAddress = centerProvince; // } else { // // 保存到mongoDB // createIPProvince(ipAddress, centerAddress); // } // // String lonAndAlt; // if (redisUtil.hasKey(centerAddress)) { // // 获取省会城市定位信息 // lonAndAlt= (String) redisUtil.get(centerAddress); // } else { // // 请求高德IP定位服务 // this.getPosFromFile(centerAddress); // lonAndAlt = (String) redisUtil.get(centerAddress); // } // // return lonAndAlt; // } // 从CSV文件读取省会城市中心点位置信息 private void getPosFromFile(String centerAddress) { // 不存在说明token是已过期了 String centerProvinceName = ""; String centerProvinceLonAndAlt = ""; List centerAddressSets = CSVUtil.readCSV(this.centerProvinceFilePath); for (String centerAddressSet:centerAddressSets) { String[] centerAddressSetArray = centerAddressSet.split(","); if (centerAddressSetArray.length < 3) { log.warn("CSV数据格式错误"); } else { centerProvinceName = centerAddressSetArray[3]; centerProvinceLonAndAlt = centerAddressSetArray[1]+","+centerAddressSetArray[2]; redisUtil.set(centerProvinceName, centerProvinceLonAndAlt, 0); } } } // 根据IP获取省会信息 private String getIpPositionProvince(String ipAddress) { // 关于IP与省份的关系保存到缓存中 // 使用时,先在缓存中获取匹配信息 // 用mongodb实现 IPProvinceEntity ipProvinceEntity = iPProvinceService.getIPProvince(ipAddress); if (ipProvinceEntity == null) { // 匹配不到,再请求高德IP定位服务。 JSONObject userObj = new JSONObject(); userObj.put("ip", ipAddress); userObj.put("key", ipPositionRequestKey); JSONObject json = okHttpUtil.postRequestWithJson(ipPositionRequestPath, null, userObj); if (ObjectUtils.isNotEmpty(json)) { String province = (String) json.get("province"); if (ObjectUtils.isEmpty(province)) { log.debug("json is :" + json.toString()); return null; } return province; } else { // 意外错误 log.debug("ip address is null"); return null; } } else { return ipProvinceEntity.getProvince(); } } // 将IP对应的省会保存到mongoDB @Async("asyncServiceExecutor") public void createIPProvince(String ipAddress, String province) { log.debug("异步创建推送失败任务记录!"); try { IPProvinceEntity ipProvinceEntity = iPProvinceService.getIPProvince(ipAddress); if (ipProvinceEntity == null) { //DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); ipProvinceEntity.setIp(ipAddress); ipProvinceEntity.setProvince(province); iPProvinceService.saveIPProvince(ipProvinceEntity); // } else { // // ipProvinceEntity.setProvince(province); // iPProvinceService.updateIPProvince(ipProvinceEntity, ipProvinceEntity); } } catch (Exception e) { log.error("创建推送失败记录异常:", e); } } /* * 获取定位辅助信息 * @param ipAddress */ @Override @Async("asyncServiceExecutor") public String pushAstPos(String ipAddress, String centerProvinceFilePath, String centerProvince, String ipPositionRequestPath, String ipPositionRequestKey) throws UnsupportedEncodingException { this.ipPositionRequestKey = ipPositionRequestKey; this.ipPositionRequestPath = ipPositionRequestPath; this.centerProvince = centerProvince; this.centerProvinceFilePath = centerProvinceFilePath; // (1) 获取省会城市信息 String centerAddress = getIpPositionProvince(ipAddress); if (ObjectUtils.isEmpty(centerAddress) || centerAddress.equals("0")) { log.warn("IP地址非法,无法获取辅助位置信息!"); // 返回武汉的定位数据 centerAddress = this.centerProvince; } else { // 保存到mongoDB createIPProvince(ipAddress, centerAddress); } String lonAndAlt; if (redisUtil.hasKey(centerAddress)) { // 获取省会城市定位信息 lonAndAlt= (String) redisUtil.get(centerAddress); } else { // 请求高德IP定位服务 this.getPosFromFile(centerAddress); lonAndAlt = (String) redisUtil.get(centerAddress); } // (2) 处理返回结果 if (lonAndAlt == null) { // null处理 log.error("系统错误,请联系系统管理员。"); return null; //return; } // push to GNNS Server String pushResult = getCmdOfPos(lonAndAlt); return pushResult; } // 组装命令发送给设备 private String getCmdOfPos(String astPos) { // 创建Socket客户端实例; // SocketClient client = new SocketClient(astServer, posAstPort, astTimeout); // 时间和位置不是从服务器获取,而是本地生成 String[] astPosArray = astPos.split(","); String lan = astPosArray[0].trim(); String alt = astPosArray[1].trim(); double lanValue = Double.parseDouble(lan) * 10000000; long lanLongValue = Double.doubleToLongBits(lanValue); if (lanLongValue < 0) { lanLongValue = lanLongValue + 4294967295L + 1; } double altValue = Double.parseDouble(alt) * 10000000; long altLongValue = Double.doubleToLongBits(altValue); if (altLongValue < 0) { altLongValue = altLongValue + 4294967295L + 1; } // 数值换算举例(以经度举例。纬度、高度、位置精度换算方法一致): // (1)经度数值为 113.431,则换算方法如下: // 113.431/比例因子 = 1134310000(十进制) //  439C3270(十六进制) //  经度数据填入 70 32 9C 43(小端模式) // (2)经度数值为-113.431,则换算方法如下: // 113.431/比例因子 = 1134310000(十进制) //  439C3270(十六进制) //  FFFFFFFF - 439C3270 + 1= BC63CD90(补码) // 经度数据填入 90 CD 63 BC(小端模式) // 指令(十六进制) // 举例: 23 3E 04 01 10 00 70 32 9C 43 D0 B2 CE 0D 70 17 00 00 40 0D 03 00 CA 95 // 其中 // 23 3E 为同步头 // 04 01 为识别码 // 10 00 表示长度为 16 // 70 32 9C 43 表示注入的辅助经度为 113.431 度 // D0 B2 CE 0D 表示注入的辅助纬度为 23.165 度 // 00 2F 为校验和 // astTimeCmd 组装 String astTimeCmd = "233E0401"; astTimeCmd += "1000"; astTimeCmd += HexConvert.encodeHEX(lanLongValue); astTimeCmd += HexConvert.encodeHEX(altLongValue); String hexIn = HexConvert.convertStringToHex(astTimeCmd) + HexConvert.makeChecksum(astTimeCmd); //String sendResult = client.sendCmd(hexIn, ackAckCheckRef); //client.closeConnection(); //return sendResult; return hexIn; } }