first commit

This commit is contained in:
LiGang 2023-10-22 19:06:05 +08:00
commit 8ddb6a0af6
329 changed files with 33920 additions and 0 deletions

30
.gitignore vendored Normal file
View File

@ -0,0 +1,30 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
log/
### 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/

31
pom.xml Normal file
View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.imdroid</groupId>
<artifactId>security-monitor</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>sec-common</module>
<module>sec-beidou</module>
<module>sec-beidou-rtcm</module>
<module>sec-api</module>
</modules>
<properties>
<moyu.version>1.0.0</moyu.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>8</java.version>
</properties>
</project>

93
sec-api/pom.xml Normal file
View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.imdroid</groupId>
<artifactId>security-monitor</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>sec-api</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-boot-starter</artifactId>
<version>1.4.3</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.24</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>central</id>
<name>ali-mirror</name>
<url>https://maven.aliyun.com/repository/central</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project>

View File

@ -0,0 +1,37 @@
package com.imdroid.secapi.dto;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.sql.Timestamp;
/**
* GNSS解算结果每个工作周期解算一次
*
* @author LiGang
*/
@Data
@TableName(value = "gnssdevicelocationrecords")
public class GnssCalcData {
@TableId(value = "id", type = IdType.AUTO)
Long id;
boolean enabled;
Timestamp createtime;
String deviceid;
double b562e;
double b562n;
double b562d;
double r9250e;
double r9250n;
double r9250d;
double resulte;
double resultn;
double resultd;
int tenantid;
double rb562e;
double rb562d;
double rb562n;
}

View File

@ -0,0 +1,11 @@
package com.imdroid.secapi.dto;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface GnssCalcDataMapper extends BaseMapper<GnssCalcData> {
@Select({"select * from gnssdevicelocationrecords where deviceid = #{deviceId} limit 1"})
GnssCalcData queryByDeviceId(String deviceId);
}

View File

@ -0,0 +1,42 @@
package com.imdroid.secapi.dto;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.sql.Timestamp;
/**
* GNSS设备配置数据
*
* @author LiGang
*/
@Data
@TableName(value = "gnssdevices")
public class GnssDevice {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private Short opmode;
private Timestamp createtime;
private String createuser;
private Timestamp updatetime;
private String updateuser;
private String deviceid;
private String name;
private String parentid;
private Integer devicetype;
private Integer tenantid;
private String tenantname;
private String gnssconfiguration;
private Integer project_id = 0;
private Integer group_id = 1;
private Integer calc_group_id = 1;
private Integer fwd_group_id = 0;
private Boolean syn;
private String pictures;
public String getObjectName(){
return "gnssdevice";
}
}

View File

@ -0,0 +1,11 @@
package com.imdroid.secapi.dto;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface GnssDeviceMapper extends BaseMapper<GnssDevice> {
@Select({"select * from gnssdevices where deviceid = #{deviceId} limit 1"})
GnssDevice queryByDeviceId(String deviceId);
}

View File

@ -0,0 +1,23 @@
package com.imdroid.secapi.dto;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
/**
* GNSS设备组参数包括工作周期工作时间等
*
* @author LiGang
*/
@Data
@TableName(value = "gnssgroup")
public class GnssGroup implements Serializable {
Integer id;
int work_cycle;
int active_time;
int active_offset;
short sample;
short power_mode;
int device_num;
}

View File

@ -0,0 +1,9 @@
package com.imdroid.secapi.dto;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface GnssGroupMapper extends BaseMapper<GnssGroup> {
}

View File

@ -0,0 +1,30 @@
package com.imdroid.secapi.dto;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.sql.Timestamp;
/**
* GNSS解算结果每个工作周期解算一次
*
* @author LiGang
*/
@Data
@TableName(value = "gnsssinglecalcdata")
public class GnssSingleCalcData {
@TableId(value = "id", type = IdType.AUTO)
Long id;
Timestamp createtime;
String deviceid;
double b562e = 0;
double b562n = 0;
double b562d = 0;
double roll = 0;
double pitch = 0;
double yaw = 0;
double shock = 0;
}

View File

@ -0,0 +1,9 @@
package com.imdroid.secapi.dto;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface GnssSingleCalcDataMapper extends BaseMapper<GnssSingleCalcData> {
}

View File

@ -0,0 +1,45 @@
package com.imdroid.secapi.dto;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.sql.Timestamp;
/**
* GNSS状态信息
*
* @author LiGang
*/
@Data
@TableName(value = "gnssstatus")
public class GnssStatus {
public static final short STATE_OFFLINE = 0;
public static final short STATE_ACTIVE = 1;
public static final short STATE_IDLE = 2;
@TableId(value = "id", type = IdType.AUTO)
Long id;
Timestamp updatetime;
Timestamp devicetime;
String deviceid;
String location;
float roll;
float pitch;
float yaw;
int rssi;
int voltage;
float temperature;
float humidity;
int satelliteinview;
int satelliteinuse;
// 这里的收发都是服务端统计的终端收发详细统计在msg_trx表里
int txbytes;
int rxbytes;
int b562bytes;
int d3xxbytes;
short state;
short warning;
}

View File

@ -0,0 +1,34 @@
package com.imdroid.secapi.dto;
import lombok.Data;
import java.sql.Timestamp;
@Data
public class GnssStatusJoin {
Long id;
Timestamp updatetime;
Timestamp devicetime;
String deviceid;
String location;
float roll;
float pitch;
float yaw;
int rssi;
int voltage;
float temperature;
float humidity;
int satelliteinview;
int satelliteinuse;
// 这里的收发都是服务端统计的终端收发详细统计在msg_trx表里
int txbytes;
int rxbytes;
int b562bytes;
int d3xxbytes;
short state;
short warning;
short devicetype;
int tenantid;
}

View File

@ -0,0 +1,19 @@
package com.imdroid.secapi.dto;
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface GnssStatusMapper extends MPJBaseMapper<GnssStatus> {
@Select({"select * from gnssstatus where deviceid = #{deviceId} limit 1"})
GnssStatus getByDeviceId(String deviceId);
@Select({"select s.*, d.devicetype, d.tenantid from gnssstatus s ,gnssdevices d where s.deviceid=d.deviceid and s.deviceid = #{deviceId}"})
GnssStatusJoin queryByDeviceId(String deviceId);
@Select({"select s.*, d.devicetype, d.tenantid from gnssstatus s ,gnssdevices d where s.deviceid=d.deviceid"})
GnssStatusJoin queryAll();
}

View File

@ -0,0 +1,31 @@
package com.imdroid.secapi.dto;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.sql.Timestamp;
/**
* GNSS状态消息每个工作周期开始时上报一次
*
* @author LiGang
*/
@Data
@TableName(value = "gnssstatusmsg")
public class GnssStatusMsg {
@TableId(value = "id", type = IdType.AUTO)
Long id;
Timestamp updatetime;
Timestamp devicetime;
String deviceid;
float roll;
float pitch;
float yaw;
short dtustate;
int rssi;
int voltage;
float temperature;
float humidity;
}

View File

@ -0,0 +1,10 @@
package com.imdroid.secapi.dto;
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface GnssStatusMsgMapper extends MPJBaseMapper<GnssStatusMsg> {
}

View File

@ -0,0 +1,34 @@
package com.imdroid.secapi.dto;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.sql.Timestamp;
/**
* GNSS收发统计消息每个工作周期结束的时候统计一次
*
* @author LiGang
*/
@Data
@TableName(value = "gnsstrxmsg")
public class GnssTrxMsg {
@TableId(value = "id", type = IdType.AUTO)
Long id;
Timestamp updatetime;
Timestamp devicetime;
String deviceid;
long uart1txbytes;
long uart1rxbytes;
long uart1unknown;
long uart2txbytes;
long uart2rxbytes;
long uart2unknown;
// 这里的收发都是服务端统计的终端收发详细统计在msg_trx表里
long servertxbytes;
long serverrxbytes;
long b562bytes;
long d3xxbytes;
}

View File

@ -0,0 +1,10 @@
package com.imdroid.secapi.dto;
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface GnssTrxMsgMapper extends MPJBaseMapper<GnssTrxMsg> {
}

183
sec-beidou-rtcm/pom.xml Normal file
View File

@ -0,0 +1,183 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.imdroid</groupId>
<artifactId>security-monitor</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>sec-beidou-rtcm</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<logback.version>1.2.3</logback.version>
<dt20.common.version>1.0-SNAPSHOT</dt20.common.version>
<dt20.util.version>1.0-SNAPSHOT</dt20.util.version>
<java.version>8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version><!--$NO-MVN-MAN-VER$ -->
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.78.Final</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.8</version>
</dependency>
<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-boot-starter</artifactId>
<version>1.4.3</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.imdroid</groupId>
<artifactId>sec-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>dt20.io</groupId>
<artifactId>dt20-common</artifactId>
<version>${dt20.common.version}</version>
</dependency>
<dependency>
<groupId>dt20.io</groupId>
<artifactId>dt20-util</artifactId>
<version>${dt20.util.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<finalName>sideslope-rtcm-server</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>central</id>
<name>ali-mirror</name>
<url>https://maven.aliyun.com/repository/central</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project>

View File

@ -0,0 +1,25 @@
package com.imdroid.sideslope;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
/**
* @author Layton
* @date 2023/1/31 20:33
*/
@SpringBootApplication(scanBasePackages = {"com.imdroid"})
@MapperScan({"com.imdroid.secapi.dto","com.imdroid.beidou.entity"})
@ComponentScan({"io.dt20.*", "com.imdroid.*"})
@EntityScan({"io.dt20.common.persistence", "com.imdroid.*"})
@EnableJpaRepositories({"io.dt20.common.repo", "com.imdroid.*"})
public class SideSlopeRtcmApp {
public static void main(String[] args) {
SpringApplication.run(SideSlopeRtcmApp.class, args);
}
}

View File

@ -0,0 +1,644 @@
package com.imdroid.sideslope.bd;
import java.io.*;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* The type Byte util.
*/
public class ByteUtil {
private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
public static byte[] getBytes(int data) {
byte[] bytes = new byte[4];
bytes[0] = (byte) (data & 0xff);
bytes[1] = (byte) ((data & 0xff00) >> 8);
bytes[2] = (byte) ((data & 0xff0000) >> 16);
bytes[3] = (byte) ((data & 0xff000000) >> 24);
return bytes;
}
public static short getShort(byte[] bytes) {
return (short) ((0xff & bytes[0]) | (0xff00 & (bytes[1] << 8)));
}
public static short getShort(byte high, byte low) {
return (short) (((high & 0xff) << 8) | (low & 0xff));
}
public static byte[] getBytes(String data, String charsetName) {
Charset charset = Charset.forName(charsetName);
return data.getBytes(charset);
}
public static byte[] getBytes(String data) {
return getBytes(data, "GBK");
}
public static String getString(byte[] bytes) {
return getString(bytes, "GBK");
}
public static String getString(byte[] bytes, String charsetName) {
return new String(bytes, Charset.forName(charsetName));
}
public static int toUnsignedInt(byte paramByte) {
return paramByte & 0xFF;
}
/**
* 获取byte类型的时间
*
* @param time
* @return 获取byte类型的时间
*/
public static byte[] getTimeToBytes(Date time) {
String times = new SimpleDateFormat("yy MM dd HH mm ss", Locale.CHINA).format(time)
.replaceAll(" ", "");
byte[] date = new byte[6];
for (int i = 0, j = 0; i < times.length(); i += 2, j++) {
date[j] = Byte.decode("0x" + times.charAt(i) + ""
+ times.charAt(i + 1));
}
return date;
}
/**
* 数组转16char数组
*
* @param data the data
* @param toLowerCase the to lower case
* @return the char [ ]
*/
public static char[] encodeHex(byte[] data, boolean toLowerCase) {
return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
}
/**
* 数组转16char数组
*
* @param data the data
* @param toDigits the to digits
* @return the char [ ]
*/
protected static char[] encodeHex(byte[] data, char[] toDigits) {
if (data == null) {
return null;
}
int l = data.length;
char[] out = new char[l << 1];
for (int i = 0, j = 0; i < l; i++) {
out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
out[j++] = toDigits[0x0F & data[i]];
}
return out;
}
/**
* 数组转16进制字符串
*
* @param data the data
* @return the string
*/
public static String encodeHexStr(byte[] data) {
return encodeHexStr(data, true);
}
/**
* 数组转16进制字符串
*
* @param data byte[]
* @param toLowerCase ture小写 false大写
* @return 结果
*/
public static String encodeHexStr(byte[] data, boolean toLowerCase) {
return encodeHexStr(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
}
/**
* 锟斤拷锟街斤拷锟斤拷锟斤拷转锟斤拷为十锟斤拷锟斤拷锟斤拷锟街凤拷锟斤拷
*
* @param data byte[]
* @param toDigits 锟斤拷锟节匡拷锟斤拷锟斤拷锟斤拷锟絚har[]
* @return 十锟斤拷锟斤拷锟斤拷String string
*/
protected static String encodeHexStr(byte[] data, char[] toDigits) {
return new String(encodeHex(data, toDigits));
}
/**
* long转16进制byte数组
*
* @param iSource the source
* @param iArrayLen the array len
* @return the byte [ ]
*/
public static byte[] tobyteArray(long iSource, int iArrayLen) {
byte[] bLocalArr = new byte[iArrayLen];
int i = 0;
int j = iArrayLen - 1;
for (; (i < 4) && (i < iArrayLen); i++, j--) {
bLocalArr[j] = (byte) (iSource >> 8 * i & 0xFF);
}
while (j >= 0) {
bLocalArr[j] = 0;
j--;
}
return bLocalArr;
}
/**
* int转16进制byte数组
*
* @param iSource the source
* @param iArrayLen the array len
* @return byte [ ]
*/
public static byte[] tobyteArray(int iSource, int iArrayLen) {
byte[] bLocalArr = new byte[iArrayLen];
int i = 0;
int j = iArrayLen - 1;
for (; (i < 4) && (i < iArrayLen); i++, j--) {
bLocalArr[j] = (byte) (iSource >> 8 * i & 0xFF);
}
while (j >= 0) {
bLocalArr[j] = 0;
j--;
}
return bLocalArr;
}
/**
* 16进制字节转成int
*
* @param bRefArr the b ref arr
* @return int
*/
public static int toInt(byte[] bRefArr) {
int iOutcome = 0;
byte bLoop;
for (int i = bRefArr.length - 1; i >= 0; i--) {
bLoop = bRefArr[i];
iOutcome += (bLoop & 0xFF) << (8 * (bRefArr.length - 1 - i));
}
return iOutcome;
}
/**
* Char tobyte byte.
*
* @param c the c
* @return the byte
*/
public static byte charTobyte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
/**
* 2进制转byte
*
* @param str the str
* @return int
*/
public static int Binarytobyte(String str) {
String intstr = Integer.toString(Integer.parseInt(str, 2), 10);
return Integer.valueOf(intstr);
}
/**
* 2进制字符转byte数组
*
* @param str the str
* @return the byte [ ]
*/
public static byte[] Binarytobytes(String str) {
int tmpint = 0;
for (int i = 0, j = 0; i < str.length(); i += 8, j++) {
String binarystr = str.charAt(i) + ""
+ str.charAt(i + 1) + "" + str.charAt(i + 2) + ""
+ str.charAt(i + 3) + "" + str.charAt(i + 4) + ""
+ str.charAt(i + 5) + "" + str.charAt(i + 6) + ""
+ str.charAt(i + 7);
System.out.println(i);
tmpint += Binarytobyte(binarystr);
}
System.out.println(tmpint);
return getBytes(tmpint);
}
/**
* 将long转为byte数组
*
* @param number
* @return 将long转为byte数组
*/
public static byte[] longTobyte(long number) {
byte[] b = new byte[8];
b[0] = (byte) (number >> 56);
b[1] = (byte) (number >> 48);
b[2] = (byte) (number >> 40);
b[3] = (byte) (number >> 32);
b[4] = (byte) (number >> 24);
b[5] = (byte) (number >> 16);
b[6] = (byte) (number >> 8);
b[7] = (byte) number;
return b;
}
/**
* 将short转为byte数组
*
* @param number
* @return 将short转为byte数组
*/
public static byte[] shortTobyte(short number) {
byte[] b = new byte[2];
b[0] = (byte) (number >> 8);
b[1] = (byte) number;
return b;
}
/**
* 将int转为byte数组
*
* @param number
* @return 将int转为byte数组
*/
public static byte[] intTobyte(int number) {
byte[] b = new byte[4];
b[0] = (byte) (number >> 24);
b[1] = (byte) (number >> 16);
b[2] = (byte) (number >> 8);
b[3] = (byte) number;
return b;
}
/**
* 八字节转成long
*
* @param b the b
* @return the long
*/
public static long toLong(byte[] b)
{
long l = 0;
l = b[0];
l |= ((long) b[1] << 8);
l |= ((long) b[2] << 16);
l |= ((long) b[3] << 24);
l |= ((long) b[4] << 32);
l |= ((long) b[5] << 40);
l |= ((long) b[6] << 48);
l |= ((long) b[7] << 56);
return l;
}
/**
* 数组转成十六进制字符串
*
* @param b the b
* @return HexString string
*/
public static String bytesToHexString(byte[] b) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < b.length; ++i) {
buffer.append(byteToHexString(b[i]));
}
return buffer.toString();
}
/**
* byte转成16进制字符串
*
* @param b the b
* @return the string
*/
public static String byteToHexString(byte b) {
String s = Integer.toHexString(b & 0xFF);
if (s.length() == 1) {
return "0" + s;
} else {
return s;
}
}
/**
* 图片路径转成byte
*
* @param path the path
* @return the byte [ ]
*/
public static byte[] image2byte(String path) {
byte[] data = null;
FileInputStream input = null;
try {
input = new FileInputStream(new File(path));
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int numBytesRead = 0;
while ((numBytesRead = input.read(buf)) != -1) {
output.write(buf, 0, numBytesRead);
}
data = output.toByteArray();
output.close();
input.close();
} catch (FileNotFoundException ex1) {
ex1.printStackTrace();
} catch (IOException ex1) {
ex1.printStackTrace();
}
return data;
}
/**
* Byte 2 image boolean.
*
* @param data the data
* @param path the path
* @return the boolean
*/
// byte数组到图片
public static boolean byte2image(byte[] data, String path) {
if (data.length < 3 || "".equals(path)) {
return false;
}
try {
FileOutputStream imageOutput = new FileOutputStream(
new File(path));
imageOutput.write(data, 0, data.length);
imageOutput.close();
System.out.println("Make Picture success,Please find image in "
+ path);
} catch (Exception ex) {
System.out.println("Exception: " + ex);
ex.printStackTrace();
return false;
}
return true;
}
/**
* byte叠加
*
* @param data1 the data 1
* @param data2 the data 2
* @return the byte [ ]
*/
public static byte[] addBytes(byte[] data1, byte[] data2) {
byte[] data3 = new byte[data1.length + data2.length];
System.arraycopy(data1, 0, data3, 0, data1.length);
System.arraycopy(data2, 0, data3, data1.length, data2.length);
return data3;
}
/**
* Bcd 2 str string.
*
* @param bytes the bytes
* @return the string
*/
public static String bcd2Str(byte[] bytes) {
StringBuffer temp = new StringBuffer(bytes.length * 2);
for (int i = 0; i < bytes.length; i++) {
temp.append((byte) ((bytes[i] & 0xf0) >>> 4));
temp.append((byte) (bytes[i] & 0x0f));
}
while (temp.charAt(0) == '0') {
temp.deleteCharAt(0);
}
return temp.toString();
}
/**
* 获得参数内容
*/
public static byte[] getParameter(byte[] body, int length) {
byte[] content = new byte[length];
System.arraycopy(body, body.length - length, content, 0, length);
return content;
}
/**
* 把16进制字符串转换成字节数组
*
* @return byte[]
*/
public static byte[] hexStringTobyte(String hex) {
hex = hex.toUpperCase();
int len = (hex.length() / 2);
byte[] result = new byte[len];
char[] achar = hex.toCharArray();
for (int i = 0; i < len; i++) {
int pos = i * 2;
result[i] = (byte) (tobyte(achar[pos]) << 4 | tobyte(achar[pos + 1]));
}
return result;
}
/**
* 字符串转16进制字符串
*
* @param strPart
* @return
*/
public static String string2HexString(String strPart) {
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < strPart.length(); i++) {
int ch = (int) strPart.charAt(i);
String strHex = Integer.toHexString(ch);
hexString.append(strHex);
}
return hexString.toString();
}
private static int tobyte(char c) {
byte b = (byte) "0123456789ABCDEF".indexOf(c);
return b;
}
/**
* 转换总里程
*
* @param value
* @return 转换总里程
*/
public static String oneDecimal(double value) {
BigDecimal b = new BigDecimal(value);
return b.setScale(1, BigDecimal.ROUND_HALF_UP).toString();
}
//------工具区(经纬度解析)--------------------------------------------------
public static Double getLONG(Double location) {
if (location != 0.0) {
int head = Integer.parseInt(String.valueOf(location).substring(0, 3));
//System.out.println(head);
return head + (location / 100 - head) * 10 / 6;
}
return 0.0;
}
//一度为60分
public static Double getLAT(Double location) {
if (location != 0.0) {
int head = Integer.parseInt(String.valueOf(location).substring(0, 2));
// System.out.println(head);
return head + (location / 100 - head) * 10 / 6;
}
return 0.0;
}
/**
* 将byte数组数据转换成float
* @param arr
* @return
*/
public static float bytes2Float(byte[] arr) {
float f = ByteBuffer.wrap(arr).order(ByteOrder.BIG_ENDIAN).getFloat();
return f;
}
/**
* byte数组中取int数值本方法适用于(低位在前高位在后)的顺序
*
* @param src byte数组
* @return int数值
*/
public static int bytesToInt(byte[] src) {
int value;
value = (int) ((src[0] & 0xFF)
| ((src[1] & 0xFF)<<8)
| ((src[2] & 0xFF)<<16)
| ((src[3] & 0xFF)<<24));
return value;
}
/**
* 把byte数组转化成2进制字符串
* @param bArr
* @return
*/
public static String getBinaryStrFromByteArr(byte[] bArr){
String result ="";
for(byte b:bArr ){
result += getBinaryStrFromByte(b);
}
return result;
}
/**
* 把byte转化成2进制字符串
* @param b
* @return
*/
public static String getBinaryStrFromByte(byte b){
String result ="";
byte a = b; ;
for (int i = 0; i < 8; i++){
byte c=a;
a=(byte)(a>>1);//每移一位如同将10进制数除以2并去掉余数
a=(byte)(a<<1);
if(a==c){
result="0"+result;
}else{
result="1"+result;
}
a=(byte)(a>>1);
}
return result;
}
/**
* 二进制字符串转int
* @param binary
* @return
*/
public static int binaryToInt(String binary) {
if (binary == null ) {
System. out .println( "can't input null " );
}
if (binary.isEmpty()) {
System. out .println( "you input is Empty !" );
}
int max = binary.length();
String new_binary = "" ;
if (max >= 2 && binary.startsWith( "0" )) {
int position = 0;
for ( int i = 0; i < binary.length(); i++) {
char a = binary.charAt(i);
if (a != '0' ) {
position = i;
break ;
}
}
if (position == 0) {
new_binary = binary.substring(max - 1, max);
} else {
new_binary = binary.substring(position, max);
}
} else {
new_binary = binary;
}
int new_width = new_binary.length();
long result = 0;
if (new_width < 32) {
for ( int i = new_width; i > 0; i--) {
char c = new_binary.charAt(i - 1);
int algorism = c - '0' ;
result += Math. pow(2, new_width - i) * algorism;
}
} else if (new_width == 32) {
for ( int i = new_width; i > 1; i--) {
char c = new_binary.charAt(i - 1);
int algorism = c - '0' ;
result += Math. pow(2, new_width - i) * algorism;
}
result += -2147483648;
}
int a = new Long(result).intValue();
return a;
}
}

View File

@ -0,0 +1,325 @@
package com.imdroid.sideslope.bd;
import java.util.*;
/**
* 1.过滤
* 2.最多取最后300个点计算
* 3.取最后100点求重心画0.25cm的球
* 4.求重心包容百分之68此重心为所求
* 5.否则扩大半径0.01再求重心包容百分之68此重心为所求
* 6.
*/
public class FocusCalculator {
private List<double[]> list = Collections.synchronizedList(new ArrayList<>());
private List<Tilt> tilts = Collections.synchronizedList(new ArrayList<>());
private Tilt tilt0;//初始状态
private double[] position0;
private double r = 10;//杆的长度cm 20230718 测试改为10
private boolean flag = false; // 是否是第一次计算
private List<Point> pointList = new ArrayList<>();
public static double[] lastFocus = null;//
/**
* 构建计算器如果tilt0和position0是null那么计算过程将不考虑与tilts数据融合
* @param r 杆的长度单位厘米
* @param tilt0 一个小时前的tilt平均值用一小时的avgTilt计算得到如果第一次用null
* @param position0 一个小时前的xyz三维坐标值用一小时前的ekf计算得到的那个如果第一次用null
*/
public FocusCalculator(double r, Tilt tilt0, double[] position0){
this.r = r;
this.tilt0 = tilt0;
this.position0 = position0;
}
/**
* 加入list
* @param xyz
*/
public void addXyz(double[] xyz){
if(filter(xyz)){
list.add(xyz);
}
if(list.size() > 300){
list.remove(0);
}
}
/**
* 计算得到最终结果
* @return
*/
public double[] resultB562(double[] r9250Result){
int count = 50;
double rate = 0.5;
try {
double r = 0.25;//初始球半径
if(list.size() >= count){
List<Point> results = new ArrayList<>();
if (r9250Result != null && r9250Result.length > 0){
// 计算所有点位与变量之间的距离并存入集合
pointList.clear();
for (double[] point : list) {
Point point1 = new Point(point[0],point[1],point[2]);
double distance = disXY(point,r9250Result); // 计算距离
point1.setDistance(distance); // 设置该点到变量的距离
results.add(point1); // 将点位加入集合
}
Collections.sort(results, Comparator.comparing(Point::getDistance));//排序
results = results.subList(0, Math.min(50, results.size()));
}else {
for (int i = list.size()-count; i < list.size(); i++) {
results.add(new Point(list.get(i)[0],list.get(i)[1],list.get(i)[2]));
}
flag = true;
}
//重心
double[] focus = focusPoint(results);
if(globeProportion(focus,r) < rate){
do{
r += 0.01;
//球附近点集个数有可能为0继续计算会导致focus结果出现NaN
List<double[]> doubles1 = globeFilter(focus, r);
if(doubles1.size() == 0){
continue;
}
focus = focus(doubles1);
}while (globeProportion(focus,r) < rate);
// if (flag){
// lastFocus = new double[3];
// lastFocus = focus;
// }
return focus;
}else{
// if (flag){
// lastFocus = new double[3];
// lastFocus = focus;
// }
return focus;
}
}
}catch (Exception e){
//如果计算过程中修改list可能引发异常
e.printStackTrace();
}
return resultB562Sub();
}
/**
* resultB562替补方法尽量不返回空
* @return x,y,z,有效点数
*/
private double[] resultB562Sub(){
if(list.size() > 0){
//重心
double[] focus = focus(list);
return focus;
}
return null;
}
/**
* 过滤剔除0,无穷大与nan
* @param xyz
* @return true表示数据正常
*/
private boolean filter(double[] xyz){
double a = xyz[0]*xyz[1]*xyz[2];
if(a == 0 || Double.isInfinite(a) || Double.isNaN(a)){
return false;
}
return true;
}
/**
* 三维点集重心计算
* @param list
* @return
*/
private double[] focus(List<double[]> list){
double sumX = 0;
double sumY = 0;
double sumZ = 0;
int count = list.size();
for (double[] doubles : list) {
sumX += doubles[0];
sumY += doubles[1];
sumZ += doubles[2];
}
return new double[]{sumX/count,sumY/count,sumZ/count};
}
private double[] focusPoint(List<Point> list){
double sumX = 0;
double sumY = 0;
double sumZ = 0;
int count = list.size();
for (Point point : list) {
sumX += point.getX();
sumY += point.getY();
sumZ += point.getZ();
}
return new double[]{sumX/count,sumY/count,sumZ/count};
}
/**
* 计算两个三维坐标的距离
* @param a
* @param b
* @return
*/
public static double dis(double[] a, double[] b){
return Math.sqrt(Math.pow(a[0]-b[0],2) + Math.pow(a[1]-b[1],2) + Math.pow(a[2]-b[2],2));
}
public static double disXY(double[] a, double[] b){
return Math.sqrt(Math.pow(a[0]-b[0],2) + Math.pow(a[1]-b[1],2));
}
/**
* 重心附近点集占总数的比例
* @param focus
* @param r
* @return
*/
private double globeProportion(double[] focus, double r){
int in = 0;//在球内的个数
for (double[] doubles : list) {
double dis = dis(doubles, focus);
if(dis < r){
in += 1;
}
}
double proportion = 1.00*in/list.size();
return proportion;
}
/**
* 获取重心附近r内的所有点
* @param focus
* @param r
* @return
*/
private List<double[]> globeFilter(double[] focus, double r){
ArrayList<double[]> arrayList = new ArrayList<>();
for (double[] doubles1 : list) {
if(dis(doubles1,focus) < r){
arrayList.add(doubles1);
}
}
return arrayList;
}
/**
* tilt计算得到的坐标与b562数据得到的坐标融合
* 1.可用点数大于50优先相信b562
* 2.可用点数大于0小于50取b562与9250平均值
* 3.可用点数无用9250
* @return
*/
public double[] ekfResult(double[] b562Xyz, double[] tiltXyz){
if(tiltXyz == null){
return b562Xyz;
}
if(b562Xyz == null){
return tiltXyz;
}
double b562Variance;
double tiltVariance = 5; //Sherlock 230802 2-5 减小惯导的长周期影响
if(list.size() >= 50){
b562Variance = 1;
}else if(list.size() >= 40){
b562Variance = 3;
}else if(list.size() >= 30){
b562Variance = 9;
}else if(list.size() >= 20){
b562Variance = 30;
}else if(list.size() >= 10){
b562Variance = 60;
}else{
b562Variance = 90;
}
double k = Math.pow(b562Variance,2)/(Math.pow(tiltVariance,2) + Math.pow(b562Variance,2));
double x = b562Xyz[0] + k*(tiltXyz[0]-b562Xyz[0]);
double y = b562Xyz[1] + k*(tiltXyz[1]-b562Xyz[1]);
//z轴更加相信9250; 2023070改为5120230706改为31 20230718 改为 4120230720 改为 51
b562Variance = 5;
tiltVariance = 1;
k = Math.pow(b562Variance,2)/(Math.pow(tiltVariance,2) + Math.pow(b562Variance,2));
double z = b562Xyz[2] + k*(tiltXyz[2]-b562Xyz[2]);
return new double[]{x,y,z};
}
/**
* 加入tilts
* @param tilt
*/
public void addTilt(Tilt tilt){
tilts.add(tilt);
if(tilts.size() > 300){
tilts.remove(0);
}
}
/**
* 取平均
* @return
*/
public Tilt avgTilt(){
if(tilts.size() == 0){
return null;
}
try {
Iterator<Tilt> iterator = tilts.iterator();
int size = tilts.size();
double sumP = 0;
double sumR = 0;
double sumY = 0;
while (iterator.hasNext()){
Tilt tilt = iterator.next();
sumP += Math.sin(tilt.getPitch()*Math.PI/180);
sumR += Math.sin(tilt.getRoll()*Math.PI/180);
sumY += Math.sin(tilt.getYaw()*Math.PI/180);
}
double pitch = (Math.asin(sumP/size) * 180/Math.PI + 360)%360;
double roll = (Math.asin(sumR/size) * 180/Math.PI + 360)%360;
double yaw = (Math.asin(sumY/size) * 180/Math.PI + 360)%360;
return new Tilt(pitch,roll,yaw);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
public double[] result9250(){
Tilt avg = avgTilt();
if(tilt0 == null || position0 == null || r == 0 || avg == null){
return null;
}
double[] _9250_result = TiltUtil.toPosition(avg,tilt0,position0,r);
return _9250_result;
}
public Tilt getTilt0(){
return tilt0;
}
public double[] getPosition0(){
return position0;
}
public double getR(){
return r;
}
}

View File

@ -0,0 +1,51 @@
package com.imdroid.sideslope.bd;
import lombok.Data;
@Data
public class Gga {
/**
* 纬度
*/
private double latitude;
/**
* 经度
*/
private double longitude;
/**
* 海拔
*/
private double altitude;
/**
* GPS状态0初始化1单点定位2码差分3无效PPS4固定解5浮点解6正在估算7人工输入固定值8模拟模式9WAAS差分
*/
private int status;
public Gga() {
}
public Gga(double latitude, double longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
public Gga(double latitude, double longitude, double altitude, int status) {
this.latitude = latitude;
this.longitude = longitude;
this.altitude = altitude;
this.status = status;
}
@Override
public String toString() {
return "Gga{" +
"latitude=" + latitude +
", longitude=" + longitude +
", altitude=" + altitude +
", status=" + status +
'}';
}
}

View File

@ -0,0 +1,22 @@
package com.imdroid.sideslope.bd;
/**
* @author Layton
* @date 2023/2/19 21:14
*/
public class NumberUtils {
public static String doubleArrayToString(double[] result) {
if (result == null) {
return null;
}
StringBuilder builder = new StringBuilder();
for (int i = 0; i < result.length; i++) {
builder.append(result[i]);
if (i < result.length - 1) {
builder.append(",");
}
}
return builder.toString();
}
}

View File

@ -0,0 +1,18 @@
package com.imdroid.sideslope.bd;
import lombok.Data;
@Data
public class Point {
private double x;
private double y;
private double z;
private double distance;
public Point(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
}

View File

@ -0,0 +1,52 @@
package com.imdroid.sideslope.bd;
import lombok.Data;
/**
* 描述杆的倾斜
*/
@Data
public class Tilt {
/**
* 前后仰角 上仰为正0-360
*/
private double pitch;
/**
* 左右倾斜角 右下为正0-360
*/
private double roll;
/**
* 航向角 北偏东为正0-360
*/
private double yaw;
/**
* 偏移量
*/
private double shock;
public Tilt(double pitch, double roll, double yaw,double shock) {
this.pitch = pitch;
this.roll = roll;
this.yaw = yaw;
this.shock = shock;
}
public Tilt(double pitch, double roll, double yaw) {
this.pitch = pitch;
this.roll = roll;
this.yaw = yaw;
}
@Override
public String toString() {
return "Tilt{" +
"pitch=" + pitch +
", roll=" + roll +
", yaw=" + yaw +", shock:"+shock+
'}';
}
}

View File

@ -0,0 +1,65 @@
package com.imdroid.sideslope.bd;
public class TiltUtil {
public static double[] toPosition(Tilt tilt, Tilt tilt0, double[] position0, double r){
if(tilt0 == null || position0 == null || r == 0 || tilt == null){
return null;
}
//杆底相对与杆顶的位置
double[] rodDownPosition = rodDownPosition(tilt0, r);
//杆底相对于基站的位置
double[] downPosition = new double[]{position0[0] + rodDownPosition[0], position0[1] + rodDownPosition[1], position0[2] + rodDownPosition[2]};
//杆顶相对于杆底的位置
double[] rodTopPosition = TiltUtil.rodTopPosition(tilt, r);
//杆顶相对于基站的位置
double[] topPosition = new double[]{downPosition[0] + rodTopPosition[0], downPosition[1] + rodTopPosition[1], downPosition[2] + rodTopPosition[2]};
return topPosition;
}
/**
* 计算得到杆顶点相对于杆底点的相对位置
* @param tilt
* @param r 杆的长度
* @return
*/
public static double[] rodTopPosition(Tilt tilt, double r){
//假设yaw=0
//杆在xoz平面投影
double xoz = r * Math.cos(toRadians(tilt.getPitch()));
double x = xoz * Math.cos(toRadians(90-tilt.getRoll()));
double z = xoz * Math.cos(toRadians(tilt.getRoll()));
//杆在yoz平面投影
double yoz = r * Math.cos(toRadians(tilt.getRoll()));
double y = -yoz * Math.cos(toRadians(90-tilt.getPitch()));
//考虑到yaw相当于逆时针旋转xoy坐标系
double yaw = (tilt.getYaw() + 360)%360;
double x1 = x*Math.cos(toRadians(yaw)) - y*Math.sin(toRadians(yaw));
double y1 = y*Math.cos(toRadians(yaw)) + x*Math.sin(toRadians(yaw));
return new double[]{x1,y1,z};
}
/**
* 计算得到杆底相对于杆顶点的相对位置
* @param tilt
* @param r 杆的长度
* @return
*/
public static double[] rodDownPosition(Tilt tilt, double r){
double[] doubles = rodTopPosition(tilt, r);
return new double[]{-doubles[0],-doubles[1],-doubles[2]};
}
/**
* 角度转弧度
* @param angle
* @return
*/
public static double toRadians(double angle) {
return angle / 180.0 * Math.PI;
}
}

View File

@ -0,0 +1,44 @@
package com.imdroid.sideslope.bd;
import io.netty.buffer.ByteBuf;
/**
* b562 01 3c 4000 01 00 0000 40235d21 8dffffff 08ffffff 00000000 11010000 8af4750100000000ddeab84864000000640000006400000064000000c55100000000000037010000 996e
* b562固定开头01是class3c是id40 00是有效数据长度低字节序号所以有效数据长度为0x40接下来是有效数据最后996e是校验位
*/
public class UBXUtil {
/**
* 解析UBX数据
* @param data UBX数据(b562开头)
* @return x,y,z 竖直 东为正数北为正数朝上为正数
*/
public static double[] getLocation(ByteBuf data){
boolean has_b562 = false;
byte[] b562_flag = {(byte) 0xb5, (byte)0x62};
int pos = 26; // 从惯导之后开始
for(; pos<data.readableBytes() - 1; pos++){
byte d0 = data.getByte(pos);
byte d1 = data.getByte(pos+1);
if(d0 == b562_flag[0] && d1 == b562_flag[1]){
has_b562 = true;
break;
}
}
if(!has_b562) return null;
pos+=6;
double relPosN = data.getIntLE(pos+8) + data.getByte(pos+32)*0.01;
double relPosE = data.getIntLE(pos+12) + data.getByte(pos+33)*0.01;
double relPosD = data.getIntLE(pos+16) + data.getByte(pos+34)*0.01;
relPosD = -relPosD;
short status = (short) ((data.getUnsignedByte(pos+60) & 0x18)>>3); //mask: 00011000
if(status == 2){
return new double[]{relPosE,relPosN,relPosD};
}else{
return null;
}
}
}

View File

@ -0,0 +1,36 @@
package com.imdroid.sideslope.calc;
import com.imdroid.sideslope.bd.Tilt;
import com.imdroid.sideslope.message.D341LocationMessage;
/**
* @author Layton
* @date 2023/2/4 19:18
*/
public interface GNSSCalcService {
/**
* 计算单条GNSS数据
*
* @param message GNSS数据
* @return x,y,z三轴数据
*/
double[] calcSingle(D341LocationMessage message);
/**
* 根据GNSS数据的中间结果计算出最终结果
*
* @param deviceId 设备id
* @return x,y,z三轴数据
*/
double[] calcResult(String deviceId,double[] b562Xyz, double[] tiltXyz);
/**
* 根据GNSS数据的中间结果计算Tilt的平均值
* @param deviceId 设备id
* @return
*/
Tilt calcAvgTilt(String deviceId);
void cleanTiltByDeviceId(String deviceId);
}

View File

@ -0,0 +1,195 @@
package com.imdroid.sideslope.calc;
import com.imdroid.sideslope.bd.*;
import com.imdroid.sideslope.message.D341LocationMessage;
import com.imdroid.sideslope.sal.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
/**
* @author Layton
* @date 2023/2/4 19:22
*/
@Service
public class SingleLineGNSSCalcService implements GNSSCalcService {
private static final Logger logger = LoggerFactory.getLogger(SingleLineGNSSCalcService.class);
private static final Map<String, FocusCalculator> calculatorMap = new ConcurrentHashMap<>();
private static final Map<String, ScheduledFuture<?>> timerMap = new ConcurrentHashMap<>();
private static final Map<String, Tilt> tiltMap = new ConcurrentHashMap<>();
private static final Map<String, double[]> positionMap = new ConcurrentHashMap<>();
private static final Map<String, Boolean> cleanTiltStatusMap = new ConcurrentHashMap<>();
private static final Map<String, Boolean> cleanPositionStatusMap = new ConcurrentHashMap<>();
private static final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(4);
//计时器
private static final ScheduledExecutorService executorService2 = Executors.newScheduledThreadPool(4);
private static Map<String, ScheduledFuture<?>> timerMap2 = new ConcurrentHashMap<>();
@Resource(name = "local")
private DeviceService deviceService;
private static Map<String, Boolean> isExceedMap = new HashMap<>();
@Override
public double[] calcSingle(D341LocationMessage message) {
String deviceId = message.getId();
Device device = deviceService.findByDeviceId(deviceId);
if (device != null && device.getDeviceType() == Device.DEVICE_ROVER) {
resultOutputTimer(deviceId);
}
//todo 创建FocusCalculator对象需获取该测站的杆长度上一小时的Tilt平均值上一小时的测站相对坐标融合值ekfResult
FocusCalculator focusCalculator = calculatorMap.computeIfAbsent(deviceId, s -> new FocusCalculator(150,tiltMap.get(deviceId),
positionMap.get(deviceId)));
// 读取惯导
Tilt tilt = message.getTilt();
//判断阈值
if (tilt.getShock() > 1.5) {
if (timerMap2.containsKey(deviceId)){
timerMap2.get(deviceId).cancel(true);
}
ScheduledFuture<?> future = executorService2.schedule(() -> {
isExceedMap.put(deviceId, false);
}, 6, TimeUnit.HOURS);
timerMap2.put(deviceId, future);
isExceedMap.put(deviceId, true);
} else {
try {
if (isExceedMap.get(deviceId)) {
isExceedMap.put(deviceId, true);
} else {
isExceedMap.put(deviceId, false);
}
} catch (Exception e) {
isExceedMap.put(deviceId, false);
}
}
focusCalculator.addTilt(tilt);
if (logger.isDebugEnabled()) {
logger.debug("测站" + deviceId + "的9250单次解析结果:{}", tilt.toString() + "," + Arrays.toString(TiltUtil.toPosition(tilt, focusCalculator.getTilt0(), focusCalculator.getPosition0(), focusCalculator.getR())));
}
//计算到单次相对位置xyz并记录
//tilt共16个字节从后边开始找b562
double[] doubles = message.getB562_loc();
if(doubles != null){
focusCalculator.addXyz(doubles);
if (logger.isDebugEnabled()) {
logger.debug("测站" + deviceId + "的b562单次解析结果:{}", Arrays.toString(doubles));
}
return doubles;
}else{
return new double[0];
}
}
private void resultOutputTimer(String deviceId){
//20秒没数据后输出结果
ScheduledFuture<?> future = timerMap.get(deviceId);
if (future != null && !future.isDone()) {
future.cancel(true);
future = null;
}
future = executorService.schedule(() -> {
try {
FocusCalculator focusCalculator = calculatorMap.get(deviceId);
double[] lastEfk = null;
if(positionMap.containsKey(deviceId)){
lastEfk = positionMap.get(deviceId);
}
double[] b562Result = focusCalculator.resultB562(lastEfk);
double[] r9250Result = null;
//判断 取到的b562 和上次融合坐标做判断如果距离>100mm 不计算9250
if (lastEfk != null && FocusCalculator.disXY(b562Result,lastEfk)<100){
r9250Result = focusCalculator.result9250();
}
double[] result = focusCalculator.ekfResult(b562Result,r9250Result);
Tilt tilt = calcAvgTilt(deviceId);
calculatorMap.remove(deviceId);
logger.info("测站 {} 的b562相对坐标重心:{}", deviceId, Arrays.toString(b562Result));
logger.info("测站 {} 的9250相对坐标:{}", deviceId, Arrays.toString(r9250Result));
logger.info("测站 {} 的相对坐标融合值:{}", deviceId, Arrays.toString(result));
logger.info("测站 {} 的Tilt平均值:{}", deviceId, tilt);
if (tilt != null) {
if (Boolean.TRUE.equals(cleanTiltStatusMap.get(deviceId))) {
// 置为false下一次计算时就可以正常设置惯导值到tiltMap了
cleanTiltStatusMap.put(deviceId, Boolean.FALSE);
logger.info("置为false下一次计算时就可以正常设置惯导值到tiltMap了");
} else {
tiltMap.put(deviceId, tilt);
}
}
if (result != null && b562Result != null) {
//这里检查一下result过滤1千米外非正常数据
if(focusCalculator.dis(result,b562Result) < 1000_00) {
if (Boolean.TRUE.equals(cleanPositionStatusMap.get(deviceId))) {
// 置为false下一次计算时就可以正常设置值到positionMap了
cleanPositionStatusMap.put(deviceId, Boolean.FALSE);
logger.info("置为false下一次计算时就可以正常设置值到positionMap了");
} else {
positionMap.put(deviceId, result);
}
postLocationRecord(deviceId, b562Result, r9250Result, result);
}else{
logger.error("融合值异常");
}
}
} catch (Exception e) {
logger.error(e.toString());
}
},40, TimeUnit.SECONDS);
timerMap.put(deviceId, future);
}
private void postLocationRecord(String deviceId, double[] b562Result, double[] r9250Result, double[] result) {
LocationRecordDTO locationRecord = new LocationRecordDTO(deviceId, NumberUtils.doubleArrayToString(b562Result),
NumberUtils.doubleArrayToString(r9250Result), NumberUtils.doubleArrayToString(result),String.valueOf(isExceedMap.get(deviceId)));
deviceService.postLocationRecord(locationRecord);
}
@Override
public double[] calcResult(String deviceId,double[] b562Xyz, double[] tiltXyz) {
FocusCalculator focusCalculator = calculatorMap.get(deviceId);
if (focusCalculator != null) {
double[] result = focusCalculator.ekfResult(b562Xyz,tiltXyz);
return result;
}
return null;
}
@Override
public Tilt calcAvgTilt(String deviceId) {
FocusCalculator focusCalculator = calculatorMap.get(deviceId);
if (focusCalculator != null) {
Tilt tilt = focusCalculator.avgTilt();
return tilt;
}
return null;
}
public void cleanTiltByDeviceId(String deviceId) {
logger.info("清空设备[{}]的tilt和position缓存", deviceId);
tiltMap.remove(deviceId);
positionMap.remove(deviceId);
cleanTiltStatusMap.put(deviceId, Boolean.TRUE);
cleanPositionStatusMap.put(deviceId, Boolean.TRUE);
}
}

View File

@ -0,0 +1,14 @@
package com.imdroid.sideslope.exception;
/**
* 设备消息校验异常
*
* @author LiGang
* @date 2023/4/8 10:55
*/
public class MessageValidateFailException extends RuntimeException {
public MessageValidateFailException(String message) {
super(message);
}
}

View File

@ -0,0 +1,8 @@
package com.imdroid.sideslope.exception;
/**
* @author Layton
* @date 2023/2/2 20:43
*/
public class UnSupportedMessageException extends RuntimeException {
}

View File

@ -0,0 +1,28 @@
package com.imdroid.sideslope.executor;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
@Component
public class BizExecutors {
private final HashMap<Class<?>, Object> executors = new HashMap<>();
private final List<Executor<?, ?>> executorList;
public BizExecutors(List<Executor<?, ?>> executorList) {
this.executorList = executorList;
for (Executor<?, ?> executor : this.executorList) {
System.out.println("executor type:" + executor.getMessageType().getName());
executors.put(executor.getMessageType(), executor);
}
}
public <Q, R> R execute(Q query) {
Executor<Q, R> executor = (Executor<Q, R>)(executors.get(query.getClass()));
return executor.execute(query);
}
}

View File

@ -0,0 +1,23 @@
package com.imdroid.sideslope.executor;
import com.imdroid.sideslope.message.D31xConfigAckMessage;
import com.imdroid.sideslope.message.D3F0SelfCheckMessage;
import org.springframework.stereotype.Component;
/**
* @author Layton
* @date 2023/2/2 20:40
*/
@Component
public class D31xConfigAckMessageExecutor implements Executor<D31xConfigAckMessage, Void> {
@Override
public Void execute(D31xConfigAckMessage message) {
return null;
}
@Override
public Class<?> getMessageType() {
return D3F0SelfCheckMessage.class;
}
}

View File

@ -0,0 +1,60 @@
package com.imdroid.sideslope.executor;
import com.imdroid.sideslope.message.D331RtcmMessage;
import com.imdroid.sideslope.sal.Device;
import com.imdroid.sideslope.sal.DeviceService;
import com.imdroid.sideslope.server.OnlineChannels;
import com.imdroid.sideslope.util.ThreadManager;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
/**
* @author Layton
* @date 2023/2/2 20:49
*/
@Component
public class D331RtcmMessageExecutor implements Executor<D331RtcmMessage, Void> {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Resource(name = "local")
private DeviceService deviceService;
@Override
public Void execute(D331RtcmMessage message) {
if (logger.isDebugEnabled()) {
logger.debug("receive d331 rtcm message of device:{}", message.getId());
}
String id = message.getId();
byte[] forwardBytes = message.getSrcData();
List<Device> deviceList = deviceService.findByParentId(id);
for (Device device : deviceList) {
String deviceId = device.getDeviceId();
OnlineChannels.INSTANCE.get(deviceId).ifPresent(deviceChannel -> {
if (logger.isDebugEnabled()) {
logger.debug("forward d331 rtcm message to device {}", deviceId);
}
ByteBuf buf = Unpooled.buffer();
buf.writeBytes(forwardBytes);
deviceChannel.writeAndFlush(buf);
});
}
final Date now = new Date();
ThreadManager.getFixedThreadPool().execute(() -> {
deviceService.updateLatestDataTime(id, now);
});
return null;
}
@Override
public Class<?> getMessageType() {
return D331RtcmMessage.class;
}
}

View File

@ -0,0 +1,42 @@
package com.imdroid.sideslope.executor;
import com.imdroid.sideslope.calc.GNSSCalcService;
import com.imdroid.sideslope.message.D341LocationMessage;
import com.imdroid.sideslope.service.GNSSDeviceLocationRecordService;
import com.imdroid.sideslope.util.ThreadManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author Layton
* @date 2023/2/2 20:50
*/
@Component
public class D341LocationMessageExecutor implements Executor<D341LocationMessage, Void> {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private GNSSCalcService gnssCalcService;
@Autowired
private GNSSDeviceLocationRecordService dataPersistService;
@Override
public Void execute(D341LocationMessage message) {
if (logger.isDebugEnabled()) {
logger.debug("receive d341 location message of device:{}", message.getId());
}
ThreadManager.getFixedThreadPool().submit(() -> {
gnssCalcService.calcSingle(message);
dataPersistService.saveSingleCalcData(message);
});
return null;
}
@Override
public Class<?> getMessageType() {
return D341LocationMessage.class;
}
}

View File

@ -0,0 +1,33 @@
package com.imdroid.sideslope.executor;
import com.imdroid.sideslope.message.D3F0SelfCheckMessage;
import com.imdroid.sideslope.service.DataPersistService;
import com.imdroid.sideslope.util.ThreadManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author Layton
* @date 2023/2/2 20:40
*/
@Component
public class D3F0SelfCheckMessageExecutor implements Executor<D3F0SelfCheckMessage, Void> {
@Autowired
private DataPersistService dataPersistService;
@Override
public Void execute(D3F0SelfCheckMessage message) {
// 存储最新设备状态信息到数据库中
ThreadManager.getFixedThreadPool().submit(() -> {
dataPersistService.saveDeviceState(message);
});
return null;
}
@Override
public Class<?> getMessageType() {
return D3F0SelfCheckMessage.class;
}
}

View File

@ -0,0 +1,46 @@
package com.imdroid.sideslope.executor;
import com.imdroid.sideslope.message.D3F2StopIndicationMessage;
import com.imdroid.sideslope.sal.DeviceService;
import com.imdroid.sideslope.service.DataPersistService;
import com.imdroid.sideslope.util.ThreadManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Date;
/**
* 停止指示消息处理器
*
* @author LiGang
*/
@Component
public class D3F2StopIndicationMessageExecutor implements Executor<D3F2StopIndicationMessage, Void> {
@Autowired
private DataPersistService dataPersistService;
@Resource(name = "local")
private DeviceService deviceService;
@Override
public Void execute(D3F2StopIndicationMessage message) {
// 储设备收发字节数统计信息
ThreadManager.getFixedThreadPool().submit(() -> {
dataPersistService.saveDeviceTrxStat(message);
});
// 更新设备的最新数据时间
final Date now = new Date();
ThreadManager.getFixedThreadPool().submit(() -> {
deviceService.updateLatestDataTime(message.getId(), now);
});
return null;
}
@Override
public Class<?> getMessageType() {
return D3F2StopIndicationMessage.class;
}
}

View File

@ -0,0 +1,12 @@
package com.imdroid.sideslope.executor;
/**
* @author Layton
* @date 2022/4/8 22:32
*/
public interface Executor<Q, R> {
R execute(Q message);
Class<?> getMessageType();
}

View File

@ -0,0 +1,47 @@
package com.imdroid.sideslope.executor;
import com.imdroid.sideslope.exception.UnSupportedMessageException;
import com.imdroid.sideslope.message.*;
import io.netty.buffer.ByteBuf;
import java.util.HashMap;
import java.util.Map;
/**
* @author Layton
* @date 2023/2/2 20:41
*/
public class MessageParser {
private static final Map<Short, Class<? extends BaseMessage>> types = new HashMap<>();
public static final MessageParser instance = new MessageParser();
private MessageParser() {
}
static {
types.put((short)0xd3f0, D3F0SelfCheckMessage.class);
types.put((short)0xd3f2, D3F2StopIndicationMessage.class);
//types.put((short)0xd330, D330RtcmMessage.class);
//types.put((short)0xd340, D340LocationMessage.class);
types.put((short)0xd331, D331RtcmMessage.class);
types.put((short)0xd341, D341LocationMessage.class);
types.put((short)0xd310, D31xConfigAckMessage.class);//GNSS配置应答
types.put((short)0xd311, D31xConfigAckMessage.class);//单片机配置应答
types.put((short)0xd31A, D31xConfigAckMessage.class);//DTU配置应答
}
public BaseMessage parse(ByteBuf src) throws Exception {
short flag = src.getShort(0);
Class<? extends BaseMessage> clz = types.get(flag);
if (clz == null) {
throw new UnSupportedMessageException();
}
BaseMessage message = clz.newInstance();
message.decode(src);
return message;
}
}

View File

@ -0,0 +1,81 @@
package com.imdroid.sideslope.message;
import com.imdroid.sideslope.util.WrongMessageRecorder;
import io.netty.buffer.ByteBuf;
/**
* @author Layton
* @date 2023/2/2 20:32
*/
public abstract class BaseMessage {
protected byte[] header;
protected String id;
protected int len;
protected int pps;
protected byte[] srcData;//message在线程中处理需要把channel传递过来的数据拷贝出来
public void decode(ByteBuf src) {
if (shouldDecodeHeader()) {
// read操作会移动ByteBuf内部指针除D331外其他都用read来读
int packetLen = src.readableBytes();
this.header = new byte[2];
src.readBytes(header);
this.len = src.readUnsignedShort();
this.id = String.valueOf(src.readUnsignedInt());
if (packetLen - 4 != this.len) {
String msg = (String.format("id[%s],长度字段值[%s]与包的消息体长度[%s]不匹配", id, this.len, packetLen - 4));
WrongMessageRecorder.INSTANCE.append("receive wrong message," + msg);
}
this.pps = src.readUnsignedShort();
}
decodeBody(src);
}
public abstract void decodeBody(ByteBuf src);
public boolean shouldDecodeHeader() {
return true;
}
public byte[] getHeader() {
return header;
}
public void setHeader(byte[] header) {
this.header = header;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getLen() {
return len;
}
public void setLen(int len) {
this.len = len;
}
public int getPps() {
return pps;
}
public void setPps(int pps) {
this.pps = pps;
}
public byte[] getSrcData() {
return srcData;
}
public void setSrcData(byte[] srcData) {
this.srcData = srcData;
}
}

View File

@ -0,0 +1,31 @@
package com.imdroid.sideslope.message;
import com.imdroid.sideslope.util.WrongMessageRecorder;
import io.netty.buffer.ByteBuf;
/**
* @author Layton
* @date 2023/2/2 20:47
*/
public class D31xConfigAckMessage extends BaseMessage {
@Override
public void decodeBody(ByteBuf src) {
// get操作不会移动指针这样可以确保整个全转发出去
this.header = new byte[2];
src.getBytes(0, header); // flag
this.len = src.getUnsignedShort(2); // length
this.id = String.valueOf(src.getUnsignedInt(4)); //id
if (src.readableBytes() - 4 != this.len) {
String msg = String.format("id[%s],长度字段值[%s]与包的消息体长度[%s]不匹配", id, this.len, src.readableBytes() - 4);
WrongMessageRecorder.INSTANCE.append("receive wrong message," + msg);
}
this.srcData = new byte[src.readableBytes()];
src.readBytes(this.srcData);
}
@Override
public boolean shouldDecodeHeader() {
return false;
}
}

View File

@ -0,0 +1,31 @@
package com.imdroid.sideslope.message;
import com.imdroid.sideslope.util.WrongMessageRecorder;
import io.netty.buffer.ByteBuf;
/**
* @author Layton
* @date 2023/2/2 20:47
*/
public class D331RtcmMessage extends BaseMessage {
@Override
public void decodeBody(ByteBuf src) {
// get操作不会移动指针这样可以确保整个全转发出去
this.header = new byte[2];
src.getBytes(0, header); // flag
this.len = src.getUnsignedShort(2); // length
this.id = String.valueOf(src.getUnsignedInt(4)); //id
if (src.readableBytes() - 4 != this.len) {
String msg = String.format("id[%s],长度字段值[%s]与包的消息体长度[%s]不匹配", id, this.len, src.readableBytes() - 4);
WrongMessageRecorder.INSTANCE.append("receive wrong message," + msg);
}
this.srcData = new byte[src.readableBytes()];
src.readBytes(this.srcData);
}
@Override
public boolean shouldDecodeHeader() {
return false;
}
}

View File

@ -0,0 +1,25 @@
package com.imdroid.sideslope.message;
import com.imdroid.sideslope.bd.Tilt;
import com.imdroid.sideslope.bd.UBXUtil;
import com.imdroid.sideslope.util.WrongMessageRecorder;
import io.netty.buffer.ByteBuf;
import lombok.Data;
/**
* @author Layton
* @date 2023/2/2 20:50
*/
@Data
public class D341LocationMessage extends BaseMessage {
Tilt tilt;
double[] b562_loc;
@Override
public void decodeBody(ByteBuf src) {
// 读到pitch了readable不不含pitch之前
tilt = new Tilt(src.readFloat(), src.readFloat(),src.readFloat(),src.readFloat());
// b562
b562_loc = UBXUtil.getLocation(src);
}
}

View File

@ -0,0 +1,40 @@
package com.imdroid.sideslope.message;
import com.imdroid.secapi.dto.GnssStatusMsg;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import java.sql.Timestamp;
/**
* 自检消息
*
* @author Layton
* @date 2023/2/2 20:38
*/
@Data
public class D3F0SelfCheckMessage extends BaseMessage {
GnssStatusMsg statusMsg = new GnssStatusMsg();
@Override
public void decodeBody(ByteBuf src) {
statusMsg.setDeviceid(getId());
statusMsg.setUpdatetime(new Timestamp(System.currentTimeMillis()));
statusMsg.setDevicetime(new Timestamp(getPps()*1000));
statusMsg.setPitch(src.readFloat());
statusMsg.setRoll(src.readFloat());
statusMsg.setYaw(src.readFloat());
// skip shock
src.readFloat();
statusMsg.setDtustate(src.readUnsignedByte());
statusMsg.setRssi(src.readUnsignedByte());
statusMsg.setVoltage(src.readUnsignedShort());
// skip version
src.readUnsignedShort();
statusMsg.setTemperature(src.readUnsignedShort()/10);
statusMsg.setHumidity(src.readUnsignedShort()/10);
}
}

View File

@ -0,0 +1,44 @@
package com.imdroid.sideslope.message;
import com.imdroid.secapi.dto.GnssTrxMsg;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import java.sql.Timestamp;
/**
* 停止指示消息
*
* @author LiGang
*/
@Data
public class D3F2StopIndicationMessage extends BaseMessage {
private GnssTrxMsg trxMsg = new GnssTrxMsg();;
@Override
public void decodeBody(ByteBuf src) {
trxMsg.setDeviceid(getId());
trxMsg.setUpdatetime(new Timestamp(System.currentTimeMillis()));
trxMsg.setDevicetime(new Timestamp(getPps()*1000));
int keys = (this.len - 6) / 5;
for (int i = 0; i < keys; i++) {
int key = src.readUnsignedByte();
long value = src.readUnsignedInt();
if (key == 0) {
trxMsg.setUart1txbytes(value);
} else if (key == 1) {
trxMsg.setUart1rxbytes(value);
} else if (key == 2) {
trxMsg.setUart1unknown(value);
} else if (key == 3) {
trxMsg.setUart2txbytes(value);
} else if (key == 4) {
trxMsg.setUart2rxbytes(value);
} else if (key == 5) {
trxMsg.setUart2unknown(value);
}
}
}
}

View File

@ -0,0 +1,36 @@
package com.imdroid.sideslope.rabbitmq;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* rabbitmq 配置类
*
* @author LiGang
*/
@Configuration
public class RabbitmqConfig {
public static final String QUEUE_GNSS_LOCATION_RECORD = "gnss_location_record";
public static final String EXCHANGE_GNSS = "exchange_gnss";
/**
* 声明交换机
*/
@Bean(EXCHANGE_GNSS)
public Exchange EXCHANGE_GNSS() {
return ExchangeBuilder.topicExchange(EXCHANGE_GNSS).durable(true).build();
}
/**
* 声明QUEUE_INFORM_EMAIL队列
* @return Queue
*/
@Bean(QUEUE_GNSS_LOCATION_RECORD)
public Queue QUEUE_INFORM_EMAIL() {
return new Queue(QUEUE_GNSS_LOCATION_RECORD);
}
}

View File

@ -0,0 +1,80 @@
package com.imdroid.sideslope.sal;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.imdroid.secapi.dto.GnssDevice;
import com.imdroid.secapi.dto.GnssDeviceMapper;
import com.imdroid.sideslope.service.GNSSDeviceLocationRecordService;
import com.imdroid.sideslope.util.ThreadManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 描述
*
* @author LiGang
*/
@Component(value = "db")
public class DbDeviceServiceImpl implements DeviceService {
private final Logger logger = LoggerFactory.getLogger(DbDeviceServiceImpl.class);
@Autowired
private GnssDeviceMapper gnssDeviceRepository;
@Autowired
private GNSSDeviceLocationRecordService gnssDeviceLocationRecordService;
@Override
public Device findByDeviceId(String deviceId) {
GnssDevice gnssDevice = gnssDeviceRepository.queryByDeviceId(deviceId);
if (gnssDevice == null) {
return null;
}
Device device = new Device();
device.setDeviceId(gnssDevice.getDeviceid());
device.setDeviceType(gnssDevice.getDevicetype());
device.setParentId(gnssDevice.getParentid());
device.setName(gnssDevice.getName());
return device;
}
@Override
public List<Device> findByParentId(String parentId) {
QueryWrapper<GnssDevice> query = new QueryWrapper();
query.eq("parentid", parentId);
List<GnssDevice> gnssDeviceList = gnssDeviceRepository.selectList(query);
List<Device> deviceList = new ArrayList<>(gnssDeviceList.size());
for (GnssDevice gnssDevice : gnssDeviceList) {
Device device = new Device();
device.setDeviceId(gnssDevice.getDeviceid());
device.setDeviceType(gnssDevice.getDevicetype());
device.setParentId(gnssDevice.getParentid());
device.setName(gnssDevice.getName());
deviceList.add(device);
}
return deviceList;
}
@Override
public boolean postLocationRecord(LocationRecordDTO locationRecord) {
ThreadManager.getFixedThreadPool().submit(() -> {
try {
gnssDeviceLocationRecordService.save(locationRecord);
} catch (Exception e) {
logger.error(e.toString());
}
});
return true;
}
@Override
public void updateLatestDataTime(String deviceId, Date latestDataTime) {
}
}

View File

@ -0,0 +1,32 @@
package com.imdroid.sideslope.sal;
import lombok.Data;
/**
* 基站 & 测站设备
*
* @author Layton
* @date 2023/2/3 20:39
*/
@Data
public class Device {
/**
* 基站
*/
public static final int DEVICE_BASE_STATION = 1;
/**
* 测站
*/
public static final int DEVICE_ROVER = 0;
private String name;
private String deviceId;
private String parentId;
private Integer deviceType;
}

View File

@ -0,0 +1,19 @@
package com.imdroid.sideslope.sal;
import java.util.Date;
import java.util.List;
/**
* @author Layton
* @date 2023/2/3 20:37
*/
public interface DeviceService {
Device findByDeviceId(String deviceId);
List<Device> findByParentId(String parentId);
boolean postLocationRecord(LocationRecordDTO locationRecord);
void updateLatestDataTime(String deviceId, Date latestDataTime);
}

View File

@ -0,0 +1,61 @@
package com.imdroid.sideslope.sal;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @author Layton
* @date 2023/2/3 20:46
*/
@Component(value = "local")
public class LocalDeviceServiceImpl implements DeviceService {
private static final Cache<String, Device> deviceCache = CacheBuilder.newBuilder().
expireAfterWrite(30, TimeUnit.MINUTES).build();
private static final Cache<String, List<Device>> subDeviceCache = CacheBuilder.newBuilder().
expireAfterWrite(10, TimeUnit.MINUTES).build();
@Resource(name = "db")
private DeviceService delegate;
@Override
public Device findByDeviceId(String deviceId) {
Device device = deviceCache.getIfPresent(deviceId);
if (device == null) {
device = delegate.findByDeviceId(deviceId);
if (device != null) {
deviceCache.put(deviceId, device);
}
}
return device;
}
@Override
public List<Device> findByParentId(String parentId) {
List<Device> device = subDeviceCache.getIfPresent(parentId);
if (device == null) {
device = delegate.findByParentId(parentId);
if (device != null) {
subDeviceCache.put(parentId, device);
}
}
return device;
}
@Override
public boolean postLocationRecord(LocationRecordDTO locationRecord) {
return delegate.postLocationRecord(locationRecord);
}
@Override
public void updateLatestDataTime(String deviceId, Date latestDataTime) {
delegate.updateLatestDataTime(deviceId, latestDataTime);
}
}

View File

@ -0,0 +1,81 @@
package com.imdroid.sideslope.sal;
/**
* @author Layton
* @date 2023/2/15 20:58
*/
public class LocationRecordDTO {
private String deviceId;
/**
* 北斗位置(b562)相对坐标
*/
private String b562;
/**
* 惯导位置(9250)相对坐标
*/
private String r9250;
/**
* 融合位置相对坐标
*/
private String result;
private String flag;
public LocationRecordDTO() {
}
public LocationRecordDTO(String deviceId, String b562, String r9250, String result, String flag) {
this.deviceId = deviceId;
this.b562 = b562;
this.r9250 = r9250;
this.result = result;
this.flag = flag;
}
public String getFlag() {
return flag;
}
public void setFlag(String flag) {
this.flag = flag;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getB562() {
return b562;
}
public void setB562(String b562) {
this.b562 = b562;
}
public String getR9250() {
return r9250;
}
public void setR9250(String r9250) {
this.r9250 = r9250;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
}

View File

@ -0,0 +1,61 @@
package com.imdroid.sideslope.server;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.socket.DatagramPacket;
import lombok.Data;
import java.net.InetSocketAddress;
/**
* @author Layton
* @date 2023/2/2 21:00
*/
@Data
public class DeviceChannel {
private String deviceId;
private Channel channel;
private InetSocketAddress address;
private long lastTime;
private boolean tcp;
int txbytes = 0;
int rxbytes = 0;
int d3xxbytes = 0;
int b562bytes = 0;
public DeviceChannel(String deviceId, Channel channel, InetSocketAddress address) {
this.deviceId = deviceId;
this.channel = channel;
this.address = address;
lastTime = System.currentTimeMillis();
this.tcp = address == null;
}
public boolean isOnline() {
if (tcp) {
return channel.isActive();
}
// return (System.currentTimeMillis() - lastTime) < 28 * 1000L;
return true;
}
public void writeAndFlush(ByteBuf buf) {
txbytes += buf.readableBytes();
if (tcp) {
channel.writeAndFlush(buf);
} else {
channel.writeAndFlush(new DatagramPacket(buf, address));
}
}
public void updateRxBytes(int bytes, byte[] header){
rxbytes += bytes;
int gnss_bytes = header[0]<<8 | header[1];
if(gnss_bytes == 0xd331) d3xxbytes += bytes;
else if(gnss_bytes == 0xd341) b562bytes += bytes;
}
}

View File

@ -0,0 +1,62 @@
package com.imdroid.sideslope.server;
import cn.hutool.core.collection.ConcurrentHashSet;
import io.netty.channel.Channel;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* @author Layton
* @date 2023/2/2 21:00
*/
public class OnlineChannels {
public static final OnlineChannels INSTANCE = new OnlineChannels();
// DTU已连接有imei上报但deviceId还没上报
// 记录DTU连接的好处当DTU重连接而设备还没上报deviceId时可以通过IMEI或广播消息来找到设备
private final Map<String, Channel> dtuChannels = new ConcurrentHashMap<>();
// 设备已连接deviceId已上报
private final Map<String, DeviceChannel> channels = new ConcurrentHashMap<>();
private OnlineChannels() {}
public boolean isNewChannel(Channel channel){
Attribute<String> attr = channel.attr(AttributeKey.valueOf("imei"));
return (attr.get()==null);
}
public boolean isNewDeviceChannel(Channel channel){
Attribute<String> attr = channel.attr(AttributeKey.valueOf("device_id"));
return (attr.get()==null);
}
public void putDtuChannel(Channel channel, String imei){
dtuChannels.put(imei, channel);
Attribute<String> attr = channel.attr(AttributeKey.valueOf("imei"));
attr.set(imei);
}
public void putDeviceChannel(DeviceChannel channel) {
Attribute<String> attr = channel.getChannel().attr(AttributeKey.valueOf("device_id"));
attr.set(channel.getDeviceId());
channels.put(channel.getDeviceId(), channel);
}
public Optional<DeviceChannel> get(String deviceId) {
return Optional.ofNullable(channels.get(deviceId));
}
public List<DeviceChannel> getIfPresent(List<String> deviceIds) {
return deviceIds.stream().map(x -> channels.get(x)).filter(Objects::nonNull).collect(Collectors.toList());
}
public DeviceChannel getDeviceChannel(String deviceId){
return channels.get(deviceId);
}
}

View File

@ -0,0 +1,88 @@
package com.imdroid.sideslope.server.udp;
import com.imdroid.sideslope.exception.UnSupportedMessageException;
import com.imdroid.sideslope.executor.BizExecutors;
import com.imdroid.sideslope.executor.MessageParser;
import com.imdroid.sideslope.message.BaseMessage;
import com.imdroid.sideslope.server.DeviceChannel;
import com.imdroid.sideslope.server.OnlineChannels;
import com.imdroid.sideslope.util.DataTypeUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.ReferenceCountUtil;
import org.apache.ibatis.javassist.bytecode.ByteArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Optional;
/**
* @author Layton
* @date 2023/2/13 11:47
*/
@ChannelHandler.Sharable
@Component
public class RtcmUdpHandler extends ChannelInboundHandlerAdapter {
private static final Logger logger = LoggerFactory.getLogger(RtcmUdpHandler.class);
@Autowired
private BizExecutors bizExecutors;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
DatagramPacket packet = (DatagramPacket) msg;
OnlineChannels onlineChannels = OnlineChannels.INSTANCE;
try {
if (packet.content() == null) {
return;
}
if (logger.isDebugEnabled()) {
byte[] data = new byte[packet.content().readableBytes()];
packet.content().getBytes(0, data);
logger.debug("receive message:" + DataTypeUtil.getHexString(data));
}
// 消息解析
BaseMessage message = MessageParser.instance.parse(packet.content());
// 更新通道
DeviceChannel deviceChannel;
if(onlineChannels.isNewDeviceChannel(ctx.channel())){
deviceChannel = new DeviceChannel(message.getId(), ctx.channel(), packet.sender());
onlineChannels.putDeviceChannel(deviceChannel);
}
else{
deviceChannel = onlineChannels.getDeviceChannel(message.getId());
}
deviceChannel.updateRxBytes(message.getLen(), message.getHeader());
// 业务处理
bizExecutors.execute(message);
} catch (UnSupportedMessageException e) {
// DTU注册消息
if(onlineChannels.isNewChannel(ctx.channel())){
byte[] data = new byte[packet.content().readableBytes()];
packet.content().getBytes(0, data);
if(data.length == 15 && data[0]=='8' && data[1]=='6') {
OnlineChannels.INSTANCE.putDtuChannel(ctx.channel(), new String(data));
}
else logger.warn("receive un supported message: {}", e.getMessage());
}
else logger.warn("receive un supported message: {}", e.getMessage());
} catch (Exception e) {
logger.error("channel read error: {}", e.toString());
} finally {
ReferenceCountUtil.release(msg);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
ctx.close();
logger.error("Exception caught: {}", cause.toString());
}
}

View File

@ -0,0 +1,60 @@
package com.imdroid.sideslope.server.udp;
import io.netty.bootstrap.Bootstrap;
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.NioDatagramChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
/**
* @author Layton
* @date 2023/2/13 11:47
*/
@Component
public class RtcmUdpServer implements ApplicationRunner {
private final Logger logger = LoggerFactory.getLogger(RtcmUdpServer.class);
@Value("${netty.port:9903}")
private Integer port;
@Autowired
private RtcmUdpHandler rtcmUdpHandler;
public RtcmUdpServer() {
}
@Override
public void run(ApplicationArguments args) throws Exception {
new Thread(this::start0, "udp-server").start();
}
private void start0() {
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioDatagramChannel.class)
.option(ChannelOption.SO_SNDBUF, 512)
.option(ChannelOption.SO_RCVBUF, 512)
.handler(rtcmUdpHandler);
try {
ChannelFuture future = bootstrap.bind(port).sync().channel().closeFuture();
logger.info("udp server start at port {}", port);
future.await();
} catch (Exception e) {
logger.error("Error starting Imdroid protocol at port {}", port, e);
} finally {
group.shutdownGracefully();
}
}
}

View File

@ -0,0 +1,16 @@
package com.imdroid.sideslope.service;
import com.imdroid.sideslope.message.D3F0SelfCheckMessage;
import com.imdroid.sideslope.message.D3F2StopIndicationMessage;
/**
* 设备数据持久化接口
*
* @author LiGang
*/
public interface DataPersistService {
void saveDeviceState(D3F0SelfCheckMessage d3F0SelfCheckMessage);
void saveDeviceTrxStat(D3F2StopIndicationMessage d3F2StopIndicationMessage);
}

View File

@ -0,0 +1,86 @@
package com.imdroid.sideslope.service;
import com.imdroid.secapi.dto.*;
import com.imdroid.sideslope.message.D3F0SelfCheckMessage;
import com.imdroid.sideslope.message.D3F2StopIndicationMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 设备数据持久化实现
*
* @author LiGang
*/
@Service
public class DataPersistServiceImpl implements DataPersistService {
@Autowired
private GnssStatusMapper deviceStateRepository;
@Autowired
private GnssStatusMsgMapper statusMsgMapper;
@Autowired
private GnssTrxMsgMapper trxMsgMapper;
@Override
public void saveDeviceState(D3F0SelfCheckMessage message) {
try {
// 保存到statusmsg数据表里
GnssStatusMsg statusMsg = message.getStatusMsg();
statusMsgMapper.insert(statusMsg);
//新增或更新到status数据表里
GnssStatus deviceState = deviceStateRepository.getByDeviceId(message.getId());
boolean new_flag = false;
if(null == deviceState) {
deviceState = new GnssStatus();
new_flag = true;
}
//deviceState.setId(SequenceUtil.getSequence());
deviceState.setDeviceid(message.getId());
deviceState.setUpdatetime(statusMsg.getUpdatetime());
deviceState.setRoll(statusMsg.getRoll());
deviceState.setPitch(statusMsg.getPitch());
deviceState.setYaw(statusMsg.getYaw());
deviceState.setRssi(statusMsg.getRssi());
deviceState.setVoltage(statusMsg.getVoltage());
deviceState.setTemperature(statusMsg.getTemperature());
deviceState.setHumidity(statusMsg.getHumidity());
// 检测状态和告警
deviceState.setState(GnssStatus.STATE_ACTIVE);
if(new_flag) deviceStateRepository.insert(deviceState);
else deviceStateRepository.updateById(deviceState);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void saveDeviceTrxStat(D3F2StopIndicationMessage message) {
try {
// 添加到trxmsg里
trxMsgMapper.insert(message.getTrxMsg());
// 检测该对象是否已存在
GnssStatus deviceState = deviceStateRepository.getByDeviceId(message.getId());
//新增或更新到status数据表里
if(null != deviceState) {
// 记录服务端收发统计
/*deviceState.setTxbytes(txbytes);
deviceState.setRxbytes(rxbytes);
deviceState.setD3xxbytes(d3xxbytes);
deviceState.setB562bytes(b562bytes);*/
deviceState.setState(GnssStatus.STATE_IDLE);
deviceStateRepository.updateById(deviceState);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,15 @@
package com.imdroid.sideslope.service;
import com.imdroid.sideslope.message.D341LocationMessage;
import com.imdroid.sideslope.sal.LocationRecordDTO;
/**
* @author Layton
* @date 2023/2/4 20:18
*/
public interface GNSSDeviceLocationRecordService {
public void save(LocationRecordDTO importRecord) throws Exception;
public void saveSingleCalcData(D341LocationMessage message);
}

View File

@ -0,0 +1,198 @@
package com.imdroid.sideslope.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.imdroid.secapi.dto.*;
import com.imdroid.sideslope.bd.Tilt;
import com.imdroid.sideslope.message.D341LocationMessage;
import com.imdroid.sideslope.rabbitmq.RabbitmqConfig;
import com.imdroid.sideslope.sal.LocationRecordDTO;
import com.imdroid.sideslope.util.GsonUtil;
import com.imdroid.sideslope.util.NumberUtils;
import io.dt20.common.persistence.Attribute;
import io.dt20.common.repo.AttributeRepository;
import io.dt20.util.SequenceUtil;
import io.dt20.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
/**
* @author Layton
* @date 2023/2/15 21:05
*/
@Service
public class GNSSDeviceLocationRecordServiceImpl implements GNSSDeviceLocationRecordService{
private final Logger logger = LoggerFactory.getLogger(this.getClazz());
@Autowired
private GnssCalcDataMapper repository;
@Autowired
private GnssSingleCalcDataMapper singleCalcDataMapper;
@Autowired
private GnssDeviceMapper gnssDeviceRepository;
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private AttributeRepository attributeRepository;
private int a, b = 25 * 60 * 60 * 1000;
protected Class<GnssCalcData> getClazz() {
return GnssCalcData.class;
}
@Override
public void save(LocationRecordDTO importRecord) throws Exception {
GnssDevice gnssDevice = gnssDeviceRepository.queryByDeviceId(importRecord.getDeviceId());
GnssCalcData locationRecord = new GnssCalcData();
locationRecord.setDeviceid(importRecord.getDeviceId());
locationRecord.setCreatetime(new Timestamp(System.currentTimeMillis()));
locationRecord.setEnabled(true);
locationRecord.setId(SequenceUtil.getSequence());
if (!StringUtil.isEmpty(importRecord.getB562())) {
String resultStr = NumberUtils.removeBrackets(importRecord.getB562());
String[] arr = resultStr.split(",");
// 由cm转化为mm
locationRecord.setB562e(NumberUtils.scaleTwo(Double.parseDouble(arr[0]) * 10));
locationRecord.setB562n(NumberUtils.scaleTwo(Double.parseDouble(arr[1]) * 10));
locationRecord.setB562d(NumberUtils.scaleTwo(Double.parseDouble(arr[2]) * 10));
}
if (!StringUtil.isEmpty(importRecord.getR9250())) {
String resultStr = NumberUtils.removeBrackets(importRecord.getR9250());
String[] arr = resultStr.split(",");
locationRecord.setR9250e(NumberUtils.scaleTwo(arr[0]));
locationRecord.setR9250n(NumberUtils.scaleTwo(arr[1]));
locationRecord.setR9250d(NumberUtils.scaleTwo(arr[2]));
}
if (!StringUtil.isEmpty(importRecord.getResult())) {
String resultStr = NumberUtils.removeBrackets(importRecord.getResult());
String[] arr = resultStr.split(",");
locationRecord.setResulte(NumberUtils.scaleTwo(arr[0]));
locationRecord.setResultn(NumberUtils.scaleTwo(arr[1]));
locationRecord.setResultd(NumberUtils.scaleTwo(arr[2]));
// 做滤波 水平方向按照shock >1.5 用6h滤波 否则用25h
// 垂直方向 用6+12
List<Attribute> attributes = attributeRepository.findByObjectAndPid(gnssDevice.getObjectName(), gnssDevice.getId());
if (!StringUtil.isEmpty(importRecord.getFlag()) && Boolean.parseBoolean(importRecord.getFlag())) {
a = 6 * 60 * 60 * 1000;
b = 6 * 60 * 60 * 1000;
}
for (Attribute attribute : attributes) {
if (attribute.getValueNumber() == null) {
continue;
}
double[] avgEND = avgEND(gnssDevice.getDeviceid(), locationRecord, a, b);
if (ATTR_B562E.equals(attribute.getKey())) {
locationRecord.setRb562e(NumberUtils.scaleTwo(avgEND[0] * 10 - attribute.getValueNumber()));
}
if (ATTR_B562N.equals(attribute.getKey())) {
locationRecord.setRb562n(NumberUtils.scaleTwo(avgEND[1] * 10 - attribute.getValueNumber()));
}
if (ATTR_B562D.equals(attribute.getKey())) {
locationRecord.setRb562d(NumberUtils.scaleTwo(avgEND[2] * 10 - attribute.getValueNumber()));
}
}
a = 25 * 60 * 60 * 1000;
b = 25 * 60 * 60 * 1000;
}
sendDataToMq(locationRecord);
repository.insert(locationRecord);
}
public static final String ATTR_B562E = "b562e";
public static final String ATTR_B562N = "b562n";
public static final String ATTR_B562D = "b562d";
/**
* 计算东北天的最近融合数据的加权平均, 刘畅20230725 copy avgEND; id>20, 滤波参数6h 25h
*/
public double[] avgEND(String deviceId, GnssCalcData last, int a, int b) {
//double c = 0.5467;
double c = 0.5;
ArrayList<GnssCalcData> gnssDeviceLocationRecords = new ArrayList<>();
QueryWrapper<GnssCalcData> wrapper = new QueryWrapper<>();
wrapper.eq("deviceid",deviceId);
wrapper.last("limit 20");
List<GnssCalcData> GNSSDeviceLocationRecords = repository.selectList(wrapper);
gnssDeviceLocationRecords.addAll(GNSSDeviceLocationRecords);
if (gnssDeviceLocationRecords.size() > 0) {
double sumE = last.getResulte(), sumE2 = last.getResulte();
double sumN = last.getResultn(), sumN2 = last.getResultn();
double sumD = last.getResultd(), sumD2 = last.getResultd();
double[] lastLocation = {last.getResulte(), last.getResultn(), last.getResultd()};
int count = 1, count2 = 1;
for (int i = 0; i < gnssDeviceLocationRecords.size(); i++) {
double[] findLocation = {gnssDeviceLocationRecords.get(i).getResulte(), gnssDeviceLocationRecords.get(i).getResultn(), gnssDeviceLocationRecords.get(i).getResultd()};
if (disXY(lastLocation, findLocation) > 100) {
continue;
}
long time = System.currentTimeMillis() - gnssDeviceLocationRecords.get(i).getCreatetime().getTime();
if (time < a) {
sumE += gnssDeviceLocationRecords.get(i).getResulte();
sumN += gnssDeviceLocationRecords.get(i).getResultn();
sumD += gnssDeviceLocationRecords.get(i).getResultd();
count++;
}
if (time < b) {
sumE2 += gnssDeviceLocationRecords.get(i).getResulte();
sumN2 += gnssDeviceLocationRecords.get(i).getResultn();
sumD2 += gnssDeviceLocationRecords.get(i).getResultd();
count2++;
}
}
double e = sumE / count * c + sumE2 / count2 * (1 - c);
double n = sumN / count * c + sumN2 / count2 * (1 - c);
double d = sumD / count * c + sumD2 / count2 * (1 - c);
return new double[]{e, n, d};
} else {
return new double[]{last.getResulte(), last.getResultn(), last.getResultd()};
}
}
public static double disXY(double[] a, double[] b) {
return Math.sqrt(Math.pow(a[0] - b[0], 2) + Math.pow(a[1] - b[1], 2));
}
private void sendDataToMq(GnssCalcData locationRecord) {
String message = GsonUtil.toJson(locationRecord);
rabbitTemplate.convertAndSend(RabbitmqConfig.EXCHANGE_GNSS, RabbitmqConfig.QUEUE_GNSS_LOCATION_RECORD, message);
}
@Override
public void saveSingleCalcData(D341LocationMessage message){
GnssSingleCalcData data = new GnssSingleCalcData();
data.setDeviceid(message.getId());
data.setCreatetime(new Timestamp(System.currentTimeMillis()));
Tilt tilt = message.getTilt();
data.setRoll(tilt.getRoll());
data.setPitch(tilt.getPitch());
data.setYaw(tilt.getYaw());
data.setShock(tilt.getShock());
double[] b562_loc = message.getB562_loc();
if(b562_loc!=null) {
data.setB562e(b562_loc[0]);
data.setB562n(b562_loc[1]);
data.setB562d(b562_loc[2]);
}
singleCalcDataMapper.insert(data);
}
}

View File

@ -0,0 +1,393 @@
package com.imdroid.sideslope.util;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
/**
* @author Layton
* @date 2022/3/21 15:36
*/
public class DataTypeUtil {
public static byte[] intToByteLittle(int n) {
byte[] b = new byte[4];
b[0] = (byte) (n & 0xff);
b[1] = (byte) (n >> 8 & 0xff);
b[2] = (byte) (n >> 16 & 0xff);
b[3] = (byte) (n >> 24 & 0xff);
return b;
}
public static byte[] intToByteBig(int number) {
byte[] b = new byte[4];
b[0] = (byte) (number >> 24);
b[1] = (byte) (number >> 16);
b[2] = (byte) (number >> 8);
b[3] = (byte) number;
return b;
}
public static byte[] floatToByteLittle(float n) {
int fbit = Float.floatToIntBits(n);
return intToByteLittle(fbit);
}
public static byte[] floatToByteBig(float n) {
int fbit = Float.floatToIntBits(n);
return intToByteBig(fbit);
}
/**
* 将byte数组转换为long数据 (大端模式)
*
* @param data
* length为8的byte数组
* @return
*/
public static long byteToLong(byte[] data) {
ByteBuffer buffer = ByteBuffer.allocate(8);
buffer.put(data, 0, 8);
buffer.flip();
return buffer.getLong();
}
/**
* 将byte数组转换为long数据 (大端模式)
*
* @param data
* length为8的byte数组
* @return
*/
public static long byteToLong(byte[] data, int offset) {
ByteBuffer buffer = ByteBuffer.allocate(8);
buffer.put(data, offset, 8);
buffer.flip();
return buffer.getLong();
}
/**
* 将byte数组转为int数据 (大端模式)
*
* @param data
* length为4的byte数组
* @return
*/
public static int byteToInt(byte[] data) {
ByteBuffer buffer = ByteBuffer.allocate(4);
buffer.put(data, 0, 4);
buffer.flip();
return buffer.getInt();
}
/**
* 将byte数组转为int数据 (大端模式)
*
* @param data
* length为4的byte数组
* @return
*/
public static int byteToInt(byte[] data, int offset) {
ByteBuffer buffer = ByteBuffer.allocate(4);
buffer.put(data, offset, 4);
buffer.flip();
return buffer.getInt();
}
/**
* 将byte数组转为short数据 (大端模式)
*
* @param data
* length为2的byte数组
* @return
*/
public static short byteToShort(byte[] data) {
ByteBuffer buffer = ByteBuffer.allocate(2);
buffer.put(data, 0, 2);
buffer.flip();
return buffer.getShort();
}
/**
* 将byte数组转为float数据(大端模式)
*
* @param data
* length为4的byte数组
* @return
*/
public static float bytesToFloat(byte[] data) {
int value = byteToInt(data);
return Float.intBitsToFloat(value);
}
/**
* 将byte数组转为float数据(小端模式)
*
* @param data
* length为4的byte数组
* @return
*/
public static float lowBytesToFloat(byte[] data) {
int len = data.length;
// 获得一个反的数组
byte[] dest = new byte[len];
for (int i = 0; i < len; i++) {
dest[len - i - 1] = data[i];
}
int value = byteToInt(dest);
return Float.intBitsToFloat(value);
}
/**
* byte数组大小端反转
*
* @param bytes 数据
*/
public static void bytesReverse(byte[] bytes) {
int half = bytes.length / 2;
for (int i = 0; i < half; i++) {
byte temp = bytes[i];
bytes[i] = bytes[bytes.length - i - 1];
bytes[bytes.length - i - 1] = temp;
}
}
/**
* 将long转为byte数组 (大端模式)
*
* @param number
* @return
*/
public static byte[] longToByte(long number) {
byte[] b = new byte[8];
b[0] = (byte) (number >> 56);
b[1] = (byte) (number >> 48);
b[2] = (byte) (number >> 40);
b[3] = (byte) (number >> 32);
b[4] = (byte) (number >> 24);
b[5] = (byte) (number >> 16);
b[6] = (byte) (number >> 8);
b[7] = (byte) number;
return b;
}
/**
* 将short转为byte数组 (小端模式)
*
* @param number
* @return
*/
public static byte[] shortToByteLittle(short number) {
byte[] src = new byte[2];
src[1] = (byte) ((number >> 8) & 0xFF);
src[0] = (byte) (number & 0xFF);
return src;
}
/**
* 将short转为byte数组 (大端模式)
*
* @param number
* @return
*/
public static byte[] shortToByteBig(short number) {
byte[] src = new byte[2];
src[0] = (byte) ((number >> 8) & 0xFF);
src[1] = (byte) (number & 0xFF);
return src;
}
public static short byteToShort(byte byte0, byte byte1) {
return (short) (((byte0 & 0xff) << 8) | (byte1 & 0xff));
}
/**
* 将byte转换为一个长度为8的byte数组数组每个值代表bit
*
* @param b
* @return
*/
public static byte[] getBitArray(byte b) {
byte[] array = new byte[8];
for (int i = 7; i >= 0; i--) {
array[i] = (byte) (b & 1);
b = (byte) (b >> 1);
}
return array;
}
/**
* 把byte转为字符串的bit
*
* @param b
* @return
*/
public static String byteToBit(byte b) {
return ""
+ (byte) ((b >> 7) & 0x1) + (byte) ((b >> 6) & 0x1)
+ (byte) ((b >> 5) & 0x1) + (byte) ((b >> 4) & 0x1)
+ (byte) ((b >> 3) & 0x1) + (byte) ((b >> 2) & 0x1)
+ (byte) ((b >> 1) & 0x1) + (byte) ((b >> 0) & 0x1);
}
/**
* bit 转换为byte
*
* @param byteStr 位字符串
* @return
*/
public static byte bitToByte(String byteStr) {
int re, len;
if (null == byteStr) {
return 0;
}
len = byteStr.length();
if (len != 4 && len != 8) {
return 0;
}
if (len == 8) {// 8 bit处理
if (byteStr.charAt(0) == '0') {// 正数
re = Integer.parseInt(byteStr, 2);
} else {// 负数
re = Integer.parseInt(byteStr, 2) - 256;
}
} else {//4 bit处理
re = Integer.parseInt(byteStr, 2);
}
return (byte) re;
}
public static String getHexString(byte[] bs, int start, int end) {
StringBuilder stringBuilder = new StringBuilder("");
if (bs == null || bs.length <= 0) {
return null;
}
for (int i = start; i < end; i++) {
int v = bs[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
//bytes to string
public static String getHexString(byte[] bs) {
StringBuilder stringBuilder = new StringBuilder("");
if (bs == null || bs.length <= 0) {
return null;
}
for (int i = 0; i < bs.length; i++) {
int v = bs[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
//Hex String to bytes
public static byte[] hexStringToBytes(String hexString) {
if (hexString == null || "".equals(hexString)) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
public static String getString(byte[] bytes) {
return getString(bytes, "GBK");
}
public static String getUTFString(byte[] bytes) {
return new String(bytes);
}
public static String getString(byte[] bytes, String charsetName) {
return new String(bytes, Charset.forName(charsetName));
}
/**
* Ascii转换为字符串
*
* @param value
* @return
*/
public static String asciiToString(String value) {
StringBuilder sbu = new StringBuilder();
String[] chars = value.split(",");
for (int i = 0; i < chars.length; i++) {
sbu.append((char) Integer.parseInt(chars[i]));
}
return sbu.toString();
}
/**
* 浮点转换为字节 (小端模式)
*
* @param f
* @return
*/
public static byte[] floatTobyteLittle(float f) {
// 把float转换为byte[]
int fbit = Float.floatToIntBits(f);
byte[] b = new byte[4];
for (int i = 0; i < 4; i++) {
b[i] = (byte) (fbit >> (24 - i * 8));
}
// 翻转数组
int len = b.length;
// 建立一个与源数组元素类型相同的数组
byte[] dest = new byte[len];
// 为了防止修改源数组将源数组拷贝一份副本
System.arraycopy(b, 0, dest, 0, len);
byte temp;
// 将顺位第i个与倒数第i个交换
for (int i = 0; i < len / 2; ++i) {
temp = dest[i];
dest[i] = dest[len - i - 1];
dest[len - i - 1] = temp;
}
return dest;
}
}

View File

@ -0,0 +1,76 @@
package com.imdroid.sideslope.util;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.lang.reflect.Type;
/**
* @author Layton
* @date 2022/3/28 15:35
*/
public class GsonUtil {
private static final Gson gson = new Gson();
private static final Gson serializeNullGson = new GsonBuilder().serializeNulls().disableHtmlEscaping().create();
private static final Gson serializeExposeGson = new GsonBuilder().serializeNulls().excludeFieldsWithoutExposeAnnotation().create();
public static String toJsonSerializeNull(Object c) {
return serializeNullGson.toJson(c);
}
public static String toJson(Object c) {
return gson.toJson(c);
}
public static String toJsonExpose(Object c) {
return serializeExposeGson.toJson(c);
}
public static <T> T fromJson(String json, Class<T> clz) {
return gson.fromJson(json, clz);
}
public static <T> T fromJson(String json, Type typeOfT) {
return gson.fromJson(json, typeOfT);
}
public static String getValue(JsonObject jsonObject, String key) {
JsonElement element = jsonObject.has(key) ? jsonObject.get(key) : null;
if (element == null) {
return "";
}
if (element.isJsonObject()) {
return element.getAsJsonObject().toString();
} else if (element.isJsonNull()) {
return "";
} else if (element.isJsonArray()) {
return element.getAsJsonArray().toString();
} else {
if (element.getAsJsonPrimitive().isBoolean()) {
return element.getAsBoolean() ? "true" : "false";
} else {
return element.getAsString();
}
}
}
public static Number getNumber(JsonElement element) { ;
if (element == null) {
return null;
}
if (element.isJsonNull()) {
return null;
} else {
try {
return element.getAsNumber();
} catch (Exception e) {
return null;
}
}
}
}

View File

@ -0,0 +1,392 @@
package com.imdroid.sideslope.util;
import com.google.gson.JsonObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLContext;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* @author layton
* @date 2021/6/21
*/
public class HttpUtils {
private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
public HttpUtils() {
}
/**
* 多线程共享实例
*/
private static final CloseableHttpClient httpClient;
static {
SSLContext sslContext = createSSLContext();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
// 注册http套接字工厂和https套接字工厂
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", sslsf)
.build();
// 连接池管理器
PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
//连接池最大连接数
connMgr.setMaxTotal(50);
//每个路由最大连接数设置的过小无法支持大并发
connMgr.setDefaultMaxPerRoute(50);
//在从连接池获取连接时连接不活跃多长时间后需要进行一次验证
connMgr.setValidateAfterInactivity(5 * 1000);
// 请求参数配置管理器
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(60000)
.setSocketTimeout(60000)
.setConnectionRequestTimeout(60000)
.build();
// 获取httpClient客户端
httpClient = HttpClients.custom()
.setConnectionManager(connMgr)
.setDefaultRequestConfig(requestConfig)
.build();
}
/**
* GET请求
*
* @param url
* @return
*/
public static String getUrl(String url) {
return sendHttp(HttpMethod.GET, url, null, null);
}
/**
* GET请求
*
* @param url
* @return
*/
public static String getUrl(String url, Map<String, String> param, Map<String, String> header) {
return sendHttp(HttpMethod.GET, url, header, param);
}
/**
* GET请求/带头部的信息
*
* @param url
* @param header
* @return
*/
public static String getUrl(String url, Map<String, String> header) {
return sendHttp(HttpMethod.GET, url, header, null);
}
/**
* POST请求/无参数
*
* @param url
* @return
*/
public static String postJson(String url) {
return postJson(url, null, null);
}
/**
* POST请求/有参数
*
* @param url
* @param param
* @return
*/
public static String postJson(String url, String param) {
return postJson(url, null, param);
}
/**
* POST请求/有参数
*
* @param url
* @param param
* @return
*/
public static String postJsonObj(String url, JsonObject param) {
return postJsonObj(url, null, param);
}
/**
* POST请求/无参数带头部
*
* @param url
* @param header
* @return
*/
public static String postJson(String url, Map<String, String> header) {
return postJson(url, header, null);
}
/**
* POST请求/有参数带头部
*
* @param url
* @param header
* @param params
* @return
*/
public static String postJson(String url, Map<String, String> header, String params) {
return sendHttp(HttpMethod.POST, url, header, params);
}
/**
* POST请求/有参数带头部
*
* @param url
* @param header
* @param params
* @return
*/
public static String postJsonObj(String url, Map<String, String> header, JsonObject params) {
return sendHttp(HttpMethod.POST, url, header, params);
}
/**
* 从下载地址获取文件流(如果链接出现双斜杠请用OKHttp)
*
* @param url
* @return
*/
public static ByteArrayOutputStream getDownloadFileStream(String url) {
String infoMessage = new StringBuilder().append("request getDownloadFileStreamurl:").append(url).toString();
log.info(infoMessage);
ByteArrayOutputStream byteOutStream = null;
try {
CloseableHttpResponse response = httpClient.execute(new HttpGet(url));
log.info("getDownloadFileStream response status:{}", response.getStatusLine());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
//请求成功
HttpEntity entity = response.getEntity();
if (entity != null && entity.getContent() != null) {
//复制输入流
byteOutStream = cloneInputStream(entity.getContent());
}
}
HttpClientUtils.closeQuietly(response);
} catch (Exception e) {
log.error(infoMessage + " failure", e);
}
return byteOutStream;
}
/**
* 发送http请求(通用方法)
*
* @param httpMethod 请求方式GETPOSTPUTDELETE
* @param url 请求路径
* @param header 请求头
* @param params 请求bodyjson数据
* @return 响应文本
*/
public static String sendHttp(HttpMethod httpMethod, String url, Map<String, String> header, Object params) {
String infoMessage = new StringBuilder().append("request sendHttpurl:").append(url)
.append("method:").append(httpMethod.name()).append("header:")
.append(GsonUtil.toJson(header)).append("param:").append(params).toString();
if (log.isDebugEnabled()) {
log.debug(infoMessage);
}
//返回结果
String result = null;
long beginTime = System.currentTimeMillis();
try {
ContentType contentType = ContentType.APPLICATION_JSON.withCharset("UTF-8");
HttpRequestBase request = buildHttpMethod(httpMethod, url);
if (Objects.nonNull(header) && !header.isEmpty()) {
for (Map.Entry<String, String> entry : header.entrySet()) {
//打印头部信息
if (log.isDebugEnabled()) {
log.debug(entry.getKey() + ":" + entry.getValue());
}
request.setHeader(entry.getKey(), entry.getValue());
}
}
if (params != null) {
if (HttpMethod.POST.equals(httpMethod) || HttpMethod.PUT.equals(httpMethod)) {
if (params instanceof JsonObject || params instanceof String) {
String jsonString = params.toString();
if (jsonString != null && jsonString.length() > 0) {
((HttpEntityEnclosingRequest) request).setEntity(new StringEntity(jsonString, contentType));
}
} else {
Map<String, String> paramsHashMap = (Map<String, String>) params;
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
for (String key : paramsHashMap.keySet()) {
formparams.add(new BasicNameValuePair(key, paramsHashMap.get(key)));
}
((HttpEntityEnclosingRequest) request).setEntity(new UrlEncodedFormEntity(formparams, "UTF-8"));
}
}
}
CloseableHttpResponse response = httpClient.execute(request);
HttpEntity httpEntity = response.getEntity();
if (log.isDebugEnabled()) {
log.debug("sendHttp response status:{}", response.getStatusLine());
}
if (Objects.nonNull(httpEntity)) {
result = EntityUtils.toString(httpEntity, "UTF-8");
if (log.isDebugEnabled()) {
log.debug("sendHttp response body:{}", result);
}
}
//关闭返回对象
HttpClientUtils.closeQuietly(response);
} catch (Exception e) {
log.error(infoMessage + " failure", e);
}
long endTime = System.currentTimeMillis();
if (log.isDebugEnabled()) {
log.debug("request sendHttp response time cost:" + (endTime - beginTime) + " ms");
}
return result;
}
/**
* 请求方法全大些GET POST PUT DELETE
*/
public enum HttpMethod {
GET, POST, PUT, DELETE
}
/**
* 构建请求方法
*
* @param method
* @param url
* @return
*/
public static HttpRequestBase buildHttpMethod(HttpMethod method, String url) {
if (HttpMethod.GET.equals(method)) {
return new HttpGet(url);
} else if (HttpMethod.POST.equals(method)) {
return new HttpPost(url);
} else if (HttpMethod.PUT.equals(method)) {
return new HttpPut(url);
} else if (HttpMethod.DELETE.equals(method)) {
return new HttpDelete(url);
} else {
return null;
}
}
/**
* 配置证书
*
* @return
*/
public static SSLContext createSSLContext() {
try {
//信任所有,支持导入ssl证书
TrustStrategy acceptingTrustStrategy = (cert, authType) -> true;
SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
return sslContext;
} catch (Exception e) {
log.error("初始化ssl配置失败", e);
throw new RuntimeException("初始化ssl配置失败");
}
}
/**
* 复制文件流
*
* @param input
* @return
*/
public static ByteArrayOutputStream cloneInputStream(InputStream input) {
try {
ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = input.read(buffer)) > -1) {
byteOutStream.write(buffer, 0, len);
}
byteOutStream.flush();
return byteOutStream;
} catch (IOException e) {
log.warn("copy InputStream error,", e);
}
return null;
}
/**
* 输入流转字节流
*
* @param in
* @return
*/
public static byte[] inputStream2byte(InputStream in) {
ByteArrayOutputStream bos = null;
try {
bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int n;
while ((n = in.read(b)) != -1) {
bos.write(b, 0, n);
}
in.close();
bos.close();
byte[] buffer = bos.toByteArray();
return buffer;
} catch (IOException e) {
log.warn("inputStream transfer byte error,", e);
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
log.error("clone inputStream error", e);
}
try {
if (bos != null) {
bos.close();
}
} catch (IOException e) {
log.error("clone outputStream error", e);
}
}
return null;
}
}

View File

@ -0,0 +1,32 @@
package com.imdroid.sideslope.util;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* @author Layton
* @date 2023/2/19 20:17
*/
public class NumberUtils {
public static Double scaleTwo(String str) {
return BigDecimal.valueOf(Double.parseDouble(str)).setScale(2, RoundingMode.HALF_UP).doubleValue();
}
public static Double scaleTwo(Double value) {
return BigDecimal.valueOf(value).setScale(2, RoundingMode.HALF_UP).doubleValue();
}
public static Double scale(Double value, int scale) {
return BigDecimal.valueOf(value).setScale(scale, RoundingMode.HALF_UP).doubleValue();
}
public static String removeBrackets(String str) {
if (StringUtils.isEmpty(str)) {
return str;
}
return str.replaceAll("\\[", "").replaceAll("]", "");
}
}

View File

@ -0,0 +1,261 @@
package com.imdroid.sideslope.util;
import com.imdroid.sideslope.bd.ByteUtil;
import com.imdroid.sideslope.bd.Gga;
import java.math.BigDecimal;
import static java.lang.Math.*;
public class RtcmGgaUtil {
//gga样本*后面跟的是校验和其中76代表校验和对$和*之间的数据不包括这两个字符按字节进行异或运算二进制的结果
private static final String ggaExample = "$GNGGA,020850.50,2258.10508,N,11317.67958,E,4,12,0.74,3.9,M,-5.4,M,1.3,0000*76";
/**
* 获取rtcm数据类型
* @param bytes
* @return
*/
public static int getType(byte[] bytes){
String binaryStrFromByteArr = ByteUtil.getBinaryStrFromByteArr(bytes);
if(binaryStrFromByteArr.length() > 8 + 6 + 10 + 12){
String substring = binaryStrFromByteArr.substring(8 + 6 + 10, 8 + 6 + 10 + 12);
int i = ByteUtil.binaryToInt(substring);
return i;
}else{
return -1;
}
}
public static String ggaMock(double lat, double lon){
String originLat = getOriginLatLon(lat);
String originLon = getOriginLatLon(lon);
StringBuilder sb = new StringBuilder(ggaExample);
sb.replace(sb.indexOf(",N,")-10,sb.indexOf(",N,"),originLat);
sb.replace(sb.indexOf(",E,")-11,sb.indexOf(",E,"),originLon);
String substring = sb.substring(sb.indexOf("$") + 1, sb.indexOf("*"));
byte[] bytes = substring.getBytes();
//校验位
byte b = bytes[0];
for (int i = 1; i < bytes.length; i++) {
b ^= bytes[i];
}
sb.replace(sb.length()-2,sb.length(),ByteUtil.byteToHexString(b));
return sb.toString();
}
public static String getGNGGAString(byte[] bytes){
String hex = ByteUtil.bytesToHexString(bytes);
int start = hex.indexOf("24474e474741");//$GNGGA
int end = hex.indexOf("0d0a");//\r\n
if(start != -1 && end > start){
String substring = hex.substring(start,end);
//System.out.println(new String(ByteUtil.hexStringTobyte(substring)));
return new String(ByteUtil.hexStringTobyte(substring));
}
return "";
}
public static Gga getGga(String msg){
try{
String[] strings = msg.split(",");
double latitude = getLatLon(Double.parseDouble(strings[2]));
double longitude = getLatLon(Double.parseDouble(strings[4]));
double altitude = 100*(Double.parseDouble(strings[9]) + Double.parseDouble(strings[11]));
int status = Integer.parseInt(strings[6]);
return new Gga(latitude,longitude,altitude,status);
}catch (Exception e){
return null;
}
}
/**
* 解析阉割版gga为了那点流量...
* @param msg
* @return
*/
public static Gga getGga2(String msg){
try{
String[] split = msg.split(",");
double lat = getLatLon(Double.parseDouble(split[1]));
double lon = getLatLon(Double.parseDouble(split[3]));
double altitude = Double.parseDouble(split[5]);
return new Gga(lat,lon,altitude,0);
}catch (Exception e){
return null;
}
}
/**
* 解析阉割版gga为了那点流量...
* @param msg
* @return
*/
public static Gga getGga3(String msg){
try{
String[] split = msg.split(",");
double lat = getLatLon(Double.parseDouble(split[1]));
double lon = getLatLon(Double.parseDouble(split[3]));
int status = Integer.parseInt(split[5]);
double altitude = Double.parseDouble(split[6]);
return new Gga(lat,lon,altitude,status);
}catch (Exception e){
return null;
}
}
/**
* 求相对坐标
* @param gps_info
* @param origin
* @return
*/
public static double[] ggaToXyz(Gga gps_info,Gga origin){
return ggaToXyz(gps_info,origin,0);
}
/**
* 求相对坐标
* @param gps_info
* @param origin
* @param angle 与北偏角
* @return
*/
public static double[] ggaToXyz(Gga gps_info,Gga origin, double angle){
double Ea = 6378137 * 100; //赤道的半径单位是cm
//cout << "Ea" << Ea << endl;
double Eb = 6356725 * 100; //极半径单位是cm
double Db = 39940638; //极周长单位是cm如果直接 39940538*100 double类型会溢出所以把*100放到 dN 的计算式中
//cout << "Db=" << Db << endl;
double R = Eb + (Ea - Eb) * (90 - origin.getLatitude()) / 90;
double pD = R * 2 * PI * cos(origin.getLatitude() * PI / 180);
double dE = pD * (gps_info.getLongitude() - origin.getLongitude()) / 360; //计算在正东方向上的位移
double dN = Db * (gps_info.getLatitude() - origin.getLatitude()) / 360 * 100; //计算在正北方向上的位移
//接下来根据场地的朝向来把朝东朝北的偏移转化成x方向和y方向的位移
//这个位移也就是车辆在场地中的x坐标和y坐标
double x = dE * cos(angle * PI / 180) - dN * sin(angle * PI / 180);
double y = dN * cos(angle * PI / 180) + dE * sin(angle * PI / 180);
double z = gps_info.getAltitude() - origin.getAltitude();
return new double[]{x,y,z};
}
//一度为60分
public static double getLatLon(Double location) {
if (location != 0.0) {
//int head = Integer.parseInt(String.valueOf(location).substring(0, 2));
int head = (int)(location/100);
// System.out.println(head);
return head + (location / 100 - head) * 10 / 6;
}
return 0.0;
}
//逆向转化
public static String getOriginLatLon(double latlon){
double result = 100*((int)latlon) + (latlon-(int)latlon)*6/10*100;
BigDecimal bd = new BigDecimal(result);
result = bd.setScale(5,BigDecimal.ROUND_HALF_EVEN).doubleValue();
return StringUtil.roundByScale(result, 5);
}
/**
* 求航向角
* @param backLat
* @param backLon
* @param frontLat
* @param frontLon
* @return
*/
public static double latLonToAngle(double backLat, double backLon, double frontLat, double frontLon){
double[] doubles = ggaToXyz(new Gga(frontLat, frontLon), new Gga(backLat, backLon));
double angle = Math.atan2(doubles[0],doubles[1]) * 180/ Math.PI;
angle = (angle + 360) % 360;
return angle;
}
/**
* 正北
* ^ ^ y轴
* \ |
* \ +-----------+ (x,y)
* \ | |
* \ | |
* \| |
* -------+-----------+---->
* origin| x轴
* |
*
* 求某一个坐标的经纬度
* @param x 单位厘米
* @param y
* @param origin 参考点的经纬度
* @param angle_from_north y轴与正北夹角
* @return
*/
public static Gga xyToGga(double x, double y, Gga origin, double angle_from_north){
double latitude1 = -x * sin(angle_from_north * PI /180)
+ y * cos(angle_from_north * PI /180);
double longitude1 = x / cos(angle_from_north * PI /180)
+ (y - (x * tan(angle_from_north * PI /180)))
* sin(angle_from_north * PI /180);
Gga ggaInfo1 = new Gga();
ggaInfo1.setLatitude(origin.getLatitude() + 0.000001);
ggaInfo1.setLongitude(origin.getLongitude());
Gga ggaInfo2 = new Gga();
ggaInfo2.setLatitude(origin.getLatitude());
ggaInfo2.setLongitude(origin.getLongitude() + 0.000001);
double[] location1 = ggaToXyz(ggaInfo1,origin);
double[] location2 = ggaToXyz(ggaInfo2,origin);
double a = location1[1];
double b = location2[0];
double latitude = latitude1 / a * 0.000001;
double longitude = longitude1 / b * 0.000001;
Gga ggaInfo = new Gga();
ggaInfo.setLatitude(origin.getLatitude() + latitude);
ggaInfo.setLongitude(origin.getLongitude() + longitude);
return ggaInfo;
}
/**
* 计算两点之间距离10厘米以下也能计算精度更高单位厘米
*/
public static double getDistance2(double latitude, double longitude, double nowLatitude, double nowLongitude) {
Gga gga1 = new Gga(latitude, longitude);
Gga gga2 = new Gga(nowLatitude, nowLongitude);
double[] doubles = ggaToXyz(gga1, gga2);
return Math.sqrt(Math.pow(doubles[0],2) + Math.pow(doubles[1],2));
}
/**
* 计算两点之间距离单位米
*/
public static double getDistance(double sourceLat, double sourceLog, double desLat, double desLog) {
//转为弧度
double lat1 = (Math.PI / 180) * sourceLat;
double lat2 = (Math.PI / 180) * desLat;
double lon1 = (Math.PI / 180) * sourceLog;
double lon2 = (Math.PI / 180) * desLog;
//地球半径
double R = 6371.004;
//两点间距离 km如果想要米的话结果*1000
double d = Math.acos(Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1)) * R;
if (Double.isNaN(d * 1000)) {
return 0.0;
}
return d * 1000;
}
}

View File

@ -0,0 +1,47 @@
package com.imdroid.sideslope.util;
import java.text.DecimalFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class StringUtil {
/**
* @param data 指定字符串
* @param str 需要定位的特殊字符或者字符串
* @param num 第n次出现
* @return 第n次出现的位置索引
*/
public static int getIndexOf(String data,String str,int num){
Pattern pattern = Pattern.compile(str);
Matcher findMatcher = pattern.matcher(data);
//标记遍历字符串的位置
int indexNum=0;
while(findMatcher.find()) {
indexNum++;
if(indexNum==num){
return findMatcher.start();
}
}
//System.out.println("字符或者字符串"+str+""+num+"次出现的位置为:"+findMatcher.start());
return -1;
}
/**
* 保留小数点多少位不足补零
* @param v
* @param scale 大于等于0
* @return
*/
public static String roundByScale(double v, int scale) {
if(scale == 0){
return new DecimalFormat("0").format(v);
}
String formatStr = "0.";
for(int i=0;i<scale;i++){
formatStr = formatStr + "0";
}
return new DecimalFormat(formatStr).format(v);
}
}

View File

@ -0,0 +1,47 @@
package com.imdroid.sideslope.util;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
public class ThreadManager {
//单线程池
private static final Map<String, ExecutorService> mExecutorServiceMap = new HashMap<>();
private static final Object lock = new Object();
private static final class FixedThreadPoolHolder {
//固定线程池
static final ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
}
public static ExecutorService getFixedThreadPool() {
return FixedThreadPoolHolder.fixedThreadPool;
}
private static final class ScheduledThreadPoolHolder {
//定时线程池
static final ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4);
}
public static ScheduledExecutorService getScheduledThreadPool() {
return ScheduledThreadPoolHolder.scheduledThreadPool;
}
public static ExecutorService getSingleThreadPool(String name) {
ExecutorService singleThreadExecutor = mExecutorServiceMap.get(name);
if (singleThreadExecutor == null) {
synchronized (lock) {
singleThreadExecutor = mExecutorServiceMap.get(name);
if (singleThreadExecutor == null) {
singleThreadExecutor = Executors.newSingleThreadExecutor();
mExecutorServiceMap.put(name, singleThreadExecutor);
}
}
}
return singleThreadExecutor;
}
}

View File

@ -0,0 +1,43 @@
package com.imdroid.sideslope.util;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileAppender;
import java.io.File;
/**
* 设备发送过来的错误消息记录器
* 错误消息长度字段与实际消息体长度不匹配
*
* @author LiGang
* @date 2023/4/8 11:15
*/
public class WrongMessageRecorder {
private FileAppender appender;
public static final WrongMessageRecorder INSTANCE = new WrongMessageRecorder();
private WrongMessageRecorder() {
try {
String filePath = "/home/devop/runtime/sideslope_wrong_message_" + DateUtil.today() + ".log";
File file = new File(filePath);
if (!file.exists()) {
file.createNewFile();
}
appender = new FileAppender(file, 2, true);
} catch (Exception e) {
e.printStackTrace();
}
}
public void append(String message) {
try {
appender.append(DateUtil.now() + ": " + message);
appender.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,107 @@
package com.imdroid.sideslope.web;
import com.imdroid.sideslope.calc.GNSSCalcService;
import com.imdroid.sideslope.server.DeviceChannel;
import com.imdroid.sideslope.server.OnlineChannels;
import com.imdroid.sideslope.util.DataTypeUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
/**
* @author LiGang
* @date 2023/9/24 10:01
*/
@RestController
public class ApiController {
private final Logger logger = LoggerFactory.getLogger(ApiController.class);
@Autowired
private GNSSCalcService gnssCalcService;
@RequestMapping(value = "/config")
public HttpResp config(String deviceId, String configuration) {
Map<String, Object> status = new HashMap<>();
HttpResp resp = new HttpResp();
OnlineChannels.INSTANCE
.get(deviceId)
.filter(DeviceChannel::isOnline)
.ifPresent(x -> {
status.put("status", "Online");
status.put("lastUpdate", x.getLastTime());
// send command
ByteBuf buf = Unpooled.buffer();
byte[] data = getBinaryData(ConfigDataTypeEnum.JSON, configuration);
logger.info("send command:{}", configuration);
buf.writeBytes(data);
x.writeAndFlush(buf);
});
if (status.isEmpty()) {
status.put("status", "Offline");
resp.setResponseCode("-10001");
resp.setResponseMessage("Offline.");
} else {
resp.setResponseMessage("Command sent.");
}
resp.setResponseObject(status);
return resp;
}
@RequestMapping(value = "/gnssconfig")
public HttpResp gnssConfig(String deviceId, String configuration) {
Map<String, Object> status = new HashMap<>();
HttpResp resp = new HttpResp();
OnlineChannels.INSTANCE
.get(deviceId)
.filter(DeviceChannel::isOnline)
.ifPresent(x -> {
status.put("status", "Online");
status.put("lastUpdate", x.getLastTime());
// send command
ByteBuf buf = Unpooled.buffer();
byte[] data = getBinaryData(ConfigDataTypeEnum.HEX, configuration);
logger.info("send command:{}", configuration);
buf.writeBytes(data);
x.writeAndFlush(buf);
});
if (status.isEmpty()) {
status.put("status", "Offline");
resp.setResponseCode("-10001");
resp.setResponseMessage("Offline.");
} else {
resp.setResponseMessage("Command sent.");
}
resp.setResponseObject(status);
return resp;
}
@RequestMapping(value = "/clean-tilt")
public HttpResp config(String deviceId) {
// 清空指定设备的惯导值
gnssCalcService.cleanTiltByDeviceId(deviceId);
HttpResp resp = new HttpResp();
resp.setResponseMessage("succeed");
return resp;
}
private static byte[] getBinaryData(ConfigDataTypeEnum dataTypeEnum, String text) {
if (dataTypeEnum == ConfigDataTypeEnum.HEX) {
return DataTypeUtil.hexStringToBytes(text);
} else if (dataTypeEnum == ConfigDataTypeEnum.JSON) {
String content = URLDecoder.decode(text);
return content.getBytes(StandardCharsets.UTF_8);
} else {
return text.getBytes(StandardCharsets.UTF_8);
}
}
}

View File

@ -0,0 +1,10 @@
package com.imdroid.sideslope.web;
/**
* @author Layton
* @date 2023/2/13 19:20
*/
public enum ConfigDataTypeEnum {
HEX, JSON;
}

View File

@ -0,0 +1,49 @@
package com.imdroid.sideslope.web;
public class HttpResp<T> {
private String responseCode = "10000";
private String responseMessage;
private String responseType;
private int rows;
private T responseObject;
public String getResponseCode() {
return responseCode;
}
public void setResponseCode(String responseCode) {
this.responseCode = responseCode;
}
public String getResponseMessage() {
return responseMessage;
}
public void setResponseMessage(String responseMessage) {
this.responseMessage = responseMessage;
}
public String getResponseType() {
return responseType;
}
public void setResponseType(String responseType) {
this.responseType = responseType;
}
public int getRows() {
return rows;
}
public void setRows(int rows) {
this.rows = rows;
}
public T getResponseObject() {
return responseObject;
}
public void setResponseObject(T responseObject) {
this.responseObject = responseObject;
}
}

View File

@ -0,0 +1,29 @@
server.port=9904
server.servlet.context-path=/gnss
spring.application.name=bis-gnss
spring.application.build=20230924
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = none
spring.jpa.database-platform = org.hibernate.dialect.MySQLDialect
spring.datasource.url = jdbc:mysql://localhost:3306/bis-device?characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
spring.datasource.username = root
spring.datasource.password =
spring.datasource.driverClassName = com.mysql.cj.jdbc.Driver
spring.jackson.dateFormat = yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone = GMT+8
# rabbitmq
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtualHost=/
netty.port=9903
app.format.date = yyyy-MM-dd
app.format.time = HH:mm:ss
app.format.datetime = yyyy-MM-dd HH:mm:ss

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="30 seconds">
<property name="LOG_HOME" value="/opt/log"/>
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/sideslopertcm.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/sideslopertcm.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>10MB</maxFileSize>
<maxHistory>20</maxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
<logger name="org.springframework" level="warn" />
</configuration>

View File

@ -0,0 +1,48 @@
import com.imdroid.sideslope.bd.FocusCalculator;
import com.imdroid.sideslope.bd.UBXUtil;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class UBXTest {
public static void main(String[] args) throws Exception {
test();
}
public static void test() throws IOException {
//读取本地数据模拟
/* FileInputStream fileInputStream = new FileInputStream("2023-02-02-151826.txt");
int mSize = 0;
int temp;
List<Byte> mList = new ArrayList<>();
FocusCalculator focusCalculator = new FocusCalculator(150,null,null);
while ((temp = fileInputStream.read()) != -1){
mList.add((byte)temp); //添加数据
mSize++;
if (mList.size() >= 2 && mList.get(mSize - 2) == '\r' && mList.get(mSize - 1) == '\n') {
byte[] bytes = new byte[mList.size() - 2];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = mList.get(i);
}
//提取得到b562数据
double[] doubles = UBXUtil.dataAnalysis(bytes,16);
//计算到单次相对位置xyz并记录
System.out.println(Arrays.toString(doubles));
focusCalculator.addXyz(doubles);
mList.clear();
mSize = 0;
}
}
//融合
double[] result = focusCalculator.resultB562(null);
if(result != null){
System.out.println("result"+ Arrays.toString(result));
}
fileInputStream.close();*/
}
}

162
sec-beidou/pom.xml Normal file
View File

@ -0,0 +1,162 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.imdroid</groupId>
<artifactId>security-monitor</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.imdroid</groupId>
<artifactId>sec-beidou</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>beidou</name>
<description>beidou</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-security</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-boot-starter</artifactId>
<version>1.4.3</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.24</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.85.Final</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.6</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.9.1</version>
</dependency>
<!-- apache http client -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.7</version>
</dependency>
<!-- request parameters validate -->
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>2.0.2</version>
</dependency>
<!-- aliyun oss -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.10.2</version>
</dependency>
<dependency>
<groupId>com.imdroid</groupId>
<artifactId>sec-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>central</id>
<name>ali-mirror</name>
<url>https://maven.aliyun.com/repository/central</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project>

View File

@ -0,0 +1,15 @@
package com.imdroid.beidou;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;
@SpringBootApplication(scanBasePackages = {"com.imdroid"})
@MapperScan({"com.imdroid.secapi","com.imdroid.beidou.entity"})
public class BeidouApplication {
public static void main(String[] args) {
SpringApplication.run(BeidouApplication.class, args);
}
}

View File

@ -0,0 +1,21 @@
package com.imdroid.beidou;
import com.imdroid.beidou.common.HttpResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
public HttpResult handleException(Exception e) {
log.error("全局捕获异常:", e);
return HttpResult.fail(e.getMessage());
}
}

View File

@ -0,0 +1,37 @@
package com.imdroid.beidou.auth;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 登录拦截器
*
* @author LiGang
*/
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String username = SessionUtils.getCurrentUser(request);
if (!StringUtils.isEmpty(username)) {
return true;
}
response.sendRedirect("/login");
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}

View File

@ -0,0 +1,37 @@
package com.imdroid.beidou.auth;
import com.imdroid.beidou.entity.Tenant;
import com.imdroid.beidou.entity.User;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* session 工具类
*
* @author LiGang
*/
public class SessionUtils {
public static final String SESSION_CURRENT_USER = "login_user";
public static String getCurrentUser(HttpServletRequest request) {
return (String) request.getSession().getAttribute(SESSION_CURRENT_USER);
}
public static void setCurrentUser(HttpServletRequest request, User user, Tenant tenant) {
HttpSession session = request.getSession();
session.setAttribute(SESSION_CURRENT_USER, user.getName());
session.setAttribute("tenant_id", user.getTenant_id());
session.setAttribute("tenant_name", tenant.getName());
session.setAttribute("role", user.getRole());
}
public static Integer getTenantId(HttpServletRequest request) {
return (Integer) request.getSession().getAttribute("tenant_id");
}
public static String getRole(HttpServletRequest request) {
return (String) request.getSession().getAttribute("role");
}
}

View File

@ -0,0 +1,26 @@
package com.imdroid.beidou.auth;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 登录拦截器配置
*
* @author LiGang
*/
@Configuration
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {
private final AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/**/*.js","/**/*.css","/**/*.jpg","/**/*.png", "/do_login", "/mini-register", "/login");
}
}

View File

@ -0,0 +1,47 @@
package com.imdroid.beidou.common;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HttpResult implements Serializable {
public static int HTTP_RSP_OK = 0;
public static int HTTP_RSP_FAILED = 1;
public static int HTTP_RSP_USER_NOT_EXIST = 2;
int code;
String msg;
Object data;
public static String result(int code, String msg) {
HttpResult rsp = new HttpResult();
rsp.code = code;
rsp.msg = msg;
return JSONObject.toJSONString(rsp);
}
public static String ok() {
return result(HTTP_RSP_OK, "ok");
}
public static String failed() {
return result(HTTP_RSP_FAILED, "failed");
}
public static HttpResult success(Object data) {
return new HttpResult(HTTP_RSP_OK, "ok", data);
}
public static HttpResult fail(String msg) {
return new HttpResult(HTTP_RSP_FAILED, msg, null);
}
public static HttpResult fail(int code, String msg) {
return new HttpResult(code, msg, null);
}
}

View File

@ -0,0 +1,15 @@
package com.imdroid.beidou.common;
/****************************************
* 1系统管理员ADMIN所有权限并且可以设置自己的企业ID
* 2企业管理员MANAGER本企业内数据的查改增删增加和删除本企业的账号查看操作日志
* 不能看设备消息和设置设备数据LOG
* 3普通用户USER本企业内的数据查看和设备配置
* 用户角色以字节传到页面bit1adminbit2managerbit3user
*/
public class Role {
public static final String ADMIN = "ADMIN";
public static final String MANAGER = "MANAGER";
public static final String USER = "USER";
}

View File

@ -0,0 +1,28 @@
package com.imdroid.beidou.config;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* 阿里云oss配置类
*
* @author LiGang
*/
@Setter
@Getter
@Configuration
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliyunOssProperties {
private String endpoint;
private String accessKey;
private String accessSecret;
private String bucket;
private String publicReadUrl;
}

View File

@ -0,0 +1,36 @@
package com.imdroid.beidou.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* 微信小程序配置
*
* @author LiGang
*/
@Configuration
@ConfigurationProperties("app.bis")
public class WxMiniProperties {
private String appid;
private String secret;
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
}

View File

@ -0,0 +1,22 @@
package com.imdroid.beidou.controller;
import org.springframework.ui.Model;
import javax.servlet.http.HttpSession;
/**
* 利用HTTP Session保存会话期的用户信息并发送到页面用于显示控制
*/
public class BasicController {
public static int QUERY_ALL = -1;
public void initModel(Model m, HttpSession session)
{
String role = (String) session.getAttribute("role");
int tenant_id = (int) session.getAttribute("tenant_id");
m.addAttribute("login_user", session.getAttribute("login_user"));
m.addAttribute("role", role);
m.addAttribute("tenant_id", tenant_id);
m.addAttribute("tenant_name", session.getAttribute("tenant_name"));
}
}

View File

@ -0,0 +1,189 @@
package com.imdroid.beidou.controller;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.StringUtil;
import com.imdroid.beidou.common.HttpResult;
import com.imdroid.beidou.data.vo.device.DeviceInstallVO;
import com.imdroid.beidou.data.vo.device.DeviceStatusVO;
import com.imdroid.beidou.entity.*;
import com.imdroid.secapi.dto.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import javax.servlet.http.HttpSession;
import java.sql.Timestamp;
import java.util.List;
@Controller
public class GnssDeviceController extends BasicController{
@Autowired
GnssGroupMapper gnssGroupMapper;
@Autowired
GnssGroupCalcMapper gnssGroupCalcMapper;
@Autowired
GnssGroupFwdMapper gnssGroupFwdMapper;
@Autowired
GnssDeviceMapper gnssDeviceMapper;
@Autowired
TenantMapper tenantMapper;
@Autowired
private GnssStatusMapper gnssStatusMapper;
/**** 推送页面 *****/
@RequestMapping("/page/gnss_dev_cfg")
public String gnssDevCfg(Model m, HttpSession session)throws Exception {
initModel(m, session);
return "/page/gnss_dev_cfg";
}
@RequestMapping("/page/table/gnss_add_dev")
public String gnssUpdateDev(Model m)throws Exception {
//以下用于下拉框数据
List<GnssGroup> gnssGroups = gnssGroupMapper.selectList(null);
List<GnssGroupCalc> gnssGroupCalcs = gnssGroupCalcMapper.selectList(null);
List<GnssGroupFwd> gnssGroupFwds = gnssGroupFwdMapper.selectList(null);
List<Tenant> tenants = tenantMapper.selectList(null);
m.addAttribute("tenant_list", tenants);
m.addAttribute("gnss_group_list", gnssGroups);
m.addAttribute("gnss_group_calc_list", gnssGroupCalcs);
m.addAttribute("gnss_group_fwd_list", gnssGroupFwds);
return "/page/table/gnss_add_dev";
}
/**** 推送数据 *****/
@RequestMapping("/gnss/device/list")
@ResponseBody
public JSONObject list(HttpSession session, int page, int limit, String searchParams) {
PageHelper.startPage(page, limit);
QueryWrapper<GnssDevice> queryWrapper = new QueryWrapper<>();
// 条件查询
if(searchParams != null) {
JSONObject search = (JSONObject) JSONObject.parse(searchParams);
//设备号
String deviceid = search.getString("deviceid");
if (StringUtil.isNotEmpty(deviceid)) {
queryWrapper.like("deviceid", deviceid);
}
//父设备号
String parentid = search.getString("parentid");
if (StringUtil.isNotEmpty(parentid)) {
queryWrapper.like("parentid", parentid);
}
//设备类型
Integer devicetype = search.getInteger("devicetype");
if (devicetype != null && devicetype != QUERY_ALL) {
queryWrapper.eq("devicetype", devicetype);
}
}
List<GnssDevice> cs = gnssDeviceMapper.selectList(queryWrapper);
PageInfo<GnssDevice> pageInfo = new PageInfo<>(cs);
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", 0);
jsonObject.put("msg", "");
jsonObject.put("count", pageInfo.getTotal());
jsonObject.put("data", pageInfo.getList());
return jsonObject;
}
@PostMapping("/gnss/device/update")
@ResponseBody
public String update(HttpSession session, @RequestBody JSONObject object) throws Exception {
// 从请求参数中创建对象
GnssDevice device = JSONObject.toJavaObject(object,GnssDevice.class);
QueryWrapper<Tenant> tenantQueryWrapper = new QueryWrapper<>();
tenantQueryWrapper.eq("name", device.getTenantname());
Tenant tenant = tenantMapper.selectOne(tenantQueryWrapper);
if(tenant==null) return HttpResult.result(2, "invalid tenant");
device.setTenantid(tenant.getId());
device.setUpdatetime(new Timestamp(System.currentTimeMillis()));
device.setUpdateuser((String) session.getAttribute("login_user"));
// 检测该对象是否已存在
QueryWrapper<GnssDevice> wrapper = new QueryWrapper<>();
wrapper.eq("deviceid",device.getDeviceid());
GnssDevice old_device = gnssDeviceMapper.selectOne(wrapper);
//新增或更新
int num = 0;
if(null != old_device) {
device.setId(old_device.getId());
device.setCreateuser(old_device.getCreateuser());
device.setCreatetime(old_device.getCreatetime());
num = gnssDeviceMapper.updateById(device);
}
else{
device.setCreatetime(new Timestamp(System.currentTimeMillis()));
device.setCreateuser((String) session.getAttribute("login_user"));
num = gnssDeviceMapper.insert(device); //id自增
}
if (num == 0) {
return HttpResult.failed();
} else return HttpResult.ok();
}
@PostMapping("/gnss/device/delete")
@ResponseBody
public String delete(@RequestParam String del_id) throws Exception {
QueryWrapper<GnssDevice> wrapper = new QueryWrapper<>();
wrapper.eq("deviceid",del_id);
int num = gnssDeviceMapper.delete(wrapper);
if (num == 0) {
return HttpResult.failed();
} else return HttpResult.ok();
}
/**
* 设备现场安装
*
* @param deviceInstallVO 设备安装信息
* @return HttpResult
* @throws Exception
*/
@PostMapping("/gnss/device/install")
@ResponseBody
public HttpResult install(@Validated DeviceInstallVO deviceInstallVO) throws Exception {
QueryWrapper<GnssDevice> wrapper = new QueryWrapper<>();
wrapper.eq("deviceid",deviceInstallVO.getDeviceId());
GnssDevice gnssDevice = gnssDeviceMapper.selectOne(wrapper);
if (gnssDevice == null) {
return HttpResult.fail("");
}
GnssDevice tempDevice = new GnssDevice();
tempDevice.setId(gnssDevice.getId());
//安装位置通过GNSS坐标自动获取
//tempDevice.setLocation(deviceInstallVO.getLocation());
tempDevice.setPictures(deviceInstallVO.getPictures());
gnssDeviceMapper.updateById(tempDevice);
return HttpResult.success(null);
}
/**
* 根据主键id查找设备信息
*
* @param id 主键id
* @return 设备信息 DeviceStatusVO
*/
@PostMapping("/gnss/device/status")
@ResponseBody
public HttpResult findById(Long id) {
GnssDevice gnssDevice = gnssDeviceMapper.selectById(id);
if (gnssDevice == null) {
return HttpResult.fail("");
}
GnssStatusJoin gnssStatus = gnssStatusMapper.queryByDeviceId(gnssDevice.getDeviceid());
DeviceStatusVO deviceStatusVO = new DeviceStatusVO(gnssDevice, gnssStatus);
return HttpResult.success(deviceStatusVO);
}
}

View File

@ -0,0 +1,168 @@
package com.imdroid.beidou.controller;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.imdroid.beidou.common.HttpResult;
import com.imdroid.beidou.entity.*;
import com.imdroid.secapi.dto.GnssGroup;
import com.imdroid.secapi.dto.GnssGroupMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Controller
public class GnssGroupController {
@Autowired
GnssGroupMapper gnssGroupMapper;
@Autowired
GnssGroupCalcMapper gnssGroupCalcMapper;
@Autowired
GnssGroupFwdMapper gnssGroupFwdMapper;
/********* 推送页面 *********/
@RequestMapping("/page/table/gnss_add_group")
public String gnssAddGroup()throws Exception {
return "/page/table/gnss_add_group";
}
@RequestMapping("/page/table/gnss_add_group_calc")
public String gnssAddCalcGroup()throws Exception {
return "/page/table/gnss_add_group_calc";
}
@RequestMapping("/page/table/gnss_add_group_fwd")
public String gnssAddPushGroup()throws Exception {
return "/page/table/gnss_add_group_fwd";
}
@RequestMapping("/page/gnss_group_cfg")
public String gnssGroupCfg()throws Exception {
return "/page/gnss_group_cfg";
}
/********* 基本参数组 *********/
@RequestMapping("/gnss/group/list")
@ResponseBody
public JSONObject list(int page, int limit) {
PageHelper.startPage(page, limit);
List<GnssGroup> cs = gnssGroupMapper.selectList(null);
PageInfo<GnssGroup> pageInfo = new PageInfo<>(cs);
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", 0);
jsonObject.put("msg", "");
jsonObject.put("count", pageInfo.getTotal());
jsonObject.put("data", pageInfo.getList());
return jsonObject;
}
@PostMapping("/gnss/group/update")
@ResponseBody
public String update(@RequestBody JSONObject object) throws Exception {
int num = 0;
GnssGroup group = JSONObject.toJavaObject(object,GnssGroup.class);
if(null != gnssGroupMapper.selectById(group.getId())) {
num = gnssGroupMapper.updateById(group);
}
else{
num = gnssGroupMapper.insert(group);
}
if (num == 0) {
return HttpResult.failed();
} else return HttpResult.ok();
}
@PostMapping("/gnss/group/delete")
@ResponseBody
public String delete(@RequestParam int del_id) throws Exception {
int num = gnssGroupMapper.deleteById(del_id);
if (num == 0) {
return HttpResult.failed();
} else return HttpResult.ok();
}
/********* 解算参数组 *********/
@RequestMapping("/gnss/group/list_calc")
@ResponseBody
public JSONObject listCalc(int page, int limit) {
PageHelper.startPage(page, limit);
List<GnssGroupCalc> cs = gnssGroupCalcMapper.selectList(null);
PageInfo<GnssGroupCalc> pageInfo = new PageInfo<>(cs);
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", 0);
jsonObject.put("msg", "");
jsonObject.put("count", pageInfo.getTotal());
jsonObject.put("data", pageInfo.getList());
return jsonObject;
}
@PostMapping("/gnss/group/update_calc")
@ResponseBody
public String updateCalc(@RequestBody JSONObject object) throws Exception {
int num = 0;
GnssGroupCalc group = JSONObject.toJavaObject(object,GnssGroupCalc.class);
if(null != gnssGroupCalcMapper.selectById(group.getId())) {
num = gnssGroupCalcMapper.updateById(group);
}
else{
num = gnssGroupCalcMapper.insert(group);
}
if (num == 0) {
return HttpResult.failed();
} else return HttpResult.ok();
}
@PostMapping("/gnss/group/delete_calc")
@ResponseBody
public String deleteCalc(@RequestParam int del_id) throws Exception {
int num = gnssGroupCalcMapper.deleteById(del_id);
if (num == 0) {
return HttpResult.failed();
} else return HttpResult.ok();
}
/********* 转发参数组 *********/
@RequestMapping("/gnss/group/list_fwd")
@ResponseBody
public JSONObject listFwd(int page, int limit) {
PageHelper.startPage(page, limit);
List<GnssGroupFwd> cs = gnssGroupFwdMapper.selectList(null);
PageInfo<GnssGroupFwd> pageInfo = new PageInfo<>(cs);
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", 0);
jsonObject.put("msg", "");
jsonObject.put("count", pageInfo.getTotal());
jsonObject.put("data", pageInfo.getList());
return jsonObject;
}
@PostMapping("/gnss/group/update_fwd")
@ResponseBody
public String updateFwd(@RequestBody JSONObject object) throws Exception {
int num = 0;
GnssGroupFwd group = JSONObject.toJavaObject(object,GnssGroupFwd.class);
if(null != gnssGroupFwdMapper.selectById(group.getId())) {
num = gnssGroupFwdMapper.updateById(group);
}
else{
num = gnssGroupFwdMapper.insert(group);
}
if (num == 0) {
return HttpResult.failed();
} else return HttpResult.ok();
}
@PostMapping("/gnss/group/delete_fwd")
@ResponseBody
public String deleteFwd(@RequestParam int del_id) throws Exception {
int num = gnssGroupFwdMapper.deleteById(del_id);
if (num == 0) {
return HttpResult.failed();
} else return HttpResult.ok();
}
}

View File

@ -0,0 +1,74 @@
package com.imdroid.beidou.controller;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.StringUtil;
import com.github.yulichang.query.MPJQueryWrapper;
import com.imdroid.secapi.dto.GnssStatus;
import com.imdroid.secapi.dto.GnssStatusJoin;
import com.imdroid.secapi.dto.GnssStatusMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpSession;
@Controller
public class GnssStatusController extends BasicController{
@Autowired
GnssStatusMapper gnssStatusMapper;
/**** 推送页面 *****/
@RequestMapping("/page/gnss_status")
public String gnssStatus(Model m, HttpSession session)throws Exception {
initModel(m, session);
return "/page/gnss_status";
}
/**** 推送数据 *****/
@RequestMapping("/gnss/status/list")
@ResponseBody
public JSONObject list(HttpSession session, int page, int limit, String searchParams) {
PageHelper.startPage(page, limit);
MPJQueryWrapper wrapper = new MPJQueryWrapper<GnssStatus>()
.selectAll(GnssStatus.class)
.select("d.devicetype as devicetype","d.tenantid as tenantid")
.leftJoin("gnssdevices d on t.deviceid = d.deviceid");
// 条件查询
if(searchParams != null) {
JSONObject search = (JSONObject) JSONObject.parse(searchParams);
//设备号
String deviceid = search.getString("deviceid");
if (StringUtil.isNotEmpty(deviceid)) {
wrapper.like("deviceid", deviceid);
}
//状态
Integer state = search.getInteger("state");
if(state!=null && state != QUERY_ALL){
wrapper.eq("state", state);
}
//告警
Integer warning = search.getInteger("warning");
if(warning!=null && warning != QUERY_ALL){
wrapper.eq("warning", warning);
}
}
//分页查询 需要启用 mybatis plus 分页插件
Page<GnssStatusJoin> listPage = gnssStatusMapper.selectJoinPage(new Page<>(page, limit), GnssStatusJoin.class, wrapper);
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", 0);
jsonObject.put("msg", "");
jsonObject.put("count", listPage.getTotal());
jsonObject.put("data", listPage.getRecords());
return jsonObject;
}
}

View File

@ -0,0 +1,63 @@
package com.imdroid.beidou.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class LayuiController extends BasicController{
@RequestMapping("/login")
public String login() throws Exception {
return "/login";
}
@RequestMapping("/")
public String index0()throws Exception {
return "/index";
}
@RequestMapping("/index")
public String index()throws Exception {
return "/index";
}
@RequestMapping("/page/device_overview")
public String deviceOverview()throws Exception {
return "/page/device_overview";
}
@RequestMapping("/page/gnss_data_calc")
public String gnssDataCalc()throws Exception {
return "/page/gnss_data_calc";
}
@RequestMapping("/page/gnss_data_raw")
public String gnssDataRaw()throws Exception {
return "/page/gnss_data_raw";
}
@RequestMapping("/page/gnss_data_tools")
public String gnssDataTools()throws Exception {
return "/page/gnss_data_tools";
}
@RequestMapping("/page/gnss_msg")
public String gnssMsg()throws Exception {
return "/page/gnss_msg";
}
@RequestMapping("/page/gnss_msg_status")
public String gnssMsgStatus()throws Exception {
return "/page/gnss_msg_status";
}
@RequestMapping("/page/gnss_msg_trx")
public String gnssMsgTrx()throws Exception {
return "/page/gnss_msg_trx";
}
@RequestMapping("/page/warning")
public String warning()throws Exception {
return "/page/warning";
}
}

View File

@ -0,0 +1,120 @@
package com.imdroid.beidou.controller;
import com.imdroid.beidou.auth.SessionUtils;
import com.imdroid.beidou.common.HttpResult;
import com.imdroid.beidou.data.WxMiniUserSession;
import com.imdroid.beidou.data.vo.MiniUserRegisterVO;
import com.imdroid.beidou.data.vo.MiniUserVO;
import com.imdroid.beidou.data.vo.UserLoginVO;
import com.imdroid.beidou.entity.Tenant;
import com.imdroid.beidou.entity.TenantMapper;
import com.imdroid.beidou.entity.User;
import com.imdroid.beidou.entity.UserMapper;
import com.imdroid.beidou.utils.WXUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 描述
*
* @author LiGang
*/
@RequestMapping
@RestController
public class LoginController {
@Autowired
private UserMapper userMapper;
@Autowired
private TenantMapper tenantMapper;
@Autowired
private WXUtils wxUtils;
@PostMapping(value = "/do_login")
@ResponseBody
public HttpResult login(UserLoginVO userLoginVO, HttpServletRequest request, HttpServletResponse response) throws Exception {
if (UserLoginVO.LOGIN_TYPE_MINI.equals(userLoginVO.getType())) {
// 小程序登录
WxMiniUserSession wxMiniUserSession = wxUtils.getMiniProgramUserOpenid(userLoginVO.getCode());
if (wxMiniUserSession == null) {
return HttpResult.fail("用户code错误");
}
User user = userMapper.queryByOpenid(wxMiniUserSession.getOpenid());
if (user == null) {
return HttpResult.fail(HttpResult.HTTP_RSP_USER_NOT_EXIST, "用户不存在");
}
Tenant tenant = tenantMapper.selectById(user.getTenant_id());
SessionUtils.setCurrentUser(request, user, tenant);
return HttpResult.success(buildMiniUser(user, tenant));
} else {
// web登录
User user = userMapper.queryByName(userLoginVO.getUsername());
if (user == null) {
return HttpResult.fail("用户不存在");
}
if (!user.getPassword().equals(userLoginVO.getPassword())) {
return HttpResult.fail("用户名或密码错误");
}
Tenant tenant = tenantMapper.selectById(user.getTenant_id());
SessionUtils.setCurrentUser(request, user, tenant);
//response.sendRedirect("/index"); //发这条没用会导致login.html收不到应答也跳转不了
HttpResult rsp = HttpResult.success(null);
return HttpResult.success(null);
}
}
private MiniUserVO buildMiniUser(User user, Tenant tenant) {
MiniUserVO miniUserVO = new MiniUserVO();
miniUserVO.setUsername(user.getUsername());
miniUserVO.setMobile(user.getMobile());
miniUserVO.setNickName(user.getNickname());
miniUserVO.setAvatarUrl(user.getAvatar_url());
miniUserVO.setTenantName(tenant.getName());
return miniUserVO;
}
/**
* 小程序用户注册
*
* @param miniUserRegisterVO miniUserRegisterVO
* @return HttpResult
*/
@PostMapping(value = "/mini-register")
public HttpResult miniUserRegister(@Validated MiniUserRegisterVO miniUserRegisterVO) {
WxMiniUserSession wxMiniUserSession = wxUtils.getMiniProgramUserOpenid(miniUserRegisterVO.getCode());
if (wxMiniUserSession == null) {
return HttpResult.fail("用户code错误");
}
User user = userMapper.queryByOpenid(wxMiniUserSession.getOpenid());
if (user != null) {
return HttpResult.fail("用户已注册");
}
user = userMapper.queryByMobile(miniUserRegisterVO.getMobile());
if (user == null) {
return HttpResult.fail(HttpResult.HTTP_RSP_USER_NOT_EXIST, "用户不存在");
}
// 更新用户信息
User newUser = new User();
newUser.setId(user.getId());
newUser.setAvatar_url(miniUserRegisterVO.getAvatarUrl());
newUser.setOpenid(wxMiniUserSession.getOpenid());
newUser.setNickname(miniUserRegisterVO.getNickName());
userMapper.updateById(newUser);
return HttpResult.success(null);
}
@RequestMapping(value = "/do_logout")
public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException {
request.getSession().invalidate();
response.sendRedirect("/login");
}
}

View File

@ -0,0 +1,54 @@
package com.imdroid.beidou.controller;
import com.imdroid.beidou.common.HttpResult;
import com.imdroid.beidou.utils.AliyunOssUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.UUID;
/**
* 文件上次接口
*
* @author LiGang
*/
@RestController
@RequestMapping("/file")
public class OssFileController {
@Autowired
private AliyunOssUtils aliyunOssUtils;
/**
* 上传文件通用接口
*
* @param multipartFile multipartFile
* @return HttpResult
* @throws Exception
*/
@RequestMapping("/upload")
public HttpResult upload(@RequestParam("file") MultipartFile multipartFile) throws Exception {
String filename = multipartFile.getOriginalFilename();
String url = aliyunOssUtils.uploadFile(multipartFile, filename, "common");
return HttpResult.success(url);
}
/**
* 上传设备现场安装图片保存到oss
*
* @param multipartFile multipartFile
* @return HttpResult
* @throws IOException
*/
@RequestMapping("/upload-device-image")
public HttpResult upload(@RequestParam("file") MultipartFile multipartFile, String deviceId) throws Exception {
String filename = deviceId + "_" + UUID.randomUUID().toString().replace("-", "") + ".jpg";
String url = aliyunOssUtils.uploadFile(multipartFile, filename, "device-img");
return HttpResult.success(url);
}
}

View File

@ -0,0 +1,37 @@
package com.imdroid.beidou.data;
/**
* 描述
*
* @author LiGang
*/
public class WxMiniUserSession {
private String sessionKey;
private String openid;
public WxMiniUserSession() {
}
public WxMiniUserSession(String sessionKey, String openid) {
this.sessionKey = sessionKey;
this.openid = openid;
}
public String getSessionKey() {
return sessionKey;
}
public void setSessionKey(String sessionKey) {
this.sessionKey = sessionKey;
}
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
}

View File

@ -0,0 +1,29 @@
package com.imdroid.beidou.data.vo;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
* 小程序用户注册VO
*
* @author LiGang
*/
@Setter
@Getter
public class MiniUserRegisterVO {
@NotBlank(message = "用户code不能为空")
private String code;
@NotBlank(message = "用户头像不能为空")
private String avatarUrl;
@NotBlank(message = "手机号不能为空")
private String mobile;
@NotBlank(message = "昵称不能为空")
private String nickName;
}

View File

@ -0,0 +1,24 @@
package com.imdroid.beidou.data.vo;
import lombok.Getter;
import lombok.Setter;
/**
* 小程序用户信息VO
*
* @author LiGang
*/
@Setter
@Getter
public class MiniUserVO {
private String avatarUrl;
private String mobile;
private String nickName;
private String username;
private String tenantName;
}

View File

@ -0,0 +1,31 @@
package com.imdroid.beidou.data.vo;
import lombok.Getter;
import lombok.Setter;
/**
* 用户登录VO
*
* @author LiGang
*/
@Setter
@Getter
public class UserLoginVO {
public static final String LOGIN_TYPE_WEB = "web";
public static final String LOGIN_TYPE_MINI = "mini";
private String username;
private String password;
private String type;
/**
* 小程序用户code
*/
private String code;
}

View File

@ -0,0 +1,26 @@
package com.imdroid.beidou.data.vo.device;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
* 设备现场安装VO类
*
* @author LiGang
*/
@Setter
@Getter
public class DeviceInstallVO {
@NotBlank(message = "设备编号不能为空")
private String deviceId;
@NotBlank(message = "设备安装位置的经纬度不能为空")
private String location;
@NotBlank(message = "现场图片不能为空")
private String pictures;
}

View File

@ -0,0 +1,85 @@
package com.imdroid.beidou.data.vo.device;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.imdroid.secapi.dto.GnssDevice;
import com.imdroid.secapi.dto.GnssStatusJoin;
import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
/**
* @author LiGang
* @date 2023/10/13 21:50
*/
@Setter
@Getter
public class DeviceStatusVO {
private Long id;
private String deviceId;
private String name;
private String location;
private String pictures;
private String tenantName;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date latestDataTime;
private Float roll;
private Float pitch;
private Float yaw;
private Integer rssi;
private Integer voltage;
private Float temperature;
private Float humidity;
private Integer txbytes;
private Integer rxbytes;
private Integer b562bytes;
private Integer d3xxbytes;
private Integer satelliteinview;
private Integer satelliteinuse;
private Short dtuState;
public DeviceStatusVO() {
}
public DeviceStatusVO(GnssDevice gnssDevice, GnssStatusJoin gnssStatus) {
this.id = gnssDevice.getId();
this.deviceId = gnssDevice.getDeviceid();
this.name = gnssDevice.getName();
//this.location = gnssDevice.getLocation();
this.pictures = gnssDevice.getPictures();
this.tenantName = gnssDevice.getTenantname();
//this.latestDataTime = gnssDevice.getLatest_data_time();
if (gnssStatus != null) {
this.latestDataTime = gnssStatus.getUpdatetime();
this.location = gnssStatus.getLocation();
this.roll = gnssStatus.getRoll();
this.pitch = gnssStatus.getPitch();
this.yaw = gnssStatus.getYaw();
this.rssi = gnssStatus.getRssi();
this.voltage = gnssStatus.getVoltage();
this.temperature = gnssStatus.getTemperature();
this.humidity = gnssStatus.getHumidity();
this.txbytes = gnssStatus.getTxbytes();
this.rxbytes = gnssStatus.getRxbytes();
this.d3xxbytes = gnssStatus.getD3xxbytes();
this.b562bytes = gnssStatus.getB562bytes();
this.satelliteinview = gnssStatus.getSatelliteinview();
this.satelliteinuse = gnssStatus.getSatelliteinuse();
this.dtuState = gnssStatus.getState();
}
}
}

View File

@ -0,0 +1,16 @@
package com.imdroid.beidou.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName(value = "gnssgroupcalc")
public class GnssGroupCalc {
int id;
int long_cycle;
int short_cycle;
float shock;
float h_weight;
float v_weight;
int device_num;
}

View File

@ -0,0 +1,9 @@
package com.imdroid.beidou.entity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface GnssGroupCalcMapper extends BaseMapper<GnssGroupCalc> {
}

View File

@ -0,0 +1,14 @@
package com.imdroid.beidou.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName(value = "gnssgroupfwd")
public class GnssGroupFwd {
int id;
String description;
String addr;
int port;
String fwd_template;
}

Some files were not shown because too many files have changed in this diff Show More