master
parent
83745a2d43
commit
ee5b061e4d
7
pom.xml
7
pom.xml
|
|
@ -3,7 +3,7 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.njzscloud</groupId>
|
||||
<artifactId>gps</artifactId>
|
||||
<artifactId>localizer</artifactId>
|
||||
<version>0.0.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
|
|
@ -18,6 +18,11 @@
|
|||
<artifactId>fastjson2</artifactId>
|
||||
<version>2.0.51</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.paho</groupId>
|
||||
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
|
||||
<version>1.2.5</version>
|
||||
</dependency>
|
||||
<!--<editor-fold desc="jackson">-->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
|
|
|
|||
|
|
@ -1,21 +1,14 @@
|
|||
package com.njzscloud;
|
||||
|
||||
import com.njzscloud.server.TcpServer;
|
||||
import com.njzscloud.tuqiang.Tuqiang;
|
||||
import com.njzscloud.common.mqtt.Mqtt;
|
||||
import com.njzscloud.common.tuqiang.Tuqiang;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class App {
|
||||
static Tuqiang tuqiang;
|
||||
|
||||
public static void main(String[] args) {
|
||||
tuqiang = new Tuqiang();
|
||||
TcpServer tcpServer = new TcpServer(18888, 1, 2);
|
||||
try {
|
||||
tcpServer.start();
|
||||
log.info("TCP服务器已停止");
|
||||
} catch (Exception e) {
|
||||
log.error("TCP服务器启动失败", e);
|
||||
}
|
||||
Mqtt.run("tcp://localhost:1883", "tuqiang", "admin", "123456");
|
||||
Mqtt.addListener(new MqttMsgHandlers());
|
||||
Tuqiang.run(18888, 1, 2);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
package com.njzscloud;
|
||||
|
||||
import com.njzscloud.common.mqtt.support.MqttListener;
|
||||
import com.njzscloud.common.mqtt.support.MqttMsg;
|
||||
import com.njzscloud.common.tuqiang.Tuqiang;
|
||||
import com.njzscloud.param.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class MqttMsgHandlers {
|
||||
|
||||
/**
|
||||
* 开启追踪
|
||||
*/
|
||||
@MqttListener(topic = "location/track")
|
||||
public void onMessage(MqttMsg msg) {
|
||||
LocationTrackParam locationTrackParam = msg.getMsg(LocationTrackParam.class);
|
||||
Tuqiang.track(locationTrackParam.getTerminalId(), locationTrackParam.getInterval());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前位置
|
||||
*/
|
||||
@MqttListener(topic = "location/current")
|
||||
public void currentLocation(MqttMsg msg) {
|
||||
LocationCurrentParam locationCurrentParam = msg.getMsg(LocationCurrentParam.class);
|
||||
Tuqiang.currentLocation(locationCurrentParam.getTerminalId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用报警
|
||||
*/
|
||||
@MqttListener(topic = "location/warn")
|
||||
public void enableWarn(MqttMsg msg) {
|
||||
EnableWarnParam enableWarnParam = msg.getMsg(EnableWarnParam.class);
|
||||
String terminalId = enableWarnParam.getTerminalId();
|
||||
boolean enable = enableWarnParam.isEnable();
|
||||
Tuqiang.enableWarn(terminalId, enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置速度阈值
|
||||
*/
|
||||
@MqttListener(topic = "location/speed_threshold")
|
||||
public void speedThreshold(MqttMsg msg) {
|
||||
SpeedThresholdParam speedThresholdParam = msg.getMsg(SpeedThresholdParam.class);
|
||||
String terminalId = speedThresholdParam.getTerminalId();
|
||||
int speed = speedThresholdParam.getSpeed();
|
||||
Tuqiang.speedThreshold(terminalId, speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备信息
|
||||
*/
|
||||
@MqttListener(topic = "location/device_info")
|
||||
public void obtainDeviceInfo(MqttMsg msg) {
|
||||
ObtainDeviceInfoParam obtainDeviceInfoParam = msg.getMsg(ObtainDeviceInfoParam.class);
|
||||
String terminalId = obtainDeviceInfoParam.getTerminalId();
|
||||
Tuqiang.obtainDeviceInfo(terminalId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备信息
|
||||
*/
|
||||
@MqttListener(topic = "location/heartbeat")
|
||||
public void setHeartbeat(MqttMsg msg) {
|
||||
SetHeartbeatParam setHeartbeatParam = msg.getMsg(SetHeartbeatParam.class);
|
||||
String terminalId = setHeartbeatParam.getTerminalId();
|
||||
Tuqiang.setHeartbeat(terminalId, setHeartbeatParam.getInterval());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
package com.njzscloud;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import com.njzscloud.common.jt808.support.MessageBody;
|
||||
import com.njzscloud.common.mqtt.Mqtt;
|
||||
import com.njzscloud.common.tuqiang.msg.DeviceInfo;
|
||||
import com.njzscloud.common.tuqiang.msg.LocationReportMsg;
|
||||
import com.njzscloud.common.tuqiang.msg.SearchLocationResponseMsg;
|
||||
import com.njzscloud.common.tuqiang.msg.TerminalTxtReportMsg;
|
||||
import com.njzscloud.common.tuqiang.support.TuqiangListener;
|
||||
import com.njzscloud.result.RealtimeLocationResult;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import static com.njzscloud.common.jt808.support.JT808MessageResolver.*;
|
||||
|
||||
@Slf4j
|
||||
public class TuqiangListeners {
|
||||
/**
|
||||
* 终端心跳消息
|
||||
*/
|
||||
@TuqiangListener(messageId = Heartbeat)
|
||||
public void onHeartbeat(MessageBody message) {
|
||||
String terminalId = message.getTerminalId();
|
||||
Mqtt.publish(terminalId + "/online", MapUtil.builder()
|
||||
.put("online", true)
|
||||
.put("terminalId", terminalId)
|
||||
.put("time", DateUtil.now())
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* 终端位置信息汇报消息
|
||||
*/
|
||||
@TuqiangListener(messageId = LocationReport)
|
||||
public void onLocationReport(MessageBody message) {
|
||||
ByteBuf byteBuf = message.getBody();
|
||||
LocationReportMsg locationReportMsg = new LocationReportMsg(byteBuf);
|
||||
log.info("终端位置信息汇报消息: {}", locationReportMsg);
|
||||
|
||||
String terminalId = message.getTerminalId();
|
||||
RealtimeLocationResult realtimeLocationResult = BeanUtil.copyProperties(locationReportMsg, RealtimeLocationResult.class)
|
||||
.setTerminalId(terminalId);
|
||||
Mqtt.publish(terminalId + "/track_location", realtimeLocationResult);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 定位数据批量上传消息
|
||||
*/
|
||||
@TuqiangListener(messageId = LocationBatchReport)
|
||||
public void onLocationBatchUpload(MessageBody message) {
|
||||
String terminalId = message.getTerminalId();
|
||||
ByteBuf body = message.getBody();
|
||||
int count = body.readUnsignedShort();
|
||||
int type = body.readByte();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
int length = body.readUnsignedShort();
|
||||
LocationReportMsg locationReportMsg = new LocationReportMsg(body.slice(body.readerIndex(), length));
|
||||
body.skipBytes(length);
|
||||
BeanUtil.copyProperties(locationReportMsg, RealtimeLocationResult.class);
|
||||
RealtimeLocationResult realtimeLocationResult = BeanUtil.copyProperties(locationReportMsg, RealtimeLocationResult.class)
|
||||
.setTerminalId(terminalId)
|
||||
.setType(type == 0 ? "正常位置汇报" : "盲区补报");
|
||||
Mqtt.publish(terminalId + "/track_location", realtimeLocationResult);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询位置响应消息
|
||||
*/
|
||||
@TuqiangListener(messageId = LocationSearch)
|
||||
public void onSearchLocationResponse(MessageBody message) {
|
||||
String terminalId = message.getTerminalId();
|
||||
ByteBuf body = message.getBody();
|
||||
SearchLocationResponseMsg searchLocationResponseMsg = new SearchLocationResponseMsg(body);
|
||||
log.info("查询位置响应消息: {}", searchLocationResponseMsg);
|
||||
|
||||
LocationReportMsg locationReportMsg = searchLocationResponseMsg.getLocationReportMsg();
|
||||
RealtimeLocationResult realtimeLocationResult = BeanUtil.copyProperties(locationReportMsg, RealtimeLocationResult.class)
|
||||
.setTerminalId(terminalId);
|
||||
Mqtt.publish(terminalId + "/current_location", realtimeLocationResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* 终端文本信息汇报消息
|
||||
*/
|
||||
@TuqiangListener(messageId = TxtReport)
|
||||
public void onTerminalTxtReport(MessageBody message) {
|
||||
TerminalTxtReportMsg terminalTxtReportMsg = new TerminalTxtReportMsg(message.getBody());
|
||||
log.info("终端文本信息汇报消息: {}", terminalTxtReportMsg);
|
||||
String txt = terminalTxtReportMsg.getTxt();
|
||||
DeviceInfo deviceInfo = DeviceInfo.parse(txt);
|
||||
if (deviceInfo != null) {
|
||||
String terminalId = message.getTerminalId();
|
||||
Mqtt.publish(terminalId + "/device_info", deviceInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.ex;
|
||||
package com.njzscloud.common.core.ex;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.ex;
|
||||
package com.njzscloud.common.core.ex;
|
||||
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.ex;
|
||||
package com.njzscloud.common.core.ex;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.ex;
|
||||
package com.njzscloud.common.core.ex;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.ex;
|
||||
package com.njzscloud.common.core.ex;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.ex;
|
||||
package com.njzscloud.common.core.ex;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.ex;
|
||||
package com.njzscloud.common.core.ex;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.ex;
|
||||
package com.njzscloud.common.core.ex;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.njzscloud.common.ex;
|
||||
package com.njzscloud.common.core.ex;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import com.njzscloud.common.jackson.Jackson;
|
||||
import com.njzscloud.common.core.jackson.Jackson;
|
||||
|
||||
/**
|
||||
* 系统异常
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.fastjson;
|
||||
package com.njzscloud.common.core.fastjson;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
package com.njzscloud.common.fastjson.serializer;
|
||||
package com.njzscloud.common.core.fastjson.serializer;
|
||||
|
||||
|
||||
import com.alibaba.fastjson2.JSONReader;
|
||||
import com.alibaba.fastjson2.reader.ObjectReader;
|
||||
import com.alibaba.fastjson2.util.TypeUtils;
|
||||
import com.njzscloud.common.ex.Exceptions;
|
||||
import com.njzscloud.common.ienum.Dict;
|
||||
import com.njzscloud.common.ienum.DictInt;
|
||||
import com.njzscloud.common.ienum.DictStr;
|
||||
import com.njzscloud.common.ienum.IEnum;
|
||||
import com.njzscloud.common.core.ex.Exceptions;
|
||||
import com.njzscloud.common.core.ienum.Dict;
|
||||
import com.njzscloud.common.core.ienum.DictInt;
|
||||
import com.njzscloud.common.core.ienum.DictStr;
|
||||
import com.njzscloud.common.core.ienum.IEnum;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
package com.njzscloud.common.fastjson.serializer;
|
||||
package com.njzscloud.common.core.fastjson.serializer;
|
||||
|
||||
import com.alibaba.fastjson2.JSONWriter;
|
||||
import com.alibaba.fastjson2.util.TypeUtils;
|
||||
import com.alibaba.fastjson2.writer.ObjectWriter;
|
||||
import com.njzscloud.common.ienum.Dict;
|
||||
import com.njzscloud.common.ienum.DictInt;
|
||||
import com.njzscloud.common.ienum.DictStr;
|
||||
import com.njzscloud.common.ienum.IEnum;
|
||||
import com.njzscloud.common.core.ienum.Dict;
|
||||
import com.njzscloud.common.core.ienum.DictInt;
|
||||
import com.njzscloud.common.core.ienum.DictStr;
|
||||
import com.njzscloud.common.core.ienum.IEnum;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
package com.njzscloud.common.ienum;
|
||||
package com.njzscloud.common.core.ienum;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.njzscloud.common.fastjson.serializer.DictObjectDeserializer;
|
||||
import com.njzscloud.common.fastjson.serializer.DictObjectSerializer;
|
||||
import com.njzscloud.common.jackson.serializer.DictDeserializer;
|
||||
import com.njzscloud.common.jackson.serializer.DictSerializer;
|
||||
import com.njzscloud.common.core.fastjson.serializer.DictObjectDeserializer;
|
||||
import com.njzscloud.common.core.fastjson.serializer.DictObjectSerializer;
|
||||
import com.njzscloud.common.core.jackson.serializer.DictDeserializer;
|
||||
import com.njzscloud.common.core.jackson.serializer.DictSerializer;
|
||||
|
||||
/**
|
||||
* 字典枚举<br/>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.ienum;
|
||||
package com.njzscloud.common.core.ienum;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.ienum;
|
||||
package com.njzscloud.common.core.ienum;
|
||||
|
||||
/**
|
||||
* "值" 类型为 String<br/>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.ienum;
|
||||
package com.njzscloud.common.core.ienum;
|
||||
|
||||
/**
|
||||
* 枚举接口
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.jackson;
|
||||
package com.njzscloud.common.core.jackson;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
|
@ -9,10 +9,10 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
|
|||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||
import com.njzscloud.common.ex.Exceptions;
|
||||
import com.njzscloud.common.jackson.serializer.BigDecimalModule;
|
||||
import com.njzscloud.common.jackson.serializer.LongModule;
|
||||
import com.njzscloud.common.jackson.serializer.TimeModule;
|
||||
import com.njzscloud.common.core.ex.Exceptions;
|
||||
import com.njzscloud.common.core.jackson.serializer.BigDecimalModule;
|
||||
import com.njzscloud.common.core.jackson.serializer.LongModule;
|
||||
import com.njzscloud.common.core.jackson.serializer.TimeModule;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.jackson.serializer;
|
||||
package com.njzscloud.common.core.jackson.serializer;
|
||||
|
||||
import com.fasterxml.jackson.databind.deser.std.NumberDeserializers;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.jackson.serializer;
|
||||
package com.njzscloud.common.core.jackson.serializer;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
package com.njzscloud.common.jackson.serializer;
|
||||
package com.njzscloud.common.core.jackson.serializer;
|
||||
|
||||
import com.fasterxml.jackson.core.*;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.node.IntNode;
|
||||
import com.fasterxml.jackson.databind.node.TextNode;
|
||||
import com.njzscloud.common.ex.Exceptions;
|
||||
import com.njzscloud.common.ienum.Dict;
|
||||
import com.njzscloud.common.ienum.DictInt;
|
||||
import com.njzscloud.common.ienum.DictStr;
|
||||
import com.njzscloud.common.ienum.IEnum;
|
||||
import com.njzscloud.common.core.ex.Exceptions;
|
||||
import com.njzscloud.common.core.ienum.Dict;
|
||||
import com.njzscloud.common.core.ienum.DictInt;
|
||||
import com.njzscloud.common.core.ienum.DictStr;
|
||||
import com.njzscloud.common.core.ienum.IEnum;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
package com.njzscloud.common.jackson.serializer;
|
||||
package com.njzscloud.common.core.jackson.serializer;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonStreamContext;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.njzscloud.common.ienum.Dict;
|
||||
import com.njzscloud.common.ienum.DictInt;
|
||||
import com.njzscloud.common.ienum.DictStr;
|
||||
import com.njzscloud.common.ienum.IEnum;
|
||||
import com.njzscloud.common.core.ienum.Dict;
|
||||
import com.njzscloud.common.core.ienum.DictInt;
|
||||
import com.njzscloud.common.core.ienum.DictStr;
|
||||
import com.njzscloud.common.core.ienum.IEnum;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.jackson.serializer;
|
||||
package com.njzscloud.common.core.jackson.serializer;
|
||||
|
||||
import com.fasterxml.jackson.databind.deser.std.NumberDeserializers;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.jackson.serializer;
|
||||
package com.njzscloud.common.core.jackson.serializer;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.jackson.serializer;
|
||||
package com.njzscloud.common.core.jackson.serializer;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.log;
|
||||
package com.njzscloud.common.core.log;
|
||||
|
||||
|
||||
import java.util.Arrays;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.log;
|
||||
package com.njzscloud.common.core.log;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.common.utils;
|
||||
package com.njzscloud.common.core.utils;
|
||||
|
||||
public class BCD {
|
||||
public static String bcdToStr(byte[] bcd) {
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
package com.njzscloud.common.utils;
|
||||
package com.njzscloud.common.core.utils;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import com.njzscloud.common.ex.Exceptions;
|
||||
import com.njzscloud.common.fastjson.Fastjson;
|
||||
import com.njzscloud.common.core.ex.Exceptions;
|
||||
import com.njzscloud.common.core.fastjson.Fastjson;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
package com.njzscloud.common.jt808;
|
||||
|
||||
import com.njzscloud.common.jt808.support.JT808Message;
|
||||
import com.njzscloud.common.jt808.support.JT808MessageResolver;
|
||||
import com.njzscloud.common.jt808.support.MessageBody;
|
||||
import com.njzscloud.common.jt808.util.FlowId;
|
||||
import com.njzscloud.common.tcp.TcpServer;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* JT808消息发送工具类
|
||||
* 提供便捷的方法发送各种类型的JT808消息
|
||||
*/
|
||||
@Slf4j
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class JT808 {
|
||||
|
||||
// 终端手机号与Channel的映射
|
||||
private static final Map<String, Channel> terminalChannels = new ConcurrentHashMap<>();
|
||||
|
||||
private static TcpServer tcpServer;
|
||||
|
||||
public static void run(int port, int bossThreads, int workerThreads) {
|
||||
tcpServer = new TcpServer(port, bossThreads, workerThreads);
|
||||
tcpServer.start();
|
||||
}
|
||||
|
||||
public static void stop() {
|
||||
if (tcpServer != null) {
|
||||
tcpServer.stop();
|
||||
tcpServer = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册消息监听器
|
||||
*/
|
||||
public static void addListener(String messageId, Consumer<MessageBody> listener) {
|
||||
JT808MessageResolver.addResolver(messageId, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册终端与通道的映射关系
|
||||
*/
|
||||
public static void register(String terminalId, Channel channel) {
|
||||
if (terminalId != null && channel != null) {
|
||||
if (terminalChannels.get(terminalId) != channel) {
|
||||
terminalChannels.put(terminalId, channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除终端与通道的映射关系
|
||||
*/
|
||||
public static void unregister(Channel channel) {
|
||||
if (channel != null) {
|
||||
terminalChannels.values().removeIf(ch -> ch == channel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送通用应答消息 (0x8001)
|
||||
*/
|
||||
public static void sendGeneralResponse(JT808Message message) {
|
||||
String terminalPhone = message.getTerminalPhone();
|
||||
int flowId = message.getFlowId();
|
||||
int messageId = message.getMessageId();
|
||||
|
||||
ByteBuf body = Unpooled.buffer();
|
||||
ByteBufUtil.writeShortBE(body, flowId);
|
||||
ByteBufUtil.writeShortBE(body, messageId);
|
||||
body.writeByte(0);
|
||||
|
||||
// 构建消息
|
||||
byte[] bytes = ByteBufUtil.getBytes(body);
|
||||
body.release();
|
||||
message = JT808.createBaseMessage(terminalPhone, 0x8001, bytes);
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 向指定终端发送消息
|
||||
*/
|
||||
public static void sendMessage(JT808Message message) {
|
||||
String terminalPhone = message.getTerminalPhone();
|
||||
|
||||
Channel channel = terminalChannels.get(terminalPhone);
|
||||
if (channel != null && channel.isActive()) {
|
||||
channel.writeAndFlush(message)
|
||||
.addListener((ChannelFutureListener) future -> {
|
||||
if (future.isSuccess()) {
|
||||
log.info("消息发送成功, 终端: {}, 消息ID: 0x{}, 流水号: {}", terminalPhone, Integer.toHexString(message.getMessageId()), message.getFlowId());
|
||||
} else {
|
||||
log.error("消息发送失败, 终端: {}, 消息ID: 0x{}, 流水号: {}", terminalPhone, Integer.toHexString(message.getMessageId()), message.getFlowId(), future.cause());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
unregister(channel);
|
||||
// 终端不在线或通道已关闭
|
||||
log.warn("终端不在线: {}", terminalPhone);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建基础消息对象
|
||||
*/
|
||||
public static JT808Message createBaseMessage(String terminalId, int messageId) {
|
||||
return createBaseMessage(terminalId, messageId, null);
|
||||
}
|
||||
|
||||
public static JT808Message createBaseMessage(String terminalId, int messageId, byte[] body) {
|
||||
JT808Message message = new JT808Message()
|
||||
.setFlowId(FlowId.next(terminalId, messageId));
|
||||
|
||||
// 设置消息ID
|
||||
message.setMessageId(messageId);
|
||||
|
||||
// 设置消息体属性
|
||||
// 其他属性默认:不分包,不加密
|
||||
if (body != null) {
|
||||
message.setMessageBodyProps(body.length);
|
||||
} else {
|
||||
message.setMessageBodyProps(0);
|
||||
}
|
||||
|
||||
// 设置终端手机号
|
||||
message.setTerminalPhone(terminalId);
|
||||
|
||||
// 设置消息体
|
||||
message.setMessageBody(body);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.jt808.protocol;
|
||||
package com.njzscloud.common.jt808.support;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.jt808.protocol;
|
||||
package com.njzscloud.common.jt808.support;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.njzscloud.jt808.protocol;
|
||||
package com.njzscloud.common.jt808.support;
|
||||
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import com.njzscloud.common.fastjson.Fastjson;
|
||||
import com.njzscloud.common.core.fastjson.Fastjson;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
|
@ -30,9 +30,6 @@ public class JT808Message {
|
|||
// 校验码 (1字节)
|
||||
private byte checkCode;
|
||||
|
||||
public JT808Message() {
|
||||
}
|
||||
|
||||
// 从消息体属性中获取消息体长度
|
||||
public int getMessageBodyLength() {
|
||||
return messageBodyProps & 0x3FF;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.njzscloud.jt808.protocol;
|
||||
package com.njzscloud.common.jt808.support;
|
||||
|
||||
import com.njzscloud.jt808.util.JT808;
|
||||
import com.njzscloud.common.jt808.JT808;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.channel.group.ChannelGroup;
|
||||
|
|
@ -25,26 +25,17 @@ public class JT808MessageHandler extends ChannelInboundHandlerAdapter {
|
|||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
if (msg instanceof JT808Message) {
|
||||
JT808Message message = (JT808Message) msg;
|
||||
log.info("收到消息, 终端: {}, 消息ID: 0x{}, 流水号: {}", message.getTerminalPhone(), Integer.toHexString(message.getMessageId()), message.getFlowId());
|
||||
// 根据消息类型处理
|
||||
handleMessageByType(ctx, message);
|
||||
int messageId = message.getMessageId();
|
||||
log.info("收到消息, 设备号: {},消息ID: 0x{}, 流水号: {}", message.getTerminalPhone(), Integer.toHexString(messageId), message.getFlowId());
|
||||
if (messageId == 0x0100) {
|
||||
JT808.register(message.getTerminalPhone(), ctx.channel());
|
||||
}
|
||||
JT808MessageResolver.dispatchMsg(messageId, message);
|
||||
} else {
|
||||
super.channelRead(ctx, msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据消息ID处理不同类型的消息
|
||||
*/
|
||||
private void handleMessageByType(ChannelHandlerContext ctx, JT808Message message) {
|
||||
int messageId = message.getMessageId();
|
||||
if (messageId == 0x0100) {
|
||||
JT808.register(message.getTerminalPhone(), ctx.channel());
|
||||
}
|
||||
|
||||
JT808.triggerListener(messageId, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
log.info("客户端断开连接: {}", ctx.channel().remoteAddress());
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
package com.njzscloud.common.jt808.support;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import com.njzscloud.common.jt808.JT808;
|
||||
import com.njzscloud.common.tuqiang.msg.TerminalAuthMsg;
|
||||
import com.njzscloud.common.tuqiang.msg.TerminalGeneralResponseMsg;
|
||||
import com.njzscloud.common.tuqiang.msg.TerminalRegisterMsg;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Slf4j
|
||||
public class JT808MessageResolver {
|
||||
public static final String Heartbeat = "Heartbeat";
|
||||
public static final String LocationReport = "LocationReport";
|
||||
public static final String LocationBatchReport = "LocationBatchReport";
|
||||
public static final String LocationSearch = "LocationSearch";
|
||||
public static final String TxtReport = "TxtReport";
|
||||
|
||||
private static Map<String, Consumer<MessageBody>> resolvers = new ConcurrentHashMap<>();
|
||||
|
||||
private static Map<Integer, Consumer<JT808Message>> stdResolvers = MapUtil.<Integer, Consumer<JT808Message>>builder()
|
||||
.put(0x0100, JT808MessageResolver::onTerminalRegister)
|
||||
.put(0x0102, JT808MessageResolver::onTerminalAuth)
|
||||
.put(0x0002, JT808MessageResolver::onHeartbeat)
|
||||
.put(0x0200, JT808MessageResolver::onLocationReport)
|
||||
.put(0x704, JT808MessageResolver::onLocationBatchUpload)
|
||||
.put(0x0201, JT808MessageResolver::onSearchLocationResponse)
|
||||
.put(0x0001, JT808MessageResolver::onTerminalGeneralResponse)
|
||||
.put(0x6006, JT808MessageResolver::onTerminalTxtReport)
|
||||
.build();
|
||||
|
||||
public static void addResolver(String messageId, Consumer<MessageBody> resolver) {
|
||||
JT808MessageResolver.resolvers.put(messageId, resolver);
|
||||
}
|
||||
|
||||
public static void dispatchMsg(String messageId, JT808Message message) {
|
||||
Consumer<MessageBody> heartbeat = resolvers.get(messageId);
|
||||
if (heartbeat != null) {
|
||||
String terminalPhone = message.getTerminalPhone();
|
||||
byte[] messageBody = message.getMessageBody();
|
||||
ByteBuf byteBuf = Unpooled.wrappedBuffer(messageBody);
|
||||
try {
|
||||
heartbeat.accept(new MessageBody()
|
||||
.setTerminalId(terminalPhone)
|
||||
.setBody(byteBuf));
|
||||
} catch (Exception e) {
|
||||
log.error("处理消息时发生异常,消息 Id:{},设备号:{} ", messageId, terminalPhone, e);
|
||||
} finally {
|
||||
byteBuf.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void dispatchMsg(Integer messageId, JT808Message message) {
|
||||
Consumer<JT808Message> stdResolver = stdResolvers.get(messageId);
|
||||
if (stdResolver != null) {
|
||||
stdResolver.accept(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 终端注册消息
|
||||
*/
|
||||
public static void onTerminalRegister(JT808Message message) {
|
||||
String terminalPhone = message.getTerminalPhone();
|
||||
ByteBuf body = Unpooled.buffer();
|
||||
ByteBufUtil.writeShortBE(body, message.getFlowId());
|
||||
body.writeByte(0);
|
||||
ByteBufUtil.writeUtf8(body, terminalPhone);
|
||||
|
||||
// 构建消息
|
||||
byte[] bytes = ByteBufUtil.getBytes(body);
|
||||
body.release();
|
||||
JT808.sendMessage(JT808.createBaseMessage(terminalPhone, 0x8100, bytes));
|
||||
|
||||
TerminalRegisterMsg terminalRegisterMsg = message.getMessageBody(TerminalRegisterMsg.class);
|
||||
|
||||
log.info("终端注册消息: {}", terminalRegisterMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 终端鉴权消息
|
||||
*/
|
||||
public static void onTerminalAuth(JT808Message message) {
|
||||
JT808.sendGeneralResponse(message);
|
||||
TerminalAuthMsg authMsg = message.getMessageBody(TerminalAuthMsg.class);
|
||||
log.info("终端鉴权消息: {}", authMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 终端通用应答消息
|
||||
*/
|
||||
public static void onTerminalGeneralResponse(JT808Message message) {
|
||||
TerminalGeneralResponseMsg terminalGeneralResponseMsg = message.getMessageBody(TerminalGeneralResponseMsg.class);
|
||||
int messageId = message.getMessageId();
|
||||
String terminalPhone = message.getTerminalPhone();
|
||||
int result = terminalGeneralResponseMsg.getResult();
|
||||
log.info("设备通用响应,设备号:{},消息 Id:{},结果:{}", terminalPhone, Integer.toHexString(messageId), result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 终端心跳消息
|
||||
*/
|
||||
public static void onHeartbeat(JT808Message message) {
|
||||
JT808.sendGeneralResponse(message);
|
||||
dispatchMsg(Heartbeat, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 终端位置信息汇报消息
|
||||
*/
|
||||
public static void onLocationReport(JT808Message message) {
|
||||
dispatchMsg(LocationReport, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 定位数据批量上传消息
|
||||
*/
|
||||
public static void onLocationBatchUpload(JT808Message message) {
|
||||
dispatchMsg(LocationBatchReport, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询位置响应消息
|
||||
*/
|
||||
public static void onSearchLocationResponse(JT808Message message) {
|
||||
JT808.sendGeneralResponse(message);
|
||||
dispatchMsg(LocationSearch, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 终端文本信息汇报消息
|
||||
*/
|
||||
public static void onTerminalTxtReport(JT808Message message) {
|
||||
JT808.sendGeneralResponse(message);
|
||||
int messageId = message.getMessageId();
|
||||
String terminalPhone = message.getTerminalPhone();
|
||||
dispatchMsg(TxtReport, message);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.njzscloud.common.jt808.support;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
public class MessageBody {
|
||||
private String terminalId;
|
||||
private ByteBuf body;
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.njzscloud.common.jt808.util;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class FlowId {
|
||||
private static final Map<String, Integer> flowId = new ConcurrentHashMap<>();
|
||||
|
||||
public static synchronized int next(String terminalId, int messageId) {
|
||||
String key = terminalId + "_" + messageId;
|
||||
Integer i = flowId.get(key);
|
||||
if (i == null || i >= 0xFFFF) {
|
||||
i = 0;
|
||||
}
|
||||
i++;
|
||||
flowId.put(key, i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
package com.njzscloud.common.mqtt;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njzscloud.common.core.jackson.Jackson;
|
||||
import com.njzscloud.common.mqtt.support.MqttListener;
|
||||
import com.njzscloud.common.mqtt.support.MqttMsg;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.paho.client.mqttv3.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Slf4j
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class Mqtt {
|
||||
private static final Map<String, Consumer<MqttMsg>> listeners = new ConcurrentHashMap<>();
|
||||
private static MqttClient client;
|
||||
|
||||
public static void run(String broker, String clientId, String username, String password) {
|
||||
try {
|
||||
client = new MqttClient(broker, clientId);
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
if (StrUtil.isNotBlank(username) && StrUtil.isNotBlank(password)) {
|
||||
options.setUserName(username);
|
||||
options.setPassword(password.toCharArray());
|
||||
}
|
||||
|
||||
client.connect(options);
|
||||
client.setCallback(new MsgHandler());
|
||||
log.info("mqtt连接成功:{} {}", broker, clientId);
|
||||
} catch (Exception e) {
|
||||
log.error("mqtt连接失败", e);
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public static void shutdown() {
|
||||
try {
|
||||
if (client != null) {
|
||||
client.disconnect();
|
||||
client = null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("mqtt关闭失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void subscribe(String topic, int qos) {
|
||||
try {
|
||||
client.subscribe(topic, qos);
|
||||
log.info("mqtt 订阅成功:{} {}", topic, qos);
|
||||
} catch (Exception e) {
|
||||
log.error("mqtt 订阅失败:{} {}", topic, qos, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void subscribe(String topic) {
|
||||
subscribe(topic, 0);
|
||||
}
|
||||
|
||||
public static void subscribe(String topic, int qos, Consumer<MqttMsg> handler) {
|
||||
listeners.put(topic, handler);
|
||||
subscribe(topic, qos);
|
||||
}
|
||||
|
||||
public static void subscribe(String topic, Consumer<MqttMsg> handler) {
|
||||
subscribe(topic, 0, handler);
|
||||
}
|
||||
|
||||
public static void publish(String topic, int qos, Object msg) {
|
||||
String jsonStr = null;
|
||||
try {
|
||||
jsonStr = Jackson.toJsonStr(msg);
|
||||
log.info("mqtt 发布消息:{} {} {}", topic, qos, jsonStr);
|
||||
MqttMessage message = new MqttMessage(jsonStr.getBytes());
|
||||
message.setQos(qos);
|
||||
client.publish(topic, message);
|
||||
} catch (Exception e) {
|
||||
log.error("mqtt 发布消息失败:{} {} {}", topic, qos, jsonStr, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void publish(String topic, Object msg) {
|
||||
publish(topic, 0, msg);
|
||||
}
|
||||
|
||||
public static void addListener(Object obj) {
|
||||
Class<?> clazz = obj.getClass();
|
||||
for (Method method : clazz.getDeclaredMethods()) {
|
||||
MqttListener mqttListener = method.getAnnotation(MqttListener.class);
|
||||
if (mqttListener == null) continue;
|
||||
String topic = mqttListener.topic();
|
||||
int qos = mqttListener.qos();
|
||||
subscribe(topic, qos);
|
||||
Consumer<MqttMsg> handler = (msg) -> {
|
||||
try {
|
||||
method.invoke(obj, msg);
|
||||
} catch (Exception e) {
|
||||
log.error("mqtt 消息处理失败:{}", topic, e);
|
||||
}
|
||||
};
|
||||
listeners.put(topic, handler);
|
||||
}
|
||||
}
|
||||
|
||||
public static class MsgHandler implements MqttCallback {
|
||||
public void messageArrived(String topic, MqttMessage message) throws Exception {
|
||||
Consumer<MqttMsg> handler = listeners.get(topic);
|
||||
if (handler == null) return;
|
||||
try {
|
||||
handler.accept(new MqttMsg(message.getPayload()));
|
||||
} catch (Exception e) {
|
||||
log.error("mqtt 消息处理失败:{} {}", topic, new String(message.getPayload()), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void connectionLost(Throwable cause) {
|
||||
log.error("mqtt 连接已断开", cause);
|
||||
}
|
||||
|
||||
public void deliveryComplete(IMqttDeliveryToken token) {
|
||||
log.info("消息投递结果:{}", token.isComplete());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.njzscloud.common.mqtt.config;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class MqttProperties {
|
||||
private boolean enabled;
|
||||
private String broker;
|
||||
private String clientId;
|
||||
private String username;
|
||||
private String password;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.njzscloud.common.mqtt.support;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD})
|
||||
public @interface MqttListener {
|
||||
String topic();
|
||||
|
||||
int qos() default 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.njzscloud.common.mqtt.support;
|
||||
|
||||
import com.njzscloud.common.core.jackson.Jackson;
|
||||
|
||||
public class MqttMsg {
|
||||
private final byte[] msg;
|
||||
|
||||
public MqttMsg(byte[] msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public <T> T getMsg(Class<T> clazz) {
|
||||
return Jackson.toBean(msg, clazz);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
package com.njzscloud.server;
|
||||
package com.njzscloud.common.tcp;
|
||||
|
||||
import com.njzscloud.jt808.protocol.JT808Decoder;
|
||||
import com.njzscloud.jt808.protocol.JT808Encoder;
|
||||
import com.njzscloud.jt808.protocol.JT808MessageHandler;
|
||||
import com.njzscloud.common.core.ex.Exceptions;
|
||||
import com.njzscloud.common.jt808.support.JT808Decoder;
|
||||
import com.njzscloud.common.jt808.support.JT808Encoder;
|
||||
import com.njzscloud.common.jt808.support.JT808MessageHandler;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.nio.NioIoHandler;
|
||||
|
|
@ -13,30 +14,23 @@ import lombok.extern.slf4j.Slf4j;
|
|||
@Slf4j
|
||||
public class TcpServer {
|
||||
private final int port;
|
||||
private final int bossThreads;
|
||||
private final int workerThreads;
|
||||
private EventLoopGroup bossGroup;
|
||||
private EventLoopGroup workerGroup;
|
||||
private ServerBootstrap bootstrap;
|
||||
|
||||
public TcpServer(int port, int bossThreads, int workerThreads) {
|
||||
this.port = port;
|
||||
this.bossThreads = bossThreads;
|
||||
this.workerThreads = workerThreads;
|
||||
}
|
||||
|
||||
public TcpServer() {
|
||||
this.port = 18888;
|
||||
this.bossThreads = 5;
|
||||
this.workerThreads = 200;
|
||||
buildServer(bossThreads, workerThreads);
|
||||
}
|
||||
|
||||
|
||||
public void start() throws Exception {
|
||||
// 创建两个EventLoopGroup,bossGroup用于接收客户端连接,workerGroup用于处理连接后的IO操作
|
||||
EventLoopGroup bossGroup = new MultiThreadIoEventLoopGroup(bossThreads, NioIoHandler.newFactory());
|
||||
EventLoopGroup workerGroup = new MultiThreadIoEventLoopGroup(workerThreads, NioIoHandler.newFactory());
|
||||
|
||||
public void buildServer(int bossThreads, int workerThreads) {
|
||||
try {
|
||||
// 创建两个EventLoopGroup,bossGroup用于接收客户端连接,workerGroup用于处理连接后的IO操作
|
||||
bossGroup = new MultiThreadIoEventLoopGroup(bossThreads, NioIoHandler.newFactory());
|
||||
workerGroup = new MultiThreadIoEventLoopGroup(workerThreads, NioIoHandler.newFactory());
|
||||
// 服务器启动辅助类
|
||||
ServerBootstrap bootstrap = new ServerBootstrap();
|
||||
bootstrap = new ServerBootstrap();
|
||||
bootstrap.group(bossGroup, workerGroup)
|
||||
// 指定使用NIO的服务器通道
|
||||
.channel(NioServerSocketChannel.class)
|
||||
|
|
@ -55,17 +49,34 @@ public class TcpServer {
|
|||
.addLast(new JT808MessageHandler()); // 消息处理器
|
||||
}
|
||||
});
|
||||
|
||||
// 绑定端口并开始接收连接
|
||||
ChannelFuture future = bootstrap.bind(port).sync();
|
||||
log.info("服务器已启动,监听端口: {}", port);
|
||||
// 等待服务器 socket 关闭
|
||||
future.channel().closeFuture().sync();
|
||||
} finally {
|
||||
// 关闭事件循环组
|
||||
workerGroup.shutdownGracefully();
|
||||
bossGroup.shutdownGracefully();
|
||||
log.info("服务器已停止");
|
||||
} catch (Exception e) {
|
||||
log.error("服务器启动失败", e);
|
||||
this.stop();
|
||||
throw Exceptions.error(e, "服务器构建失败");
|
||||
}
|
||||
}
|
||||
|
||||
public void start() {
|
||||
try {
|
||||
ChannelFuture future = bootstrap.bind(port).sync();
|
||||
log.info("服务器已启动,监听端口: {}", port);
|
||||
future.channel().closeFuture().sync();
|
||||
} catch (Exception e) {
|
||||
log.error("服务器启动失败,端口: {}", port, e);
|
||||
stop();
|
||||
throw Exceptions.error(e, "服务器启动失败");
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (bossGroup != null) {
|
||||
bossGroup.shutdownGracefully();
|
||||
bossGroup = null;
|
||||
}
|
||||
if (workerGroup != null) {
|
||||
workerGroup.shutdownGracefully();
|
||||
workerGroup = null;
|
||||
}
|
||||
log.info("服务器已停止");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
package com.njzscloud.common.tuqiang;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njzscloud.TuqiangListeners;
|
||||
import com.njzscloud.common.jt808.JT808;
|
||||
import com.njzscloud.common.jt808.support.JT808Message;
|
||||
import com.njzscloud.common.tuqiang.msg.PublishTxtMsg;
|
||||
import com.njzscloud.common.tuqiang.support.TuqiangListener;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@Slf4j
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class Tuqiang {
|
||||
public static void run(int port, int bossThreads, int workerThreads) {
|
||||
addListener(new TuqiangListeners());
|
||||
JT808.run(port, bossThreads, workerThreads);
|
||||
}
|
||||
|
||||
private static void addListener(Object object) {
|
||||
Method[] methods = object.getClass().getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
if (method.isAnnotationPresent(TuqiangListener.class)) {
|
||||
TuqiangListener tuqiangListener = method.getAnnotation(TuqiangListener.class);
|
||||
String messageId = tuqiangListener.messageId();
|
||||
JT808.addListener(messageId, (msg) -> {
|
||||
try {
|
||||
method.invoke(object, msg);
|
||||
} catch (Exception e) {
|
||||
log.error("途强处理消息 {} 时出错", messageId, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启追踪
|
||||
*
|
||||
* @param terminalId 终端ID
|
||||
* @param interval 上报间隔,单位秒,0-3600秒,0表示不追踪
|
||||
*/
|
||||
public static void track(String terminalId, int interval) {
|
||||
Assert.isTrue(interval >= 0 && interval <= 3600, "上报间隔必须为0-3600秒");
|
||||
JT808.sendMessage(JT808.createBaseMessage(terminalId, 0x8300, new PublishTxtMsg(StrUtil.format("<SPBSJ*P:BSJGPS*C:{}*H:300>", interval)).toBytes()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备信息
|
||||
*
|
||||
* @param terminalId 终端ID
|
||||
*/
|
||||
public static void obtainDeviceInfo(String terminalId) {
|
||||
JT808.sendMessage(JT808.createBaseMessage(terminalId, 0x8300, new PublishTxtMsg("<CKBSJ>").toBytes()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置心跳
|
||||
*
|
||||
* @param terminalId 终端ID
|
||||
*/
|
||||
public static void setHeartbeat(String terminalId, int interval) {
|
||||
ByteBuf body = Unpooled.buffer();
|
||||
body.writeByte(1);
|
||||
body.writeByte(1);
|
||||
body.writeInt(0x0001);
|
||||
// body.writeByte(1);
|
||||
body.writeByte(interval);
|
||||
byte[] bytes = ByteBufUtil.getBytes(body);
|
||||
body.release();
|
||||
JT808.sendMessage(JT808.createBaseMessage(terminalId, 0x8103, bytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用报警
|
||||
*
|
||||
* @param terminalId 终端ID
|
||||
*/
|
||||
public static void enableWarn(String terminalId, boolean enable) {
|
||||
JT808.sendMessage(JT808.createBaseMessage(terminalId, 0x8300, new PublishTxtMsg(StrUtil.format("<SPBSJ*P:BSJGPS*6W:{}>", enable ? 1 : 0)).toBytes()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置速度报警
|
||||
*
|
||||
* @param terminalId 终端ID
|
||||
* @param speed 速度,单位km/h
|
||||
*/
|
||||
public static void speedThreshold(String terminalId, int speed) {
|
||||
JT808.sendMessage(JT808.createBaseMessage(terminalId, 0x8300, new PublishTxtMsg(StrUtil.format("<SPBSJ*P:BSJGPS*CS:{}*H:300>", speed)).toBytes()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前位置
|
||||
*
|
||||
* @param terminalId 终端ID
|
||||
*/
|
||||
public static void currentLocation(String terminalId) {
|
||||
JT808Message baseMessage = JT808.createBaseMessage(terminalId, 0x8201);
|
||||
JT808.sendMessage(baseMessage);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.tuqiang;
|
||||
package com.njzscloud.common.tuqiang.msg;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
|
@ -10,34 +10,90 @@ import lombok.experimental.Accessors;
|
|||
@ToString
|
||||
@Accessors(chain = true)
|
||||
public class DeviceInfo {
|
||||
// GPS定位状态
|
||||
// region GPS定位状态
|
||||
/**
|
||||
* 这是 GPS 定位的核心状态,三个参数分别代表:
|
||||
* 1. 定位有效性:V = Valid(有效定位),若为N则表示 No Valid(无效定位,如无卫星信号);
|
||||
* 2. 卫星数量:0 = 当前参与定位的卫星数量(此处为 0,可能是瞬时值或信号弱导致,正常定位时通常≥4);
|
||||
* 3. 定位精度 / 备用参数:0 = 部分设备此处代表定位精度(单位:米),或备用状态码(具体需结合设备型号,途强部分设备此参数为 “定位类型”,0 = 未知,1=GPS,2 = 北斗)。
|
||||
*/
|
||||
private String gpsValid; // 定位有效性(V/N)
|
||||
private int satelliteCount; // 卫星数量
|
||||
private int gpsAccuracy; // 定位精度或备用参数
|
||||
/**
|
||||
* GPS 模块硬件状态:OK = GPS 模块正常工作(供电、硬件无故障);若为ERR则表示 GPS 模块故障(如硬件损坏、供电异常)。
|
||||
*/
|
||||
private String gpsModuleStatus; // GPS模块状态(OK/ERR)
|
||||
// endregion
|
||||
|
||||
// 网络与信号状态
|
||||
// region 网络与信号状态
|
||||
private String serverIp; // 服务器IP
|
||||
private int serverPort; // 服务器端口
|
||||
/**
|
||||
* 2G/4G 网络注册状态(CGREG 是 GSM/UMTS 网络的 “小区注册状态” 指令):
|
||||
* 1 = 设备已成功注册到本地移动网络(可正常联网);
|
||||
* 其他常见值:0= 未注册,2= 正在注册,3= 注册被拒绝(如 SIM 卡欠费、无信号)
|
||||
*/
|
||||
private int cgregStatus; // 网络注册状态
|
||||
/**
|
||||
* 网络信号强度(CSQ = Carrier Signal Quality,载波信号质量):
|
||||
* 取值范围0-31,22属于良好信号(12-20 为中等,21-31 为良好,0 为无信号);
|
||||
* 对应信号强度约为 -78dBm(CSQ 与 dBm 换算公式:dBm = -113 + (CSQ×2),22 时即 - 113+44=-69dBm,数值越接近 0 信号越强)。
|
||||
*/
|
||||
private int csq; // 信号强度
|
||||
// endregion
|
||||
|
||||
// 硬件与电源状态
|
||||
// region 硬件与电源状态
|
||||
/**
|
||||
* 设备内置电池电压:单位为 “V(伏特)”,3.5V 属于正常电压范围(途强设备电池电压通常在 3.3V-4.2V 之间,低于 3.3V 可能触发低电报警)。
|
||||
*/
|
||||
private double batteryVoltage; // 电池电压(V)
|
||||
/**
|
||||
* 供电模式 / 电池状态:
|
||||
* 常见含义(途强设备自定义):1= 外接电源供电(如车充、市电),2= 电池供电,0= 供电异常;
|
||||
* 部分设备此参数代表 “电池健康度”,2= 良好(需结合具体型号确认)。
|
||||
*/
|
||||
private int powerMode; // 供电模式(1=外接电源,2=电池)
|
||||
/**
|
||||
* 北斗定位模块状态(BD = BeiDou):
|
||||
* 0 = 北斗模块未启用 / 未定位(若设备支持北斗,此值为1表示北斗已参与定位);0不代表故障,仅表示当前未使用北斗信号。
|
||||
*/
|
||||
private int beidouStatus; // 北斗模块状态(0=未启用,1=启用)
|
||||
// endregion
|
||||
|
||||
// 功能与附加状态
|
||||
// region 功能与附加状态
|
||||
/**
|
||||
* 报警状态:* = 无当前报警(途强设备常用 “*” 表示无报警,若有报警会显示具体报警码,如A:1= 低电报警,A:2= 位移报警)
|
||||
*/
|
||||
private String alarmStatus; // 报警状态(*)
|
||||
/**
|
||||
* 计数器 / 里程相关:常见为 “累计里程计数状态” 或 “指令执行计数”,0通常表示 “无异常” 或 “初始值”(部分设备此为 “充电次数”,需结合型号)。
|
||||
*/
|
||||
private int counter; // 计数器/里程相关
|
||||
/**
|
||||
* 定位上报间隔:单位为 “秒”,300 = 设备每 5 分钟自动上报一次定位数据(途强设备支持远程配置此间隔,如 10 秒、60 秒、300 秒等)
|
||||
*/
|
||||
private int reportInterval; // 定位上报间隔(秒)
|
||||
private int powerSavingMode; // 省电模式(0=关闭,1=开启)
|
||||
private int backupPower; // 备用电源状态
|
||||
private int vibrationStatus; // 震动传感器状态
|
||||
/**
|
||||
* 超速阈值
|
||||
*/
|
||||
private int speedThreshold; // 超速阈值(km/h)
|
||||
/**
|
||||
* 关闭日志
|
||||
*/
|
||||
private int logOff; // 关闭日志(0=关闭,1=开启)
|
||||
/**
|
||||
* 关闭拐点
|
||||
*/
|
||||
private int inflectionPointOff; // 拐点关闭状态(0=关闭,1=开启)
|
||||
private int heartbeatInterval; // 心跳包间隔(秒)
|
||||
private int accStatus; // ACC点火状态(1=通电,0=断电)
|
||||
/**
|
||||
* 关闭基站
|
||||
*/
|
||||
private int baseStationOff; // 基站关闭状态(1=关闭,0=开启)
|
||||
private int chargingStatus; // 充电状态(0=未充电,1=充电中)
|
||||
private int bluetoothStatus; // 蓝牙状态(1=开启,0=关闭)
|
||||
private int enableWarn; // 蓝牙状态(1=开启,0=关闭)
|
||||
private String extendStatus; // 扩展状态码(十六进制)
|
||||
private String temperature; // 温度传感器状态
|
||||
private String deviceTime; // 设备本地时间
|
||||
|
|
@ -48,16 +104,19 @@ public class DeviceInfo {
|
|||
private int lowBatteryThreshold; // 低电阈值状态
|
||||
private int accelerometerStatus; // 加速度传感器状态
|
||||
private int flightMode; // 飞行模式(0=关闭,1=开启)
|
||||
// endregion
|
||||
|
||||
|
||||
public static DeviceInfo parse(String gpsString) {
|
||||
public static DeviceInfo parse(String str) {
|
||||
DeviceInfo data = new DeviceInfo();
|
||||
if (gpsString == null || gpsString.isEmpty()) {
|
||||
return data;
|
||||
if (str == null || str.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (!str.startsWith("<") || !str.endsWith(">")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 去除首尾的<和>
|
||||
String content = gpsString.replaceAll("[<>]", "");
|
||||
String content = str.replaceAll("[<>]", "");
|
||||
// 按*分割字段
|
||||
String[] fields = content.split("\\*");
|
||||
|
||||
|
|
@ -111,19 +170,19 @@ public class DeviceInfo {
|
|||
data.reportInterval = parseInt(value);
|
||||
break;
|
||||
case "CS":
|
||||
data.powerSavingMode = parseInt(value);
|
||||
data.speedThreshold = parseInt(value);
|
||||
break;
|
||||
case "3U":
|
||||
data.backupPower = parseInt(value);
|
||||
data.logOff = parseInt(value);
|
||||
break;
|
||||
case "3Z":
|
||||
data.vibrationStatus = parseInt(value);
|
||||
data.inflectionPointOff = parseInt(value);
|
||||
break;
|
||||
case "H":
|
||||
data.heartbeatInterval = parseInt(value);
|
||||
break;
|
||||
case "2A":
|
||||
data.accStatus = parseInt(value);
|
||||
data.baseStationOff = parseInt(value);
|
||||
break;
|
||||
case "5C":
|
||||
data.chargingStatus = parseInt(value);
|
||||
|
|
@ -131,6 +190,9 @@ public class DeviceInfo {
|
|||
case "60":
|
||||
data.bluetoothStatus = parseInt(value);
|
||||
break;
|
||||
case "6W":
|
||||
data.enableWarn = parseInt(value);
|
||||
break;
|
||||
case "3E":
|
||||
data.extendStatus = value;
|
||||
break;
|
||||
|
|
@ -202,6 +264,4 @@ public class DeviceInfo {
|
|||
return -1; // 用-1表示解析失败
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package com.njzscloud.tuqiang.msg;
|
||||
package com.njzscloud.common.tuqiang.msg;
|
||||
|
||||
import com.njzscloud.common.utils.BCD;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.njzscloud.common.core.utils.BCD;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
|
@ -33,50 +33,33 @@ public class LocationReportMsg {
|
|||
private int direction;
|
||||
private String time;
|
||||
|
||||
public LocationReportMsg(byte[] bytes) {
|
||||
ByteBuf body = Unpooled.wrappedBuffer(bytes);
|
||||
private boolean overspeed;
|
||||
private boolean powerUnderVoltage;
|
||||
private boolean soundAlarm;
|
||||
private boolean accOn;
|
||||
private boolean position;
|
||||
private boolean south;
|
||||
private boolean west;
|
||||
|
||||
public LocationReportMsg(ByteBuf body) {
|
||||
this.alarmFlag = body.readUnsignedInt();
|
||||
this.status = body.readUnsignedInt();
|
||||
double longitude = body.readUnsignedInt() * 1.0 / 1000000;
|
||||
this.longitude = isWest() ? -longitude : longitude;
|
||||
double latitude = body.readUnsignedInt() * 1.0 / 1000000;
|
||||
this.latitude = isSouth() ? -latitude : latitude;
|
||||
this.latitude = isWest() ? -latitude : latitude;
|
||||
double longitude = body.readUnsignedInt() * 1.0 / 1000000;
|
||||
this.longitude = isSouth() ? -longitude : longitude;
|
||||
this.altitude = body.readUnsignedShort();
|
||||
this.speed = body.readUnsignedShort() * 1.0 / 10;
|
||||
this.direction = body.readUnsignedShort();
|
||||
byte[] terminalIdBytes = new byte[7];
|
||||
byte[] terminalIdBytes = new byte[6];
|
||||
body.readBytes(terminalIdBytes);
|
||||
this.time = BCD.bcdToStr(terminalIdBytes);
|
||||
|
||||
|
||||
body.release();
|
||||
}
|
||||
|
||||
public boolean isOverspeed() {
|
||||
return (alarmFlag & 0x02) == 0x02;
|
||||
}
|
||||
|
||||
public boolean isPowerUnderVoltage() {
|
||||
return (alarmFlag & 0x40) == 0x40;
|
||||
}
|
||||
|
||||
public boolean isSoundAlarm() {
|
||||
return (alarmFlag & 0x80) == 0x80;
|
||||
}
|
||||
|
||||
public boolean isAccOn() {
|
||||
return (status & 0x01) == 0x01;
|
||||
}
|
||||
|
||||
public boolean isPosition() {
|
||||
return (status & 0x02) == 0x02;
|
||||
}
|
||||
|
||||
public boolean isSouth() {
|
||||
return (status & 0x04) == 0x04;
|
||||
}
|
||||
|
||||
public boolean isWest() {
|
||||
return (status & 0x08) == 0x08;
|
||||
this.time = DateUtil.format(DateUtil.parse(BCD.bcdToStr(terminalIdBytes), "yyMMddHHmmss"), "yyyy-MM-dd HH:mm:ss");
|
||||
this.overspeed = (alarmFlag & 0x02) == 0x02;
|
||||
this.powerUnderVoltage = (alarmFlag & 0x40) == 0x40;
|
||||
this.soundAlarm = (alarmFlag & 0x80) == 0x80;
|
||||
this.accOn = (status & 0x01) == 0x01;
|
||||
this.position = (status & 0x02) == 0x02;
|
||||
this.south = (status & 0x04) == 0x04;
|
||||
this.west = (status & 0x08) == 0x08;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.njzscloud.common.tuqiang.msg;
|
||||
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Slf4j
|
||||
@Accessors(chain = true)
|
||||
public class PublishTxtMsg {
|
||||
private byte flag;
|
||||
private String txt;
|
||||
|
||||
public PublishTxtMsg(String txt) {
|
||||
this.flag = 0x01;
|
||||
this.txt = txt;
|
||||
}
|
||||
|
||||
public byte[] toBytes() {
|
||||
byte[] messageBody = new byte[txt.length() + 1];
|
||||
messageBody[0] = flag;
|
||||
try {
|
||||
System.arraycopy(txt.getBytes(CharsetUtil.GBK), 0, messageBody, 1, txt.length());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
log.error("文本消息构建失败,原文本:{}", txt, e);
|
||||
}
|
||||
return messageBody;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
package com.njzscloud.tuqiang.msg;
|
||||
package com.njzscloud.common.tuqiang.msg;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
|
@ -17,10 +15,9 @@ public class SearchLocationResponseMsg {
|
|||
private int flowId;
|
||||
private LocationReportMsg locationReportMsg;
|
||||
|
||||
public SearchLocationResponseMsg(byte[] bytes) {
|
||||
ByteBuf body = Unpooled.wrappedBuffer(bytes);
|
||||
public SearchLocationResponseMsg(ByteBuf body) {
|
||||
this.flowId = body.readUnsignedShort();
|
||||
byte[] locationReportMsgBytes = ByteBufUtil.getBytes(body);
|
||||
this.locationReportMsg = new LocationReportMsg(locationReportMsgBytes);
|
||||
ByteBuf locationReportMsgBody = body.slice(body.readerIndex(), body.readableBytes());
|
||||
this.locationReportMsg = new LocationReportMsg(locationReportMsgBody);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.tuqiang.msg;
|
||||
package com.njzscloud.common.tuqiang.msg;
|
||||
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
|
@ -20,5 +20,6 @@ public class TerminalAuthMsg {
|
|||
byte[] authCodeBytes = new byte[body.readableBytes()];
|
||||
body.readBytes(authCodeBytes);
|
||||
this.authCode = new String(authCodeBytes, CharsetUtil.CHARSET_GBK);
|
||||
body.release();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.tuqiang.msg;
|
||||
package com.njzscloud.common.tuqiang.msg;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
|
|
@ -14,6 +14,9 @@ import lombok.experimental.Accessors;
|
|||
public class TerminalGeneralResponseMsg {
|
||||
private int flowId;
|
||||
private int messageId;
|
||||
/**
|
||||
* 0:成功/确认;1:失败;2:消息有误;3:不支持
|
||||
*/
|
||||
private int result;
|
||||
|
||||
public TerminalGeneralResponseMsg(byte[] bytes) {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.njzscloud.tuqiang.msg;
|
||||
package com.njzscloud.common.tuqiang.msg;
|
||||
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
package com.njzscloud.tuqiang.msg;
|
||||
package com.njzscloud.common.tuqiang.msg;
|
||||
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
|
@ -17,12 +16,11 @@ public class TerminalTxtReportMsg {
|
|||
/**
|
||||
* 文本信息
|
||||
*/
|
||||
private String text;
|
||||
private String txt;
|
||||
|
||||
public TerminalTxtReportMsg(byte[] bytes) {
|
||||
ByteBuf body = Unpooled.wrappedBuffer(bytes);
|
||||
public TerminalTxtReportMsg(ByteBuf body) {
|
||||
this.type = body.readByte();
|
||||
this.text = body.toString(body.readerIndex(), body.readableBytes(),
|
||||
this.txt = body.toString(body.readerIndex(), body.readableBytes(),
|
||||
this.type == 0x00 ?
|
||||
CharsetUtil.CHARSET_GBK :
|
||||
CharsetUtil.CHARSET_UTF_8);
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
package com.njzscloud.common.tuqiang.support;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public enum Directive {
|
||||
/**
|
||||
* 设置位置信息传输间隔
|
||||
*/
|
||||
_C("C"),
|
||||
/**
|
||||
* 设置心跳间隔
|
||||
*/
|
||||
_H("H"),
|
||||
/**
|
||||
* 设置IP、端口
|
||||
*/
|
||||
_T("T"),
|
||||
/**
|
||||
* 设置速度阈值
|
||||
*/
|
||||
_CS("CS"),
|
||||
/**
|
||||
* 关闭日志
|
||||
*/
|
||||
_3U("3U"),
|
||||
/**
|
||||
* 关闭位拐点
|
||||
*/
|
||||
_3Z("3Z"),
|
||||
/**
|
||||
* 关闭基站
|
||||
*/
|
||||
_2A("2A"),
|
||||
/**
|
||||
* 低电压阈值
|
||||
*/
|
||||
_5Y("5Y"),
|
||||
/**
|
||||
* 设置时区,8:00 东8区
|
||||
*/
|
||||
_9E("9E"),
|
||||
/**
|
||||
* 设置防震动阈值
|
||||
*/
|
||||
_3D("3D"),
|
||||
/**
|
||||
* 设置允许报警
|
||||
*/
|
||||
_6W("6W"),
|
||||
/**
|
||||
* 设置录音灵敏度,【5-100】
|
||||
*/
|
||||
_3E("3E"),
|
||||
/**
|
||||
* 设置设备ID
|
||||
*/
|
||||
_N("N"),
|
||||
/**
|
||||
* 2G/4G 网络注册状态
|
||||
*/
|
||||
_CGREG("CGREG"),
|
||||
/**
|
||||
* 信号质量,取值范围0-31,22属于良好信号(12-20 为中等,21-31 为良好,0 为无信号)
|
||||
*/
|
||||
_CSQ("CSQ"),
|
||||
/**
|
||||
* GPS 状态,V-->有效,N-->无效定位,值:(V,0,0)
|
||||
*/
|
||||
_GPS("GPS"),
|
||||
/**
|
||||
* GPS 模块硬件状态,OK-->正常,ERR-->故障
|
||||
*/
|
||||
_GP("GP"),
|
||||
/**
|
||||
* 充电状态:0 = 未充电;1 = 正在充电
|
||||
*/
|
||||
_5C("5C"),
|
||||
/**
|
||||
* 1= 外接电源供电(,2= 电池供电,0= 供电异常
|
||||
*/
|
||||
_B("B"),
|
||||
|
||||
|
||||
;
|
||||
|
||||
private final String value;
|
||||
|
||||
{
|
||||
String[] strings = {"N:61000602070", "T:139.224.54.144,30100", "CGREG:1", "CSQ:23", "GPS:(V,0,0)", "A:", "C:0", "O:300", "CS:0", "3U:0", "3Z:0", "H:300", "2A:1", "GP:OK", "5C:0", "60:1", "5Y:3.5", "6W:0", "3E:000300", "5T:2,2", "9E:08:00", "1H:1", "3D:000000", "2S:0", "I:0000000", "B:2", "LT:0", "AG:1", "BD:0", "FLY:0"};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.njzscloud.common.tuqiang.support;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
public class TuqiangDirectiveMsg {
|
||||
|
||||
}
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
package com.njzscloud.tuqiang;
|
||||
package com.njzscloud.common.tuqiang.support;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD})
|
||||
public @interface Listener {
|
||||
int messageId();
|
||||
public @interface TuqiangListener {
|
||||
String messageId();
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
package com.njzscloud.jt808.util;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class FlowId {
|
||||
private static final Map<Integer, Integer> flowId = new ConcurrentHashMap<>();
|
||||
|
||||
public static synchronized int next(int messageId) {
|
||||
Integer i = flowId.get(messageId);
|
||||
if (i == null || i >= 0xFFFF) {
|
||||
i = 0;
|
||||
}
|
||||
flowId.put(messageId, i++);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,213 +0,0 @@
|
|||
package com.njzscloud.jt808.util;
|
||||
|
||||
import com.njzscloud.jt808.protocol.JT808Message;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* JT808消息发送工具类
|
||||
* 提供便捷的方法发送各种类型的JT808消息
|
||||
*/
|
||||
@Slf4j
|
||||
public class JT808 {
|
||||
// 终端手机号与Channel的映射
|
||||
private static final Map<String, Channel> terminalChannels = new ConcurrentHashMap<>();
|
||||
|
||||
private static final Map<Integer, List<Consumer<JT808Message>>> listeners = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 注册消息监听器
|
||||
*/
|
||||
public static void addListener(Integer messageId, Consumer<JT808Message> listener) {
|
||||
if (messageId != null && listener != null) {
|
||||
listeners.computeIfAbsent(messageId, k -> new java.util.ArrayList<>()).add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发消息监听器
|
||||
*/
|
||||
public static void triggerListener(Integer messageId, JT808Message message) {
|
||||
if (messageId != null && message != null) {
|
||||
List<Consumer<JT808Message>> consumers = listeners.get(messageId);
|
||||
if (consumers != null) {
|
||||
consumers.forEach(m -> m.accept(message));
|
||||
} else {
|
||||
|
||||
log.warn("当前消息无处理函数: 0x{}、消息内容: {}", Integer.toHexString(messageId), message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除消息监听器
|
||||
*/
|
||||
public static void unregisterListener(String messageId) {
|
||||
if (messageId != null) {
|
||||
listeners.remove(messageId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册终端与通道的映射关系
|
||||
*/
|
||||
public static void register(String terminalId, Channel channel) {
|
||||
if (terminalId != null && channel != null) {
|
||||
if (terminalChannels.get(terminalId) != channel) {
|
||||
terminalChannels.put(terminalId, channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除终端与通道的映射关系
|
||||
*/
|
||||
public static void unregister(Channel channel) {
|
||||
if (channel != null) {
|
||||
terminalChannels.values().removeIf(ch -> ch == channel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 发送通用应答消息 (0x8001)
|
||||
*/
|
||||
public static void sendGeneralResponse(JT808Message message) {
|
||||
sendMessage(message.getTerminalPhone(), createGeneralMessage(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送终端注册应答消息 (0x8100)
|
||||
*/
|
||||
public static void sendTerminalRegisterResponse(String terminalPhone, int flowId, String authCode, int result) {
|
||||
// 构建消息体
|
||||
ByteBuf body = Unpooled.buffer();
|
||||
body.writeByte(result); // 结果
|
||||
if (result == 0) { // 成功才需要后面的字段
|
||||
writeString(body, authCode); // 鉴权码
|
||||
}
|
||||
|
||||
// 构建消息
|
||||
byte[] bytes = ByteBufUtil.getBytes(body);
|
||||
body.release();
|
||||
JT808Message message = createBaseMessage(terminalPhone, 0x8100, bytes);
|
||||
message.setFlowId(flowId);
|
||||
|
||||
// 发送消息
|
||||
sendMessage(terminalPhone, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送文本信息下发消息 (0x8300)
|
||||
*/
|
||||
public static void sendTextMessage(String terminalPhone, String content, int messageType) {
|
||||
// 构建消息体
|
||||
ByteBuf body = Unpooled.buffer();
|
||||
body.writeByte(messageType); // 消息类型
|
||||
writeString(body, content); // 消息内容
|
||||
byte[] bytes = ByteBufUtil.getBytes(body);
|
||||
body.release();
|
||||
// 构建消息
|
||||
JT808Message message = createBaseMessage(terminalPhone, 0x8300, bytes);
|
||||
|
||||
// 发送消息
|
||||
sendMessage(terminalPhone, message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 向指定终端发送消息
|
||||
*/
|
||||
public static void sendMessage(String terminalId, JT808Message message) {
|
||||
if (terminalId == null || message == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Channel channel = terminalChannels.get(terminalId);
|
||||
if (channel != null && channel.isActive()) {
|
||||
channel.writeAndFlush(message)
|
||||
.addListener((ChannelFutureListener) future -> {
|
||||
if (future.isSuccess()) {
|
||||
log.info("消息发送成功, 终端: {}, 消息ID: 0x{}, 流水号: {}", terminalId, Integer.toHexString(message.getMessageId()), message.getFlowId());
|
||||
} else {
|
||||
log.error("消息发送失败, 终端: {}", terminalId, future.cause());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
unregister(channel);
|
||||
// 终端不在线或通道已关闭
|
||||
log.warn("终端不在线: {}", terminalId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建基础消息对象
|
||||
*/
|
||||
public static JT808Message createBaseMessage(String terminalId, int messageId) {
|
||||
return createBaseMessage(terminalId, messageId, null);
|
||||
}
|
||||
|
||||
public static JT808Message createBaseMessage(String terminalId, int messageId, byte[] body) {
|
||||
JT808Message message = new JT808Message()
|
||||
.setFlowId(FlowId.next(messageId));
|
||||
|
||||
// 设置消息ID
|
||||
message.setMessageId(messageId);
|
||||
|
||||
// 设置消息体属性
|
||||
// 其他属性默认:不分包,不加密
|
||||
if (body != null) {
|
||||
message.setMessageBodyProps(body.length);
|
||||
} else {
|
||||
message.setMessageBodyProps(0);
|
||||
}
|
||||
|
||||
// 设置终端手机号
|
||||
message.setTerminalPhone(terminalId);
|
||||
|
||||
// 设置消息体
|
||||
message.setMessageBody(body);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
public static JT808Message createGeneralMessage(JT808Message message) {
|
||||
String terminalPhone = message.getTerminalPhone();
|
||||
int flowId = message.getFlowId();
|
||||
int messageId = message.getMessageId();
|
||||
|
||||
ByteBuf body = Unpooled.buffer();
|
||||
ByteBufUtil.writeShortBE(body, flowId);
|
||||
ByteBufUtil.writeShortBE(body, messageId);
|
||||
body.writeByte(0);
|
||||
|
||||
// 构建消息
|
||||
byte[] bytes = ByteBufUtil.getBytes(body);
|
||||
body.release();
|
||||
return JT808.createBaseMessage(terminalPhone, 0x8001, bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入字符串(JT808协议格式:1字节长度 + 内容)
|
||||
*/
|
||||
private static void writeString(ByteBuf buf, String str) {
|
||||
if (str == null || str.isEmpty()) {
|
||||
buf.writeByte(0);
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] bytes = str.getBytes();
|
||||
// 字符串长度(1字节) + 字符串内容
|
||||
buf.writeByte(bytes.length);
|
||||
buf.writeBytes(bytes);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.njzscloud.param;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
public class EnableWarnParam {
|
||||
private String terminalId;
|
||||
private boolean enable;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.njzscloud.param;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
public class LocationCurrentParam {
|
||||
private String terminalId;
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.njzscloud.param;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
public class LocationTrackParam {
|
||||
private String terminalId;
|
||||
private int interval;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.njzscloud.param;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
public class ObtainDeviceInfoParam {
|
||||
private String terminalId;
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.njzscloud.param;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
public class SetHeartbeatParam {
|
||||
private String terminalId;
|
||||
|
||||
private int interval;
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.njzscloud.param;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
public class SpeedThresholdParam {
|
||||
private String terminalId;
|
||||
private int speed;
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.njzscloud.result;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
public class RealtimeLocationResult {
|
||||
private String terminalId;
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 1 1:超速报警 标志维持至报警条件解除
|
||||
* 7 1:终端主电源欠压 标志维持至报警条件解除
|
||||
* 8 1:声控录音报警
|
||||
*/
|
||||
private long alarmFlag;
|
||||
/**
|
||||
* 0 0:ACC 关 1:ACC 开
|
||||
* 1 0:未定位 1:定位
|
||||
* 2 0:北纬 1:南纬
|
||||
* 3 0:东经 1:西经
|
||||
*/
|
||||
private long status;
|
||||
private double longitude;
|
||||
private double latitude;
|
||||
private int altitude;
|
||||
private double speed;
|
||||
private int direction;
|
||||
private String time;
|
||||
private boolean overspeed;
|
||||
private boolean powerUnderVoltage;
|
||||
private boolean soundAlarm;
|
||||
private boolean accOn;
|
||||
private boolean position;
|
||||
private boolean south;
|
||||
private boolean west;
|
||||
}
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
package com.njzscloud.tuqiang;
|
||||
|
||||
import com.njzscloud.jt808.protocol.JT808Message;
|
||||
import com.njzscloud.jt808.util.JT808;
|
||||
import com.njzscloud.tuqiang.msg.*;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class Listeners {
|
||||
|
||||
@Listener(messageId = 0x0100)
|
||||
public void onTerminalRegister(JT808Message message) {
|
||||
String terminalPhone = message.getTerminalPhone();
|
||||
ByteBuf body = Unpooled.buffer();
|
||||
ByteBufUtil.writeShortBE(body, message.getFlowId());
|
||||
body.writeByte(0);
|
||||
ByteBufUtil.writeUtf8(body, terminalPhone);
|
||||
|
||||
// 构建消息
|
||||
byte[] bytes = ByteBufUtil.getBytes(body);
|
||||
body.release();
|
||||
JT808.sendMessage(terminalPhone, JT808.createBaseMessage(terminalPhone, 0x8100, bytes));
|
||||
|
||||
TerminalRegisterMsg terminalRegisterMsg = message.getMessageBody(TerminalRegisterMsg.class);
|
||||
|
||||
log.info("终端注册消息: {}", terminalRegisterMsg);
|
||||
}
|
||||
|
||||
@Listener(messageId = 0x0102)
|
||||
public void onTerminalAuth(JT808Message message) {
|
||||
JT808.sendGeneralResponse(message);
|
||||
TerminalAuthMsg authMsg = message.getMessageBody(TerminalAuthMsg.class);
|
||||
log.info("终端鉴权消息: {}", authMsg);
|
||||
|
||||
// ThreadUtil.sleep(10000);
|
||||
// log.info("发送指令: {}", "<SPBSJ*P:BSJGPS*C:0*H:300>");
|
||||
// JT808.sendMessage("61000602070", JT808.createBaseMessage("61000602070", 0x8300, new PublishDirectiveMsg("<SPBSJ*P:BSJGPS*C:0*H:300>").toBytes()));
|
||||
// ThreadUtil.sleep(10000);
|
||||
// JT808.sendMessage("61000602070", JT808.createBaseMessage("61000602070", 0x8300, new PublishDirectiveMsg("<CKBSJ>").toBytes()));
|
||||
|
||||
}
|
||||
|
||||
@Listener(messageId = 0x0002)
|
||||
public void onHeartbeat(JT808Message message) {
|
||||
log.info("终端心跳消息: {}", message.getTerminalPhone());
|
||||
JT808.sendGeneralResponse(message);
|
||||
}
|
||||
|
||||
@Listener(messageId = 0x0200)
|
||||
public void onLocationReport(JT808Message message) {
|
||||
LocationReportMsg locationReportMsg = message.getMessageBody(LocationReportMsg.class);
|
||||
log.info("终端位置信息汇报消息: {}", locationReportMsg);
|
||||
JT808.sendGeneralResponse(message);
|
||||
}
|
||||
|
||||
@Listener(messageId = 0x0001)
|
||||
public void onTerminalGeneralResponse(JT808Message message) {
|
||||
TerminalGeneralResponseMsg terminalGeneralResponseMsg = message.getMessageBody(TerminalGeneralResponseMsg.class);
|
||||
log.info("终端通用应答消息: {}", terminalGeneralResponseMsg);
|
||||
JT808.sendGeneralResponse(message);
|
||||
}
|
||||
|
||||
@Listener(messageId = 0x6006)
|
||||
public void onTerminalTxtReport(JT808Message message) {
|
||||
TerminalTxtReportMsg terminalTxtReportMsg = message.getMessageBody(TerminalTxtReportMsg.class);
|
||||
log.info("终端文本信息汇报消息: {}", terminalTxtReportMsg);
|
||||
JT808.sendGeneralResponse(message);
|
||||
}
|
||||
|
||||
@Listener(messageId = 0x0201)
|
||||
public void onSearchLocationResponse(JT808Message message) {
|
||||
SearchLocationResponseMsg searchLocationResponseMsg = message.getMessageBody(SearchLocationResponseMsg.class);
|
||||
log.info("查询位置响应消息: {}", searchLocationResponseMsg);
|
||||
JT808.sendGeneralResponse(message);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
package com.njzscloud.tuqiang;
|
||||
|
||||
import com.njzscloud.jt808.util.JT808;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@Slf4j
|
||||
public class Tuqiang {
|
||||
|
||||
public Tuqiang() {
|
||||
addListeners(new Listeners());
|
||||
}
|
||||
|
||||
private void addListeners(Object object) {
|
||||
Method[] methods = object.getClass().getMethods();
|
||||
for (Method method : methods) {
|
||||
if (method.isAnnotationPresent(Listener.class)) {
|
||||
Listener listener = method.getAnnotation(Listener.class);
|
||||
JT808.addListener(listener.messageId(), (msg) -> {
|
||||
try {
|
||||
method.invoke(object, msg);
|
||||
} catch (Exception e) {
|
||||
log.error("处理消息 {} 时出错", listener.messageId(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
package com.njzscloud.tuqiang.msg;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
public class PublishDirectiveMsg {
|
||||
private byte flag;
|
||||
private String directive;
|
||||
|
||||
public PublishDirectiveMsg(String directive) {
|
||||
this.flag = 0x01;
|
||||
this.directive = directive;
|
||||
}
|
||||
|
||||
public byte[] toBytes() {
|
||||
byte[] messageBody = new byte[directive.length() + 1];
|
||||
messageBody[0] = flag;
|
||||
System.arraycopy(directive.getBytes(), 0, messageBody, 1, directive.length());
|
||||
return messageBody;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration debug="false">
|
||||
<conversionRule conversionWord="clr" converterClass="com.njzscloud.common.log.ColorConverter"/>
|
||||
<conversionRule conversionWord="clr" converterClass="com.njzscloud.common.core.log.ColorConverter"/>
|
||||
|
||||
<property name="log_path" value="logs"/>
|
||||
<property name="service_name" value="gps"/>
|
||||
|
|
|
|||
Loading…
Reference in New Issue