diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d4dfde6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/** +!**/src/test/** + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..190741e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM java:8 +MAINTAINER king <1609724385@qq.com> +VOLUME /tmp +COPY target/dipperposition.jar dipperposition.jar +COPY --from=hengyunabc/arthas:latest /opt/arthas /opt/arthas +ENV TimeZone=Asia/Shanghai +ENV active=dev +ENV JAVA_OPTS="-Xmx256M -Xms256M" +RUN ln -snf /usr/share/zoneinfo/$TimeZone /etc/localtime && echo $TimeZone > /etc/timezone +ENTRYPOINT java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -Dio.netty.leakDetectionLevel=ADVANCED -jar /dipperposition.jar --spring.profiles.active=$active + +java -Xmx256M -Xms256M -Djava.security.egd=file:/dev/./urandom -Dio.netty.leakDetectionLevel=ADVANCED -jar /dipperposition.jar --spring.profiles.active= \ No newline at end of file diff --git a/dipper_position_run.sh b/dipper_position_run.sh new file mode 100644 index 0000000..fb9d25a --- /dev/null +++ b/dipper_position_run.sh @@ -0,0 +1,30 @@ +#!/bin/bash +environment=$1 +version=$2 +echo "环境变量为${environment},版本为$version!" + +#processID='ps -ef | grep dipperposition | awk '{print $2}' | awk NR==1' +ps -ef | grep dipperposition | awk '{print $2}' | xargs kill -9 +#echo $processID +#if [[ "$processID" != "" ]]; then +# kill -9 $processID +#fi + +if [[ ${environment} == 'pro' ]]; then + echo 'run in production environment' + cd /home/data/dipperposition + if [[ -f /home/linwl/dipperposition/dipperposition.jar ]]; then + echo 'mv /home/linwl/dipperposition/dipperposition.jar to destination' + mv /home/linwl/dipperposition/dipperposition.jar /home/data/dipperposition/dipperposition.jar + fi + + nohup java -Xmx1024M -Xms1024M -Djava.security.egd=file:/dev/./urandom -Dio.netty.leakDetectionLevel=ADVANCED -jar dipperposition.jar --spring.profiles.active=pro & + +fi +if [[ ${environment} == 'test' ]]; then + cd /home/data/dipperposition + if [[ -f /home/linwl/Work/DipperPosition/dipperposition.jar ]]; then + mv /home/linwl/Work/DipperPosition/dipperposition.jar /home/data/dipperposition/dipperposition.jar + fi + nohup java -Xmx128M -Xms128M -Djava.security.egd=file:/dev/./urandom -Dio.netty.leakDetectionLevel=ADVANCED -jar dipperposition.jar --spring.profiles.active=test & +fi diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..cabac44 --- /dev/null +++ b/pom.xml @@ -0,0 +1,159 @@ + + + 4.0.0 + com.telpo + dipperposition + 1.0-SNAPSHOT + dipperposition + 北斗定位服务 + jar + + + org.springframework.boot + spring-boot-starter-parent + 2.2.5.RELEASE + + + + UTF-8 + UTF-8 + 1.8 + UTF-8 + 2.2.0.RELEASE + Hoxton.RELEASE + true + + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + + org.projectlombok + lombok + true + + + + cn.hutool + hutool-core + 5.5.2 + + + + org.springframework.boot + spring-boot-starter-webflux + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + + org.apache.commons + commons-lang3 + 3.10 + + + + + org.yaml + snakeyaml + 1.25 + + + + com.alibaba + fastjson + 1.2.28 + + + + io.netty + netty-all + 4.1.13.Final + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + org.apache.commons + commons-pool2 + + + + + com.squareup.okhttp3 + okhttp + 4.8.0 + + + + + de.codecentric + spring-boot-admin-starter-client + 2.2.4 + + + + + net.sourceforge.javacsv + javacsv + 2.0 + + + + org.springframework.data + spring-data-mongodb + 2.2.5.RELEASE + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + + + true + + + + + repackage + + + + + + + \ No newline at end of file diff --git a/setup_dev.sh b/setup_dev.sh new file mode 100644 index 0000000..b64f8da --- /dev/null +++ b/setup_dev.sh @@ -0,0 +1,65 @@ +#!/bin/bash +mvn clean +mvn package -Dmaven.test.skip=true +#image_version=$(date +%Y%m%d%H%M) +image_version=$version + +#docker cp docker_jenkins:/var/jenkins_home/workspace/dipperpos_service/target/dipperposition.jar +# /usr/local/dipperposition/dipperposition.jar +docker stop dipperposition_service || true +docker rm dipperposition_service || true + +# 删除镜像 +docker rmi -f $(docker images | grep telpo/dipperposition_service | awk '{print $3}') + +docker build . -t telpo/dipperposition_service:$image_version + +#TODO:推送镜像到私有仓库 +echo '=================开始推送镜像=======================' +docker tag telpo/dipperposition_service:$image_version 139.224.254.18:5000/dipperposition_service:$image_version +docker push 139.224.254.18:5000/dipperposition_service:$image_version +echo '=================推送镜像完成=======================' + +#删除产生的None镜像 +docker rmi -f $(docker images | grep none | awk '{print $3}') +# 查看镜像列表 +docker images +# 启动容器 +docker run -v /home/data/dipperposition/log:/var/log/dipperposition -d -e active=dev --network host --restart=always -p 9011:9011 -p 9012:9012 -p 9013:9013 --name dipperposition_service 139.224.254.18:5000/dipperposition_service:$image_version + +#echo "scp ${WORKSPACE} files......begin" +#set passwd "telpo#1234" +#scp /var/jenkins_home/workspace/dipperpos_service/target/dipperposition.jar root@47.116.142.20:/home/data/dipperposition/dipperposition.jar +#expect { +# "密码:" +# { +# send "$passwd\n" +# } +# "pass" +# { +# send "$passwd\n" +# } +# +# "yes/no" +# { +# sleep 5 +# send_user "send yes" +# send "yes\n" +# } +# eof +# { +# sleep 5 +# send_user "eof\n" +# } +#} +#send "exit\r" +#expect eof +#echo "scp ${WORKSPACE} files......end" +# 查看日志 +#docker logs dipperposition_service + +#echo '=================启动NettyAPP=======================' +#ps -ef |grep dipperposition |awk '{print $2}'|xargs kill -9 +#java -jar -Xms256m -Xmx256m -Xss256k -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m +# /usr/local/dipperposition/dipperposition.jar --spring.profiles.active=dev +#echo '=================完成NettyAPP启动=======================' diff --git a/setup_pro.sh b/setup_pro.sh new file mode 100644 index 0000000..7de562d --- /dev/null +++ b/setup_pro.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +mvn clean +mvn package -Dmaven.test.skip=true +image_version=$version +# 删除镜像 +docker rmi -f $( + docker images | grep registry.cn-shanghai.aliyuncs.com/telpo_platform/dipperposition_service | awk '{print $3}' +) +# 构建telpo/mrp:$image_version镜像 +docker build . -t telpo/dipperposition_service:$image_version +#TODO:推送镜像到阿里仓库 +echo '=================开始推送镜像=======================' +docker login --username=rzl_wangjx@1111649216405698 --password=telpo.123 registry.cn-shanghai.aliyuncs.com +docker tag telpo/dipperposition_service:$image_version registry.cn-shanghai.aliyuncs.com/telpo_platform/dipperposition_service:$image_version +docker push registry.cn-shanghai.aliyuncs.com/telpo_platform/dipperposition_service:$image_version +echo '=================推送镜像完成=======================' +#删除产生的None镜像 +docker rmi -f $(docker images | grep none | awk '{print $3}') +# 查看镜像列表 +docker images diff --git a/setup_test.sh b/setup_test.sh new file mode 100644 index 0000000..1c0d5f8 --- /dev/null +++ b/setup_test.sh @@ -0,0 +1,27 @@ +#!/bin/bash +mvn clean +mvn package -Dmaven.test.skip=true +#image_version=$(date +%Y%m%d%H%M) +image_version=$version +docker stop dipperposition_service || true +docker rm dipperposition_service || true + +# 删除镜像 +docker rmi -f $(docker images | grep telpo/dipperposition_service | awk '{print $3}') + +docker build . -t telpo/dipperposition_service:$image_version + +#TODO:推送镜像到私有仓库 +echo '=================开始推送镜像=======================' +docker tag telpo/dipperposition_service:$image_version 139.224.254.18:5000/dipperposition_service:$image_version +docker push 139.224.254.18:5000/dipperposition_service:$image_version +echo '=================推送镜像完成=======================' + +#删除产生的None镜像 +docker rmi -f $(docker images | grep none | awk '{print $3}') +# 查看镜像列表 +docker images +# 启动容器 +docker run -v /home/data/dipperposition/log:/var/log/dipperposition -d -e active=test --network host --restart=always -p 9012:9012 --name dipperposition_service 139.224.254.18:5000/dipperposition_service:$image_version +# 查看日志 +# docker logs dipperposition_service diff --git a/src/main/java/com/telpo/dipperposition/DipperPositionApplication.java b/src/main/java/com/telpo/dipperposition/DipperPositionApplication.java new file mode 100644 index 0000000..452e6e9 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/DipperPositionApplication.java @@ -0,0 +1,39 @@ +package com.telpo.dipperposition; + +import com.telpo.dipperposition.server.DipperPositionServer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * @program: gateway + * @description: 网关启动类 + * @author: linwl + * @create: 2020-06-18 16:39 + */ +@SpringBootApplication +@ConfigurationPropertiesScan +@EnableAsync +@EnableScheduling +@Slf4j +public class DipperPositionApplication { + + public static void main(String[] args) { + try { + log.info("北斗定位服务开始!"); + ConfigurableApplicationContext applicationContext = SpringApplication.run(DipperPositionApplication.class, args); + log.info("北斗定位服务启动!"); + //启动服务端 + ConfigurableEnvironment environment = applicationContext.getEnvironment(); + DipperPositionServer nettyServer = new DipperPositionServer(environment); + nettyServer.start(); + } catch (Exception e) { + log.error(e.getMessage()); + } + } +} diff --git a/src/main/java/com/telpo/dipperposition/annotation/MongoSwitch.java b/src/main/java/com/telpo/dipperposition/annotation/MongoSwitch.java new file mode 100644 index 0000000..6153006 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/annotation/MongoSwitch.java @@ -0,0 +1,22 @@ +package com.telpo.dipperposition.annotation; + +import java.lang.annotation.*; + +/** + * @program: DataPushServer + * @description: mongo数据源切换注解 + * @author: linwl + * @create: 2020-07-11 15:06 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface MongoSwitch { + + /** + * mongo数据库名称 + * + * @return + */ + String value() default ""; +} diff --git a/src/main/java/com/telpo/dipperposition/co/PositionConfigInfo.java b/src/main/java/com/telpo/dipperposition/co/PositionConfigInfo.java new file mode 100644 index 0000000..47c2d16 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/co/PositionConfigInfo.java @@ -0,0 +1,35 @@ +package com.telpo.dipperposition.co; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import okhttp3.*; +import okhttp3.internal.ws.RealWebSocket; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import javax.net.SocketFactory; + +/** + * @program: RzlAccount + * @description: 融智联账号配置 + * @author: king + * @create: 2021-01-12 14:02 + **/ +@Getter +@Setter +@Component +@ConfigurationProperties(prefix = "position-server") +public class PositionConfigInfo { + + private String serverAddr; + + private String timeAsycPort; + + private String posAsycPort; + + private String starsAsycPort; + +} diff --git a/src/main/java/com/telpo/dipperposition/common/CSVUtil.java b/src/main/java/com/telpo/dipperposition/common/CSVUtil.java new file mode 100644 index 0000000..0d840a2 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/common/CSVUtil.java @@ -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 readCSV(String readPath) { + String filePath = readPath; + List listData = new ArrayList<>(); + try { + filePath = readPath; + CsvReader csvReader = new CsvReader(filePath,',',Charset.forName("UTF-8")); + // 读表头 + 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(); + } + } + } +} diff --git a/src/main/java/com/telpo/dipperposition/common/HexConvert.java b/src/main/java/com/telpo/dipperposition/common/HexConvert.java new file mode 100644 index 0000000..20a8708 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/common/HexConvert.java @@ -0,0 +1,174 @@ +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> 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; + } + + + /** + * 生成校验码的int值 + * */ + public static String makeChecksumForBytes(byte[] byteDatas) { + if (byteDatas == null || byteDatas.length == 0) { + return ""; + } + int total = 0; + int len = byteDatas.length; + + final String HEX = "0123456789abcdef"; + StringBuilder sb = null; + for (byte b : byteDatas) { + sb = new StringBuilder(2); + // 取出这个字节的高4位,然后与0x0f与运算,得到一个0-15之间的数据,通过HEX.charAt(0-15)即为16进制数 + sb.append(HEX.charAt((b >> 4) & 0x0f)); + // 取出这个字节的低位,与0x0f与运算,得到一个0-15之间的数据,通过HEX.charAt(0-15)即为16进制数 + sb.append(HEX.charAt(b & 0x0f)); + total += Integer.parseInt(sb.toString(), 16); + } + /** + * 用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 )); +// } + +} diff --git a/src/main/java/com/telpo/dipperposition/common/OkHttpUtil.java b/src/main/java/com/telpo/dipperposition/common/OkHttpUtil.java new file mode 100644 index 0000000..5e4dd18 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/common/OkHttpUtil.java @@ -0,0 +1,172 @@ +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 javax.annotation.PostConstruct; +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; + + public static OkHttpUtil okHttpUtil; + + @PostConstruct + public void init() { + okHttpUtil = this; + } + /** + * 根据map获取get请求参数 + * + * @param queries + * @return + */ + public StringBuffer getQueryString(String url, Map 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) 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 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 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请求发送JSON数据....{"name":"zhangsan","pwd":"123456"} 参数一:请求Url 参数二:请求的JSON 参数三:请求回调 */ + public String getJsonParams(String url, String jsonParams) { + Request request = new Request.Builder().url(url).addHeader("application/json","charset=utf-8").build(); + log.debug(MessageFormat.format("get json to url<{0}>", url)); + + 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); + } + } + } +} diff --git a/src/main/java/com/telpo/dipperposition/common/RedisUtil.java b/src/main/java/com/telpo/dipperposition/common/RedisUtil.java new file mode 100644 index 0000000..f1e85eb --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/common/RedisUtil.java @@ -0,0 +1,672 @@ +package com.telpo.dipperposition.common; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import javax.annotation.PostConstruct; +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 redisTemplate; + +// public static RedisUtil redisUtil; +// @PostConstruct +// public void init() { +// redisUtil = this; +// } + // =============================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 hmget(String key) { + return redisTemplate.opsForHash().entries(key); + } + + /** + * HashSet + * + * @param key 键 + * @param map 对应多个键值 + * @return true 成功 false 失败 + */ + public boolean hmset(String key, Map 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 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 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 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 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 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 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; + } + } +} diff --git a/src/main/java/com/telpo/dipperposition/common/SocketClient.java b/src/main/java/com/telpo/dipperposition/common/SocketClient.java new file mode 100644 index 0000000..8b7fca4 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/common/SocketClient.java @@ -0,0 +1,88 @@ +package com.telpo.dipperposition.common; + +import lombok.extern.slf4j.Slf4j; + +import java.io.*; +import java.net.Socket; +import java.nio.charset.StandardCharsets; + +/** + * @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 byte[] sendCmd(String astCmd) { + 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, StandardCharsets.UTF_8)); + ByteArrayOutputStream swapStream = new ByteArrayOutputStream(); + byte[] buff = new byte[100]; + + int rc = 0; + while ((rc = is.read(buff, 0, 100)) > 0) { + swapStream.write(buff, 0, rc); + } + byte[] in2b = swapStream.toByteArray(); + + //4.关闭资源 + swapStream.close(); + is.close(); + pw.close(); + os.close(); + //log.debug(ackResult); + log.debug("接收服务器的信息:"+HexConvert.BinaryToHexString(in2b)); + //return HexConvert.BinaryToHexString(in2b); + return in2b; + } 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()); + } + } +} diff --git a/src/main/java/com/telpo/dipperposition/config/AsyncExecutorConfig.java b/src/main/java/com/telpo/dipperposition/config/AsyncExecutorConfig.java new file mode 100644 index 0000000..32fe03f --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/config/AsyncExecutorConfig.java @@ -0,0 +1,71 @@ +package com.telpo.dipperposition.config; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.AsyncConfigurer; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * @program: DataPushServer + * @description: + * @author: linwl + * @create: 2020-07-11 09:17 + */ +@Getter +@Setter +@Configuration +@Slf4j +public class AsyncExecutorConfig implements AsyncConfigurer { + + @Value(value = "${async.pool.corePoolSize:4}") + private int corePoolSize; + + @Value(value = "${async.pool.maxPoolSize:8}") + private int maxPoolSize; + + @Value(value = "${async.pool.queueCapacity:5000}") + private int queueCapacity; + + @Bean(name = "asyncServiceExecutor") + public Executor asyncServiceExecutor() { + log.info("start asyncServiceExecutor"); + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + // 配置核心线程数 + executor.setCorePoolSize(corePoolSize); + // 配置最大线程数 + executor.setMaxPoolSize(maxPoolSize); + // 配置队列大小 + executor.setQueueCapacity(queueCapacity); + // 配置线程池中的线程的名称前缀 + String threadNamePrefix = "async-pool-"; + executor.setThreadNamePrefix(threadNamePrefix); + + // 设置拒绝策略:当pool已经达到max size的时候,如何处理新任务 + // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行 + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + // 执行初始化 + executor.initialize(); + return executor; + } + + /** + * 异步任务中异常处理 + * + * @return + */ + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return (arg0, arg1, arg2) -> { + log.error("==========================" + arg0.getMessage() + "=======================", arg0); + log.error("com.telpo.auth.exception method:" + arg1.getName()); + }; + } +} diff --git a/src/main/java/com/telpo/dipperposition/config/NettyServerConfig.java b/src/main/java/com/telpo/dipperposition/config/NettyServerConfig.java new file mode 100644 index 0000000..4e5a66d --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/config/NettyServerConfig.java @@ -0,0 +1,31 @@ +package com.telpo.dipperposition.config; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +/** + * @program: NettyServerConfig + * @description: jwt设置 + * @author: linwl + * @create: 2020-06-18 17:45 + */ +@Getter +@Setter +@Configuration +public class NettyServerConfig { + + @Value(value = "${position-server.serverAddr}") + private String serverAddr; + + @Value(value = "${position-server.timeAsycPort:9011}") + private String timeAsycServerPort; + + @Value(value = "${position-server.posAsycPort:9013}") + private String posAsycServerPort; + + @Value(value = "${position-server.starsAsycPort:9012}") + private String starsAsycServerPort; + +} diff --git a/src/main/java/com/telpo/dipperposition/config/OkHttpConfig.java b/src/main/java/com/telpo/dipperposition/config/OkHttpConfig.java new file mode 100644 index 0000000..185ced1 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/config/OkHttpConfig.java @@ -0,0 +1,103 @@ +package com.telpo.dipperposition.config; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import okhttp3.ConnectionPool; +import okhttp3.OkHttpClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.concurrent.TimeUnit; + +/** + * @program: DataPushServer + * @description: http设置 + * @author: linwl + * @create: 2020-07-17 15:29 + */ +@Getter +@Setter +@Configuration +@Slf4j +public class OkHttpConfig { + + @Value(value = "${OkHttp-config.pool.max-conn}") + private Integer maxConn; + + @Value(value = "${OkHttp-config.pool.keep-alive}") + private Integer keepAlive; + + @Value(value = "${OkHttp-config.read-timeout}") + private long readTimeout; + + @Value(value = "${OkHttp-config.conn-timeout}") + private long connTimeout; + + @Value(value = "${OkHttp-config.write-timeout}") + private long writeTimeout; + + @Bean + public X509TrustManager x509TrustManager() { + return new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) + throws CertificateException {} + + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) + throws CertificateException {} + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + }; + } + + @Bean + public SSLSocketFactory sslSocketFactory() { + try { + // 信任任何链接 + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, new TrustManager[] {x509TrustManager()}, new SecureRandom()); + return sslContext.getSocketFactory(); + } catch (NoSuchAlgorithmException | KeyManagementException e) { + log.error("okhttp3 send https error:", e); + } + return null; + } + + /** + * Create a new connection pool with tuning parameters appropriate for a single-user application. + * The tuning parameters in this pool are subject to change in future OkHttp releases. Currently + */ + @Bean + public ConnectionPool pool() { + return new ConnectionPool(maxConn, keepAlive, TimeUnit.MINUTES); + } + + @Bean + public OkHttpClient okHttpClient() { + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + builder + .connectTimeout(connTimeout, TimeUnit.SECONDS) + .readTimeout(readTimeout, TimeUnit.SECONDS) + .writeTimeout(writeTimeout, TimeUnit.SECONDS) + .connectionPool(pool()) // 连接池 + .retryOnConnectionFailure(true) + .hostnameVerifier((s, sslSession) -> true) + .sslSocketFactory(sslSocketFactory(), x509TrustManager()); + return builder.build(); + } +} diff --git a/src/main/java/com/telpo/dipperposition/config/PositionConfig.java b/src/main/java/com/telpo/dipperposition/config/PositionConfig.java new file mode 100644 index 0000000..cc1e5b5 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/config/PositionConfig.java @@ -0,0 +1,26 @@ +package com.telpo.dipperposition.config; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +/** + * @program: PositionConfig + * @description: jwt设置 + * @author: linwl + * @create: 2020-06-18 17:45 + */ +@Getter +@Setter +@Configuration +public class PositionConfig { + + @Value(value = "${pos.ipPositionRequestPath}") + private String ipPositionRequestPath; + @Value(value = "${pos.ipPositionRequestKey}") + private String ipPositionRequestKey; + @Value(value = "${pos.centerProvince}") + private String centerProvince; + +} diff --git a/src/main/java/com/telpo/dipperposition/config/SchedulingExecutorConfig.java b/src/main/java/com/telpo/dipperposition/config/SchedulingExecutorConfig.java new file mode 100644 index 0000000..46dac6b --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/config/SchedulingExecutorConfig.java @@ -0,0 +1,53 @@ +package com.telpo.dipperposition.config; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.SchedulingConfigurer; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.scheduling.config.ScheduledTaskRegistrar; + +/** + * @program: DataPushServer + * @description: 定时任务线程配置 + * @author: linwl + * @create: 2020-07-24 10:53 + */ +@Getter +@Setter +@Configuration +public class SchedulingExecutorConfig implements SchedulingConfigurer { + + @Value(value = "${scheduler.pool.size}") + private int pollSize; + + @Value(value = "${scheduler.pool.await-seconds}") + private int awaitSeconds; + + @Value(value = "${pos.astServer}") + private String astServer; + @Value(value = "${pos.astPosAstPort}") + private int posAstPort; + @Value(value = "${pos.astEphAstHexPort}") + private int astEphAstHexPort; + @Value(value = "${pos.astTimeout}") + private int astTimeout; + + @Override + public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { + ThreadPoolTaskScheduler taskScheduler = taskScheduler(); + taskRegistrar.setTaskScheduler(taskScheduler); + } + + @Bean(destroyMethod = "shutdown", name = "taskScheduler") + public ThreadPoolTaskScheduler taskScheduler() { + ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); + scheduler.setPoolSize(pollSize); + scheduler.setThreadNamePrefix("task-"); + scheduler.setAwaitTerminationSeconds(awaitSeconds); + scheduler.setWaitForTasksToCompleteOnShutdown(true); + return scheduler; + } +} diff --git a/src/main/java/com/telpo/dipperposition/entity/mongo/IpProvinceEntity.java b/src/main/java/com/telpo/dipperposition/entity/mongo/IpProvinceEntity.java new file mode 100644 index 0000000..0bc7e99 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/entity/mongo/IpProvinceEntity.java @@ -0,0 +1,24 @@ +package com.telpo.dipperposition.entity.mongo; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.springframework.data.mongodb.core.mapping.Document; + +/** + * @program: IpProvinceEntity + * @description: 位置实体类 + * @author: linwl + * @create: 2020-07-11 15:33 + */ +@ToString +@Getter +@Setter +@Document +public class IpProvinceEntity { + + /** Ip */ + private String ip; + /** Ip所在省份 */ + private String province; +} diff --git a/src/main/java/com/telpo/dipperposition/entity/mongo/ProvinceInfoEntity.java b/src/main/java/com/telpo/dipperposition/entity/mongo/ProvinceInfoEntity.java new file mode 100644 index 0000000..38ad6d2 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/entity/mongo/ProvinceInfoEntity.java @@ -0,0 +1,28 @@ +package com.telpo.dipperposition.entity.mongo; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.springframework.data.mongodb.core.mapping.Document; + +/** + * @program: IpProvinceEntity + * @description: 省份位置实体类 + * @author: linwl + * @create: 2020-07-11 15:33 + */ +@ToString +@Getter +@Setter +@Document +public class ProvinceInfoEntity { + + /** 所在省份 */ + private String province; + /** lon */ + private String lon; + /** alt */ + private String alt; + /** centerAddress */ + private String centerAddress; +} diff --git a/src/main/java/com/telpo/dipperposition/enums/DipperReturnValue.java b/src/main/java/com/telpo/dipperposition/enums/DipperReturnValue.java new file mode 100644 index 0000000..68fa68f --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/enums/DipperReturnValue.java @@ -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; + } +} diff --git a/src/main/java/com/telpo/dipperposition/handler/NettyServerHandler.java b/src/main/java/com/telpo/dipperposition/handler/NettyServerHandler.java new file mode 100644 index 0000000..b275124 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/handler/NettyServerHandler.java @@ -0,0 +1,269 @@ +package com.telpo.dipperposition.handler; + +import com.telpo.dipperposition.common.HexConvert; +import com.telpo.dipperposition.config.PositionConfig; +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.ByteBufAllocator; +import io.netty.buffer.CompositeByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.util.CharsetUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +/** + * @program: dipperposition + * @description: Netty服务器处理句柄 + * @author: linwl + * @create: 2021-01-13 13:56 + **/ +@Slf4j +@Component +public class NettyServerHandler extends ChannelInboundHandlerAdapter { + + private static String AST_TIME_CMD = "TIME"; + private static String AST_POS_CMD = "POS"; + private static String AST_EPH_CMD = "EPH"; + private static String AST_ALL_CMD = "ALL"; + private static String AST_TIME_CMD_BYTE = "54494d45"; + private static String AST_POS_CMD_BYTE = "504f53"; + private static String AST_EPH_CMD_BYTE = "455048"; + private static String AST_ALL_CMD_BYTE = "616C6C"; + + @Autowired + private PositionConfig positionConfig; + @Autowired + private IDipperAstTimeAsyncTaskService dipperTimeAsyncTaskService; + @Autowired + private IDipperAstPosAsyncTaskService dipperAstPosAsyncTaskService; + @Autowired + private IDipperDataAsyncTaskService dipperDataAsyncTaskService; + + private static NettyServerHandler nettyServerHandler; + public NettyServerHandler() {} + @PostConstruct + public void init() { + nettyServerHandler = this; + nettyServerHandler.positionConfig = this.positionConfig; + nettyServerHandler.dipperTimeAsyncTaskService = this.dipperTimeAsyncTaskService; + nettyServerHandler.dipperAstPosAsyncTaskService = this.dipperAstPosAsyncTaskService; + nettyServerHandler.dipperDataAsyncTaskService = this.dipperDataAsyncTaskService; + } + + /** + * 客户端连接会触发 + */ + @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"; + //String ackAckCheckRef = "23 3E 01 01 02 00 04 21 29 3C"; + //ByteBuf buf = Unpooled.buffer(ackAckCheckRef.getBytes().length); + //buf.writeBytes(ackAckCheckRef.getBytes(CharsetUtil.UTF_8)); + //ctx.writeAndFlush(buf); + } + + + /** + * 当客户端主动断开服务端的链接后,这个通道就是不活跃的。 + * 也就是说客户端与服务端的关闭了通信通道并且不可以传输数据 + */ + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + log.info("客户端断开链接,IP:{}", ctx.channel().localAddress().toString()); + ctx.channel().close(); + } + + /** + * 客户端发消息会触发 + */ + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + //接收msg消息与上一章节相比,此处已经不需要自己进行解码} + SocketChannel channel = (SocketChannel) ctx.channel(); + ByteBufAllocator bba = channel.config().getAllocator(); + String ipAddress = channel.remoteAddress().getHostString(); + log.info("接收到消息:" + msg + ",客户端IP:" + ipAddress); + if(ipAddress.contains(":")) { + String[] ipAddressArr = ipAddress.split(":"); + ipAddress = ipAddressArr[0].replace("/",""); + } + log.info("新客户端IP:" + ipAddress); + + String channelAns = ""; + // 返回时间指令 + ByteBuf buf = null; + if (AST_TIME_CMD.equals(msg)) { + // 初始时间辅助输入; + channelAns = nettyServerHandler.dipperTimeAsyncTaskService.pushAstTime(); + //log.debug(channelAns); + if (channelAns != null) { +// buf = bba.buffer(channelAns.getBytes().length); + byte[] returnBytes = getReturnBytes(channelAns); + buf = bba.buffer(returnBytes.length + 4); + //Unpooled.buffer(channelAns.getBytes().length); +// buf.writeBytes(channelAns.getBytes(CharsetUtil.UTF_8)); + buf.writeBytes(returnBytes); + buf.writeBytes(getCheckSumBytes(channelAns)); + buf.writeBytes(getReturnBytes()); + // 确保通道处于活跃状态 + // 不活跃状态继续写会产生CLOSE_WAIT现象 + if(ctx.channel().isActive()) { + ctx.write(buf); + ctx.flush(); + } + } + } + // 发送SDBP-AST-POS获取辅助位置信息 + if (AST_POS_CMD.equals(msg)) { + channelAns = nettyServerHandler.dipperAstPosAsyncTaskService.pushAstPos(ipAddress); + //log.debug(channelAns); + if (channelAns != null) { +// buf = bba.buffer(channelAns.getBytes().length); + byte[] returnBytes = getReturnBytes(channelAns); + buf = bba.buffer(returnBytes.length + 4); + //Unpooled.buffer(channelAns.getBytes().length); +// buf.writeBytes(channelAns.getBytes(CharsetUtil.UTF_8)); + buf.writeBytes(returnBytes); + buf.writeBytes(getCheckSumBytes(channelAns)); + buf.writeBytes(getReturnBytes()); + // 确保通道处于活跃状态 + // 不活跃状态继续写会产生CLOSE_WAIT现象 + if(ctx.channel().isActive()) { + ctx.write(buf); + ctx.flush(); + } + } + } + + // 从缓存获取SDBP-AST-EPH星历数 + if (AST_EPH_CMD.equals(msg)) { + //channelAns = nettyServerHandler.dipperDataAsyncTaskService.getAstEPH(); + byte[] returnBytes = nettyServerHandler.dipperDataAsyncTaskService.getAstEPH(); + //log.debug(channelAns); + //if (channelAns != null) { + // buf = bba.buffer(channelAns.getBytes().length); + buf = bba.buffer(returnBytes.length); + //Unpooled.buffer(channelAns.getBytes().length); + buf.writeBytes(returnBytes); + // 确保通道处于活跃状态 + // 不活跃状态继续写会产生CLOSE_WAIT现象 + if(ctx.channel().isActive()) { + ctx.write(buf); + ctx.flush(); + } + //} + } + + // 最后把SDBP-AST-TIME、SDBP-AST-POS、SDBP-AST-EPH并包一起发给设备。 + // 设备采用16进制获取数据,则代理服务器也是采用16进制返回数据。 + // 通知客户端链消息发送成功 + if (AST_ALL_CMD.equals(msg.toString().toUpperCase())) { + channelAns = nettyServerHandler.dipperTimeAsyncTaskService.pushAstTime(); + + if (channelAns != null) { + byte[] returnBytes = getReturnBytes(channelAns); + buf = bba.buffer(returnBytes.length + 4); + buf.writeBytes(returnBytes); + buf.writeBytes(getCheckSumBytes(channelAns)); + buf.writeBytes(getReturnBytes()); + + // 确保通道处于活跃状态 + // 不活跃状态继续写会产生CLOSE_WAIT现象 + if(ctx.channel().isActive()) { + ctx.write(buf); + ctx.flush(); + } + } + channelAns = nettyServerHandler.dipperAstPosAsyncTaskService.pushAstPos(ipAddress); + + if (channelAns != null) { + byte[] returnBytes = getReturnBytes(channelAns); + buf = bba.buffer(returnBytes.length + 4); + buf.writeBytes(returnBytes); + buf.writeBytes(getCheckSumBytes(channelAns)); + buf.writeBytes(getReturnBytes()); + // 确保通道处于活跃状态 + // 不活跃状态继续写会产生CLOSE_WAIT现象 + if(ctx.channel().isActive()) { + ctx.write(buf); + } + } + + byte[] returnBytes = nettyServerHandler.dipperDataAsyncTaskService.getAstEPH(); + //if (channelAns != null) { + log.debug("PEH Buffer Length is:" + returnBytes.length); + // 使用池化的堆内存,以减少内存碎片 + //ByteBuf channelPehAnsBuf = Unpooled.buffer(channelAns.getBytes().length); + //ByteBuf channelPehAnsBuf = bba.buffer(channelAns.getBytes().length); + ByteBuf channelPehAnsBuf = bba.buffer(returnBytes.length); + //channelPehAnsBuf.writeBytes(channelAns.getBytes(CharsetUtil.UTF_8)); + channelPehAnsBuf.writeBytes(returnBytes); + // compositeByteBuf.addComponent(channelPehAnsBuf); + // log.info("CompositeByteBuf Length is:" + compositeByteBuf.capacity()); + // 确保通道处于活跃状态 + // 不活跃状态继续写会产生CLOSE_WAIT现象 + if(ctx.channel().isActive()) { + ctx.write(channelPehAnsBuf); + ctx.flush(); + } + //} + + // 写给下一个Handler,最后一个Handler将内容移出pipeline + // ctx.writeAndFlush(compositeByteBuf); + } + + } + + /** + * 发生异常触发 + */ + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + ctx.close(); + } + + /* + * 取得byte数组 + */ + private byte[] getReturnBytes(String astCmdBuf) { + return HexConvert.hexStringToBytes(astCmdBuf); + } + + private byte[] getCheckSumBytes(String astCmdBuf) { + String checkSum = HexConvert.makeChecksum(astCmdBuf).toUpperCase(); + StringBuffer astCheckSumBuf = new StringBuffer(); + astCheckSumBuf.append(checkSum); + while (astCheckSumBuf.length()<4) { + astCheckSumBuf.insert(0,"0"); + } + return getReturnBytes(astCheckSumBuf.toString()); + //log.info(checkSum); + } + + + private byte[] getReturnBytes() { + String returnStr = "0D0A"; + return getReturnBytes(returnStr); + } + + +} diff --git a/src/main/java/com/telpo/dipperposition/handler/ServerChannelInitializer.java b/src/main/java/com/telpo/dipperposition/handler/ServerChannelInitializer.java new file mode 100644 index 0000000..a6fb9de --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/handler/ServerChannelInitializer.java @@ -0,0 +1,26 @@ +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 { + @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)); + // pipeline的第一个ChannelHandler:ChannelInboundHandlerAdapter + socketChannel.pipeline().addLast(new NettyServerHandler()); + // addLast后会自动创建ChannelHandlerContext + } + +} diff --git a/src/main/java/com/telpo/dipperposition/mapper/IpProvinceMapper.java b/src/main/java/com/telpo/dipperposition/mapper/IpProvinceMapper.java new file mode 100644 index 0000000..8d176ce --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/mapper/IpProvinceMapper.java @@ -0,0 +1,15 @@ +package com.telpo.dipperposition.mapper; + +import com.telpo.dipperposition.entity.mongo.IpProvinceEntity; +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.stereotype.Repository; + + +/** + * @program: DataPushServer + * @description: 推送记录mapper + * @author: linwl + * @create: 2020-07-20 11:12 + */ +@Repository +public interface IpProvinceMapper extends MongoRepository {} diff --git a/src/main/java/com/telpo/dipperposition/mapper/ProvinceInfoMapper.java b/src/main/java/com/telpo/dipperposition/mapper/ProvinceInfoMapper.java new file mode 100644 index 0000000..2033a8e --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/mapper/ProvinceInfoMapper.java @@ -0,0 +1,15 @@ +package com.telpo.dipperposition.mapper; + +import com.telpo.dipperposition.entity.mongo.ProvinceInfoEntity; +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.stereotype.Repository; + +/** + * @program: ProvinceInfoMapper + * @description: 省份位置记录mapper + * @author: linwl + * @create: 2020-07-20 11:12 + */ +@Repository +public interface ProvinceInfoMapper + extends MongoRepository {} diff --git a/src/main/java/com/telpo/dipperposition/server/DipperPositionServer.java b/src/main/java/com/telpo/dipperposition/server/DipperPositionServer.java new file mode 100644 index 0000000..c8e0f44 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/server/DipperPositionServer.java @@ -0,0 +1,83 @@ +package com.telpo.dipperposition.server; + +import com.telpo.dipperposition.handler.ServerChannelInitializer; +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.core.env.ConfigurableEnvironment; +import org.springframework.stereotype.Component; + +import java.net.InetSocketAddress; + +/** + * @program: DipperPositionServer + * @description: 北斗定位 + * @author: king + * @create: 2021-01-13 14:01 + */ +@Slf4j +@Component +public class DipperPositionServer { + + private String serverAddr; + private Integer starsAsycPort; + + public DipperPositionServer(ConfigurableEnvironment environment) { + + this.serverAddr = environment.getProperty("position-server.serverAddr"); + + this.starsAsycPort = Integer.parseInt(environment.getProperty("position-server.starsAsycPort")); + } + + /* + * 星历同步进程线程 + */ + public void start() { + + //new 一个主线程组 + EventLoopGroup mainThreadGroup = new NioEventLoopGroup(1); + //new 一个工作线程组 + EventLoopGroup workThreadGroup = new NioEventLoopGroup(200); + InetSocketAddress socketAddress = new InetSocketAddress(serverAddr,starsAsycPort); + ServerBootstrap bootstrap = new ServerBootstrap() + .group(mainThreadGroup, workThreadGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ServerChannelInitializer()) + .localAddress(socketAddress) + //设置队列大小, 多少合适???? + .option(ChannelOption.SO_BACKLOG, 1024) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000) + // 两小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文 + .childOption(ChannelOption.SO_LINGER, 1000); + //.childOption(ChannelOption.SO_KEEPALIVE, true); + + + //绑定端口,开始接收进来的连接 + try { + + ChannelFuture channelFuture = bootstrap.bind(socketAddress).sync(); + log.info("星历服务器启动开始监听端口: {}", starsAsycPort); + //log.info("服务器: {}", myServerAddr); + channelFuture.addListener(future -> { + if (future.isSuccess()){ + log.info("start success"); + }else{ + log.info("start failed"); + } + }); + channelFuture.channel().closeFuture().sync(); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + //关闭主线程组 + mainThreadGroup.shutdownGracefully(); + //关闭工作线程组 + workThreadGroup.shutdownGracefully(); + } + } + +} diff --git a/src/main/java/com/telpo/dipperposition/service/IDipperAstPosAsyncTaskService.java b/src/main/java/com/telpo/dipperposition/service/IDipperAstPosAsyncTaskService.java new file mode 100644 index 0000000..5c85f4b --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/service/IDipperAstPosAsyncTaskService.java @@ -0,0 +1,31 @@ +package com.telpo.dipperposition.service; + +import org.springframework.beans.factory.annotation.Autowired; + +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); + +// String pushAstPos(String ipAddress, +// String centerProvinceFilePath, +// String centerProvince, +// String ipPositionRequestPath, +// String ipPositionRequestKey) throws UnsupportedEncodingException; + +} diff --git a/src/main/java/com/telpo/dipperposition/service/IDipperAstTimeAsyncTaskService.java b/src/main/java/com/telpo/dipperposition/service/IDipperAstTimeAsyncTaskService.java new file mode 100644 index 0000000..7703a56 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/service/IDipperAstTimeAsyncTaskService.java @@ -0,0 +1,22 @@ +package com.telpo.dipperposition.service; + +import com.telpo.dipperposition.service.impl.DipperDataAsyncTaskServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @program: IDipperDataAsyncTaskService + * @description: 发送SDBP-AST-TIME获取时间信息 + * @author: king + * @create: 2021-01-17 16:24 + */ +public interface IDipperAstTimeAsyncTaskService { + +// @Autowired +// void setDipperAstTimeAsyncTaskService(IDipperAstTimeAsyncTaskService dipperAstTimeAsyncTaskService); + /** + * 同步任务 + * + */ + String pushAstTime(); + +} diff --git a/src/main/java/com/telpo/dipperposition/service/IDipperDataAsyncTaskService.java b/src/main/java/com/telpo/dipperposition/service/IDipperDataAsyncTaskService.java new file mode 100644 index 0000000..5af5cb2 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/service/IDipperDataAsyncTaskService.java @@ -0,0 +1,31 @@ +package com.telpo.dipperposition.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +/** + * @program: IDipperDataAsyncTaskService + * @description: 发送bds获取星历数据。 + * * 每30分钟获取1次,30秒超时, + * * 如果失败,则可以等待10秒再获取1次 + * @author: king + * @create: 2021-01-17 16:24 + */ +public interface IDipperDataAsyncTaskService { + +// @Autowired +// void setDipperDataAsyncTaskService(IDipperDataAsyncTaskService IDipperDataAsyncTaskService); + /** + * 同步任务 + * + */ + void pullAstEPH(int tryTimes) throws InterruptedException; + + + /** + * 根据IP获取EPH + * + */ + byte[] getAstEPH(); + +} diff --git a/src/main/java/com/telpo/dipperposition/service/IProvinceInfoService.java b/src/main/java/com/telpo/dipperposition/service/IProvinceInfoService.java new file mode 100644 index 0000000..a924d91 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/service/IProvinceInfoService.java @@ -0,0 +1,54 @@ +package com.telpo.dipperposition.service; + +import com.telpo.dipperposition.entity.mongo.IpProvinceEntity; +import com.telpo.dipperposition.entity.mongo.ProvinceInfoEntity; + +import java.util.List; + +/** + * @program: IProvinceInfoService + * @description: 省份经纬度信息 + * @author: king + * @create: 2020-07-20 11:09 + */ +public interface IProvinceInfoService { + +// @Autowired +// void setIPProvinceService(IpProvinceService ipProvinceService); + /** + * 保存省份经纬度信息 + * + * @param entity + * @return + */ + boolean saveProvinceInfo(ProvinceInfoEntity entity); + + /** + * 更新省份经纬度信息 + * + * @param query + * @return + */ + boolean updateProvinceInfoEntity(ProvinceInfoEntity query); + + /** + * 根据ID移除IP省份记录 + * + * @param id + * @return + */ + boolean romveById(String id); + + /* + * @param ipAddress + * 获取省份经纬度信息 + */ + ProvinceInfoEntity getProvinceInfo(String provicne); + + /** + * 获取省份经纬度信息 + * + * @return + */ + List getProvinceInfoEntitys(); +} diff --git a/src/main/java/com/telpo/dipperposition/service/IpProvinceService.java b/src/main/java/com/telpo/dipperposition/service/IpProvinceService.java new file mode 100644 index 0000000..a216dac --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/service/IpProvinceService.java @@ -0,0 +1,37 @@ +package com.telpo.dipperposition.service; + +import com.telpo.dipperposition.entity.mongo.IpProvinceEntity; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @program: IPProvinceService + * @description: IP省份服务接口 + * @author: king + * @create: 2020-07-20 11:09 + */ +public interface IpProvinceService { + +// @Autowired +// void setIPProvinceService(IpProvinceService ipProvinceService); + /** + * 保存IP省份 + * + * @param entity + * @return + */ + boolean saveIpProvince(IpProvinceEntity entity); + + /** + * 根据ID移除IP省份记录 + * + * @param id + * @return + */ + boolean romveById(String id); + + /* + * @param ipAddress + * 获取IP省份 + */ + IpProvinceEntity getIpProvince(String ipAddress); +} diff --git a/src/main/java/com/telpo/dipperposition/service/impl/DipperAstPosAsyncTaskServiceImpl.java b/src/main/java/com/telpo/dipperposition/service/impl/DipperAstPosAsyncTaskServiceImpl.java new file mode 100644 index 0000000..ef21201 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/service/impl/DipperAstPosAsyncTaskServiceImpl.java @@ -0,0 +1,261 @@ +package com.telpo.dipperposition.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.telpo.dipperposition.common.*; +import com.telpo.dipperposition.config.PositionConfig; +import com.telpo.dipperposition.entity.mongo.IpProvinceEntity; +import com.telpo.dipperposition.entity.mongo.ProvinceInfoEntity; +import com.telpo.dipperposition.service.IDipperAstPosAsyncTaskService; +import com.telpo.dipperposition.service.IProvinceInfoService; +import com.telpo.dipperposition.service.IpProvinceService; +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.HashMap; +import java.util.Map; + +/** + * @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 OkHttpUtil okHttpUtil; + @Autowired + private PositionConfig positionConfig; + @Autowired + private IpProvinceService ipProvinceService; + @Autowired + private IProvinceInfoService provinceInfoService; + + private String centerProvince; + private String ipPositionRequestPath; + private String ipPositionRequestKey; + + // 根据IP获取省会信息 + private String getIpPositionProvince(String ipAddress) { + + // 关于IP与省份的关系保存到缓存中 + // 使用时,先在缓存中获取匹配信息 + // 用mongodb实现 + IpProvinceEntity ipProvinceEntity = ipProvinceService.getIpProvince(ipAddress); + if (ipProvinceEntity == null) { + // 匹配不到,再请求高德IP定位服务。 + //JSONObject userObj = new JSONObject(); + Map dataMap = new HashMap(); + dataMap.put("ip", ipAddress); + dataMap.put("key", ipPositionRequestKey); + StringBuffer buffer = okHttpUtil.getQueryString(ipPositionRequestPath, dataMap); + JSONObject paramObject = new JSONObject(); + String result = okHttpUtil.getJsonParams(buffer.toString(), paramObject.toJSONString()); + if (ObjectUtils.isNotEmpty(result)) { + if (ObjectUtils.isEmpty(result)) { + log.debug("IP省份获取错误,结果为空"); + return null; + } else { + if (result.equals("FAIL")) { + log.debug("IP省份获取错误,结果为FAIL"); + return null; + } + //log.debug("IP省份获取错误,结果为:" + result); + JSONObject provinceJson = JSONObject.parseObject(result); + String province = null; + try { + province = (String)provinceJson.get("province"); + if (ObjectUtils.isEmpty(province)) { + log.debug("json is :" + buffer.toString()); + return null; + } + } catch (Exception e) { + log.error("JSONObject分析出错,provinceJson:" + provinceJson); + } + + return province; + } + } else { + // 意外错误 + log.debug("ip address is null"); + return null; + } + } else { + return ipProvinceEntity.getProvince(); + } + } + + // 将IP对应的省会保存到mongoDB + public void createIPProvince(String ipAddress, String province) { + log.debug("创建IP省份记录!"); + try { + IpProvinceEntity ipProvinceEntity = ipProvinceService.getIpProvince(ipAddress); + if (ipProvinceEntity == null) { + ipProvinceEntity = new IpProvinceEntity(); + ipProvinceEntity.setIp(ipAddress); + ipProvinceEntity.setProvince(province); + ipProvinceService.saveIpProvince(ipProvinceEntity); + } + } catch (Exception e) { + log.error("创建IP省份记录异常:", e); + } + } + + /* + * 获取定位辅助信息 + * @param ipAddress + */ + @Override + //@Async("asyncServiceExecutor") + public String pushAstPos(String ipAddress) { + this.ipPositionRequestKey = positionConfig.getIpPositionRequestKey(); + this.ipPositionRequestPath = positionConfig.getIpPositionRequestPath(); + this.centerProvince = positionConfig.getCenterProvince(); + //this.centerProvinceFilePath = positionConfig.getCenterProvinceFilePath(); + // (1) 获取省会城市信息 + String centerAddress = getIpPositionProvince(ipAddress); + if (centerAddress == null || ObjectUtils.isEmpty(centerAddress) || centerAddress.equals("0")) { + log.warn("IP地址非法,无法获取辅助位置信息!"); + // 返回武汉的定位数据 + centerAddress = this.centerProvince; + } else { + // 保存到mongoDB + createIPProvince(ipAddress, centerAddress); + } + + String lonValue = null; + String altValue = null; + try { + byte[] utf8 = centerAddress.getBytes("UTF-8"); + String utf8CenterAddress = new String(utf8, "UTF-8"); + log.debug("centerAddress is " + utf8CenterAddress); + + if (utf8CenterAddress.endsWith("省") || utf8CenterAddress.endsWith("区") || utf8CenterAddress.endsWith("市")) { + + ProvinceInfoEntity entity = provinceInfoService.getProvinceInfo(utf8CenterAddress); + if (entity != null) { + lonValue = entity.getLon(); + altValue = entity.getAlt(); + } + } else { + log.error("非法省份:" + utf8CenterAddress); + return null; + } + } catch (Exception e) { + log.error(e.getMessage()); + } + + + // (2) 处理返回结果 + if (lonValue == null) { + // null处理 + log.error("系统错误,请联系系统管理员。"); + return null; + } + + // push to GNNS Server + return getCmdOfPos(lonValue, altValue); + } + + // 组装命令发送给设备 + private String getCmdOfPos(String lonStr, String altStr) { + + // 时间和位置不是从服务器获取,而是本地生成 +// String[] astPosArray = astPos.split(","); +// String lan = astPosArray[0].trim(); +// String alt = astPosArray[1].trim(); + double lanValue = Double.parseDouble(lonStr) * 10000000; + long lanLongValue = Double.doubleToLongBits(lanValue); + if (lanLongValue < 0) { + // FFFFFFFF - 439C3270 + 1= BC63CD90(补码) + lanLongValue = lanLongValue + 4294967295L + 1; + } + double altValue = Double.parseDouble(altStr) * 10000000; + long altLongValue = Double.doubleToLongBits(altValue); + if (altLongValue < 0) { + // FFFFFFFF - 439C3270 + 1= BC63CD90(补码) + 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 度 + // 70 17 00 00 表示注入的辅助高度为 60 米 + // 40 0D 03 00 表示注入的位置精度为 2000 米 030d40 + // A0 86 01 00 表示注入的位置精度为 1000 米 0186a0 + // 00 2F 为校验和 + + // astPosCmd 组装 + StringBuilder astPosCmdBuf = new StringBuilder(); + astPosCmdBuf.append("233E0401"); + astPosCmdBuf.append("1000"); + + + // 小端模式 + String lanString = HexConvert.encodeHEX(lanLongValue).toUpperCase(); + String altSting = HexConvert.encodeHEX(altLongValue).toUpperCase(); + //astPosCmdBuf.append(HexConvert.encodeHEX(lanLongValue).toUpperCase()); + astPosCmdBuf.append(lanString.substring(6,8)); + astPosCmdBuf.append(lanString.substring(4,6)); + astPosCmdBuf.append(lanString.substring(2,4)); + astPosCmdBuf.append(lanString.substring(0,2)); + + //astPosCmdBuf.append(HexConvert.encodeHEX(altLongValue).toUpperCase()); + + astPosCmdBuf.append(altSting.substring(6,8)); + astPosCmdBuf.append(altSting.substring(4,6)); + astPosCmdBuf.append(altSting.substring(2,4)); + astPosCmdBuf.append(altSting.substring(0,2)); + astPosCmdBuf.append("70170000"); + astPosCmdBuf.append("A0860100"); + + //log.info(astPosCmd); +// String checkSum = HexConvert.makeChecksum(astPosCmdBuf.toString()).toUpperCase(); +// StringBuffer astCheckSumBuf = new StringBuffer(); +// astCheckSumBuf.append(checkSum); +// while (astCheckSumBuf.length()<4) { +// astCheckSumBuf.insert(0,"0"); +// } +// checkSum = astCheckSumBuf.toString(); +// //log.info(checkSum); +// +// byte[] astPosCmdBytes = HexConvert.hexStringToBytes(astPosCmdBuf.toString()); +// StringBuilder astPosCmdNewBuf = new StringBuilder(); +// for (byte astPosCmdByte : astPosCmdBytes) { +// String s = Integer.toHexString(astPosCmdByte & 0xff); +// if (s.length() < 2) { +// astPosCmdNewBuf.append('0'); +// } +// astPosCmdNewBuf.append(s + " "); +// } +// + return astPosCmdBuf.toString(); + //+ checkSum.substring(0,2) + " " + checkSum.substring(2,4); + + + + } +} diff --git a/src/main/java/com/telpo/dipperposition/service/impl/DipperAstTimeAsyncTaskServiceImpl.java b/src/main/java/com/telpo/dipperposition/service/impl/DipperAstTimeAsyncTaskServiceImpl.java new file mode 100644 index 0000000..f31cf22 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/service/impl/DipperAstTimeAsyncTaskServiceImpl.java @@ -0,0 +1,110 @@ +package com.telpo.dipperposition.service.impl; + +import com.telpo.dipperposition.common.HexConvert; +import com.telpo.dipperposition.service.IDipperAstTimeAsyncTaskService; +import lombok.extern.slf4j.Slf4j; +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() { + + // 创建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 5E D0 B2 表示 3 秒的时间精度(十六进制 B2 D0 5E 00 转为十进制为3000000000,乘以比 例因子 10-9就是 3 秒 小端模式00 5E D0 B2) + // 00 2F 为校验和 + // TODO astTimeCmd 组装 + StringBuilder astTimeCmdBuf = new StringBuilder(); + astTimeCmdBuf.append("233E0402"); + astTimeCmdBuf.append("1000"); + astTimeCmdBuf.append("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; + astTimeCmdBuf.append(hexYearString.substring(2,3).toUpperCase() + hexYearString.substring(0,1).toUpperCase()); + String hexMonthString = Integer.toHexString(month); + hexMonthString = "0" + hexMonthString; + astTimeCmdBuf.append(hexMonthString.toUpperCase()); + + String hexDayString = Integer.toHexString(day); + if (day < 16) { + hexDayString = "0" + hexDayString; + } + astTimeCmdBuf.append(hexDayString.toUpperCase()); + + int hour = now.getHour(); + int minitor = now.getMinute(); + int second = now.getSecond(); + String hexHourString = Integer.toHexString(hour); + if (hour < 16) { + hexHourString = "0" + hexHourString; + } + astTimeCmdBuf.append(hexHourString.toUpperCase()); + String hexMinitorString = Integer.toHexString(minitor); + if (minitor < 16) { + hexMinitorString = "0" + hexMinitorString; + } + astTimeCmdBuf.append(hexMinitorString.toUpperCase()); + String hexSecondString = Integer.toHexString(second); + if (second < 16) { + hexSecondString = "0" + hexSecondString; + } + astTimeCmdBuf.append(hexSecondString.toUpperCase()); + astTimeCmdBuf.append("00000000"); + astTimeCmdBuf.append("005ED0B2"); + + return astTimeCmdBuf.toString(); + +// byte[] astTimeCmdBytes = HexConvert.hexStringToBytes(astTimeCmdBuf.toString()); +// StringBuilder astTimeCmdNewBuf = new StringBuilder(); +// for(int i=0; i0) { + log.info("等待10秒再获取1次。"); + sleep(10000); + pullAstEPH(tryTimes); + } + } else { + // 保存到DB或者缓存 + log.info("保存到DB或者缓存"); + redisUtil.set(DIPPER_DATA_KEY,dipperData); + } + } + + private byte[] pullEPHFromDipper() { + + // 创建Socket客户端实例; + String serverAddr = schedulingExecutorConfig.getAstServer(); + int serverPort = schedulingExecutorConfig.getAstEphAstHexPort(); + SocketClient client = new SocketClient(serverAddr,serverPort,schedulingExecutorConfig.getAstTimeout()); + + // astTimeCmd 组装 + String astTimeCmd = DIPPER_ALL_DATA_REQ; + String checkSum = HexConvert.makeChecksum(astTimeCmd.toString()).toUpperCase(); + StringBuilder astCheckSumBuf = new StringBuilder(); + astCheckSumBuf.append(checkSum); + while (astCheckSumBuf.length()<4) { + astCheckSumBuf.insert(0,"0"); + } + checkSum = astCheckSumBuf.toString(); + + String hexIn = astTimeCmd + checkSum.substring(0,2) + " " + checkSum.substring(2,4); + + byte[] sendResult = null; + //String ackAckCheckRef = "233E010102000421293C"; + sendResult = client.sendCmd(hexIn); + client.closeConnection(); + + return sendResult; + } + + @Override + public byte[] getAstEPH(){ + // String dipperData = pullEPHFromDipper(); + byte[] dipperData; + if (!redisUtil.hasKey(DIPPER_DATA_KEY)) { + try { + this.pullAstEPH(1); + } catch (InterruptedException e) { + log.error("获取星历数据发生异常:", e); + } + } + + dipperData = (byte[])redisUtil.get(DIPPER_DATA_KEY); + return dipperData; + } +} diff --git a/src/main/java/com/telpo/dipperposition/service/impl/IpProvinceServiceImpl.java b/src/main/java/com/telpo/dipperposition/service/impl/IpProvinceServiceImpl.java new file mode 100644 index 0000000..10bc544 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/service/impl/IpProvinceServiceImpl.java @@ -0,0 +1,69 @@ +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 lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Example; +import org.springframework.data.domain.ExampleMatcher; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +/** + * @program: DataPushServer + * @description: 推送记录服务接口实现类 + * @author: linwl + * @create: 2020-07-20 11:09 + */ +@Slf4j +@Service +public class IpProvinceServiceImpl implements IpProvinceService { + + @Autowired + private IpProvinceMapper ipProvinceMapper; + +// private static IpProvinceService ipProvinceService; +// /** +// * spring会自动从ioc容器当中根据IPProvinceService类型找到ipProvinceService,当做参数传进来 +// * +// */ +// @Override +// public void setIPProvinceService(IpProvinceService ipProvinceService) { +// this.ipProvinceService = ipProvinceService; +// } + @Override + public boolean saveIpProvince(IpProvinceEntity entity) { + ipProvinceMapper.save(entity); + 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); + //忽略_class属性,不参与查询 + ExampleMatcher matcher = ExampleMatcher.matching().withIgnorePaths("_class"); + Example example = Example.of(query, matcher); + Optional data = ipProvinceMapper.findOne(example); + if (data.isPresent() == true) { + return data.get(); + } else { + return null; + } + //return data.orElse(null); + } catch (Exception e) { + log.error("获取IP省份异常:", e); + return null; + } + } +} diff --git a/src/main/java/com/telpo/dipperposition/service/impl/ProvinceInfoServiceImpl.java b/src/main/java/com/telpo/dipperposition/service/impl/ProvinceInfoServiceImpl.java new file mode 100644 index 0000000..46ae674 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/service/impl/ProvinceInfoServiceImpl.java @@ -0,0 +1,85 @@ +package com.telpo.dipperposition.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.telpo.dipperposition.entity.mongo.ProvinceInfoEntity; +import com.telpo.dipperposition.mapper.ProvinceInfoMapper; +import com.telpo.dipperposition.service.IProvinceInfoService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Example; +import org.springframework.data.domain.ExampleMatcher; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +/** + * @program: DataPushServer + * @description: 推送记录服务接口实现类 + * @author: linwl + * @create: 2020-07-20 11:09 + */ +@Slf4j +@Service +public class ProvinceInfoServiceImpl implements IProvinceInfoService { + + @Autowired + private ProvinceInfoMapper provinceInfoMapper; + + + @Override + public boolean saveProvinceInfo(ProvinceInfoEntity entity) { + + provinceInfoMapper.save(entity); + return false; + } + + @Override + public boolean updateProvinceInfoEntity(ProvinceInfoEntity entity) { + provinceInfoMapper.save(entity); + return false; + } + + @Override + public boolean romveById(String id) { + + provinceInfoMapper.deleteById(id); + return false; + } + + @Override + public ProvinceInfoEntity getProvinceInfo(String provicne) { + try { + ProvinceInfoEntity query = new ProvinceInfoEntity(); + query.setProvince(provicne); + //忽略_class属性,不参与查询 + ExampleMatcher matcher = ExampleMatcher.matching().withIgnorePaths("_class"); + Example example = Example.of(query, matcher); + Optional data = provinceInfoMapper.findOne(example); + if (ObjectUtil.isNotEmpty(data)) { + return data.get(); + } else { + return null; + } + } catch (Exception e) { + log.error("获取省份异常:", e); + return null; + } + } + + @Override + public List getProvinceInfoEntitys() { + try { + List records = provinceInfoMapper.findAll(); + if (ObjectUtils.isNotEmpty(records)) { + return records; + } else { + return null; + } + } catch (Exception e) { + log.error("获取IP省份异常:", e); + return null; + } + } +} diff --git a/src/main/java/com/telpo/dipperposition/task/ScheduleService.java b/src/main/java/com/telpo/dipperposition/task/ScheduleService.java new file mode 100644 index 0000000..34eaddc --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/task/ScheduleService.java @@ -0,0 +1,43 @@ +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 { + // 如果失败,则可以等待10秒再获取1次。 + int tryTimes = 59; + dipperDataAsyncTaskService.pullAstEPH(tryTimes); + } catch (InterruptedException e) { + log.error("获取星历数据重试睡眠发生异常:", e); + } catch (Exception e) { + log.error("执行定时获取星历数据发生异常:", e); + } + } +} diff --git a/src/main/java/com/telpo/dipperposition/vo/IPProvinceVo.java b/src/main/java/com/telpo/dipperposition/vo/IPProvinceVo.java new file mode 100644 index 0000000..df9abeb --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/vo/IPProvinceVo.java @@ -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; +} diff --git a/src/main/java/com/telpo/dipperposition/vo/ProvinceInfoVo.java b/src/main/java/com/telpo/dipperposition/vo/ProvinceInfoVo.java new file mode 100644 index 0000000..7d5cb00 --- /dev/null +++ b/src/main/java/com/telpo/dipperposition/vo/ProvinceInfoVo.java @@ -0,0 +1,24 @@ +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 ProvinceInfoVo { + + /** Ip所在省份 */ + private String province; + /** lon */ + private String lon; + /** lon */ + private String alt; + /** centerAddress */ + private String centerAddress; +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..f168b0d --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,61 @@ +server.port=8105 +logging.config=classpath:log/logback-spring.xml +logging.level.com.telpo.dipperposition.service.impl=DEBUG +logging.level.com.telpo.dipperposition.service.mapper=DEBUG +spring.application.name=dipperposition-service + +spring.redis.database=1 +spring.redis.host=127.0.0.1 +#8090 +spring.redis.port=6379 +spring.redis.password=telpo#1234 +spring.redis.timeout=3000 +spring.redis.lettuce.pool.max-active=100 +# 连接池最大连接数(使用负值表示没有限制) +spring.redis.lettuce.pool.max-idle=100 +# 连接池中的最大空闲连接 +spring.redis.lettuce.pool.min-idle=50 +# 连接池中的最小空闲连接 +spring.redis.lettuce.pool.max-wait=6000 +# 连接池最大阻塞等待时间(使用负值表示没有限制) +spring.data.mongodb.host=172.19.42.45 +spring.data.mongodb.port=27017 +spring.data.mongodb.database=common +spring.data.mongodb.username=wangjx +spring.data.mongodb.password=wangjx#1234 + +position-server.serverAddr=172.19.42.45 +position-server.timeAsycPort=9011 +position-server.posAsycPort=9013 +position-server.starsAsycPort=9012 + +#等待任务完成退出最大秒数 +scheduler.pool.size=2 +scheduler.pool.await-seconds=600 +scheduler.task.cron=0 */30 * * * * + +pos.ipPositionRequestPath=https://restapi.amap.com/v3/ip +pos.ipPositionRequestKey=46eb0eba39494a6e9a90a0dc9e76639e +pos.centerProvince=湖北省 +# 测试 agnss.techtotop.com +pos.astServer=agnss.techtotop.com +pos.astPosAstPort=8012 +# 占青霞说北斗的是9112端口 +pos.astEphAstHexPort=9112 +pos.astTimeout=30000 + +OkHttp-config.pool.max-conn=200 +OkHttp-config.pool.keep-alive=5 +OkHttp-config.read-timeout=10 +OkHttp-config.conn-timeout=10 +OkHttp-config.write-timeout=10 + +async.pool.corePoolSize=4 +async.pool.maxPoolSize=8 +async.pool.queueCapacity=5000 + +mongo.datasource.dblist.uri=mongodb://wangjx:wangjx#1234@172.19.42.45:27017/common +mongo.datasource.dblist.database=common + + + diff --git a/src/main/resources/bootstrap-dev.yaml b/src/main/resources/bootstrap-dev.yaml new file mode 100644 index 0000000..8f21889 --- /dev/null +++ b/src/main/resources/bootstrap-dev.yaml @@ -0,0 +1,10 @@ +spring: + main: + allow-bean-definition-overriding: true + application: + name: dipperposition-service + cloud: + nacos: + config: + server-addr: 172.16.192.26:8848 + file-extension: yaml \ No newline at end of file diff --git a/src/main/resources/bootstrap-pro.yaml b/src/main/resources/bootstrap-pro.yaml new file mode 100644 index 0000000..1c50d09 --- /dev/null +++ b/src/main/resources/bootstrap-pro.yaml @@ -0,0 +1,79 @@ +server: + port: 8105 + +logging: + config: classpath:log/logback-spring.xml + level: + com: + telpo: + dipperposition: + service: + impl: debug + mapper: debug + org.springframework.data.mongodb.core.MongoTemplate: DEBUG +spring: + application: + name: dipperposition-service + redis: + database: 1 + host: 172.19.42.45 + #8090 + port: 6379 + password: telpo#1234 + timeout: 3000 + lettuce: + pool: + max-active: 100 # 连接池最大连接数(使用负值表示没有限制) + max-idle: 100 # 连接池中的最大空闲连接 + min-idle: 50 # 连接池中的最小空闲连接 + max-wait: 6000 # 连接池最大阻塞等待时间(使用负值表示没有限制) + data: + mongodb: + host: 172.19.42.45 + port: 27017 + database: common + username: wangjx + password: wangjx#1234 + +mongo: + datasource: + dblist: + - uri: mongodb://wangjx:wangjx#1234@172.19.42.45:27015/common + database: common + +scheduler: + pool: + size: 2 + #等待任务完成退出最大秒数 + await-seconds: 600 + task: + cron: "0 */30 * * * *" + +pos: + ipPositionRequestPath: https://restapi.amap.com/v3/ip + ipPositionRequestKey: 46eb0eba39494a6e9a90a0dc9e76639e + centerProvince: 湖北省 + astServer: agnss.techtotop.com + astPosAstPort: 8012 + astEphAstHexPort: 9012 + astTimeout: 30000 + +position-server: + serverAddr: 172.19.42.45 + timeAsycPort: 9011 + posAsycPort: 9013 + starsAsycPort: 9012 + +OkHttp-config: + pool: + max-conn: 200 + keep-alive: 5 + read-timeout: 10 + conn-timeout: 10 + write-timeout: 10 + +async: + pool: + corePoolSize: 4 + maxPoolSize: 8 + queueCapacity: 5000 \ No newline at end of file diff --git a/src/main/resources/bootstrap-test.yaml b/src/main/resources/bootstrap-test.yaml new file mode 100644 index 0000000..22f9b81 --- /dev/null +++ b/src/main/resources/bootstrap-test.yaml @@ -0,0 +1,87 @@ +server: + port: 8105 + +logging: + config: classpath:log/logback-spring.xml + level: + com: + telpo: + dipperposition: + service: + impl: debug + mapper: debug + org.springframework.data.mongodb.core.MongoTemplate: DEBUG +spring: + application: + name: dipperposition-service + cloud: + nacos: + config: + server-addr: 172.19.42.44:8848 + namespace: fee328ef-7348-4984-879a-fd75f9f59cd2 + redis: + database: 1 + host: 172.19.42.44 + #8090 + port: 8090 + password: telpo#1234 + timeout: 3000 + lettuce: + pool: + max-active: 100 # 连接池最大连接数(使用负值表示没有限制) + max-idle: 100 # 连接池中的最大空闲连接 + min-idle: 50 # 连接池中的最小空闲连接 + max-wait: 6000 # 连接池最大阻塞等待时间(使用负值表示没有限制) + data: + mongodb: + host: 172.19.42.40 + port: 27018 + database: common + username: wangjx + password: wangjx#1234 + +mongo: + datasource: + dblist: + - uri: mongodb://wangjx:wangjx#1234@172.19.42.40:27018/common + database: common + - uri: mongodb://wangjx:wangjx#1234@172.19.42.40:27018/basicdata + database: basicdata + +scheduler: + pool: + size: 2 + #等待任务完成退出最大秒数 + await-seconds: 600 + task: + cron: "0 */30 * * * *" + +pos: + centerProvinceFilePath: /csv/provinceLonAlt.csv + ipPositionRequestPath: https://restapi.amap.com/v3/ip + ipPositionRequestKey: 46eb0eba39494a6e9a90a0dc9e76639e + centerProvince: 湖北省 + astServer: agnss.techtotop.com + astPosAstPort: 8012 + astEphAstHexPort: 9112 + astTimeout: 30000 + +position-server: + serverAddr: 172.19.42.44 + timeAsycPort: 9011 + posAsycPort: 9013 + starsAsycPort: 9012 + +OkHttp-config: + pool: + max-conn: 200 + keep-alive: 5 + read-timeout: 10 + conn-timeout: 10 + write-timeout: 10 + +async: + pool: + corePoolSize: 4 + maxPoolSize: 8 + queueCapacity: 5000 \ No newline at end of file diff --git a/src/main/resources/bootstrap.yaml b/src/main/resources/bootstrap.yaml new file mode 100644 index 0000000..c34181b --- /dev/null +++ b/src/main/resources/bootstrap.yaml @@ -0,0 +1,73 @@ +logging: + config: classpath:log/logback-spring.xml + level: + com: + telpo: + dipperposition: debug +spring: + application: + name: dipperposition-service + cloud: + nacos: + config: + server-addr: 172.16.192.26:8848 + file-extension: yaml + redis: + database: 1 + host: 172.16.192.26 + port: 8090 + password: telpo#1234 + timeout: 3000 + lettuce: + pool: + max-active: 100 # 连接池最大连接数(使用负值表示没有限制) + max-idle: 100 # 连接池中的最大空闲连接 + min-idle: 50 # 连接池中的最小空闲连接 + max-wait: 6000 # 连接池最大阻塞等待时间(使用负值表示没有限制) + +scheduler: + pool: + size: 2 + #等待任务完成退出最大秒数 + await-seconds: 600 + task: + cron: "0 0 1 * * ?" + +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: + serverAddr: localhost + timeAsycPort: 9011 + posAsycPort: 9013 + starsAsycPort: 9012 + +mongo: + datasource: + dblist: + - uri: mongodb://wangjx:wangjx#1234@172.16.192.26:27017/basicdata + database: basicdata + - uri: mongodb://wangjx:wangjx#1234@172.16.192.26:27017/common + database: common + +OkHttp-config: + pool: + max-conn: 200 + keep-alive: 5 + read-timeout: 10 + conn-timeout: 10 + write-timeout: 10 + +async: + pool: + corePoolSize: 4 + maxPoolSize: 8 + queueCapacity: 5000 \ No newline at end of file diff --git a/src/main/resources/log/logback-spring.xml b/src/main/resources/log/logback-spring.xml new file mode 100644 index 0000000..4b080ce --- /dev/null +++ b/src/main/resources/log/logback-spring.xml @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + debug + + + ${CONSOLE_LOG_PATTERN} + + UTF-8 + + + + + + + + + + ${log.path}/log_debug.log + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + + + ${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log + + 100MB + + + 15 + + + + debug + ACCEPT + DENY + + + + + + + ${log.path}/log_info.log + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + + + ${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log + + 100MB + + + 15 + + + + info + ACCEPT + DENY + + + + + + + ${log.path}/log_warn.log + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + + ${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log + + 100MB + + + 15 + + + + warn + ACCEPT + DENY + + + + + + + + ${log.path}/log_error.log + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + + ${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log + + 100MB + + + 15 + + + + ERROR + ACCEPT + DENY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file