使用debug查看位置数据的数据结构
1.数据表
CREATE TABLE `gps` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`longitude` decimal(9,6) DEFAULT '0.000000',
`latitude` decimal(9,6) DEFAULT '0.000000',
`machine_no` varchar(15) DEFAULT '',
`device_time` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4;
2.yml配置文件, 注释掉h2数据库
spring:
application:
name: jt808
datasource:
url: jdbc:mysql://localhost:3306/ssm
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
# datasource:
# url: jdbc:h2:file:~/.h2/jt;auto_server=true;ignorecase=true;mode=mysql
# username: root
# password: root
# driver-class-name: org.h2.Driver
# type: com.zaxxer.hikari.HikariDataSource
# hikari:
# minimum-idle: 8
# maximum-pool-size: 8
# transaction-isolation: TRANSACTION_READ_COMMITTED #降低事务隔离级别,提高写入速度
# data-source-properties:
# useSSL: false
# sslMode: disabled
# serverTimezone: GMT+8
# characterEncoding: UTF-8
# zeroDateTimeBehavior: convertToNull #日期时间0000-00-00 00:00:00转换为null
# allowPublicKeyRetrieval: true #MySQL8.0 允许特殊的握手往返,直接从服务器获取RSA公钥。
# cachePrepStmts: true #是否缓存客户端的预编译语句(PreparedStatement),检查预编译语句的可准备性?
# cacheResultSetMetadata: true #是否应该缓存预编译语句的元数据(ResultSetMetaData)?
# cacheServerConfiguration: true #是否应该缓存基于每个URL“SHOW VARIABLES”和“SHOW COLLATION”的结果?
# prepStmtCacheSize: 64 #如果启用了预编译语句缓存,应缓存多少个?
# prepStmtCacheSqlLimit: 65535 #如果启用了预编译语句缓存,将缓存解析的最大SQL长度是多少字节?
# useServerPrepStmts: true #如果服务器支持的话,使用服务器端的预编译语句吗?
# useLocalTransactionState: true #是否使用MySQL协议提供的事务状态来决定将commit()或rollback()发送到数据库?
# useLocalSessionState: true #是否参考由Connection.setAutoCommit()和Connection.setTransactionIsolation()设置的自动提交和事务隔离等级以及协议维护的事务状态,而不是查询数据库或盲目地向数据库发送commit()或rollback()命令?
# alwaysSendSetIsolation: false #当调用Connection.setTransactionIsolation()时,驱动程序是否应该始终与数据库通信?如果设置为false,则只有当请求的事务隔离等级与较新的、通过setTransactionIsolation()设置的最后一个值或在建立连接时从服务器读取的值不同时,驱动程序才会与数据库通信。注意,无论alwaysSendSetIsolation是如何设置的,useLocalSessionState=true都将强制执行与alwaysSendSetIsolation=false相同的行为。
# elideSetAutoCommits: true #是否应该仅在服务器状态与Connection.setAutoCommit(boolean)所请求的状态不匹配时才发出“set autocommit = n”查询?
# allowMultiQueries: true #是否允许使用“;”在一条语句中分隔多个语句。它不影响addBatch()和executeBatch()方法,它们依赖于rewriteBatchStatements。
# rewriteBatchedStatements: true #当executeBatch()被调用时,驱动程序是否应该重写预编译语句以多值方式批量插入?
# enableQueryTimeouts: false #启用后,通过Statement.setQueryTimeout()设置的timeout将使用共享的java.util.Timer实例进行调度。即便查询没有超时,TimerTask也会在指定的timeout时间内使用内存,如果没有被驱动程序取消,这些内存直到timeout到期时才会被回收。高负载环境可能需要考虑禁用此功能。
# maintainTimeStats: false #与服务器连接失败时,驱动程序是否应该维护各种内部计时器以启用空闲时间计算以及更多详细的错误消息?设为false会取消每个查询至少两次调用System.getCurrentTimeMillis()。
# useCompression: false #与服务器通信时使用zlib压缩
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
mvc:
format:
date-time: yyyy-MM-dd HH:mm:ss
date: yyyy-MM-dd
time: HH:mm:ss
mybatis:
configuration:
use-generated-keys: true
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
mapper-locations:
- classpath:/mapper/*.xml
server:
port: 8000
jt-server:
jt808:
enable: true
port:
udp: 7611
tcp: 7611
media-file:
path: D:/jt_data/media_file
alarm-file:
host: 127.0.0.1
port: 7612
alarm-file:
enable: true
port: 7612
path: D:/jt_data/alarm_file
2.2 入口文件 src/main/java/org/yzh/web/Application.java
@MapperScan("org.yzh.mapper") // 确保这里的包路径是正确的
2.3 pom文件, 增加了lombook和mysql,mybatis
<?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.yzh</groupId>
<artifactId>jtt808-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>jtt808-server</artifactId>
<packaging>jar</packaging>
<url>https://gitee.com/yezhihao/jt808-server</url>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<dependencies>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-spring-boot-starter</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-starter-logging</artifactId>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
</exclusion>
<exclusion>
<groupId>jakarta.websocket</groupId>
<artifactId>jakarta.websocket-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-server</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>javax-websocket-server-impl</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-typehandlers-jsr310</artifactId>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<dependency>
<groupId>org.yzh</groupId>
<artifactId>jtt808-protocol</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.yzh</groupId>
<artifactId>commons</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.2</version>
<configuration>
<verbose>true</verbose>
<overwrite>true</overwrite>
<configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
</configuration>
<dependencies>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>${mariadb.version}</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
3.pojo模型类
package org.yzh.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.sql.Timestamp;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Gps {
private double longitude;
private double latitude;
private String machineNo;
private Timestamp deviceTime;
}
4.Mapper类
package org.yzh.mapper;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.yzh.pojo.Gps;
@Mapper
public interface GpsMapper {
// 插入数据
@Insert("INSERT INTO `gps` (longitude, latitude, machine_no, device_time) values (#{longitude}, #{latitude}, #{machineNo}, #{deviceTime})")
public void insert(Gps gps);
}
5.入库代码 T0200方法
package org.yzh.web.endpoint;
import io.github.yezhihao.netmc.core.annotation.Async;
import io.github.yezhihao.netmc.core.annotation.AsyncBatch;
import io.github.yezhihao.netmc.core.annotation.Endpoint;
import io.github.yezhihao.netmc.core.annotation.Mapping;
import io.github.yezhihao.netmc.session.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.yzh.mapper.GpsMapper;
import org.yzh.pojo.Gps;
import org.yzh.protocol.basics.JTMessage;
import org.yzh.protocol.commons.JT808;
import org.yzh.protocol.t808.*;
import org.yzh.web.model.entity.DeviceDO;
import org.yzh.web.model.enums.SessionKey;
import org.yzh.web.service.FileService;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import static org.yzh.protocol.commons.JT808.*;
@Endpoint
@Component
public class JT808Endpoint {
private static final Logger log = LoggerFactory.getLogger(JT808Endpoint.class);
@Autowired
private FileService fileService;
@Mapping(types = 终端通用应答, desc = "终端通用应答")
public Object T0001(T0001 message, Session session) {
session.response(message);
return null;
}
@Mapping(types = 终端心跳, desc = "终端心跳")
public void T0002(JTMessage message, Session session) {
}
@Mapping(types = 终端注销, desc = "终端注销")
public void T0003(JTMessage message, Session session) {
session.invalidate();
}
@Mapping(types = 查询服务器时间, desc = "查询服务器时间")
public T8004 T0004(JTMessage message, Session session) {
T8004 result = new T8004(LocalDateTime.now(ZoneOffset.UTC));
return result;
}
@Mapping(types = 终端补传分包请求, desc = "终端补传分包请求")
public void T8003(T8003 message, Session session) {
}
@Mapping(types = 终端注册, desc = "终端注册")
public T8100 T0100(T0100 message, Session session) {
session.register(message);
DeviceDO device = new DeviceDO();
device.setProtocolVersion(message.getProtocolVersion());
device.setMobileNo(message.getClientId());
device.setDeviceId(message.getDeviceId());
device.setPlateNo(message.getPlateNo());
session.setAttribute(SessionKey.Device, device);
T8100 result = new T8100();
result.setResponseSerialNo(message.getSerialNo());
result.setToken(message.getDeviceId() + "," + message.getPlateNo());
result.setResultCode(T8100.Success);
return result;
}
@Mapping(types = 终端鉴权, desc = "终端鉴权")
public T0001 T0102(T0102 message, Session session) {
session.register(message);
DeviceDO device = new DeviceDO();
String[] token = message.getToken().split(",");
device.setProtocolVersion(message.getProtocolVersion());
device.setMobileNo(message.getClientId());
device.setDeviceId(token[0]);
if (token.length > 1)
device.setPlateNo(token[1]);
session.setAttribute(SessionKey.Device, device);
T0001 result = new T0001();
result.setResponseSerialNo(message.getSerialNo());
result.setResponseMessageId(message.getMessageId());
result.setResultCode(T0001.Success);
return result;
}
@Mapping(types = 查询终端参数应答, desc = "查询终端参数应答")
public void T0104(T0104 message, Session session) {
session.response(message);
}
@Mapping(types = 查询终端属性应答, desc = "查询终端属性应答")
public void T0107(T0107 message, Session session) {
session.response(message);
}
@Mapping(types = 终端升级结果通知, desc = "终端升级结果通知")
public void T0108(T0108 message, Session session) {
}
@Autowired
private GpsMapper gpsMapper;
/**
* 异步批量处理
* poolSize:参考数据库CPU核心数量
* maxElements:最大累积4000条记录处理一次
* maxWait:最大等待时间1秒
*/
@AsyncBatch(poolSize = 2, maxElements = 4000, maxWait = 1000)
@Mapping(types = 位置信息汇报, desc = "位置信息汇报")
public void T0200(List<T0200> list) {
List<Gps> getDataList = new ArrayList<>();
for (T0200 t0200 : list) {
Gps getData = new Gps();
getData.setLongitude(t0200.getLongitude() / 1000000.0);
getData.setLatitude(t0200.getLatitude() / 1000000.0);
getData.setMachineNo(t0200.getClientId());
getData.setDeviceTime(Timestamp.valueOf(t0200.getDeviceTime()));
getDataList.add(getData);
}
// 调用数据插入方法
for (Gps getData : getDataList) {
gpsMapper.insert(getData);
}
}
@Mapping(types = 定位数据批量上传, desc = "定位数据批量上传")
public void T0704(T0704 message) {
}
@Mapping(types = {位置信息查询应答, 车辆控制应答}, desc = "位置信息查询应答/车辆控制应答")
public void T0201_0500(T0201_0500 message, Session session) {
session.response(message);
}
@Mapping(types = 事件报告, desc = "事件报告")
public void T0301(T0301 message, Session session) {
}
@Mapping(types = 提问应答, desc = "提问应答")
public void T0302(T0302 message, Session session) {
}
@Mapping(types = 信息点播_取消, desc = "信息点播/取消")
public void T0303(T0303 message, Session session) {
}
@Mapping(types = 查询区域或线路数据应答, desc = "查询区域或线路数据应答")
public void T0608(T0608 message, Session session) {
session.response(message);
}
@Mapping(types = 行驶记录数据上传, desc = "行驶记录仪数据上传")
public void T0700(T0700 message, Session session) {
session.response(message);
}
@Mapping(types = 电子运单上报, desc = "电子运单上报")
public void T0701(JTMessage message, Session session) {
}
@Mapping(types = 驾驶员身份信息采集上报, desc = "驾驶员身份信息采集上报")
public void T0702(T0702 message, Session session) {
session.response(message);
}
@Mapping(types = CAN总线数据上传, desc = "CAN总线数据上传")
public void T0705(T0705 message, Session session) {
}
@Mapping(types = 多媒体事件信息上传, desc = "多媒体事件信息上传")
public void T0800(T0800 message, Session session) {
}
@Async
@Mapping(types = 多媒体数据上传, desc = "多媒体数据上传")
public JTMessage T0801(T0801 message, Session session) {
if (message.getPacket() == null) {
T0001 result = new T0001();
result.copyBy(message);
result.setMessageId(JT808.平台通用应答);
result.setSerialNo(session.nextSerialNo());
result.setResponseSerialNo(message.getSerialNo());
result.setResponseMessageId(message.getMessageId());
result.setResultCode(T0001.Success);
return result;
}
fileService.saveMediaFile(message);
T8800 result = new T8800();
result.setMediaId(message.getId());
return result;
}
@Mapping(types = 存储多媒体数据检索应答, desc = "存储多媒体数据检索应答")
public void T0802(T0802 message, Session session) {
session.response(message);
}
@Mapping(types = 摄像头立即拍摄命令应答, desc = "摄像头立即拍摄命令应答")
public void T0805(T0805 message, Session session) {
session.response(message);
}
@Mapping(types = 数据上行透传, desc = "数据上行透传")
public void T0900(T0900 message, Session session) {
}
@Mapping(types = 数据压缩上报, desc = "数据压缩上报")
public void T0901(T0901 message, Session session) {
}
@Mapping(types = 终端RSA公钥, desc = "终端RSA公钥")
public void T0A00(T0A00_8A00 message, Session session) {
session.response(message);
}
}
项目结构