@@ -87,6 +87,51 @@ | |||||
<version>1.2.28</version> | <version>1.2.28</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>io.netty</groupId> | |||||
<artifactId>netty-all</artifactId> | |||||
<version>4.1.13.Final</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.telpo</groupId> | |||||
<artifactId>common</artifactId> | |||||
<version>1.1.19</version> | |||||
</dependency> | |||||
<!-- 开启redis缓存 --> | |||||
<dependency> | |||||
<groupId>org.springframework.boot</groupId> | |||||
<artifactId>spring-boot-starter-data-redis</artifactId> | |||||
</dependency> | |||||
<!-- redis依赖commons-pool 这个依赖一定要添加 --> | |||||
<dependency> | |||||
<groupId>org.apache.commons</groupId> | |||||
<artifactId>commons-pool2</artifactId> | |||||
</dependency> | |||||
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp --> | |||||
<dependency> | |||||
<groupId>com.squareup.okhttp3</groupId> | |||||
<artifactId>okhttp</artifactId> | |||||
<version>4.8.0</version> | |||||
</dependency> | |||||
<!-- https://mvnrepository.com/artifact/de.codecentric/spring-boot-admin-starter-client --> | |||||
<dependency> | |||||
<groupId>de.codecentric</groupId> | |||||
<artifactId>spring-boot-admin-starter-client</artifactId> | |||||
<version>2.2.4</version> | |||||
</dependency> | |||||
<!-- https://mvnrepository.com/artifact/net.sourceforge.javacsv/javacsv --> | |||||
<dependency> | |||||
<groupId>net.sourceforge.javacsv</groupId> | |||||
<artifactId>javacsv</artifactId> | |||||
<version>2.0</version> | |||||
</dependency> | |||||
</dependencies> | </dependencies> | ||||
<dependencyManagement> | <dependencyManagement> | ||||
@@ -1,11 +1,15 @@ | |||||
package com.telpo.dipperposition; | package com.telpo.dipperposition; | ||||
import com.telpo.dipperposition.server.DipperPositionServer; | |||||
import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||
import org.springframework.boot.SpringApplication; | import org.springframework.boot.SpringApplication; | ||||
import org.springframework.boot.autoconfigure.SpringBootApplication; | import org.springframework.boot.autoconfigure.SpringBootApplication; | ||||
import org.springframework.boot.context.properties.ConfigurationPropertiesScan; | |||||
import org.springframework.boot.context.properties.EnableConfigurationProperties; | import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; | ||||
import java.net.InetSocketAddress; | |||||
/** | /** | ||||
* @program: gateway | * @program: gateway | ||||
* @description: 网关启动类 | * @description: 网关启动类 | ||||
@@ -16,11 +20,17 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient; | |||||
@EnableConfigurationProperties | @EnableConfigurationProperties | ||||
@EnableDiscoveryClient | @EnableDiscoveryClient | ||||
@Slf4j | @Slf4j | ||||
@ConfigurationPropertiesScan | |||||
public class DipperPositionApplication { | public class DipperPositionApplication { | ||||
public static void main(String[] args) { | public static void main(String[] args) { | ||||
log.info("北斗定位服务开始!"); | log.info("北斗定位服务开始!"); | ||||
SpringApplication.run(DipperPositionApplication.class, args); | SpringApplication.run(DipperPositionApplication.class, args); | ||||
log.info("北斗定位服务启动!"); | log.info("北斗定位服务启动!"); | ||||
//启动服务端 | |||||
DipperPositionServer nettyServer = new DipperPositionServer(); | |||||
nettyServer.startTimeAsnc(); | |||||
nettyServer.startPosAsnc(); | |||||
nettyServer.startStarsAsnc(); | |||||
} | } | ||||
} | } |
@@ -0,0 +1,87 @@ | |||||
package com.telpo.dipperposition.common; | |||||
import com.csvreader.CsvReader; | |||||
import com.csvreader.CsvWriter; | |||||
import java.io.FileNotFoundException; | |||||
import java.io.FileWriter; | |||||
import java.io.IOException; | |||||
import java.nio.charset.Charset; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
/** | |||||
* @program: dipperposition | |||||
* @description: CSV文件读取单元 | |||||
* @author: linwl | |||||
* @create: 2021-01-14 11:19 | |||||
**/ | |||||
public class CSVUtil { | |||||
/** | |||||
* 读取每行的数据 | |||||
* | |||||
* @param readPath | |||||
* @return | |||||
*/ | |||||
public static List<String> readCSV(String readPath) { | |||||
String filePath = readPath; | |||||
List<String> listData = new ArrayList<>(); | |||||
try { | |||||
filePath = readPath; | |||||
CsvReader csvReader = new CsvReader(filePath); | |||||
// 读表头 | |||||
boolean re = csvReader.readHeaders(); | |||||
while (csvReader.readRecord()) { | |||||
String rawRecord = csvReader.getRawRecord(); | |||||
listData.add(rawRecord); | |||||
} | |||||
return listData; | |||||
} catch (FileNotFoundException e) { | |||||
throw new RuntimeException("文件未找到"); | |||||
} catch (IOException e) { | |||||
throw new RuntimeException(e.getMessage()); | |||||
} | |||||
} | |||||
/** | |||||
* 写入文件头 | |||||
* @param writePath | |||||
* @param header | |||||
*/ | |||||
public static void writeCSV(String writePath, String[] header) { | |||||
String filePath = writePath; | |||||
try { | |||||
CsvWriter csvWriter = new CsvWriter(writePath, ',', Charset.forName("UTF-8")); | |||||
//String [] header = {"SkuId","SsuId","图片地址","大小(bit)","高度","宽度"}; | |||||
csvWriter.writeRecord(header); | |||||
csvWriter.close(); | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
/** | |||||
* 利用输入输出流持续写 | |||||
* @param fileName | |||||
* @param content | |||||
*/ | |||||
public static void writeContent(String fileName, String content) { | |||||
FileWriter writer = null; | |||||
try { | |||||
// 打开一个写文件器,构造函数中的第二个参数true表示以追加形式写文件 | |||||
writer = new FileWriter(fileName, true); | |||||
writer.write(content + "\r\n"); | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} finally { | |||||
try { | |||||
if (writer != null) { | |||||
writer.close(); | |||||
} | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,140 @@ | |||||
package com.telpo.dipperposition.common; | |||||
/** | |||||
* @program: dipperposition | |||||
* @description: 16进制处理 | |||||
* @author: linwl | |||||
* @create: 2021-01-14 22:05 | |||||
**/ | |||||
public class HexConvert { | |||||
public static String convertStringToHex(String str){ | |||||
char[] chars = str.toCharArray(); | |||||
StringBuffer hex = new StringBuffer(); | |||||
for(int i = 0; i < chars.length; i++){ | |||||
hex.append(Integer.toHexString((int)chars[i])); | |||||
} | |||||
return hex.toString(); | |||||
} | |||||
public static String convertHexToString(String hex){ | |||||
StringBuilder sb = new StringBuilder(); | |||||
StringBuilder sb2 = new StringBuilder(); | |||||
for( int i=0; i<hex.length()-1; i+=2 ){ | |||||
String s = hex.substring(i, (i + 2)); | |||||
int decimal = Integer.parseInt(s, 16); | |||||
sb.append((char)decimal); | |||||
sb2.append(decimal); | |||||
} | |||||
return sb.toString(); | |||||
} | |||||
public static byte[] hexStringToBytes(String hexString) { | |||||
if (hexString == null || hexString.equals("")) { | |||||
return null; | |||||
} | |||||
// toUpperCase将字符串中的所有字符转换为大写 | |||||
hexString = hexString.toUpperCase(); | |||||
int length = hexString.length() / 2; | |||||
// toCharArray将此字符串转换为一个新的字符数组。 | |||||
char[] hexChars = hexString.toCharArray(); | |||||
byte[] d = new byte[length]; | |||||
for (int i = 0; i < length; i++) { | |||||
int pos = i * 2; | |||||
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])); | |||||
} | |||||
return d; | |||||
} | |||||
//返回匹配字符 | |||||
private static byte charToByte(char c) { | |||||
return (byte) "0123456789ABCDEF".indexOf(c); | |||||
} | |||||
//将字节数组转换为short类型,即统计字符串长度 | |||||
public static short bytes2Short2(byte[] b) { | |||||
short i = (short) (((b[1] & 0xff) << 8) | b[0] & 0xff); | |||||
return i; | |||||
} | |||||
//将字节数组转换为16进制字符串 | |||||
public static String BinaryToHexString(byte[] bytes) { | |||||
String hexStr = "0123456789ABCDEF"; | |||||
String result = ""; | |||||
String hex = ""; | |||||
for (byte b : bytes) { | |||||
hex = String.valueOf(hexStr.charAt((b & 0xF0) >> 4)); | |||||
hex += String.valueOf(hexStr.charAt(b & 0x0F)); | |||||
result += hex + " "; | |||||
} | |||||
return result; | |||||
} | |||||
//將10進制轉換為16進制 | |||||
public static String encodeHEX(long numb){ | |||||
String hex= Long.toHexString(numb); | |||||
return hex; | |||||
} | |||||
//將16進制字符串轉換為10進制數字 | |||||
public static long decodeHEX(String hexs){ | |||||
long longValue= Long.parseLong("123ABC", 16); | |||||
return longValue; | |||||
} | |||||
/** | |||||
* 生成校验码的int值 | |||||
* */ | |||||
public static String makeChecksum(String data) { | |||||
if (data == null || data.equals("")) { | |||||
return ""; | |||||
} | |||||
int total = 0; | |||||
int len = data.length(); | |||||
int num = 0; | |||||
while (num < len) { | |||||
String s = data.substring(num, num + 2); | |||||
//System.out.println(s); | |||||
total += Integer.parseInt(s, 16); | |||||
num = num + 2; | |||||
} | |||||
/** | |||||
* 用256求余最大是255,即16进制的FF | |||||
*/ | |||||
int mod = total % 256; | |||||
String hex = Integer.toHexString(mod); | |||||
len = hex.length(); | |||||
// 如果不够校验位的长度,补0,这里用的是两位校验 | |||||
if (len < 2) { | |||||
hex = "0" + hex; | |||||
} | |||||
return hex; | |||||
} | |||||
// | |||||
// public static void main(String[] args) { | |||||
// | |||||
// | |||||
// System.out.println("======ASCII码转换为16进制======"); | |||||
// String str = "*00007VERSION\\n1$"; | |||||
// System.out.println("字符串: " + str); | |||||
// String hex = HexConvert.convertStringToHex(str); | |||||
// System.out.println("====转换为16进制=====" + hex); | |||||
// | |||||
// System.out.println("======16进制转换为ASCII======"); | |||||
// System.out.println("Hex : " + hex); | |||||
// System.out.println("ASCII : " + HexConvert.convertHexToString(hex)); | |||||
// | |||||
// byte[] bytes = HexConvert.hexStringToBytes( hex ); | |||||
// | |||||
// System.out.println(HexConvert.BinaryToHexString( bytes )); | |||||
// } | |||||
} |
@@ -0,0 +1,155 @@ | |||||
package com.telpo.dipperposition.common; | |||||
import com.alibaba.fastjson.JSONObject; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import okhttp3.*; | |||||
import org.apache.commons.lang3.ObjectUtils; | |||||
import org.apache.commons.lang3.exception.ExceptionUtils; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.stereotype.Component; | |||||
import java.text.MessageFormat; | |||||
import java.util.Iterator; | |||||
import java.util.Map; | |||||
import java.util.Objects; | |||||
/** | |||||
* @program: DataPushServer | |||||
* @description: okhttp工具类 | |||||
* @author: linwl | |||||
* @create: 2020-07-17 15:43 | |||||
*/ | |||||
@Slf4j | |||||
@Component | |||||
public class OkHttpUtil { | |||||
@Autowired | |||||
private OkHttpClient okHttpClient; | |||||
/** | |||||
* 根据map获取get请求参数 | |||||
* | |||||
* @param queries | |||||
* @return | |||||
*/ | |||||
public StringBuffer getQueryString(String url, Map<String, String> queries) { | |||||
StringBuffer sb = new StringBuffer(url); | |||||
if (queries != null && queries.keySet().size() > 0) { | |||||
boolean firstFlag = true; | |||||
Iterator iterator = queries.entrySet().iterator(); | |||||
while (iterator.hasNext()) { | |||||
Map.Entry entry = (Map.Entry<String, String>) iterator.next(); | |||||
if (firstFlag) { | |||||
sb.append("?" + entry.getKey() + "=" + entry.getValue()); | |||||
firstFlag = false; | |||||
} else { | |||||
sb.append("&" + entry.getKey() + "=" + entry.getValue()); | |||||
} | |||||
} | |||||
} | |||||
return sb; | |||||
} | |||||
/** | |||||
* get | |||||
* | |||||
* @param url 请求的url | |||||
* @param queries 请求的参数,在浏览器?后面的数据,没有可以传null | |||||
* @return | |||||
*/ | |||||
public String get(String url, Map<String, String> queries) { | |||||
StringBuffer sb = getQueryString(url, queries); | |||||
Request request = new Request.Builder().url(sb.toString()).build(); | |||||
log.debug(MessageFormat.format("发送Get to url<{0}>,参数为:{1}", url, queries)); | |||||
return execNewCall(request); | |||||
} | |||||
/** | |||||
* post | |||||
* | |||||
* @param url 请求的url | |||||
* @param params post form 提交的参数 | |||||
* @return | |||||
*/ | |||||
public String postFormParams(String url, Map<String, String> params) { | |||||
FormBody.Builder builder = new FormBody.Builder(); | |||||
// 添加参数 | |||||
if (params != null && params.keySet().size() > 0) { | |||||
for (String key : params.keySet()) { | |||||
builder.add(key, params.get(key)); | |||||
} | |||||
} | |||||
log.debug(MessageFormat.format("发送post from to url<{0}>,参数为:{1}", url, params)); | |||||
Request request = new Request.Builder().url(url).post(builder.build()).build(); | |||||
return execNewCall(request); | |||||
} | |||||
/** Post请求发送JSON数据....{"name":"zhangsan","pwd":"123456"} 参数一:请求Url 参数二:请求的JSON 参数三:请求回调 */ | |||||
public String postJsonParams(String url, String jsonParams) { | |||||
RequestBody requestBody = RequestBody.create(jsonParams, MediaType.parse("application/json; charset=utf-8")); | |||||
Request request = new Request.Builder().url(url).post(requestBody).build(); | |||||
log.debug(MessageFormat.format("发送post json to url<{0}>,参数为:{1}", url, jsonParams)); | |||||
return execNewCall(request); | |||||
} | |||||
/** Post请求发送xml数据.... 参数一:请求Url 参数二:请求的xmlString 参数三:请求回调 */ | |||||
public String postXmlParams(String url, String xml) { | |||||
RequestBody requestBody = | |||||
RequestBody.create(xml, MediaType.parse("application/xml; charset=utf-8")); | |||||
Request request = new Request.Builder().url(url).post(requestBody).build(); | |||||
log.debug(MessageFormat.format("发送post xml to url<{0}>,参数为:{1}", url, xml)); | |||||
return execNewCall(request); | |||||
} | |||||
/** | |||||
* 调用okhttp的newCall方法 | |||||
* | |||||
* @param request | |||||
* @return | |||||
*/ | |||||
private String execNewCall(Request request) { | |||||
try (Response response = okHttpClient.newCall(request).execute()) { | |||||
if (response.isSuccessful()) { | |||||
return Objects.requireNonNull(response.body()).string(); | |||||
} | |||||
} catch (Exception e) { | |||||
log.error("okhttp3 put error >> ex = {}", ExceptionUtils.getStackTrace(e)); | |||||
} | |||||
return "FAIL"; | |||||
} | |||||
/** | |||||
* Post请求发送JSON数据....{"name":"zhangsan","pwd":"123456"} 参数一:请求Url 参数二:请求的JSON 参数三:请求回调 | |||||
*/ | |||||
public String postJsonParamsWithToken(String url, String token, String jsonParams) { | |||||
RequestBody requestBody = | |||||
RequestBody.create(jsonParams, MediaType.parse("application/json; charset=utf-8")); | |||||
Request request = new Request.Builder().url(url). | |||||
addHeader("Authorization", token).post(requestBody).build(); | |||||
log.debug(MessageFormat.format("发送post json to url<{0}>,参数为:{1}", url, jsonParams)); | |||||
return execNewCall(request); | |||||
} | |||||
public JSONObject postRequestWithJson(String url, String accessToken, JSONObject postData) { | |||||
String postResult; | |||||
if (ObjectUtils.isNotEmpty(accessToken)) { | |||||
postResult = postJsonParamsWithToken(url, accessToken, JSONObject.toJSONString(postData)); | |||||
} else { | |||||
postResult = postJsonParams(url, JSONObject.toJSONString(postData)); | |||||
} | |||||
if (postResult == null) { | |||||
log.error("访问错误"); | |||||
return null; | |||||
} else { | |||||
log.debug(postResult); | |||||
if(("FAIL").equals(postResult.toString())) { | |||||
JSONObject object = new JSONObject(); | |||||
object.put("result", "FAIL"); | |||||
return object; | |||||
} else { | |||||
return JSONObject.parseObject(postResult); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,665 @@ | |||||
package com.telpo.dipperposition.common; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.springframework.data.redis.core.RedisTemplate; | |||||
import org.springframework.stereotype.Component; | |||||
import org.springframework.util.CollectionUtils; | |||||
import javax.annotation.Resource; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import java.util.Set; | |||||
import java.util.concurrent.TimeUnit; | |||||
/** | |||||
* @program: DataPushServer | |||||
* @description: redis工具类 | |||||
* @author: linwl | |||||
* @create: 2020-07-11 10:26 | |||||
*/ | |||||
@Component | |||||
@Slf4j | |||||
public class RedisUtil { | |||||
@Resource private RedisTemplate<String, Object> redisTemplate; | |||||
// =============================common============================ | |||||
/** | |||||
* 指定缓存失效时间 | |||||
* | |||||
* @param key 键 | |||||
* @param time 时间(秒) | |||||
* @return | |||||
*/ | |||||
public boolean expire(String key, long time) { | |||||
try { | |||||
if (time > 0) { | |||||
redisTemplate.expire(key, time, TimeUnit.SECONDS); | |||||
} | |||||
return true; | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 根据key 获取过期时间 | |||||
* | |||||
* @param key 键 不能为null | |||||
* @return 时间(秒) 返回0代表为永久有效 | |||||
*/ | |||||
public long getExpire(String key) { | |||||
return redisTemplate.getExpire(key, TimeUnit.SECONDS); | |||||
} | |||||
/** | |||||
* 判断key是否存在 | |||||
* | |||||
* @param key 键 | |||||
* @return true 存在 false不存在 | |||||
*/ | |||||
public boolean hasKey(String key) { | |||||
try { | |||||
return redisTemplate.hasKey(key); | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 删除缓存 | |||||
* | |||||
* @param key 可以传一个值 或多个 | |||||
*/ | |||||
@SuppressWarnings("unchecked") | |||||
public void del(String... key) { | |||||
if (key != null && key.length > 0) { | |||||
if (key.length == 1) { | |||||
redisTemplate.delete(key[0]); | |||||
} else { | |||||
redisTemplate.delete(CollectionUtils.arrayToList(key)); | |||||
} | |||||
} | |||||
} | |||||
// ============================String============================= | |||||
/** | |||||
* 普通缓存获取 | |||||
* | |||||
* @param key 键 | |||||
* @return 值 | |||||
*/ | |||||
public Object get(String key) { | |||||
return key == null ? null : redisTemplate.opsForValue().get(key); | |||||
} | |||||
/** | |||||
* 普通缓存放入 | |||||
* | |||||
* @param key 键 | |||||
* @param value 值 | |||||
* @return true成功 false失败 | |||||
*/ | |||||
public boolean set(String key, Object value) { | |||||
try { | |||||
redisTemplate.opsForValue().set(key, value); | |||||
return true; | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 普通缓存放入并设置时间 | |||||
* | |||||
* @param key 键 | |||||
* @param value 值 | |||||
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 | |||||
* @return true成功 false 失败 | |||||
*/ | |||||
public boolean set(String key, Object value, long time) { | |||||
try { | |||||
if (time > 0) { | |||||
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); | |||||
} else { | |||||
set(key, value); | |||||
} | |||||
return true; | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 递增 适用场景: https://blog.csdn.net/y_y_y_k_k_k_k/article/details/79218254 高并发生成订单号,秒杀类的业务逻辑等。。 | |||||
* | |||||
* @param key 键 | |||||
* @param delta 要增加几(大于0) | |||||
* @return | |||||
*/ | |||||
public long incr(String key, long delta) { | |||||
if (delta < 0) { | |||||
throw new RuntimeException("递增因子必须大于0"); | |||||
} | |||||
return redisTemplate.opsForValue().increment(key, delta); | |||||
} | |||||
/** | |||||
* 递减 | |||||
* | |||||
* @param key 键 | |||||
* @param delta 要减少几(小于0) | |||||
* @return | |||||
*/ | |||||
public long decr(String key, long delta) { | |||||
if (delta < 0) { | |||||
throw new RuntimeException("递减因子必须大于0"); | |||||
} | |||||
return redisTemplate.opsForValue().increment(key, -delta); | |||||
} | |||||
// ================================Map================================= | |||||
/** | |||||
* HashGet | |||||
* | |||||
* @param key 键 不能为null | |||||
* @param item 项 不能为null | |||||
* @return 值 | |||||
*/ | |||||
public Object hget(String key, String item) { | |||||
return redisTemplate.opsForHash().get(key, item); | |||||
} | |||||
/** | |||||
* 获取hashKey对应的所有键值 | |||||
* | |||||
* @param key 键 | |||||
* @return 对应的多个键值 | |||||
*/ | |||||
public Map<Object, Object> hmget(String key) { | |||||
return redisTemplate.opsForHash().entries(key); | |||||
} | |||||
/** | |||||
* HashSet | |||||
* | |||||
* @param key 键 | |||||
* @param map 对应多个键值 | |||||
* @return true 成功 false 失败 | |||||
*/ | |||||
public boolean hmset(String key, Map<String, Object> map) { | |||||
try { | |||||
redisTemplate.opsForHash().putAll(key, map); | |||||
return true; | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* HashSet 并设置时间 | |||||
* | |||||
* @param key 键 | |||||
* @param map 对应多个键值 | |||||
* @param time 时间(秒) | |||||
* @return true成功 false失败 | |||||
*/ | |||||
public boolean hmset(String key, Map<String, Object> map, long time) { | |||||
try { | |||||
redisTemplate.opsForHash().putAll(key, map); | |||||
if (time > 0) { | |||||
expire(key, time); | |||||
} | |||||
return true; | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 向一张hash表中放入数据,如果不存在将创建 | |||||
* | |||||
* @param key 键 | |||||
* @param item 项 | |||||
* @param value 值 | |||||
* @return true 成功 false失败 | |||||
*/ | |||||
public boolean hset(String key, String item, Object value) { | |||||
try { | |||||
redisTemplate.opsForHash().put(key, item, value); | |||||
return true; | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 向一张hash表中放入数据,如果不存在将创建 | |||||
* | |||||
* @param key 键 | |||||
* @param item 项 | |||||
* @param value 值 | |||||
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 | |||||
* @return true 成功 false失败 | |||||
*/ | |||||
public boolean hset(String key, String item, Object value, long time) { | |||||
try { | |||||
redisTemplate.opsForHash().put(key, item, value); | |||||
if (time > 0) { | |||||
expire(key, time); | |||||
} | |||||
return true; | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 删除hash表中的值 | |||||
* | |||||
* @param key 键 不能为null | |||||
* @param item 项 可以使多个 不能为null | |||||
*/ | |||||
public void hdel(String key, Object... item) { | |||||
redisTemplate.opsForHash().delete(key, item); | |||||
} | |||||
/** | |||||
* 判断hash表中是否有该项的值 | |||||
* | |||||
* @param key 键 不能为null | |||||
* @param item 项 不能为null | |||||
* @return true 存在 false不存在 | |||||
*/ | |||||
public boolean hHasKey(String key, String item) { | |||||
return redisTemplate.opsForHash().hasKey(key, item); | |||||
} | |||||
/** | |||||
* hash递增 如果不存在,就会创建一个 并把新增后的值返回 | |||||
* | |||||
* @param key 键 | |||||
* @param item 项 | |||||
* @param by 要增加几(大于0) | |||||
* @return | |||||
*/ | |||||
public double hincr(String key, String item, double by) { | |||||
return redisTemplate.opsForHash().increment(key, item, by); | |||||
} | |||||
/** | |||||
* hash递减 | |||||
* | |||||
* @param key 键 | |||||
* @param item 项 | |||||
* @param by 要减少记(小于0) | |||||
* @return | |||||
*/ | |||||
public double hdecr(String key, String item, double by) { | |||||
return redisTemplate.opsForHash().increment(key, item, -by); | |||||
} | |||||
// ============================set============================= | |||||
/** | |||||
* 根据key获取Set中的所有值 | |||||
* | |||||
* @param key 键 | |||||
* @return | |||||
*/ | |||||
public Set<Object> sGet(String key) { | |||||
try { | |||||
return redisTemplate.opsForSet().members(key); | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return null; | |||||
} | |||||
} | |||||
/** | |||||
* 根据value从一个set中查询,是否存在 | |||||
* | |||||
* @param key 键 | |||||
* @param value 值 | |||||
* @return true 存在 false不存在 | |||||
*/ | |||||
public boolean sHasKey(String key, Object value) { | |||||
try { | |||||
return redisTemplate.opsForSet().isMember(key, value); | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 将数据放入set缓存 | |||||
* | |||||
* @param key 键 | |||||
* @param values 值 可以是多个 | |||||
* @return 成功个数 | |||||
*/ | |||||
public long sSet(String key, Object... values) { | |||||
try { | |||||
return redisTemplate.opsForSet().add(key, values); | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return 0; | |||||
} | |||||
} | |||||
/** | |||||
* 将set数据放入缓存 | |||||
* | |||||
* @param key 键 | |||||
* @param time 时间(秒) | |||||
* @param values 值 可以是多个 | |||||
* @return 成功个数 | |||||
*/ | |||||
public long sSetAndTime(String key, long time, Object... values) { | |||||
try { | |||||
Long count = redisTemplate.opsForSet().add(key, values); | |||||
if (time > 0) { | |||||
expire(key, time); | |||||
} | |||||
return count; | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return 0; | |||||
} | |||||
} | |||||
/** | |||||
* 获取set缓存的长度 | |||||
* | |||||
* @param key 键 | |||||
* @return | |||||
*/ | |||||
public long sGetSetSize(String key) { | |||||
try { | |||||
return redisTemplate.opsForSet().size(key); | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return 0; | |||||
} | |||||
} | |||||
/** | |||||
* 移除值为value的 | |||||
* | |||||
* @param key 键 | |||||
* @param values 值 可以是多个 | |||||
* @return 移除的个数 | |||||
*/ | |||||
public long setRemove(String key, Object... values) { | |||||
try { | |||||
Long count = redisTemplate.opsForSet().remove(key, values); | |||||
return count; | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return 0; | |||||
} | |||||
} | |||||
// ============================zset============================= | |||||
/** | |||||
* 根据key获取Set中的所有值 | |||||
* | |||||
* @param key 键 | |||||
* @return | |||||
*/ | |||||
public Set<Object> zSGet(String key) { | |||||
try { | |||||
return redisTemplate.opsForSet().members(key); | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return null; | |||||
} | |||||
} | |||||
/** | |||||
* 根据value从一个set中查询,是否存在 | |||||
* | |||||
* @param key 键 | |||||
* @param value 值 | |||||
* @return true 存在 false不存在 | |||||
*/ | |||||
public boolean zSHasKey(String key, Object value) { | |||||
try { | |||||
return redisTemplate.opsForSet().isMember(key, value); | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return false; | |||||
} | |||||
} | |||||
public Boolean zSSet(String key, Object value, double score) { | |||||
try { | |||||
return redisTemplate.opsForZSet().add(key, value, 2); | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 将set数据放入缓存 | |||||
* | |||||
* @param key 键 | |||||
* @param time 时间(秒) | |||||
* @param values 值 可以是多个 | |||||
* @return 成功个数 | |||||
*/ | |||||
public long zSSetAndTime(String key, long time, Object... values) { | |||||
try { | |||||
Long count = redisTemplate.opsForSet().add(key, values); | |||||
if (time > 0) { | |||||
expire(key, time); | |||||
} | |||||
return count; | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return 0; | |||||
} | |||||
} | |||||
/** | |||||
* 获取set缓存的长度 | |||||
* | |||||
* @param key 键 | |||||
* @return | |||||
*/ | |||||
public long zSGetSetSize(String key) { | |||||
try { | |||||
return redisTemplate.opsForSet().size(key); | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return 0; | |||||
} | |||||
} | |||||
/** | |||||
* 移除值为value的 | |||||
* | |||||
* @param key 键 | |||||
* @param values 值 可以是多个 | |||||
* @return 移除的个数 | |||||
*/ | |||||
public long zSetRemove(String key, Object... values) { | |||||
try { | |||||
Long count = redisTemplate.opsForSet().remove(key, values); | |||||
return count; | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return 0; | |||||
} | |||||
} | |||||
// ===============================list================================= | |||||
/** | |||||
* 获取list缓存的内容 取出来的元素 总数 end-start+1 | |||||
* | |||||
* @param key 键 | |||||
* @param start 开始 0 是第一个元素 | |||||
* @param end 结束 -1代表所有值 | |||||
* @return | |||||
*/ | |||||
public List<Object> lGet(String key, long start, long end) { | |||||
try { | |||||
return redisTemplate.opsForList().range(key, start, end); | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return null; | |||||
} | |||||
} | |||||
/** | |||||
* 获取list缓存的长度 | |||||
* | |||||
* @param key 键 | |||||
* @return | |||||
*/ | |||||
public long lGetListSize(String key) { | |||||
try { | |||||
return redisTemplate.opsForList().size(key); | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return 0; | |||||
} | |||||
} | |||||
/** | |||||
* 通过索引 获取list中的值 | |||||
* | |||||
* @param key 键 | |||||
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 | |||||
* @return | |||||
*/ | |||||
public Object lGetIndex(String key, long index) { | |||||
try { | |||||
return redisTemplate.opsForList().index(key, index); | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return null; | |||||
} | |||||
} | |||||
/** | |||||
* 将list放入缓存 | |||||
* | |||||
* @param key 键 | |||||
* @param value 值 | |||||
* @return | |||||
*/ | |||||
public boolean lSet(String key, Object value) { | |||||
try { | |||||
redisTemplate.opsForList().rightPush(key, value); | |||||
return true; | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 将list放入缓存 | |||||
* | |||||
* @param key 键 | |||||
* @param value 值 | |||||
* @param time 时间(秒) | |||||
* @return | |||||
*/ | |||||
public boolean lSet(String key, Object value, long time) { | |||||
try { | |||||
redisTemplate.opsForList().rightPush(key, value); | |||||
if (time > 0) { | |||||
expire(key, time); | |||||
} | |||||
return true; | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 将list放入缓存 | |||||
* | |||||
* @param key 键 | |||||
* @param value 值 | |||||
* @return | |||||
*/ | |||||
public boolean lSet(String key, List<Object> value) { | |||||
try { | |||||
redisTemplate.opsForList().rightPushAll(key, value); | |||||
return true; | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 将list放入缓存 | |||||
* | |||||
* @param key 键 | |||||
* @param value 值 | |||||
* @param time 时间(秒) | |||||
* @return | |||||
*/ | |||||
public boolean lSet(String key, List<Object> value, long time) { | |||||
try { | |||||
redisTemplate.opsForList().rightPushAll(key, value); | |||||
if (time > 0) { | |||||
expire(key, time); | |||||
} | |||||
return true; | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 根据索引修改list中的某条数据 | |||||
* | |||||
* @param key 键 | |||||
* @param index 索引 | |||||
* @param value 值 | |||||
* @return | |||||
*/ | |||||
public boolean lUpdateIndex(String key, long index, Object value) { | |||||
try { | |||||
redisTemplate.opsForList().set(key, index, value); | |||||
return true; | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 移除N个值为value | |||||
* | |||||
* @param key 键 | |||||
* @param count 移除多少个 | |||||
* @param value 值 | |||||
* @return 移除的个数 | |||||
*/ | |||||
public long lRemove(String key, long count, Object value) { | |||||
try { | |||||
Long remove = redisTemplate.opsForList().remove(key, count, value); | |||||
return remove; | |||||
} catch (Exception e) { | |||||
log.error(key, e); | |||||
return 0; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,85 @@ | |||||
package com.telpo.dipperposition.common; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import java.io.*; | |||||
import java.net.Socket; | |||||
/** | |||||
* @program: dipperposition | |||||
* @description: socket连接单元 | |||||
* @author: king | |||||
* @create: 2021-01-14 13:52 | |||||
**/ | |||||
@Slf4j | |||||
public class SocketClient { | |||||
//定义一个Socket对象 | |||||
Socket socket = null; | |||||
public SocketClient(String host, int port, int timeout) { | |||||
try { | |||||
//需要服务器的IP地址和端口号,才能获得正确的Socket对象 | |||||
socket = new Socket(host, port); | |||||
socket.setSoTimeout(timeout); | |||||
} catch (IOException e) { | |||||
log.error("Socket Connect Error:" + e.getMessage()); | |||||
} | |||||
} | |||||
public String getOutput() { | |||||
try { | |||||
OutputStream os = socket.getOutputStream(); | |||||
return os.toString(); | |||||
} catch (IOException e) { | |||||
log.error("Socket getOutputStream Error:" + e.getMessage()); | |||||
return null; | |||||
} | |||||
} | |||||
public String sendCmd(String astCmd, String ackAckCheckRef) { | |||||
try { | |||||
OutputStream os=socket.getOutputStream(); | |||||
PrintWriter pw=new PrintWriter(os); | |||||
// TODO 发生命令 | |||||
String info="用户名:Tom,用户密码:123456"; | |||||
pw.write(astCmd); | |||||
pw.flush(); | |||||
socket.shutdownOutput(); | |||||
//接收服务器的相应 | |||||
String reply=null; | |||||
//输入流 | |||||
InputStream is=socket.getInputStream(); | |||||
BufferedReader br=new BufferedReader(new InputStreamReader(is)); | |||||
String ackResult=""; | |||||
String ackHexOut = HexConvert.convertStringToHex(ackAckCheckRef); | |||||
while(!((reply=br.readLine())==null)){ | |||||
log.debug("接收服务器的信息:"+reply); | |||||
if (ackHexOut.equals(reply)) { | |||||
reply=br.readLine(); | |||||
ackResult = HexConvert.convertHexToString(reply); | |||||
break; | |||||
} | |||||
} | |||||
//4.关闭资源 | |||||
br.close(); | |||||
is.close(); | |||||
pw.close(); | |||||
os.close(); | |||||
return ackResult; | |||||
} catch (IOException e) { | |||||
log.error("Socket sendCmd Error:" + e.getMessage()); | |||||
return null; | |||||
} | |||||
} | |||||
public void closeConnection() { | |||||
try { | |||||
socket.close(); | |||||
//socket.shutdownOutput(); | |||||
} catch (IOException e) { | |||||
log.error("Socket getOutputStream Error:" + e.getMessage()); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,39 @@ | |||||
package com.telpo.dipperposition.common; | |||||
import tools.CommonTools; | |||||
import java.time.LocalTime; | |||||
import java.time.format.DateTimeFormatter; | |||||
/** | |||||
* @program: DataPushServer | |||||
* @description: 时间工具类 | |||||
* @author: linwl | |||||
* @create: 2020-08-05 11:16 | |||||
*/ | |||||
public class TimeTools { | |||||
private TimeTools() {} | |||||
/** | |||||
* 校验时间段 | |||||
* | |||||
* @param startTime 起始时间 HH:mm | |||||
* @param endTime 结束时间 HH:mm | |||||
* @return | |||||
*/ | |||||
public static boolean checkTime(String startTime, String endTime) { | |||||
boolean result = false; | |||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm"); | |||||
LocalTime pushStartTime = LocalTime.parse(startTime, dateTimeFormatter); | |||||
LocalTime pushEndTime = LocalTime.parse(endTime, dateTimeFormatter); | |||||
LocalTime zeroTime = LocalTime.parse("00:00"); | |||||
if (zeroTime.equals(pushEndTime)) { | |||||
pushEndTime = pushEndTime.plusNanos(-10); | |||||
} | |||||
if (CommonTools.checkInTime(pushStartTime, pushEndTime)) { | |||||
result = true; | |||||
} | |||||
return result; | |||||
} | |||||
} |
@@ -1,22 +1,11 @@ | |||||
package com.telpo.dipperposition.config; | package com.telpo.dipperposition.config; | ||||
import com.alibaba.nacos.api.NacosFactory; | |||||
import com.alibaba.nacos.api.PropertyKeyConst; | |||||
import com.alibaba.nacos.api.config.ConfigService; | |||||
import com.telpo.dipperposition.co.RzlAccount; | |||||
import lombok.Getter; | import lombok.Getter; | ||||
import lombok.Setter; | import lombok.Setter; | ||||
import lombok.ToString; | import lombok.ToString; | ||||
import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
import org.springframework.beans.factory.annotation.Value; | |||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory; | |||||
import org.springframework.boot.context.properties.ConfigurationProperties; | |||||
import org.springframework.context.ConfigurableApplicationContext; | import org.springframework.context.ConfigurableApplicationContext; | ||||
import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||
import org.springframework.context.annotation.Lazy; | |||||
import org.springframework.context.annotation.Scope; | |||||
import java.util.Properties; | |||||
/** | /** | ||||
* @program: gateway | * @program: gateway | ||||
@@ -0,0 +1,66 @@ | |||||
package com.telpo.dipperposition.config.db; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.context.annotation.Bean; | |||||
import org.springframework.data.mongodb.MongoDbFactory; | |||||
import org.springframework.data.mongodb.core.SimpleMongoClientDbFactory; | |||||
import org.springframework.stereotype.Component; | |||||
import org.springframework.util.CollectionUtils; | |||||
import javax.annotation.PostConstruct; | |||||
import java.util.HashMap; | |||||
import java.util.Iterator; | |||||
import java.util.Map; | |||||
/** | |||||
* @program: DataPushServer | |||||
* @description: mongdb数据库连接上下文 | |||||
* @author: linwl | |||||
* @create: 2020-07-11 14:31 | |||||
*/ | |||||
@Component | |||||
public class MongoDbContext { | |||||
private static final Map<String, MongoDbFactory> MONGO_CLIENT_DB_FACTORY_MAP = new HashMap<>(); | |||||
private static final ThreadLocal<MongoDbFactory> MONGO_DB_FACTORY_THREAD_LOCAL = | |||||
new ThreadLocal<>(); | |||||
@Autowired | |||||
MongoListProperties mongoListProperties; | |||||
public static MongoDbFactory getMongoDbFactory() { | |||||
return MONGO_DB_FACTORY_THREAD_LOCAL.get(); | |||||
} | |||||
public static void setMongoDbFactory(String name) { | |||||
MONGO_DB_FACTORY_THREAD_LOCAL.set(MONGO_CLIENT_DB_FACTORY_MAP.get(name)); | |||||
} | |||||
public static void removeMongoDbFactory() { | |||||
MONGO_DB_FACTORY_THREAD_LOCAL.remove(); | |||||
} | |||||
@PostConstruct | |||||
public void afterPropertiesSet() { | |||||
if (!CollectionUtils.isEmpty(mongoListProperties.getDblist())) { | |||||
mongoListProperties | |||||
.getDblist() | |||||
.forEach( | |||||
info -> { | |||||
MONGO_CLIENT_DB_FACTORY_MAP.put( | |||||
info.getDatabase(), new SimpleMongoClientDbFactory(info.getUri())); | |||||
}); | |||||
} | |||||
} | |||||
@Bean(name = "mongoTemplate") | |||||
public MultiMongoTemplate dynamicMongoTemplate() { | |||||
Iterator<MongoDbFactory> iterator = MONGO_CLIENT_DB_FACTORY_MAP.values().iterator(); | |||||
return new MultiMongoTemplate(iterator.next()); | |||||
} | |||||
@Bean(name = "mongoDbFactory") | |||||
public MongoDbFactory mongoDbFactory() { | |||||
Iterator<MongoDbFactory> iterator = MONGO_CLIENT_DB_FACTORY_MAP.values().iterator(); | |||||
return iterator.next(); | |||||
} | |||||
} |
@@ -0,0 +1,30 @@ | |||||
package com.telpo.dipperposition.config.db; | |||||
import lombok.Data; | |||||
import lombok.Getter; | |||||
import lombok.Setter; | |||||
import lombok.ToString; | |||||
import org.springframework.boot.context.properties.ConfigurationProperties; | |||||
import java.util.List; | |||||
/** | |||||
* @program: DataPushServer | |||||
* @description: mongo连接配置类 | |||||
* @author: linwl | |||||
* @create: 2020-07-11 14:41 | |||||
*/ | |||||
@Getter | |||||
@Setter | |||||
@ToString | |||||
@ConfigurationProperties(prefix = "mongo.datasource") | |||||
public class MongoListProperties { | |||||
private List<MongoList> dblist; | |||||
@Data | |||||
public static class MongoList { | |||||
private String uri; | |||||
private String database; | |||||
} | |||||
} |
@@ -0,0 +1,26 @@ | |||||
package com.telpo.dipperposition.config.db; | |||||
import com.mongodb.client.MongoDatabase; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.springframework.data.mongodb.MongoDbFactory; | |||||
import org.springframework.data.mongodb.core.MongoTemplate; | |||||
/** | |||||
* @program: DataPushServer | |||||
* @description: 多mongo数据源配置 | |||||
* @author: linwl | |||||
* @create: 2020-07-11 14:21 | |||||
*/ | |||||
@Slf4j | |||||
public class MultiMongoTemplate extends MongoTemplate { | |||||
public MultiMongoTemplate(MongoDbFactory mongoDbFactory) { | |||||
super(mongoDbFactory); | |||||
} | |||||
@Override | |||||
protected MongoDatabase doGetDatabase() { | |||||
MongoDbFactory mongoDbFactory = MongoDbContext.getMongoDbFactory(); | |||||
return mongoDbFactory == null ? super.doGetDatabase() : mongoDbFactory.getDb(); | |||||
} | |||||
} |
@@ -1,23 +1,10 @@ | |||||
package com.telpo.dipperposition.controller; | package com.telpo.dipperposition.controller; | ||||
import com.alibaba.cloud.nacos.parser.NacosDataParserHandler; | |||||
import com.alibaba.nacos.api.PropertyKeyConst; | |||||
import com.alibaba.nacos.api.exception.NacosException; | |||||
import com.telpo.dipperposition.co.RzlAccount; | |||||
import com.telpo.dipperposition.config.PositionConfig; | |||||
import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.beans.factory.annotation.Value; | import org.springframework.beans.factory.annotation.Value; | ||||
import org.springframework.web.bind.annotation.RequestMapping; | import org.springframework.web.bind.annotation.RequestMapping; | ||||
import org.springframework.web.bind.annotation.RestController; | import org.springframework.web.bind.annotation.RestController; | ||||
import java.io.IOException; | |||||
import java.util.Map; | |||||
import java.util.Properties; | |||||
import java.util.concurrent.Executor; | |||||
import com.alibaba.nacos.api.NacosFactory; | |||||
import com.alibaba.nacos.api.config.ConfigService; | |||||
import com.alibaba.nacos.api.config.listener.Listener; | |||||
/** | /** | ||||
* @program: DipperPositionController | * @program: DipperPositionController | ||||
@@ -33,22 +20,7 @@ public class DipperPositionController { | |||||
//RzlAccount rzlAccount; | //RzlAccount rzlAccount; | ||||
@RequestMapping("/getPos") | @RequestMapping("/getPos") | ||||
public String getPos() throws NacosException, InterruptedException, IOException { | |||||
// String group = "DEFAULT_GROUP"; | |||||
// String dataId = "dipperposition-service"; | |||||
// String positionId = "position.hello"; | |||||
// Properties properties = new Properties(); | |||||
// String serverAddr = "172.16.192.26"; | |||||
// properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr); | |||||
// ConfigService configService = NacosFactory.createConfigService(properties); | |||||
// String content = configService.getConfig(dataId, group, 10000); | |||||
// System.out.println(content); | |||||
// //log.info(positionId + ":" + content.positionId) | |||||
// Map<String, Object> dataMap = NacosDataParserHandler.getInstance().parseNacosData(content,"yaml"); | |||||
// return dataMap == null ? "" : (String)dataMap.get(positionId); | |||||
String returnStr= "return position = " + hello; | |||||
return returnStr; | |||||
//return "Helle world!"; //ContextLoader.getCurrentWebApplicationContext().toString(); | |||||
public String getPos() { | |||||
return "return position = " + hello; | |||||
} | } | ||||
} | } |
@@ -0,0 +1,24 @@ | |||||
package com.telpo.dipperposition.entity.mongo; | |||||
import com.telpo.dipperposition.vo.IPProvinceVo; | |||||
import lombok.Getter; | |||||
import lombok.Setter; | |||||
import lombok.ToString; | |||||
import models.BaseMongoDbEntity; | |||||
/** | |||||
* @program: IPProvinceEntity | |||||
* @description: 位置实体类 | |||||
* @author: linwl | |||||
* @create: 2020-07-11 15:33 | |||||
*/ | |||||
@ToString | |||||
@Getter | |||||
@Setter | |||||
public class IPProvinceEntity extends BaseMongoDbEntity { | |||||
/** Ip */ | |||||
private String ip; | |||||
/** Ip所在省份 */ | |||||
private String province; | |||||
} |
@@ -0,0 +1,53 @@ | |||||
package com.telpo.dipperposition.enums; | |||||
/** | |||||
* @program: DipperReturnValue | |||||
* @description: 推送类型枚举 | |||||
* @author: king | |||||
* @create: 2021-01-24 11:44 | |||||
*/ | |||||
public enum DipperReturnValue { | |||||
ACK(0, "SDBP-PUB–ACK"), | |||||
NACK(1, "SDBP-PUB–NACK"); | |||||
/** 状态值 */ | |||||
private int value; | |||||
/** 描述 */ | |||||
private String describe; | |||||
private DipperReturnValue(int value, String describe) { | |||||
this.value = value; | |||||
this.describe = describe; | |||||
} | |||||
/** | |||||
* 获取推送类型 | |||||
* | |||||
* @param value | |||||
* @return | |||||
*/ | |||||
public static DipperReturnValue getByValue(int value) { | |||||
for (DipperReturnValue enums : DipperReturnValue.values()) { | |||||
if (enums.getValue() == value) { | |||||
return enums; | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
public int getValue() { | |||||
return value; | |||||
} | |||||
public void setValue(int value) { | |||||
this.value = value; | |||||
} | |||||
public String getDescribe() { | |||||
return describe; | |||||
} | |||||
public void setDescribe(String describe) { | |||||
this.describe = describe; | |||||
} | |||||
} |
@@ -0,0 +1,145 @@ | |||||
package com.telpo.dipperposition.handler; | |||||
import com.telpo.dipperposition.enums.DipperReturnValue; | |||||
import com.telpo.dipperposition.service.IDipperAstPosAsyncTaskService; | |||||
import com.telpo.dipperposition.service.IDipperAstTimeAsyncTaskService; | |||||
import com.telpo.dipperposition.service.IDipperDataAsyncTaskService; | |||||
import io.netty.buffer.ByteBuf; | |||||
import io.netty.buffer.Unpooled; | |||||
import io.netty.channel.socket.SocketChannel; | |||||
import io.netty.channel.ChannelHandlerContext; | |||||
import io.netty.channel.ChannelInboundHandlerAdapter; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.beans.factory.annotation.Value; | |||||
import java.time.LocalDateTime; | |||||
/** | |||||
* @program: dipperposition | |||||
* @description: Netty服务器处理句柄 | |||||
* @author: linwl | |||||
* @create: 2021-01-13 13:56 | |||||
**/ | |||||
@Slf4j | |||||
public class NettyServerHandler extends ChannelInboundHandlerAdapter { | |||||
@Autowired | |||||
private IDipperAstTimeAsyncTaskService dipperTimeAsyncTaskService; | |||||
@Autowired | |||||
private IDipperAstPosAsyncTaskService dipperAstPosAsyncTaskService; | |||||
@Autowired | |||||
private IDipperDataAsyncTaskService dipperDataAsyncTaskService; | |||||
@Value(value = "${position.server.timeAsycPort}") | |||||
private String timeAsycServerPort; | |||||
@Value(value = "${position.server.posAsycPort}") | |||||
private String posAsycServerPort; | |||||
@Value(value = "${position.server.starsAsycPort}") | |||||
private String starsAsycServerPort; | |||||
/** | |||||
* 客户端连接会触发 | |||||
*/ | |||||
@Override | |||||
public void channelActive(ChannelHandlerContext ctx) throws Exception { | |||||
log.info("Channel active......"); | |||||
SocketChannel channel = (SocketChannel) ctx.channel(); | |||||
log.info("链接报告开始"); | |||||
log.info("链接报告信息:有一客户端链接到本服务端"); | |||||
log.info("链接报告IP:" + channel.localAddress().getHostString()); | |||||
log.info("链接报告Port:" + channel.localAddress().getPort()); | |||||
log.info("链接报告完毕"); | |||||
//通知客户端链接建立成功 | |||||
// 默认返回取得时间成功 | |||||
String ackAckCheckRef = "233E0101020004020A1D"; | |||||
if (Integer.parseInt(posAsycServerPort) == channel.localAddress().getPort()) { | |||||
ackAckCheckRef = "233E010102000401091C"; | |||||
} | |||||
if (Integer.parseInt(starsAsycServerPort) == channel.localAddress().getPort()) { | |||||
ackAckCheckRef = "233E010102000421293C"; | |||||
} | |||||
//String str = "通知客户端链接建立成功" + " " + LocalDateTime.now() + " " + channel.localAddress().getHostString() + | |||||
// "\r\n"; | |||||
ByteBuf buf = Unpooled.buffer(ackAckCheckRef.getBytes().length); | |||||
buf.writeBytes(ackAckCheckRef.getBytes("GBK")); | |||||
ctx.writeAndFlush(buf); | |||||
} | |||||
/** | |||||
* 当客户端主动断开服务端的链接后,这个通道就是不活跃的。也就是说客户端与服务端的关闭了通信通道并且不可以传输数据 | |||||
*/ | |||||
@Override | |||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception { | |||||
log.info("客户端断开链接,IP:{}", ctx.channel().localAddress().toString()); | |||||
} | |||||
/** | |||||
* 客户端发消息会触发 | |||||
*/ | |||||
@Override | |||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { | |||||
//接收msg消息{与上一章节相比,此处已经不需要自己进行解码} | |||||
SocketChannel channel = (SocketChannel) ctx.channel(); | |||||
String ipAddress = channel.remoteAddress().toString(); | |||||
String message = " 接收到消息:{0}, 客户端IP:{1}"; | |||||
log.info(message ,msg, ipAddress); | |||||
String channelAns = ""; | |||||
// 返回时间指令 | |||||
if (Integer.parseInt(timeAsycServerPort) == channel.localAddress().getPort()) { | |||||
// 初始时间辅助输入; | |||||
channelAns = dipperTimeAsyncTaskService.pushAstTime(); | |||||
} | |||||
// 发送SDBP-AST-POS获取辅助位置信息 | |||||
if (Integer.parseInt(posAsycServerPort) == channel.localAddress().getPort()) { | |||||
channelAns = dipperAstPosAsyncTaskService.pushAstPos(ipAddress); | |||||
} | |||||
// 从缓存获取SDBP-AST-EPH星历数 | |||||
if (Integer.parseInt(starsAsycServerPort) == channel.localAddress().getPort()) { | |||||
channelAns = dipperDataAsyncTaskService.getAstEPH(); | |||||
} | |||||
// 最后把SDBP-AST-TIME、SDBP-AST-POS、SDBP-AST-EPH并包一起发给设备。 | |||||
// 设备采用16进制获取数据,则代理服务器也是采用16进制返回数据。 | |||||
// 通知客户端链消息发送成功 | |||||
// String str = "服务端收到:" + LocalDateTime.now() + " " + msg + "\r\n"; | |||||
ByteBuf buf = Unpooled.buffer(channelAns.getBytes().length); | |||||
buf.writeBytes(channelAns.getBytes("GBK")); | |||||
ctx.writeAndFlush(buf); | |||||
//ctx.write("你也好哦"); | |||||
//ctx.flush(); | |||||
} | |||||
// @Override | |||||
// public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) | |||||
// throws Exception { | |||||
// if (msg instanceof HttpRequest) { | |||||
// HttpRequest mReq = (HttpRequest) msg; | |||||
// String clientIP = mReq.headers().get("X-Forwarded-For"); | |||||
// if (clientIP == null) { | |||||
// InetSocketAddress insocket = (InetSocketAddress) ctx.channel() | |||||
// .remoteAddress(); | |||||
// clientIP = insocket.getAddress().getHostAddress(); | |||||
// } | |||||
// } | |||||
// } | |||||
/** | |||||
* 发生异常触发 | |||||
*/ | |||||
@Override | |||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { | |||||
cause.printStackTrace(); | |||||
ctx.close(); | |||||
} | |||||
} |
@@ -0,0 +1,24 @@ | |||||
package com.telpo.dipperposition.handler; | |||||
import io.netty.channel.ChannelInitializer; | |||||
import io.netty.channel.ChannelPipeline; | |||||
import io.netty.channel.socket.SocketChannel; | |||||
import io.netty.handler.codec.string.StringDecoder; | |||||
import io.netty.handler.codec.string.StringEncoder; | |||||
import io.netty.util.CharsetUtil; | |||||
/** | |||||
* @program: dipperposition | |||||
* @description: 服务器通道初始化 | |||||
* @author: king | |||||
* @create: 2021-01-13 13:54 | |||||
**/ | |||||
public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> { | |||||
@Override | |||||
protected void initChannel(SocketChannel socketChannel) throws Exception { | |||||
//添加编解码 | |||||
socketChannel.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8)); | |||||
socketChannel.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8)); | |||||
socketChannel.pipeline().addLast(new NettyServerHandler()); | |||||
} | |||||
} |
@@ -0,0 +1,52 @@ | |||||
package com.telpo.dipperposition.mapper; | |||||
import com.telpo.dipperposition.entity.mongo.IPProvinceEntity; | |||||
import db.BaseMongoDbDao; | |||||
import org.springframework.stereotype.Repository; | |||||
import java.util.List; | |||||
/** | |||||
* @program: DataPushServer | |||||
* @description: 推送记录mapper | |||||
* @author: linwl | |||||
* @create: 2020-07-20 11:12 | |||||
*/ | |||||
@Repository | |||||
public class IPProvinceMapper extends BaseMongoDbDao<IPProvinceEntity> { | |||||
@Override | |||||
protected Class<IPProvinceEntity> getEntityClass() { | |||||
return IPProvinceEntity.class; | |||||
} | |||||
@Override | |||||
public void save(IPProvinceEntity entity, String collectionName) { | |||||
super.save(entity, collectionName); | |||||
} | |||||
@Override | |||||
public void updateFirst(IPProvinceEntity srcObj, IPProvinceEntity targetObj) { | |||||
super.updateFirst(srcObj, targetObj); | |||||
} | |||||
@Override | |||||
public List<IPProvinceEntity> getPage(IPProvinceEntity object, int start, int size) { | |||||
return super.getPage(object, start, size); | |||||
} | |||||
@Override | |||||
public List<IPProvinceEntity> queryList(IPProvinceEntity object) { | |||||
return super.queryList(object); | |||||
} | |||||
@Override | |||||
public List<IPProvinceEntity> queryList(IPProvinceEntity object, String collectionName) { | |||||
return super.queryList(object, collectionName); | |||||
} | |||||
@Override | |||||
public void deleteById(String id) { | |||||
super.deleteById(id); | |||||
} | |||||
} |
@@ -0,0 +1,153 @@ | |||||
package com.telpo.dipperposition.server; | |||||
import com.telpo.dipperposition.handler.ServerChannelInitializer; | |||||
import com.telpo.dipperposition.service.IDipperDataAsyncTaskService; | |||||
import io.netty.bootstrap.ServerBootstrap; | |||||
import io.netty.channel.ChannelFuture; | |||||
import io.netty.channel.ChannelOption; | |||||
import io.netty.channel.EventLoopGroup; | |||||
import io.netty.channel.nio.NioEventLoopGroup; | |||||
import io.netty.channel.socket.nio.NioServerSocketChannel; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.beans.factory.annotation.Value; | |||||
import java.net.InetSocketAddress; | |||||
/** | |||||
* @program: DipperPositionServer | |||||
* @description: 北斗定位 | |||||
* @author: king | |||||
* @create: 2021-01-13 14:01 | |||||
*/ | |||||
@Slf4j | |||||
public class DipperPositionServer { | |||||
@Value(value = "${position.serverAddr}") | |||||
private String serverAddr; | |||||
@Value(value = "${position.server.timeAsycPort}") | |||||
private String timeAsycServerPort; | |||||
@Value(value = "${position.server.posAsycPort}") | |||||
private String posAsycServerPort; | |||||
@Value(value = "${position.server.starsAsycPort}") | |||||
private String starsAsycServerPort; | |||||
/* | |||||
* 时间同步进程线程 | |||||
*/ | |||||
public void startTimeAsnc() { | |||||
//new 一个主线程组 | |||||
EventLoopGroup mainThreadGroup = new NioEventLoopGroup(1); | |||||
//new 一个工作线程组 | |||||
EventLoopGroup workThreadGroup = new NioEventLoopGroup(200); | |||||
InetSocketAddress socketAddress = new InetSocketAddress(serverAddr, Integer.parseInt(timeAsycServerPort)); | |||||
ServerBootstrap bootstrap = new ServerBootstrap() | |||||
.group(mainThreadGroup, workThreadGroup) | |||||
.channel(NioServerSocketChannel.class) | |||||
.childHandler(new ServerChannelInitializer()) | |||||
.localAddress(socketAddress) | |||||
//设置队列大小 | |||||
.option(ChannelOption.SO_BACKLOG, 1024) | |||||
// 两小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文 | |||||
.childOption(ChannelOption.SO_KEEPALIVE, true); | |||||
//绑定端口,开始接收进来的连接 | |||||
try { | |||||
ChannelFuture future = bootstrap.bind(socketAddress).sync(); | |||||
log.info("服务器启动开始监听端口: {}", socketAddress.getPort()); | |||||
future.channel().closeFuture().sync(); | |||||
} catch (InterruptedException e) { | |||||
e.printStackTrace(); | |||||
} finally { | |||||
//关闭主线程组 | |||||
mainThreadGroup.shutdownGracefully(); | |||||
//关闭工作线程组 | |||||
workThreadGroup.shutdownGracefully(); | |||||
} | |||||
} | |||||
/* | |||||
* 时间同步进程线程 | |||||
*/ | |||||
public void startPosAsnc() { | |||||
//new 一个主线程组 | |||||
EventLoopGroup mainThreadGroup = new NioEventLoopGroup(1); | |||||
//new 一个工作线程组 | |||||
EventLoopGroup workThreadGroup = new NioEventLoopGroup(200); | |||||
InetSocketAddress socketAddress = new InetSocketAddress(serverAddr, Integer.parseInt(posAsycServerPort)); | |||||
ServerBootstrap bootstrap = new ServerBootstrap() | |||||
.group(mainThreadGroup, workThreadGroup) | |||||
.channel(NioServerSocketChannel.class) | |||||
.childHandler(new ServerChannelInitializer()) | |||||
.localAddress(socketAddress) | |||||
//设置队列大小 | |||||
.option(ChannelOption.SO_BACKLOG, 1024) | |||||
// 两小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文 | |||||
.childOption(ChannelOption.SO_KEEPALIVE, true); | |||||
//绑定端口,开始接收进来的连接 | |||||
try { | |||||
ChannelFuture future = bootstrap.bind(socketAddress).sync(); | |||||
log.info("服务器启动开始监听端口: {}", socketAddress.getPort()); | |||||
future.channel().closeFuture().sync(); | |||||
} catch (InterruptedException e) { | |||||
e.printStackTrace(); | |||||
} finally { | |||||
//关闭主线程组 | |||||
mainThreadGroup.shutdownGracefully(); | |||||
//关闭工作线程组 | |||||
workThreadGroup.shutdownGracefully(); | |||||
} | |||||
} | |||||
/* | |||||
* 星历同步进程线程 | |||||
*/ | |||||
public void startStarsAsnc() { | |||||
//new 一个主线程组 | |||||
EventLoopGroup mainThreadGroup = new NioEventLoopGroup(1); | |||||
//new 一个工作线程组 | |||||
EventLoopGroup workThreadGroup = new NioEventLoopGroup(200); | |||||
InetSocketAddress socketAddress = new InetSocketAddress(serverAddr, Integer.parseInt(starsAsycServerPort)); | |||||
ServerBootstrap bootstrap = new ServerBootstrap() | |||||
.group(mainThreadGroup, workThreadGroup) | |||||
.channel(NioServerSocketChannel.class) | |||||
.childHandler(new ServerChannelInitializer()) | |||||
.localAddress(socketAddress) | |||||
//设置队列大小 | |||||
.option(ChannelOption.SO_BACKLOG, 1024) | |||||
// 两小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文 | |||||
.childOption(ChannelOption.SO_KEEPALIVE, true); | |||||
//绑定端口,开始接收进来的连接 | |||||
try { | |||||
ChannelFuture future = bootstrap.bind(socketAddress).sync(); | |||||
log.info("服务器启动开始监听端口: {}", socketAddress.getPort()); | |||||
future.channel().closeFuture().sync(); | |||||
} catch (InterruptedException e) { | |||||
e.printStackTrace(); | |||||
} finally { | |||||
//关闭主线程组 | |||||
mainThreadGroup.shutdownGracefully(); | |||||
//关闭工作线程组 | |||||
workThreadGroup.shutdownGracefully(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,23 @@ | |||||
package com.telpo.dipperposition.service; | |||||
import java.io.UnsupportedEncodingException; | |||||
/** | |||||
* @program: IDipperAstPosAsyncTaskService | |||||
* @description: 系统预先基于省份的省会城市的经纬度作为辅助信息, | |||||
* 根据设备请求的IP地址,从高德IP定位服务获取相关的省份,再匹配相应的位置信息作为辅助位置信息。 | |||||
* 如果匹配不到省份,则以武汉中心作为辅助为位置信息。 | |||||
* 关于IP与省份的关系保存到缓存中,用于下次使用时,先在缓存中获取匹配信息,匹配不到,再请求高德IP定位服务。 | |||||
* 高德IP定位服务:https://lbs.amap.com/api/webservice/guide/api/ipconfig。 | |||||
* @author: king | |||||
* @create: 2021-01-17 16:24 | |||||
*/ | |||||
public interface IDipperAstPosAsyncTaskService { | |||||
/** | |||||
* 同步任务 | |||||
* | |||||
*/ | |||||
String pushAstPos(String ipAddress) throws UnsupportedEncodingException; | |||||
} |
@@ -0,0 +1,17 @@ | |||||
package com.telpo.dipperposition.service; | |||||
/** | |||||
* @program: IDipperDataAsyncTaskService | |||||
* @description: 发送SDBP-AST-TIME获取时间信息 | |||||
* @author: king | |||||
* @create: 2021-01-17 16:24 | |||||
*/ | |||||
public interface IDipperAstTimeAsyncTaskService { | |||||
/** | |||||
* 同步任务 | |||||
* | |||||
*/ | |||||
String pushAstTime(); | |||||
} |
@@ -0,0 +1,26 @@ | |||||
package com.telpo.dipperposition.service; | |||||
/** | |||||
* @program: IDipperDataAsyncTaskService | |||||
* @description: 发送bds获取星历数据。 | |||||
* * 每30分钟获取1次,30秒超时, | |||||
* * 如果失败,则可以等待10秒再获取1次 | |||||
* @author: king | |||||
* @create: 2021-01-17 16:24 | |||||
*/ | |||||
public interface IDipperDataAsyncTaskService { | |||||
/** | |||||
* 同步任务 | |||||
* | |||||
*/ | |||||
void pullAstEPH(); | |||||
/** | |||||
* 根据IP获取EPH | |||||
* | |||||
*/ | |||||
String getAstEPH(); | |||||
} |
@@ -0,0 +1,45 @@ | |||||
package com.telpo.dipperposition.service; | |||||
import com.telpo.dipperposition.entity.mongo.IPProvinceEntity; | |||||
import com.telpo.dipperposition.vo.IPProvinceVo; | |||||
/** | |||||
* @program: IPProvinceService | |||||
* @description: IP省份服务接口 | |||||
* @author: king | |||||
* @create: 2020-07-20 11:09 | |||||
*/ | |||||
public interface IPProvinceService { | |||||
/** | |||||
* 保存IP省份 | |||||
* | |||||
* @param entity | |||||
* @return | |||||
*/ | |||||
boolean saveIPProvince(IPProvinceEntity entity); | |||||
/** | |||||
* 更新IP省份 | |||||
* | |||||
* @param query | |||||
* @param update | |||||
* @return | |||||
*/ | |||||
boolean updateIPProvince( | |||||
IPProvinceEntity query, IPProvinceEntity update); | |||||
/** | |||||
* 根据ID移除IP省份记录 | |||||
* | |||||
* @param id | |||||
* @return | |||||
*/ | |||||
boolean romveById(String id); | |||||
/* | |||||
* @param ipAddress | |||||
* 获取IP省份 | |||||
*/ | |||||
IPProvinceEntity getIPProvince(String ipAddress); | |||||
} |
@@ -0,0 +1,251 @@ | |||||
package com.telpo.dipperposition.service.impl; | |||||
import com.alibaba.fastjson.JSONObject; | |||||
import com.google.common.base.Joiner; | |||||
import com.telpo.dipperposition.common.*; | |||||
import com.telpo.dipperposition.entity.mongo.IPProvinceEntity; | |||||
import com.telpo.dipperposition.mapper.IPProvinceMapper; | |||||
import com.telpo.dipperposition.service.IDipperAstPosAsyncTaskService; | |||||
import com.telpo.dipperposition.service.IPProvinceService; | |||||
import com.telpo.dipperposition.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; | |||||
@Value("${pos.centerProvinceFilePath}") | |||||
String centerProvinceFilePath; | |||||
@Value("${pos.ipPositionRequestPath}") | |||||
String ipPositionRequestPath; | |||||
@Value("${pos.ipPositionRequestKey}") | |||||
String ipPositionRequestKey; | |||||
@Value("${pos.centerProvince}") | |||||
String centerProvince; | |||||
@Value("${pos.ast.server}") | |||||
String astServer; | |||||
@Value("${pos.ast.posAstPort}") | |||||
int posAstPort; | |||||
@Value("${pos.ast.timeout}") | |||||
int astTimeout; | |||||
// 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<String> centerAddressSets = CSVUtil.readCSV(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 | |||||
private 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 | |||||
public String pushAstPos(String ipAddress) throws UnsupportedEncodingException { | |||||
// (1) 获取省会城市信息 | |||||
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); | |||||
} | |||||
// (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; | |||||
} | |||||
} |
@@ -0,0 +1,104 @@ | |||||
package com.telpo.dipperposition.service.impl; | |||||
import com.telpo.dipperposition.common.HexConvert; | |||||
import com.telpo.dipperposition.common.SocketClient; | |||||
import com.telpo.dipperposition.service.IDipperAstTimeAsyncTaskService; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.springframework.beans.factory.annotation.Value; | |||||
import org.springframework.stereotype.Service; | |||||
import java.time.LocalDateTime; | |||||
/** | |||||
* @program: DipperDataAsyncTaskServiceImpl | |||||
* @description: 发送SDBP-AST-TIME获取时间信息 | |||||
* @author: king | |||||
* @create: 2021-01-10 14:01 | |||||
*/ | |||||
@Service | |||||
@Slf4j | |||||
public class DipperAstTimeAsyncTaskServiceImpl implements IDipperAstTimeAsyncTaskService { | |||||
@Override | |||||
public String pushAstTime() { | |||||
// (1) 发送SDBP-AST-TIME | |||||
// String sendResult = pushTimeToDipper(); | |||||
//if (sendResult == null) { | |||||
// log.error("取不到时间。"); | |||||
// return null; | |||||
//} | |||||
// (2) 获取时间信息 | |||||
return pushTimeToDipper(); | |||||
//return sendResult; | |||||
} | |||||
private String pushTimeToDipper() { | |||||
// 创建Socket客户端实例; | |||||
// SocketClient client = new SocketClient(astServer, timeAstPort, astTimeout); | |||||
// 时间和位置不是从服务器获取,而是本地生成(其中时间误差不超过3s) | |||||
// 23 3E 04 02 10 00 20 E1 07 09 14 0C 22 38 00 00 00 00 00 28 6B EE 22 98 | |||||
// 23 3E 为同步头 | |||||
// 04 02 为识别码 | |||||
// 10 00 表示长度为 16 | |||||
// --日期-- | |||||
// 20 E1 表示闰秒改正数为 | |||||
// E1 07 表示年为 2017 年(十六进制 07E1 转为十进制) | |||||
// 09 表示 9 月 | |||||
// 14 表示 20 日 | |||||
// 0C 22 38 00 00 00 00 00 表示 UTC时间,为12时34分56.0秒(小数秒建议固定为 0) | |||||
// 00 28 6B EE 表示 4 秒的时间精度(十六进制 EE6B2800 转为十进制为 4000000000,乘以比 例因子 10-9就是 4 秒) | |||||
// 00 2F 为校验和 | |||||
// TODO astTimeCmd 组装 | |||||
String astTimeCmd = "233E0402"; | |||||
astTimeCmd += "1000"; | |||||
astTimeCmd += "20E1"; | |||||
LocalDateTime now = LocalDateTime.now(); | |||||
int year = now.getYear(); | |||||
int month = now.getMonthValue(); | |||||
int day = now.getDayOfMonth(); | |||||
String hexYearString = Integer.toHexString(year); | |||||
hexYearString = "0" + hexYearString; | |||||
astTimeCmd += hexYearString.substring(2,2) + hexYearString.substring(0,2); | |||||
String hexMonthString = Integer.toHexString(month); | |||||
hexMonthString = "0" + hexMonthString; | |||||
astTimeCmd += hexMonthString; | |||||
String hexDayString = Integer.toHexString(day); | |||||
if (day < 16) { | |||||
hexDayString = "0" + hexDayString; | |||||
} | |||||
astTimeCmd += hexDayString; | |||||
int hour = now.getHour(); | |||||
int minitor = now.getMinute(); | |||||
int second = now.getSecond(); | |||||
String hexHourString = Integer.toHexString(hour); | |||||
if (hour < 16) { | |||||
hexHourString = "0" + hexHourString; | |||||
} | |||||
astTimeCmd += hexHourString; | |||||
String hexMinitorString = Integer.toHexString(minitor); | |||||
if (minitor < 16) { | |||||
hexMinitorString = "0" + hexMinitorString; | |||||
} | |||||
astTimeCmd += hexMinitorString; | |||||
String hexSecondString = Integer.toHexString(second); | |||||
if (second < 16) { | |||||
hexSecondString = "0" + hexSecondString; | |||||
} | |||||
astTimeCmd += hexSecondString; | |||||
astTimeCmd += "0000000000"; | |||||
astTimeCmd += "00286BEE"; | |||||
String hexIn = HexConvert.convertStringToHex(astTimeCmd) + HexConvert.makeChecksum(astTimeCmd); | |||||
//String ackAckCheckRef = "233E0101020004020A1D"; | |||||
//String sendResult = client.sendCmd(hexIn, ackAckCheckRef); | |||||
//client.closeConnection(); | |||||
return hexIn; | |||||
} | |||||
} |
@@ -0,0 +1,73 @@ | |||||
package com.telpo.dipperposition.service.impl; | |||||
import com.telpo.dipperposition.common.HexConvert; | |||||
import com.telpo.dipperposition.common.RedisUtil; | |||||
import com.telpo.dipperposition.common.SocketClient; | |||||
import com.telpo.dipperposition.service.IDipperDataAsyncTaskService; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.beans.factory.annotation.Value; | |||||
import org.springframework.stereotype.Service; | |||||
/** | |||||
* @program: DipperDataAsyncTaskServiceImpl | |||||
* @description: 获取星历数据。 | |||||
* @author: king | |||||
* @create: 2021-01-10 14:01 | |||||
*/ | |||||
@Service | |||||
@Slf4j | |||||
public class DipperDataAsyncTaskServiceImpl implements IDipperDataAsyncTaskService { | |||||
@Autowired | |||||
private RedisUtil redisUtil; | |||||
@Value("${pos.ast.server}") | |||||
String astServer; | |||||
@Value("${pos.ast.ephAstPort}") | |||||
int ephAstPort; | |||||
@Value("${pos.ast.ephAstHexPort}") | |||||
int ephAstHexPort; | |||||
@Value("${pos.ast.timeout}") | |||||
int astTimeout; | |||||
private static String DIPPER_DATA_KEY = "TaidouDipperData"; | |||||
@Override | |||||
public void pullAstEPH() { | |||||
// (1) 发送bds获取星历数据 | |||||
String dipperData = pullEPHFromDipper(); | |||||
// (2) 获取星历数据 | |||||
if (dipperData == null) { | |||||
log.error("获取星历数据错误,取不到星历数据。"); | |||||
} else { | |||||
// 保存到DB或者缓存 | |||||
redisUtil.set(DIPPER_DATA_KEY,dipperData); | |||||
} | |||||
} | |||||
private String pullEPHFromDipper() { | |||||
// 创建Socket客户端实例; | |||||
SocketClient client = new SocketClient(astServer, ephAstPort, astTimeout); | |||||
// astTimeCmd 组装 | |||||
String astTimeCmd = "all"; | |||||
String hexIn = HexConvert.convertStringToHex(astTimeCmd) + HexConvert.makeChecksum(astTimeCmd); | |||||
String ackAckCheckRef = "233E010102000421293C"; | |||||
String sendResult = client.sendCmd(hexIn, ackAckCheckRef); | |||||
client.closeConnection(); | |||||
return sendResult; | |||||
} | |||||
@Override | |||||
public String getAstEPH(){ | |||||
return (String)redisUtil.get(DIPPER_DATA_KEY); | |||||
} | |||||
} |
@@ -0,0 +1,62 @@ | |||||
package com.telpo.dipperposition.service.impl; | |||||
import com.telpo.dipperposition.entity.mongo.IPProvinceEntity; | |||||
import com.telpo.dipperposition.mapper.IPProvinceMapper; | |||||
import com.telpo.dipperposition.service.IPProvinceService; | |||||
import com.telpo.dipperposition.vo.IPProvinceVo; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.apache.commons.lang3.ObjectUtils; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.stereotype.Service; | |||||
import java.util.List; | |||||
/** | |||||
* @program: DataPushServer | |||||
* @description: 推送记录服务接口实现类 | |||||
* @author: linwl | |||||
* @create: 2020-07-20 11:09 | |||||
*/ | |||||
@Slf4j | |||||
@Service | |||||
public class IPProvinceServiceImpl implements IPProvinceService { | |||||
@Autowired | |||||
private IPProvinceMapper iPProvinceMapper; | |||||
@Override | |||||
public boolean saveIPProvince(IPProvinceEntity entity) { | |||||
iPProvinceMapper.save(entity); | |||||
return true; | |||||
} | |||||
@Override | |||||
public boolean updateIPProvince( | |||||
IPProvinceEntity query, IPProvinceEntity update) { | |||||
iPProvinceMapper.updateFirst(query, update); | |||||
return true; | |||||
} | |||||
@Override | |||||
public boolean romveById(String id) { | |||||
iPProvinceMapper.deleteById(id); | |||||
return false; | |||||
} | |||||
@Override | |||||
public IPProvinceEntity getIPProvince(String ipAddress) { | |||||
try { | |||||
IPProvinceEntity query = new IPProvinceEntity(); | |||||
query.setIp(ipAddress); | |||||
List<IPProvinceEntity> pushRecords = iPProvinceMapper.queryList(query); | |||||
if (ObjectUtils.isNotEmpty(pushRecords)) { | |||||
return pushRecords.get(0); | |||||
} else { | |||||
return null; | |||||
} | |||||
} catch (Exception e) { | |||||
log.error("获取IP省份异常:", e); | |||||
return null; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,39 @@ | |||||
package com.telpo.dipperposition.task; | |||||
import com.telpo.dipperposition.service.IDipperDataAsyncTaskService; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.scheduling.annotation.Scheduled; | |||||
import org.springframework.stereotype.Component; | |||||
/** | |||||
* @program: DataPushServer | |||||
* @description: 定时执行任务服务 | |||||
* @author: king | |||||
* @create: 2021-01-17 16:24 | |||||
*/ | |||||
@Component | |||||
@Slf4j | |||||
public class ScheduleService { | |||||
@Autowired | |||||
private IDipperDataAsyncTaskService dipperDataAsyncTaskService; | |||||
/* | |||||
* 调用9012端口的接口获取星历数据。 | |||||
* 通过TCP连接服务器agnss.techtotop.com:9012,发送bds获取星历数据。 | |||||
* 每30分钟获取1次,30秒超时, | |||||
* 如果失败,则可以等待10秒再获取1次。 * | |||||
*/ | |||||
@Scheduled(cron = "${scheduler.task.cron}") | |||||
public void pullData() { | |||||
log.info("开始星历数据同步!"); | |||||
// 获取推送失败的记录 | |||||
try { | |||||
dipperDataAsyncTaskService.pullAstEPH(); | |||||
} catch (Exception e) { | |||||
log.error("执行定时获取星历数据发生异常:", e); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,20 @@ | |||||
package com.telpo.dipperposition.vo; | |||||
import lombok.Getter; | |||||
import lombok.Setter; | |||||
/** | |||||
* @program: DataPushServer | |||||
* @description: 基础类 | |||||
* @author: linwl | |||||
* @create: 2020-07-17 16:41 | |||||
*/ | |||||
@Setter | |||||
@Getter | |||||
public class IPProvinceVo { | |||||
/** Ip */ | |||||
private String ip; | |||||
/** Ip所在省份 */ | |||||
private String province; | |||||
} |
@@ -7,4 +7,28 @@ spring: | |||||
nacos: | nacos: | ||||
config: | config: | ||||
server-addr: 172.16.192.26:8848 | server-addr: 172.16.192.26:8848 | ||||
file-extension: yml | |||||
file-extension: yaml | |||||
scheduler: | |||||
task: | |||||
pool: | |||||
size: 2 | |||||
#等待任务完成退出最大秒数 | |||||
await-seconds: 600 | |||||
cron: "0 */30 * * * *" | |||||
pos: | |||||
centerProvinceFilePath: /csv/provinceLonAlt.csv | |||||
ipPositionRequestPath: https://restapi.amap.com/v3/ip | |||||
ipPositionRequestKey: 65e794b0a1a4b87eeec86f93fea05411 | |||||
centerProvince: 湖北省 | |||||
ast: | |||||
server: agnss.techtotop.com | |||||
ephAstPort: 8012 | |||||
ephAstHexPort: 9012 | |||||
timeout: 30000 | |||||
position: | |||||
server: | |||||
timeAsycPort: | |||||
posAsycPort: | |||||
starsAsycPort: |