├── src ├── main │ ├── resources │ │ ├── baseconf.properties │ │ ├── log4j.xml │ │ └── log4j.dtd │ ├── java │ │ └── cn │ │ │ └── hylexus │ │ │ └── jt808 │ │ │ ├── common │ │ │ ├── GpsServerConsts.java │ │ │ ├── MyClassificationLogAppender.java │ │ │ ├── TPMSParamterConsts.java │ │ │ └── TPMSConsts.java │ │ │ ├── util │ │ │ ├── ByteUtils.java │ │ │ ├── ts │ │ │ │ └── ConvertValue.java │ │ │ ├── PrintHex.java │ │ │ ├── ReadConfUtil.java │ │ │ ├── BCD8421Operater.java │ │ │ ├── HexStringUtils.java │ │ │ ├── BaseUtil.java │ │ │ ├── JT808ProtocolUtils.java │ │ │ └── BitOperator.java │ │ │ ├── socket │ │ │ ├── MessageVo.java │ │ │ ├── SocketThread.java │ │ │ ├── SocketOperate.java │ │ │ └── PojoToMessage.java │ │ │ ├── vo │ │ │ ├── req │ │ │ │ ├── TerminalLocationAdditionalInfoMsg.java │ │ │ │ ├── PolygonDelArea.java │ │ │ │ ├── PolygonParamItem.java │ │ │ │ ├── TerminalParamQuery.java │ │ │ │ ├── LocationInformationQuery.java │ │ │ │ ├── TerminalParamItem.java │ │ │ │ ├── TerminalAuthenticationMsg.java │ │ │ │ ├── LocationInformationQueryResp.java │ │ │ │ ├── TerminalParamQueryMsgResp.java │ │ │ │ ├── PolygonSettingArea.java │ │ │ │ ├── TerminalRegisterMsg.java │ │ │ │ ├── TerminalLoctionInfoReportMsg.java │ │ │ │ └── TerminalParametersSettingInfo.java │ │ │ ├── resp │ │ │ │ ├── TerminalRegisterMsgRespBody.java │ │ │ │ ├── ServerCommonRespMsgBody.java │ │ │ │ └── TerminalCommonRespMsg.java │ │ │ ├── Session.java │ │ │ └── PackageData.java │ │ │ ├── service │ │ │ ├── codec │ │ │ │ ├── Decoder4LoggingOnly.java │ │ │ │ ├── MsgEncoder.java │ │ │ │ └── MsgDecoder.java │ │ │ ├── BaseMsgProcessService.java │ │ │ ├── TerminalMsgSendService.java │ │ │ ├── TerminalMsgProcessService.java │ │ │ ├── handler │ │ │ │ └── TCPServerHandler.java │ │ │ └── MsgToDPlatformGpsPojoService.java │ │ │ └── server │ │ │ ├── SessionManager.java │ │ │ └── TCPServer.java │ └── test │ │ └── MainTest.java └── test │ └── java │ └── cn │ └── hylexus │ └── jt808 │ └── server │ └── TestSocket.java ├── .gitignore └── pom.xml /src/main/resources/baseconf.properties: -------------------------------------------------------------------------------- 1 | #server ipaddress 2 | gps.server.ip=127.0.0.1 3 | gps.server.port=8080 4 | gps.server.name=server 5 | 6 | # gps communication port 7 | gpsport = 81 -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/common/GpsServerConsts.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.common; 2 | /** 3 | * gps 服务端的相关配置 4 | * @author cheryl 5 | * 6 | */ 7 | public class GpsServerConsts { 8 | public static final String gps_server_base = "http://127.0.0.1:8080/server/services/gpsBaseSvc"; 9 | public static final String gps_server_business = "http://127.0.0.1:8080/server/services/gpsBusinessSvc"; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/common/MyClassificationLogAppender.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.common; 2 | 3 | import org.apache.log4j.DailyRollingFileAppender; 4 | import org.apache.log4j.Priority; 5 | 6 | public class MyClassificationLogAppender extends DailyRollingFileAppender { 7 | 8 | @Override 9 | public boolean isAsSevereAsThreshold(Priority priority) { 10 | return this.getThreshold().equals(priority); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/util/ByteUtils.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.util; 2 | /** 3 | * 字节数组操作的工具类 4 | * @author cheryl 5 | * 6 | */ 7 | public class ByteUtils { 8 | /** 9 | * 截取 字节数组 10 | * @param src 11 | * @param begin 12 | * @param count 13 | * @return 14 | */ 15 | public static byte[] subBytes(byte[] src, int begin, int count) { 16 | byte[] bs = new byte[count]; 17 | System.arraycopy(src, begin, bs, 0, count); 18 | return bs; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/util/ts/ConvertValue.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.util.ts; 2 | 3 | import java.util.Arrays; 4 | 5 | public class ConvertValue { 6 | 7 | public static void main(String[] args) { 8 | int a = 999900000; 9 | byte[] b = new byte[4]; 10 | 11 | b[3] = (byte)(a & 0xff); 12 | b[2] = (byte)(a & 0xff); 13 | b[1] = (byte)(a & 0xff); 14 | b[0] = (byte)(a & 0xff); 15 | 16 | System.out.println(Arrays.toString(b)); 17 | 18 | int ai = 0; 19 | for(int i=0;i>>= 4; 15 | } while (Num != 0); 16 | 17 | for (int i = length; i < result.length; i++) { 18 | System.out.println(result[i]); 19 | } 20 | 21 | System.out.println(32 >>> 4); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/socket/MessageVo.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.socket; 2 | /** 3 | * 发送报文的消息类 4 | * @author cheryl 5 | * 6 | */ 7 | public class MessageVo { 8 | private int messageId; //消息id 9 | private String phone;//终端手机号 10 | private String paramStr;//报文所需的消息的json str 11 | 12 | public int getMessageId() { 13 | return messageId; 14 | } 15 | public void setMessageId(int messageId) { 16 | this.messageId = messageId; 17 | } 18 | public String getPhone() { 19 | return phone; 20 | } 21 | public void setPhone(String phone) { 22 | this.phone = phone; 23 | } 24 | public String getParamStr() { 25 | return paramStr; 26 | } 27 | public void setParamStr(String paramStr) { 28 | this.paramStr = paramStr; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/vo/req/TerminalLocationAdditionalInfoMsg.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.vo.req; 2 | /** 3 | * 位置附加信息 4 | * @author cheryl 5 | * 6 | */ 7 | public class TerminalLocationAdditionalInfoMsg { 8 | //附加消息id 9 | private int msgId; 10 | //附加消息长度 11 | private int msgCount; 12 | //附加消息 13 | private int msgContent; 14 | public int getMsgId() { 15 | return msgId; 16 | } 17 | public void setMsgId(int msgId) { 18 | this.msgId = msgId; 19 | } 20 | public int getMsgCount() { 21 | return msgCount; 22 | } 23 | public void setMsgCount(int msgCount) { 24 | this.msgCount = msgCount; 25 | } 26 | public int getMsgContent() { 27 | return msgContent; 28 | } 29 | public void setMsgContent(int msgContent) { 30 | this.msgContent = msgContent; 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/vo/req/PolygonDelArea.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.vo.req; 2 | /** 3 | * 删除多边形区域 4 | * @author cheryl 5 | * 6 | */ 7 | 8 | import java.util.Arrays; 9 | 10 | public class PolygonDelArea { 11 | // 区域数, BYTE, 12 | private int areaCount; 13 | // 区域ID,如“区域 ID1 区域 ID2......区域 IDn”。 14 | private byte[] areaIds; 15 | 16 | public int getAreaCount() { 17 | return areaCount; 18 | } 19 | 20 | public void setAreaCount(int areaCount) { 21 | this.areaCount = areaCount; 22 | } 23 | 24 | public byte[] getAreaIds() { 25 | return areaIds; 26 | } 27 | 28 | public void setAreaIds(byte[] areaIds) { 29 | this.areaIds = areaIds; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | return "PolygonDelArea [areaCount=" + areaCount + ", areaIds=" + Arrays.toString(areaIds) + "]"; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/vo/req/PolygonParamItem.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.vo.req; 2 | 3 | /** 4 | * 设置多边形区域 ------>顶点项 5 | * 6 | * @author cheryl 7 | * 8 | */ 9 | public class PolygonParamItem { 10 | 11 | // 顶点纬度 DWORD 12 | private int topLatitude; 13 | // 顶点经度 DWORD 14 | private int topLongitude; 15 | 16 | public int getTopLatitude() { 17 | return topLatitude; 18 | } 19 | 20 | public void setTopLatitude(int topLatitude) { 21 | this.topLatitude = topLatitude; 22 | } 23 | 24 | public int getTopLongitude() { 25 | return topLongitude; 26 | } 27 | 28 | public void setTopLongitude(int topLongitude) { 29 | this.topLongitude = topLongitude; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | return "PolygonParamItem [topLatitude=" + topLatitude + ", topLongitude=" + topLongitude + "]"; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/vo/req/TerminalParamQuery.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.vo.req; 2 | /** 3 | * 终端参数查询 4 | * @author cheryl 5 | * 6 | */ 7 | 8 | import java.util.Arrays; 9 | 10 | public class TerminalParamQuery { 11 | // 参数总数n, BYTE, 12 | private int paramCount; 13 | // BYTE[4*n] 参数顺序排列,如“参数 ID1 参数 ID2......参数 IDn”。 14 | private byte[] msgIds; 15 | 16 | public int getParamCount() { 17 | return paramCount; 18 | } 19 | 20 | public void setParamCount(int paramCount) { 21 | this.paramCount = paramCount; 22 | } 23 | 24 | public byte[] getMsgIds() { 25 | return msgIds; 26 | } 27 | 28 | public void setMsgIds(byte[] msgIds) { 29 | this.msgIds = msgIds; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | return "TerminalParamQueryInfo [paramCount=" + paramCount + ", msgIds=" + Arrays.toString(msgIds) + "]"; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/vo/req/LocationInformationQuery.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.vo.req; 2 | 3 | import java.util.Arrays; 4 | 5 | import cn.hylexus.jt808.vo.PackageData; 6 | 7 | /** 8 | * 位置信息查询 9 | * 10 | * @author hylexus 11 | * 12 | */ 13 | public class LocationInformationQuery extends PackageData { 14 | 15 | public LocationInformationQuery() { 16 | } 17 | 18 | public LocationInformationQuery(PackageData packageData) { 19 | this(); 20 | this.channel = packageData.getChannel(); 21 | this.checkSum = packageData.getCheckSum(); 22 | this.msgBodyBytes = packageData.getMsgBodyBytes(); 23 | this.msgHeader = packageData.getMsgHeader(); 24 | } 25 | 26 | @Override 27 | public String toString() { 28 | return "LocationInformationQuery [msgHeader=" + msgHeader 29 | + ", msgBodyBytes=" + Arrays.toString(msgBodyBytes) + ", checkSum=" + checkSum + ", channel=" + channel 30 | + "]"; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/common/TPMSParamterConsts.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.common; 2 | /** 3 | * 消息体中的 4 | * @author cheryl 5 | * 6 | */ 7 | public class TPMSParamterConsts { 8 | 9 | public static int heartbeatInterval = 0x0001; //终端心跳发送间隔,单位为秒(s) 10 | public static int serverAddress = 0x0013; //主服务器地址,IP 或域名 11 | public static int serverPort = 0x0018; // 服务器 TCP 端口 12 | public static int sleepTimeReportInteval = 0x0027; //休眠时汇报时间间隔,单位为秒(s),>0 13 | public static int defaultTimeReportInteval = 0x0029; //缺省时间汇报间隔,单位为秒(s),>0 14 | 15 | public static int maxspeed =0x0055; //最高速度,单位为公里每小时(km/h) 16 | public static int overspeedDuration = 0x0056; //超速持续时间,单位为秒(s) 17 | public static int odometerReading = 0x0080; //车辆里程表读数,1/10km 18 | public static int provinceId = 0x0081; //车辆所在的省域 ID 19 | public static int cityId= 0x0082; //车辆所在的市域 ID 20 | public static int licensePlate= 0x0083; //公安交通管理部门颁发的机动车号牌 21 | public static int licensePlateColor = 0x0084; //车牌颜色,按照 JT/T415-2006 的 5.4.12 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/vo/req/TerminalParamItem.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.vo.req; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 终端参数设置 ------>参数项 7 | * @author cheryl 8 | * 9 | */ 10 | public class TerminalParamItem { 11 | 12 | // 参数ID DWORD 13 | private int msgId; 14 | // 参数长度 BYTE 15 | private int paramLength; 16 | // 参数值 17 | private byte[] paramValue; 18 | 19 | public int getMsgId() { 20 | return msgId; 21 | } 22 | 23 | public void setMsgId(int msgId) { 24 | this.msgId = msgId; 25 | } 26 | 27 | public int getParamLength() { 28 | return paramLength; 29 | } 30 | 31 | public void setParamLength(int paramLength) { 32 | this.paramLength = paramLength; 33 | } 34 | 35 | public byte[] getParamValue() { 36 | return paramValue; 37 | } 38 | 39 | public void setParamValue(byte[] paramValue) { 40 | this.paramValue = paramValue; 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return "TerminalParamItem [msgId=" + msgId + ", paramLength=" + paramLength + ", paramValue=" + Arrays.toString(paramValue) 46 | + "]"; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/vo/req/TerminalAuthenticationMsg.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.vo.req; 2 | 3 | import java.util.Arrays; 4 | 5 | import cn.hylexus.jt808.common.TPMSConsts; 6 | import cn.hylexus.jt808.vo.PackageData; 7 | 8 | /** 9 | * 终端鉴权消息 10 | * 11 | * @author hylexus 12 | * 13 | */ 14 | public class TerminalAuthenticationMsg extends PackageData { 15 | private String authCode; 16 | 17 | public TerminalAuthenticationMsg() { 18 | } 19 | 20 | public TerminalAuthenticationMsg(PackageData packageData) { 21 | this(); 22 | this.channel = packageData.getChannel(); 23 | this.checkSum = packageData.getCheckSum(); 24 | this.msgBodyBytes = packageData.getMsgBodyBytes(); 25 | this.msgHeader = packageData.getMsgHeader(); 26 | this.authCode = new String(packageData.getMsgBodyBytes(), TPMSConsts.string_charset); 27 | } 28 | 29 | public void setAuthCode(String authCode) { 30 | this.authCode = authCode; 31 | } 32 | 33 | public String getAuthCode() { 34 | return authCode; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return "TerminalAuthenticationMsg [authCode=" + authCode + ", msgHeader=" + msgHeader + ", msgBodyBytes=" 40 | + Arrays.toString(msgBodyBytes) + ", checkSum=" + checkSum + ", channel=" + channel + "]"; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/cn/hylexus/jt808/server/TestSocket.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.server; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.io.OutputStreamWriter; 8 | import java.net.ServerSocket; 9 | import java.net.Socket; 10 | 11 | import org.junit.Test; 12 | 13 | public class TestSocket { 14 | 15 | @Test 16 | public void createSocketServer() { 17 | // try { 18 | // ServerSocket ss = new ServerSocket(8888); 19 | // System.out.println("启动服务器...."); 20 | // Socket s = ss.accept(); 21 | // System.out.println("客户端:"+s.getInetAddress().getLocalHost()+"已连接到服务器"); 22 | // 23 | // BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())); 24 | // //读取客户端发送来的消息 25 | // String mess = br.readLine(); 26 | // System.out.println("客户端:"+mess); 27 | // BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); 28 | // bw.write(mess+"\n"); 29 | // bw.flush(); 30 | // } catch (IOException e) { 31 | // e.printStackTrace(); 32 | // } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/service/codec/Decoder4LoggingOnly.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.service.codec; 2 | 3 | import java.util.List; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import cn.hylexus.jt808.util.HexStringUtils; 9 | import io.netty.buffer.ByteBuf; 10 | import io.netty.buffer.Unpooled; 11 | import io.netty.channel.ChannelHandlerContext; 12 | import io.netty.handler.codec.ByteToMessageDecoder; 13 | 14 | /** 15 | * 该解码器只是为了自己日志所用,没其他作用.
16 | * 最终删除 17 | * 18 | * @author hylexus 19 | * 20 | */ 21 | public class Decoder4LoggingOnly extends ByteToMessageDecoder { 22 | 23 | private final Logger log = LoggerFactory.getLogger(getClass()); 24 | private final Logger weblog = LoggerFactory.getLogger("weblog"); 25 | 26 | @Override 27 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { 28 | String hex = buf2Str(in); 29 | log.info("ip={},hex = {}", ctx.channel().remoteAddress(), hex); 30 | weblog.info("ip={},hex = {}", ctx.channel().remoteAddress(), hex); 31 | 32 | ByteBuf buf = Unpooled.buffer(); 33 | while (in.isReadable()) { 34 | buf.writeByte(in.readByte()); 35 | } 36 | out.add(buf); 37 | } 38 | 39 | private String buf2Str(ByteBuf in) { 40 | byte[] dst = new byte[in.readableBytes()]; 41 | in.getBytes(0, dst); 42 | return HexStringUtils.toHexString(dst); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/vo/resp/TerminalRegisterMsgRespBody.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.vo.resp; 2 | 3 | public class TerminalRegisterMsgRespBody { 4 | 5 | public static final byte success = 0; 6 | public static final byte car_already_registered = 1; 7 | public static final byte car_not_found = 2; 8 | public static final byte terminal_already_registered = 3; 9 | public static final byte terminal_not_found = 4; 10 | // byte[0-1] 应答流水号(WORD) 对应的终端注册消息的流水号 11 | private int replyFlowId; 12 | /*** 13 | * byte[2] 结果(BYTE)
14 | * 0:成功
15 | * 1:车辆已被注册
16 | * 2:数据库中无该车辆
17 | **/ 18 | private byte replyCode; 19 | // byte[3-x] 鉴权码(STRING) 只有在成功后才有该字段 20 | private String replyToken; 21 | 22 | public TerminalRegisterMsgRespBody() { 23 | } 24 | 25 | public int getReplyFlowId() { 26 | return replyFlowId; 27 | } 28 | 29 | public void setReplyFlowId(int flowId) { 30 | this.replyFlowId = flowId; 31 | } 32 | 33 | public byte getReplyCode() { 34 | return replyCode; 35 | } 36 | 37 | public void setReplyCode(byte code) { 38 | this.replyCode = code; 39 | } 40 | 41 | public String getReplyToken() { 42 | return replyToken; 43 | } 44 | 45 | public void setReplyToken(String token) { 46 | this.replyToken = token; 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return "TerminalRegisterMsgResp [replyFlowId=" + replyFlowId + ", replyCode=" + replyCode + ", replyToken=" 52 | + replyToken + "]"; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/util/ReadConfUtil.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.util; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.util.Properties; 6 | 7 | import cn.hylexus.jt808.common.GpsServerConsts; 8 | 9 | public class ReadConfUtil { 10 | 11 | /** 12 | * 系统服务端的配置 13 | * @return 14 | */ 15 | public static String getServerConf() { 16 | String ipaddress =null; 17 | try { 18 | Properties pro = new Properties(); 19 | InputStream in = GpsServerConsts.class.getResourceAsStream("/baseconf.properties"); 20 | pro.load(in); 21 | String ip = pro.getProperty("gps.server.ip"); 22 | String port = pro.getProperty("gps.server.port"); 23 | String name = pro.getProperty("gps.server.name"); 24 | ipaddress = ip+"/"+port+"/"+name; 25 | } catch (IOException e) { 26 | // TODO Auto-generated catch block 27 | e.printStackTrace(); 28 | } 29 | return ipaddress; 30 | } 31 | 32 | /** 33 | * 读取gps通讯服务的端口的配置 34 | * @return 35 | */ 36 | public static int getGpsPort() { 37 | int port = 0; 38 | try { 39 | Properties pro = new Properties(); 40 | InputStream in = GpsServerConsts.class.getResourceAsStream("/baseconf.properties"); 41 | pro.load(in); 42 | port = Integer.parseInt(pro.getProperty("gpsport")); 43 | } catch (IOException e) { 44 | // TODO Auto-generated catch block 45 | e.printStackTrace(); 46 | } 47 | return port; 48 | } 49 | public static void main(String[] args) { 50 | System.out.println(getServerConf()); 51 | System.out.println(getGpsPort()); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/vo/resp/ServerCommonRespMsgBody.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.vo.resp; 2 | 3 | public class ServerCommonRespMsgBody { 4 | 5 | public static final byte success = 0; 6 | public static final byte failure = 1; 7 | public static final byte msg_error = 2; 8 | public static final byte unsupported = 3; 9 | public static final byte warnning_msg_ack = 4; 10 | 11 | // byte[0-1] 应答流水号 对应的终端消息的流水号 12 | private int replyFlowId; 13 | // byte[2-3] 应答ID 对应的终端消息的ID 14 | private int replyId; 15 | /** 16 | * 0:成功∕确认
17 | * 1:失败
18 | * 2:消息有误
19 | * 3:不支持
20 | * 4:报警处理确认
21 | */ 22 | private byte replyCode; 23 | 24 | public ServerCommonRespMsgBody() { 25 | } 26 | 27 | public ServerCommonRespMsgBody(int replyFlowId, int replyId, byte replyCode) { 28 | super(); 29 | this.replyFlowId = replyFlowId; 30 | this.replyId = replyId; 31 | this.replyCode = replyCode; 32 | } 33 | 34 | public int getReplyFlowId() { 35 | return replyFlowId; 36 | } 37 | 38 | public void setReplyFlowId(int flowId) { 39 | this.replyFlowId = flowId; 40 | } 41 | 42 | public int getReplyId() { 43 | return replyId; 44 | } 45 | 46 | public void setReplyId(int msgId) { 47 | this.replyId = msgId; 48 | } 49 | 50 | public byte getReplyCode() { 51 | return replyCode; 52 | } 53 | 54 | public void setReplyCode(byte code) { 55 | this.replyCode = code; 56 | } 57 | 58 | @Override 59 | public String toString() { 60 | return "ServerCommonRespMsg [replyFlowId=" + replyFlowId + ", replyId=" + replyId + ", replyCode=" + replyCode 61 | + "]"; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/service/BaseMsgProcessService.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.service; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import cn.hylexus.jt808.server.SessionManager; 7 | import cn.hylexus.jt808.vo.Session; 8 | import io.netty.buffer.ByteBuf; 9 | import io.netty.buffer.PooledByteBufAllocator; 10 | import io.netty.buffer.Unpooled; 11 | import io.netty.channel.Channel; 12 | import io.netty.channel.ChannelFuture; 13 | 14 | public class BaseMsgProcessService { 15 | 16 | protected final Logger log = LoggerFactory.getLogger(getClass()); 17 | 18 | protected SessionManager sessionManager; 19 | 20 | public BaseMsgProcessService() { 21 | this.sessionManager = SessionManager.getInstance(); 22 | } 23 | 24 | protected ByteBuf getByteBuf(byte[] arr) { 25 | ByteBuf byteBuf = PooledByteBufAllocator.DEFAULT.directBuffer(arr.length); 26 | byteBuf.writeBytes(arr); 27 | return byteBuf; 28 | } 29 | 30 | public boolean send2Client(Channel channel, byte[] arr) throws InterruptedException { 31 | log.error("给客户端发送消息:{}", ""); 32 | boolean flag = false; 33 | ChannelFuture future = channel.writeAndFlush(Unpooled.copiedBuffer(arr)).sync(); 34 | 35 | if (!future.isSuccess()) { 36 | log.error("发送数据出错:{}", future.cause()); 37 | }else { 38 | flag = true; 39 | log.error("发送数据成功:{}", ""); 40 | } 41 | return flag; 42 | } 43 | 44 | protected int getFlowId(Channel channel, int defaultValue) { 45 | Session session = this.sessionManager.findBySessionId(Session.buildId(channel)); 46 | if (session == null) { 47 | return defaultValue; 48 | } 49 | 50 | return session.currentFlowId(); 51 | } 52 | 53 | protected int getFlowId(Channel channel) { 54 | return this.getFlowId(channel, 0); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/common/TPMSConsts.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.common; 2 | 3 | import java.nio.charset.Charset; 4 | /** 5 | * 消息常用id 6 | * @author cheryl 7 | * 8 | */ 9 | public class TPMSConsts { 10 | 11 | public static final String string_encoding = "GBK"; 12 | 13 | public static final Charset string_charset = Charset.forName(string_encoding); 14 | // 标识位 15 | public static final int pkg_delimiter = 0x7e; 16 | // 客户端发呆15分钟后,服务器主动断开连接 17 | public static int tcp_client_idle_minutes = 45; 18 | 19 | // 终端通用应答 20 | public static final int msg_id_terminal_common_resp = 0x0001; 21 | // 终端心跳 22 | public static final int msg_id_terminal_heart_beat = 0x0002; 23 | // 终端注册 24 | public static final int msg_id_terminal_register = 0x0100; 25 | // 终端注销 26 | public static final int msg_id_terminal_log_out = 0x0003; 27 | // 终端鉴权 28 | public static final int msg_id_terminal_authentication = 0x0102; 29 | 30 | // 位置信息汇报 31 | public static final int msg_id_terminal_location_info_upload = 0x0200; 32 | //位置信息查询 33 | public static final int cmd_position_query = 0x8201; 34 | //位置信息查询应答 35 | public static final int cmd_position_query_resp = 0x0201; 36 | 37 | // 胎压数据透传 38 | public static final int msg_id_terminal_transmission_tyre_pressure = 0x0600; 39 | 40 | 41 | // 平台通用应答 42 | public static final int cmd_common_resp = 0x8001; 43 | // 终端注册应答 44 | public static final int cmd_terminal_register_resp = 0x8100; 45 | 46 | // 设置终端参数 47 | public static final int cmd_terminal_param_settings = 0X8103; 48 | // 查询终端参数 49 | public static final int cmd_terminal_param_query = 0x8104; 50 | // 查询终端参数应答 51 | public static final int msg_id_terminal_param_query_resp = 0x0104; 52 | 53 | // 设置多边形区域 54 | public static final int cmd_polygon_area_settings = 0x8604; 55 | // 删除多边形区域 56 | public static final int cmd_polygon_area_del = 0x8605; 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/util/BCD8421Operater.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.util; 2 | 3 | import java.util.Arrays; 4 | 5 | public class BCD8421Operater { 6 | 7 | /** 8 | * BCD字节数组===>String 9 | * 10 | * @param bytes 11 | * @return 十进制字符串 12 | */ 13 | public String bcd2String(byte[] bytes) { 14 | StringBuilder temp = new StringBuilder(bytes.length * 2); 15 | for (int i = 0; i < bytes.length; i++) { 16 | // 高四位 17 | temp.append((bytes[i] & 0xf0) >>> 4); 18 | // 低四位 19 | temp.append(bytes[i] & 0x0f); 20 | } 21 | return temp.toString().substring(0, 1).equalsIgnoreCase("0") ? temp.toString().substring(1) : temp.toString(); 22 | } 23 | 24 | /** 25 | * 字符串==>BCD字节数组 26 | * 27 | * @param str 28 | * @return BCD字节数组 29 | */ 30 | public byte[] string2Bcd(String str) { 31 | // 奇数,前补零 32 | if ((str.length() & 0x1) == 1) { 33 | str = "0" + str; 34 | } 35 | 36 | byte ret[] = new byte[str.length() / 2]; 37 | byte bs[] = str.getBytes(); 38 | for (int i = 0; i < ret.length; i++) { 39 | 40 | byte high = ascII2Bcd(bs[2 * i]); 41 | byte low = ascII2Bcd(bs[2 * i + 1]); 42 | 43 | // TODO 只遮罩BCD低四位? 44 | ret[i] = (byte) ((high << 4) | low); 45 | } 46 | return ret; 47 | } 48 | 49 | private byte ascII2Bcd(byte asc) { 50 | if ((asc >= '0') && (asc <= '9')) 51 | return (byte) (asc - '0'); 52 | else if ((asc >= 'A') && (asc <= 'F')) 53 | return (byte) (asc - 'A' + 10); 54 | else if ((asc >= 'a') && (asc <= 'f')) 55 | return (byte) (asc - 'a' + 10); 56 | else 57 | return (byte) (asc - 48); 58 | } 59 | 60 | public static void main(String[] args) { 61 | System.out.println("52 二进制:" + Integer.toBinaryString(52)); 62 | System.out.println("100 二进制:" + Integer.toBinaryString(100)); 63 | System.out.println(52 & 100); 64 | 65 | System.out.println(Integer.toBinaryString(10)); 66 | 67 | System.out.println(Double.doubleToLongBits(0.125d)); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/socket/SocketThread.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.socket; 2 | import java.io.*; 3 | import java.net.*; 4 | public class SocketThread extends Thread { 5 | 6 | private ServerSocket serverSocket = null; 7 | 8 | public SocketThread(ServerSocket serverScoket){ 9 | try { 10 | if(null == serverSocket){ 11 | this.serverSocket = new ServerSocket(8877); 12 | System.out.println("socket start"); 13 | } 14 | } catch (Exception e) { 15 | System.out.println("SocketThread创建socket服务出错"); 16 | e.printStackTrace(); 17 | } 18 | 19 | } 20 | 21 | public void run(){ 22 | System.out.println("开始启动线程"); 23 | while(!this.isInterrupted()){ 24 | try { 25 | Socket socket = serverSocket.accept(); 26 | 27 | if(null != socket && !socket.isClosed()){ 28 | System.out.println("客户端:"+socket.getInetAddress().getLocalHost()+"已连接到服务器"); 29 | //处理接受的数据 30 | new SocketOperate(socket).start(); 31 | } 32 | // setSoTimeout(30000) 是表示如果对方连接状态30秒没有收到数据的话强制断开客户端 33 | socket.setSoTimeout(30000); 34 | 35 | }catch (Exception e) { 36 | e.printStackTrace(); 37 | } 38 | } 39 | } 40 | 41 | 42 | public void closeSocketServer(){ 43 | System.out.println("准备关闭线程"); 44 | try { 45 | if(null!=serverSocket && !serverSocket.isClosed()) 46 | { 47 | serverSocket.close(); 48 | } 49 | } catch (IOException e) { 50 | // TODO Auto-generated catch block 51 | e.printStackTrace(); 52 | } 53 | } 54 | 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/vo/req/LocationInformationQueryResp.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.vo.req; 2 | 3 | import cn.hylexus.jt808.vo.PackageData; 4 | import cn.hylexus.jt808.vo.req.TerminalLoctionInfoReportMsg.TerminalLoctionInfo; 5 | 6 | /** 7 | * 位置信息查询应答 8 | * @author Administrator 9 | * 10 | */ 11 | public class LocationInformationQueryResp extends PackageData { 12 | 13 | private LocationInformationQueryInfo locationInformationQueryInfo; 14 | 15 | public LocationInformationQueryResp() { 16 | } 17 | 18 | public LocationInformationQueryResp(PackageData packageData) { 19 | this(); 20 | this.channel = packageData.getChannel(); 21 | this.checkSum = packageData.getCheckSum(); 22 | this.msgBodyBytes = packageData.getMsgBodyBytes(); 23 | this.msgHeader = packageData.getMsgHeader(); 24 | } 25 | 26 | public LocationInformationQueryInfo getLocationInformationQueryInfo() { 27 | return locationInformationQueryInfo; 28 | } 29 | 30 | public void setLocationInformationQueryInfo(LocationInformationQueryInfo locationInformationQueryInfo) { 31 | this.locationInformationQueryInfo = locationInformationQueryInfo; 32 | } 33 | 34 | 35 | 36 | public static class LocationInformationQueryInfo extends TerminalLoctionInfo{ 37 | // WORD 应答流水号 对应的终端消息的流水号 38 | private int replyFlowId; 39 | 40 | public int getReplyFlowId() { 41 | return replyFlowId; 42 | } 43 | 44 | public void setReplyFlowId(int replyFlowId) { 45 | this.replyFlowId = replyFlowId; 46 | } 47 | 48 | @Override 49 | public String toString() { 50 | return "LocationInformationQueryInfo [replyFlowId=" + replyFlowId + ", warningFlag=" + warningFlag 51 | + ", status=" + status + ", latitude=" + latitude + ", longitude=" + longitude + ", altitude=" 52 | + altitude + ", speed=" + speed + ", course=" + course + ", time=" + time + ", mileage=" + mileage 53 | + "]"; 54 | } 55 | 56 | 57 | 58 | 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/vo/resp/TerminalCommonRespMsg.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.vo.resp; 2 | 3 | import cn.hylexus.jt808.vo.PackageData; 4 | 5 | /** 6 | * 终端通用应答消息 7 | * @author cheryl 8 | * 9 | */ 10 | public class TerminalCommonRespMsg extends PackageData { 11 | 12 | private TerminalCommonRespInfo terminalCommonRespInfo; 13 | 14 | 15 | public TerminalCommonRespMsg() { 16 | } 17 | 18 | public TerminalCommonRespMsg(PackageData packageData) { 19 | this(); 20 | this.channel = packageData.getChannel(); 21 | this.checkSum = packageData.getCheckSum(); 22 | this.msgBodyBytes = packageData.getMsgBodyBytes(); 23 | this.msgHeader = packageData.getMsgHeader(); 24 | } 25 | 26 | public TerminalCommonRespInfo getTerminalCommonRespInfo() { 27 | return terminalCommonRespInfo; 28 | } 29 | 30 | public void setTerminalCommonRespInfo(TerminalCommonRespInfo terminalCommonRespInfo) { 31 | this.terminalCommonRespInfo = terminalCommonRespInfo; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "TerminalCommonRespMsg [terminalCommonRespInfo=" + terminalCommonRespInfo + "]"; 37 | } 38 | 39 | 40 | public static class TerminalCommonRespInfo { 41 | // byte[0-1] 应答流水号 对应的终端消息的流水号 42 | private int replyFlowId; 43 | // byte[2-3] 应答ID 对应的终端消息的ID 44 | private int replyId; 45 | /** 46 | * 0:成功∕确认
47 | * 1:失败
48 | * 2:消息有误
49 | * 3:不支持
50 | * 4:报警处理确认
51 | */ 52 | private byte replyCode; 53 | 54 | public int getReplyFlowId() { 55 | return replyFlowId; 56 | } 57 | 58 | public void setReplyFlowId(int flowId) { 59 | this.replyFlowId = flowId; 60 | } 61 | 62 | public int getReplyId() { 63 | return replyId; 64 | } 65 | 66 | public void setReplyId(int msgId) { 67 | this.replyId = msgId; 68 | } 69 | 70 | public byte getReplyCode() { 71 | return replyCode; 72 | } 73 | 74 | public void setReplyCode(byte code) { 75 | this.replyCode = code; 76 | } 77 | 78 | @Override 79 | public String toString() { 80 | return "ServerCommonRespMsg [replyFlowId=" + replyFlowId + ", replyId=" + replyId + ", replyCode=" + replyCode 81 | + "]"; 82 | } 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/vo/req/TerminalParamQueryMsgResp.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.vo.req; 2 | 3 | import java.util.List; 4 | 5 | import cn.hylexus.jt808.vo.PackageData; 6 | 7 | /** 8 | * 查询终端参数应答 9 | * @author cheryl 10 | */ 11 | public class TerminalParamQueryMsgResp extends PackageData { 12 | 13 | private TerminalParametersqQueryInfo terminalParametersqQueryInfo; 14 | 15 | public TerminalParamQueryMsgResp() { 16 | } 17 | 18 | public TerminalParamQueryMsgResp(PackageData packageData) { 19 | this(); 20 | this.channel = packageData.getChannel(); 21 | this.checkSum = packageData.getCheckSum(); 22 | this.msgBodyBytes = packageData.getMsgBodyBytes(); 23 | this.msgHeader = packageData.getMsgHeader(); 24 | } 25 | 26 | 27 | public TerminalParametersqQueryInfo getTerminalParametersqQueryInfo() { 28 | return terminalParametersqQueryInfo; 29 | } 30 | 31 | public void setTerminalParametersqQueryInfo(TerminalParametersqQueryInfo terminalParametersqQueryInfo) { 32 | this.terminalParametersqQueryInfo = terminalParametersqQueryInfo; 33 | } 34 | 35 | 36 | public static class TerminalParametersqQueryInfo extends TerminalParametersSettingInfo{ 37 | // WORD 应答流水号 对应的终端消息的流水号 38 | private int replyFlowId; 39 | 40 | public int getReplyFlowId() { 41 | return replyFlowId; 42 | } 43 | 44 | public void setReplyFlowId(int replyFlowId) { 45 | this.replyFlowId = replyFlowId; 46 | } 47 | 48 | @Override 49 | public String toString() { 50 | return "TerminalParametersqQueryInfo [replyFlowId=" + replyFlowId + ", count=" + count 51 | + ", terminalParamItemList=" + terminalParamItemList + ", heartbeatInterval=" + heartbeatInterval 52 | + ", locationReportingStrategy=" + locationReportingStrategy + ", serverAddress=" + serverAddress 53 | + ", serverPort=" + serverPort + ", sleepTimeReportInteval=" + sleepTimeReportInteval 54 | + ", defaultTimeReportInteval=" + defaultTimeReportInteval + ", maxSpeed=" + maxSpeed 55 | + ", overspeedDuration=" + overspeedDuration + ", mileage=" + mileage + ", provinceId=" + provinceId 56 | + ", cityId=" + cityId + ", licensePlate=" + licensePlate + ", licensePlateColor=" 57 | + licensePlateColor + "]"; 58 | } 59 | 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Eclipse template 2 | *.pydevproject 3 | .metadata 4 | .gradle 5 | bin/ 6 | tmp/ 7 | *.tmp 8 | *.bak 9 | *.swp 10 | *~.nib 11 | local.properties 12 | .settings/ 13 | .loadpath 14 | 15 | # Svn 16 | *.svn 17 | 18 | # Eclipse Core 19 | .project 20 | 21 | # External tool builders 22 | .externalToolBuilders/ 23 | 24 | # Locally stored "Eclipse launch configurations" 25 | *.launch 26 | 27 | # CDT-specific 28 | .cproject 29 | 30 | # JDT-specific (Eclipse Java Development Tools) 31 | .classpath 32 | 33 | # Java annotation processor (APT) 34 | .factorypath 35 | 36 | # PDT-specific 37 | .buildpath 38 | 39 | # sbteclipse plugin 40 | .target 41 | 42 | # TeXlipse plugin 43 | .texlipse 44 | 45 | 46 | ### JetBrains template 47 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion 48 | 49 | *.iml 50 | 51 | ## Directory-based project format: 52 | .idea/ 53 | # if you remove the above rule, at least ignore the following: 54 | 55 | # User-specific stuff: 56 | # .idea/workspace.xml 57 | # .idea/tasks.xml 58 | # .idea/dictionaries 59 | 60 | # Sensitive or high-churn files: 61 | # .idea/dataSources.ids 62 | # .idea/dataSources.xml 63 | # .idea/sqlDataSources.xml 64 | # .idea/dynamic.xml 65 | # .idea/uiDesigner.xml 66 | 67 | # Gradle: 68 | # .idea/gradle.xml 69 | # .idea/libraries 70 | 71 | # Mongo Explorer plugin: 72 | # .idea/mongoSettings.xml 73 | 74 | ## File-based project format: 75 | *.ipr 76 | *.iws 77 | 78 | ## Plugin-specific files: 79 | 80 | # IntelliJ 81 | /out/ 82 | 83 | # mpeltonen/sbt-idea plugin 84 | .idea_modules/ 85 | 86 | # JIRA plugin 87 | atlassian-ide-plugin.xml 88 | 89 | # Crashlytics plugin (for Android Studio and IntelliJ) 90 | com_crashlytics_export_strings.xml 91 | crashlytics.properties 92 | crashlytics-build.properties 93 | 94 | 95 | ### Java template 96 | *.class 97 | 98 | # Mobile Tools for Java (J2ME) 99 | .mtj.tmp/ 100 | 101 | # Package Files # 102 | *.jar 103 | *.war 104 | *.ear 105 | 106 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 107 | hs_err_pid* 108 | 109 | 110 | /project/project/ 111 | /project/target/ 112 | /project/activator-* 113 | /logs/ 114 | /RUNNING_PID 115 | .DS_Store 116 | /target/ 117 | /workspace/ 118 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/vo/req/PolygonSettingArea.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.vo.req; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 设置多边形区域 7 | * 8 | * @author cheryl 9 | */ 10 | public class PolygonSettingArea { 11 | // 区域 ID 12 | protected int areaID; 13 | // 区域属性 14 | protected int areaAttribute; 15 | // 起始时间 16 | protected int startTime; 17 | // 结束时间 18 | protected int endTime; 19 | // 最高速度 20 | protected int maxSpeed; 21 | // 超速持续时间 22 | protected int continueTime; 23 | // 区域总顶点数 24 | protected int count; 25 | // 附加消息列表(顶点项) 26 | protected List polygonParamItemList; 27 | 28 | public int getAreaID() { 29 | return areaID; 30 | } 31 | 32 | public void setAreaID(int areaID) { 33 | this.areaID = areaID; 34 | } 35 | 36 | public int getAreaAttribute() { 37 | return areaAttribute; 38 | } 39 | 40 | public void setAreaAttribute(int areaAttribute) { 41 | this.areaAttribute = areaAttribute; 42 | } 43 | 44 | public int getStartTime() { 45 | return startTime; 46 | } 47 | 48 | public void setStartTime(int startTime) { 49 | this.startTime = startTime; 50 | } 51 | 52 | public int getEndTime() { 53 | return endTime; 54 | } 55 | 56 | public void setEndTime(int endTime) { 57 | this.endTime = endTime; 58 | } 59 | 60 | public int getMaxSpeed() { 61 | return maxSpeed; 62 | } 63 | 64 | public void setMaxSpeed(int maxSpeed) { 65 | this.maxSpeed = maxSpeed; 66 | } 67 | 68 | public int getContinueTime() { 69 | return continueTime; 70 | } 71 | 72 | public void setContinueTime(int continueTime) { 73 | this.continueTime = continueTime; 74 | } 75 | 76 | public int getCount() { 77 | return count; 78 | } 79 | 80 | public void setCount(int count) { 81 | this.count = count; 82 | } 83 | 84 | public List getPolygonParamItemList() { 85 | return polygonParamItemList; 86 | } 87 | 88 | public void setPolygonParamItemList(List polygonParamItemList) { 89 | this.polygonParamItemList = polygonParamItemList; 90 | } 91 | 92 | @Override 93 | public String toString() { 94 | return "PolygonSettingInfo [areaID=" + areaID + ", areaAttribute=" + areaAttribute + ", startTime=" + startTime 95 | + ", endTime=" + endTime + ", maxSpeed=" + maxSpeed + ", continueTime=" + continueTime + ", count=" 96 | + count + ", polygonParamItemList=" + polygonParamItemList + "]"; 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/util/HexStringUtils.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.util; 2 | 3 | public class HexStringUtils { 4 | 5 | private static final char[] DIGITS_HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 6 | 7 | protected static char[] encodeHex(byte[] data) { 8 | int l = data.length; 9 | char[] out = new char[l << 1]; 10 | for (int i = 0, j = 0; i < l; i++) { 11 | out[j++] = DIGITS_HEX[(0xF0 & data[i]) >>> 4]; 12 | out[j++] = DIGITS_HEX[0x0F & data[i]]; 13 | } 14 | return out; 15 | } 16 | 17 | protected static byte[] decodeHex(char[] data) { 18 | int len = data.length; 19 | if ((len & 0x01) != 0) { 20 | throw new RuntimeException("字符个数应该为偶数"); 21 | } 22 | byte[] out = new byte[len >> 1]; 23 | for (int i = 0, j = 0; j < len; i++) { 24 | int f = toDigit(data[j], j) << 4; 25 | j++; 26 | f |= toDigit(data[j], j); 27 | j++; 28 | out[i] = (byte) (f & 0xFF); 29 | } 30 | return out; 31 | } 32 | 33 | protected static int toDigit(char ch, int index) { 34 | int digit = Character.digit(ch, 16); 35 | if (digit == -1) { 36 | throw new RuntimeException("Illegal hexadecimal character " + ch + " at index " + index); 37 | } 38 | return digit; 39 | } 40 | 41 | public static String toHexString(byte[] bs) { 42 | return new String(encodeHex(bs)); 43 | } 44 | 45 | public static String hexString2Bytes(String hex) { 46 | return new String(decodeHex(hex.toCharArray())); 47 | } 48 | 49 | public static byte[] chars2Bytes(char[] bs) { 50 | return decodeHex(bs); 51 | } 52 | 53 | 54 | /* 55 | * 把16进制字符串转换成字节数组 56 | * @param hex 57 | * @return 58 | */ 59 | public static byte[] hexStringToByte(String hex) { 60 | int len = (hex.length() / 2); //除以2是因为十六进制比如a1使用两个字符代表一个byte 61 | byte[] result = new byte[len]; 62 | char[] achar = hex.toCharArray(); 63 | for (int i = 0; i < len; i++) { 64 | //乘以2是因为十六进制比如a1使用两个字符代表一个byte,pos代表的是数组的位置 65 | //第一个16进制数的起始位置是0第二个是2以此类推 66 | int pos = i * 2; 67 | //<<4位就是乘以16 比如说十六进制的"11",在这里也就是1*16|1,而其中的"|"或运算就相当于十进制中的加法运算 68 | //如00010000|00000001结果就是00010001 而00010000就有点类似于十进制中10而00000001相当于十进制中的1,与是其中的或运算就相当于是10+1(此处说法可能不太对,) 69 | result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1])); 70 | } 71 | return result; 72 | } 73 | 74 | private static byte toByte(char c) { 75 | byte b = (byte) "0123456789ABCDEF".indexOf(c); 76 | return b; 77 | } 78 | public static void main(String[] args) { 79 | String s = "abc你好"; 80 | String hex = toHexString(s.getBytes()); 81 | String decode = hexString2Bytes(hex); 82 | System.out.println("原字符串:" + s); 83 | System.out.println("十六进制字符串:" + hex); 84 | System.out.println("还原:" + decode); 85 | } 86 | } -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/vo/Session.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.vo; 2 | 3 | import java.net.SocketAddress; 4 | 5 | import io.netty.channel.Channel; 6 | 7 | public class Session { 8 | 9 | private String id; 10 | private String terminalPhone; 11 | private Channel channel = null; 12 | private boolean isAuthenticated = false; 13 | // 消息流水号 word(16) 按发送顺序从 0 开始循环累加 14 | private int currentFlowId = 0; 15 | // private ChannelGroup channelGroup = new 16 | // DefaultChannelGroup(GlobalEventExecutor.INSTANCE); 17 | // 客户端上次的连接时间,该值改变的情况: 18 | // 1. terminal --> server 心跳包 19 | // 2. terminal --> server 数据包 20 | private long lastCommunicateTimeStamp = 0l; 21 | 22 | public Session() { 23 | } 24 | 25 | public Channel getChannel() { 26 | return channel; 27 | } 28 | 29 | public void setChannel(Channel channel) { 30 | this.channel = channel; 31 | } 32 | 33 | public String getTerminalPhone() { 34 | return terminalPhone; 35 | } 36 | 37 | public void setTerminalPhone(String terminalPhone) { 38 | this.terminalPhone = terminalPhone; 39 | } 40 | 41 | public void setId(String id) { 42 | this.id = id; 43 | } 44 | 45 | public String getId() { 46 | return id; 47 | } 48 | 49 | public static String buildId(Channel channel) { 50 | return channel.id().asLongText(); 51 | } 52 | 53 | public static Session buildSession(Channel channel) { 54 | return buildSession(channel, null); 55 | } 56 | 57 | public static Session buildSession(Channel channel, String phone) { 58 | Session session = new Session(); 59 | session.setChannel(channel); 60 | session.setId(buildId(channel)); 61 | session.setTerminalPhone(phone); 62 | session.setLastCommunicateTimeStamp(System.currentTimeMillis()); 63 | return session; 64 | } 65 | 66 | public long getLastCommunicateTimeStamp() { 67 | return lastCommunicateTimeStamp; 68 | } 69 | 70 | public void setLastCommunicateTimeStamp(long lastCommunicateTimeStamp) { 71 | this.lastCommunicateTimeStamp = lastCommunicateTimeStamp; 72 | } 73 | 74 | public SocketAddress getRemoteAddr() { 75 | System.out.println(this.channel.remoteAddress().getClass()); 76 | 77 | return this.channel.remoteAddress(); 78 | } 79 | 80 | public boolean isAuthenticated() { 81 | return isAuthenticated; 82 | } 83 | 84 | public void setAuthenticated(boolean isAuthenticated) { 85 | this.isAuthenticated = isAuthenticated; 86 | } 87 | 88 | @Override 89 | public int hashCode() { 90 | final int prime = 31; 91 | int result = 1; 92 | result = prime * result + ((id == null) ? 0 : id.hashCode()); 93 | return result; 94 | } 95 | 96 | @Override 97 | public boolean equals(Object obj) { 98 | if (this == obj) 99 | return true; 100 | if (obj == null) 101 | return false; 102 | if (getClass() != obj.getClass()) 103 | return false; 104 | Session other = (Session) obj; 105 | if (id == null) { 106 | if (other.id != null) 107 | return false; 108 | } else if (!id.equals(other.id)) 109 | return false; 110 | return true; 111 | } 112 | 113 | @Override 114 | public String toString() { 115 | return "Session [id=" + id + ", terminalPhone=" + terminalPhone + ", channel=" + channel + "]"; 116 | } 117 | 118 | public synchronized int currentFlowId() { 119 | if (currentFlowId >= 0xffff) 120 | currentFlowId = 0; 121 | return currentFlowId++; 122 | } 123 | 124 | } -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/server/SessionManager.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.server; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.Map.Entry; 6 | import java.util.Set; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | import java.util.function.BiConsumer; 9 | import java.util.stream.Collectors; 10 | 11 | import cn.hylexus.jt808.vo.Session; 12 | 13 | public class SessionManager { 14 | 15 | private static volatile SessionManager instance = null; 16 | // netty生成的sessionID和Session的对应关系 17 | private Map sessionIdMap; 18 | // 终端手机号和netty生成的sessionID的对应关系 19 | private Map phoneMap; 20 | 21 | public static SessionManager getInstance() { 22 | if (instance == null) { 23 | synchronized (SessionManager.class) { 24 | if (instance == null) { 25 | instance = new SessionManager(); 26 | } 27 | } 28 | } 29 | return instance; 30 | } 31 | 32 | public SessionManager() { 33 | this.sessionIdMap = new ConcurrentHashMap<>(); 34 | this.phoneMap = new ConcurrentHashMap<>(); 35 | } 36 | 37 | public boolean containsKey(String sessionId) { 38 | return sessionIdMap.containsKey(sessionId); 39 | } 40 | 41 | public boolean containsSession(Session session) { 42 | return sessionIdMap.containsValue(session); 43 | } 44 | 45 | public Session findBySessionId(String id) { 46 | return sessionIdMap.get(id); 47 | } 48 | 49 | public Session findByTerminalPhone(String phone) { 50 | String sessionId = this.phoneMap.get(phone); 51 | if (sessionId == null) 52 | return null; 53 | return this.findBySessionId(sessionId); 54 | } 55 | 56 | public synchronized Session put(String key, Session value) { 57 | if (value.getTerminalPhone() != null && !"".equals(value.getTerminalPhone().trim())) { 58 | this.phoneMap.put(value.getTerminalPhone(), value.getId()); 59 | } 60 | return sessionIdMap.put(key, value); 61 | } 62 | 63 | public synchronized Session removeBySessionId(String sessionId) { 64 | if (sessionId == null) 65 | return null; 66 | Session session = sessionIdMap.remove(sessionId); 67 | if (session == null) 68 | return null; 69 | if (session.getTerminalPhone() != null) 70 | this.phoneMap.remove(session.getTerminalPhone()); 71 | return session; 72 | } 73 | 74 | // public synchronized void remove(String sessionId) { 75 | // if (sessionId == null) 76 | // return; 77 | // Session session = sessionIdMap.remove(sessionId); 78 | // if (session == null) 79 | // return; 80 | // if (session.getTerminalPhone() != null) 81 | // this.phoneMap.remove(session.getTerminalPhone()); 82 | // try { 83 | // if (session.getChannel() != null) { 84 | // if (session.getChannel().isActive() || session.getChannel().isOpen()) { 85 | // session.getChannel().close(); 86 | // } 87 | // session = null; 88 | // } 89 | // } catch (Exception e) { 90 | // e.printStackTrace(); 91 | // } 92 | // } 93 | 94 | public Set keySet() { 95 | return sessionIdMap.keySet(); 96 | } 97 | 98 | public void forEach(BiConsumer action) { 99 | sessionIdMap.forEach(action); 100 | } 101 | 102 | public Set> entrySet() { 103 | return sessionIdMap.entrySet(); 104 | } 105 | 106 | public List toList() { 107 | return this.sessionIdMap.entrySet().stream().map(e -> e.getValue()).collect(Collectors.toList()); 108 | } 109 | 110 | } -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/vo/req/TerminalRegisterMsg.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.vo.req; 2 | 3 | import java.util.Arrays; 4 | 5 | import cn.hylexus.jt808.vo.PackageData; 6 | 7 | /** 8 | * 终端注册消息 9 | * 10 | * @author hylexus 11 | * 12 | */ 13 | public class TerminalRegisterMsg extends PackageData { 14 | 15 | private TerminalRegInfo terminalRegInfo; 16 | 17 | public TerminalRegisterMsg() { 18 | } 19 | 20 | public TerminalRegisterMsg(PackageData packageData) { 21 | this(); 22 | this.channel = packageData.getChannel(); 23 | this.checkSum = packageData.getCheckSum(); 24 | this.msgBodyBytes = packageData.getMsgBodyBytes(); 25 | this.msgHeader = packageData.getMsgHeader(); 26 | } 27 | 28 | public TerminalRegInfo getTerminalRegInfo() { 29 | return terminalRegInfo; 30 | } 31 | 32 | public void setTerminalRegInfo(TerminalRegInfo msgBody) { 33 | this.terminalRegInfo = msgBody; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return "TerminalRegisterMsg [terminalRegInfo=" + terminalRegInfo + ", msgHeader=" + msgHeader 39 | + ", msgBodyBytes=" + Arrays.toString(msgBodyBytes) + ", checkSum=" + checkSum + ", channel=" + channel 40 | + "]"; 41 | } 42 | 43 | public static class TerminalRegInfo { 44 | // 省域ID(WORD),设备安装车辆所在的省域,省域ID采用GB/T2260中规定的行政区划代码6位中前两位 45 | // 0保留,由平台取默认值 46 | private int provinceId; 47 | // 市县域ID(WORD) 设备安装车辆所在的市域或县域,市县域ID采用GB/T2260中规定的行 政区划代码6位中后四位 48 | // 0保留,由平台取默认值 49 | private int cityId; 50 | // 制造商ID(BYTE[5]) 5 个字节,终端制造商编码 51 | private String manufacturerId; 52 | // 终端型号(BYTE[8]) 八个字节, 此终端型号 由制造商自行定义 位数不足八位的,补空格。 53 | private String terminalType; 54 | // 终端ID(BYTE[7]) 七个字节, 由大写字母 和数字组成, 此终端 ID由制造 商自行定义 55 | private String terminalId; 56 | /** 57 | * 车牌颜色(BYTE) 车牌颜色,按照 JT/T415-2006 的 5.4.12 未上牌时,取值为0
58 | * 0===未上车牌
59 | * 1===蓝色
60 | * 2===黄色
61 | * 3===黑色
62 | * 4===白色
63 | * 9===其他 64 | */ 65 | private int licensePlateColor; 66 | // 车牌(STRING) 公安交 通管理部门颁 发的机动车号牌 67 | private String licensePlate; 68 | 69 | public TerminalRegInfo() { 70 | } 71 | 72 | public int getProvinceId() { 73 | return provinceId; 74 | } 75 | 76 | public void setProvinceId(int provinceId) { 77 | this.provinceId = provinceId; 78 | } 79 | 80 | public int getCityId() { 81 | return cityId; 82 | } 83 | 84 | public void setCityId(int cityId) { 85 | this.cityId = cityId; 86 | } 87 | 88 | public String getManufacturerId() { 89 | return manufacturerId; 90 | } 91 | 92 | public void setManufacturerId(String manufacturerId) { 93 | this.manufacturerId = manufacturerId; 94 | } 95 | 96 | public String getTerminalType() { 97 | return terminalType; 98 | } 99 | 100 | public void setTerminalType(String terminalType) { 101 | this.terminalType = terminalType; 102 | } 103 | 104 | public String getTerminalId() { 105 | return terminalId; 106 | } 107 | 108 | public void setTerminalId(String terminalId) { 109 | this.terminalId = terminalId; 110 | } 111 | 112 | public int getLicensePlateColor() { 113 | return licensePlateColor; 114 | } 115 | 116 | public void setLicensePlateColor(int licensePlate) { 117 | this.licensePlateColor = licensePlate; 118 | } 119 | 120 | public String getLicensePlate() { 121 | return licensePlate; 122 | } 123 | 124 | public void setLicensePlate(String licensePlate) { 125 | this.licensePlate = licensePlate; 126 | } 127 | 128 | @Override 129 | public String toString() { 130 | return "TerminalRegInfo [provinceId=" + provinceId + ", cityId=" + cityId + ", manufacturerId=" 131 | + manufacturerId + ", terminalType=" + terminalType + ", terminalId=" + terminalId 132 | + ", licensePlateColor=" + licensePlateColor + ", licensePlate=" + licensePlate + "]"; 133 | } 134 | 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/vo/req/TerminalLoctionInfoReportMsg.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.vo.req; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | import cn.hylexus.jt808.vo.PackageData; 7 | 8 | /** 9 | * 终端位置信息汇报 10 | * 11 | * @author cheryl 12 | * 13 | */ 14 | public class TerminalLoctionInfoReportMsg extends PackageData { 15 | 16 | private TerminalLoctionInfo terminalLoctionInfo; 17 | 18 | 19 | public TerminalLoctionInfoReportMsg() { 20 | } 21 | 22 | public TerminalLoctionInfoReportMsg(PackageData packageData) { 23 | this(); 24 | this.channel = packageData.getChannel(); 25 | this.checkSum = packageData.getCheckSum(); 26 | this.msgBodyBytes = packageData.getMsgBodyBytes(); 27 | this.msgHeader = packageData.getMsgHeader(); 28 | } 29 | 30 | public TerminalLoctionInfo getTerminalLoctionInfo() { 31 | return terminalLoctionInfo; 32 | } 33 | 34 | public void setTerminalLoctionInfo(TerminalLoctionInfo terminalLoctionInfo) { 35 | this.terminalLoctionInfo = terminalLoctionInfo; 36 | } 37 | 38 | 39 | @Override 40 | public String toString() { 41 | return "TerminalLoctionInfoReportMsg [terminalLoctionInfo=" + terminalLoctionInfo + ", msgHeader=" + msgHeader 42 | + ", msgBodyBytes=" + Arrays.toString(msgBodyBytes) + ", checkSum=" + checkSum + ", channel=" + channel 43 | + "]"; 44 | } 45 | 46 | 47 | public static class TerminalLoctionInfo { 48 | // ------位置基本信息------ 49 | /** 50 | * 报警标志(DWORD) 51 | */ 52 | protected int warningFlag; 53 | /** 54 | * 状态(DWORD) 55 | */ 56 | protected int status; 57 | /** 58 | * 纬度(DWORD),以度为单位的经度值乘以10的6次方,精确到百万 分之一度 59 | */ 60 | protected int latitude; 61 | /** 62 | * 经度(DWORD),以度为单位的经度值乘以10的6次方,精确到百万 分之一度 63 | */ 64 | protected int longitude; 65 | // 高程 (WORD),海拔高度,单位为米(m) 66 | protected int altitude; 67 | //速度 (WORD)1/10km/h 68 | protected int speed; 69 | //方向 【 0-359,正北为 0,顺时针】 70 | protected int course; 71 | //时间 BCD[6] 【YY-MM-DD-hh-mm-ss(GMT+8 时间】 72 | protected String time; 73 | //附加消息 74 | //里程 DWORD,1/10km,对应车上⾥程表读数 ,附加消息id为0x01 75 | protected int mileage; 76 | 77 | public int getWarningFlag() { 78 | return warningFlag; 79 | } 80 | 81 | public void setWarningFlag(int warningFlag) { 82 | this.warningFlag = warningFlag; 83 | } 84 | 85 | public int getStatus() { 86 | return status; 87 | } 88 | 89 | public void setStatus(int status) { 90 | this.status = status; 91 | } 92 | 93 | public int getLatitude() { 94 | return latitude; 95 | } 96 | 97 | public void setLatitude(int latitude) { 98 | this.latitude = latitude; 99 | } 100 | 101 | public int getLongitude() { 102 | return longitude; 103 | } 104 | 105 | public void setLongitude(int longitude) { 106 | this.longitude = longitude; 107 | } 108 | 109 | public int getAltitude() { 110 | return altitude; 111 | } 112 | 113 | public void setAltitude(int altitude) { 114 | this.altitude = altitude; 115 | } 116 | 117 | public int getSpeed() { 118 | return speed; 119 | } 120 | 121 | public void setSpeed(int speed) { 122 | this.speed = speed; 123 | } 124 | 125 | public int getCourse() { 126 | return course; 127 | } 128 | 129 | public void setCourse(int course) { 130 | this.course = course; 131 | } 132 | 133 | public String getTime() { 134 | return time; 135 | } 136 | 137 | public void setTime(String time) { 138 | this.time = time; 139 | } 140 | 141 | public int getMileage() { 142 | return mileage; 143 | } 144 | 145 | public void setMileage(int mileage) { 146 | this.mileage = mileage; 147 | } 148 | 149 | @Override 150 | public String toString() { 151 | return "TerminalLoctionInfo [warningFlag=" + warningFlag + ", status=" + status + ", latitude=" + latitude 152 | + ", longitude=" + longitude + ", altitude=" + altitude + ", speed=" + speed + ", course=" 153 | + course + ", time=" + time + ", mileage=" + mileage + "]"; 154 | } 155 | 156 | } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/socket/SocketOperate.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.socket; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.InputStreamReader; 6 | import java.io.OutputStreamWriter; 7 | import java.io.PrintWriter; 8 | import java.net.Socket; 9 | 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import com.rksp.util.GsonUtil; 14 | import com.rksp.util.StringUtil; 15 | import com.sharetime.gps.pojo.Gps区域; 16 | import com.sharetime.gps.pojo.Gps指令集; 17 | import com.sharetime.gps.vo.TerminalParamSettingVo; 18 | 19 | import cn.hylexus.jt808.common.TPMSConsts; 20 | import cn.hylexus.jt808.service.TerminalMsgSendService; 21 | import cn.hylexus.jt808.vo.req.PolygonSettingArea; 22 | import cn.hylexus.jt808.vo.req.TerminalParametersSettingInfo; 23 | 24 | /** 25 | * 处理客户端发送报文的类 26 | * 用来保存终端传送过来的报文 27 | * @author cheryl 28 | * 29 | */ 30 | public class SocketOperate extends Thread { 31 | private Logger logger = LoggerFactory.getLogger(getClass()); 32 | private Socket socket; 33 | private final String encoding = "utf-8"; 34 | private TerminalMsgSendService msgSendService; 35 | private PojoToMessage pojoToMessage; 36 | public SocketOperate(Socket socket) { 37 | this.socket = socket; 38 | this.msgSendService = new TerminalMsgSendService(); 39 | this.pojoToMessage = new PojoToMessage(); 40 | } 41 | 42 | @SuppressWarnings("unused") 43 | public void run() { 44 | logger.info("监听客户端发送的消息"); 45 | try { 46 | BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(),encoding)); 47 | BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),encoding)); 48 | PrintWriter out = new PrintWriter(socket.getOutputStream()); 49 | // 读取客户端发送来的消息 50 | String strReq = in.readLine(); 51 | logger.info("Client:" + strReq); 52 | String strResp =""; 53 | MessageVo messageVo = (MessageVo) GsonUtil.getObject(strReq, MessageVo.class); 54 | boolean flag = false; 55 | System.out.println(messageVo.getMessageId()); 56 | if( TPMSConsts.cmd_terminal_param_settings == messageVo.getMessageId()) { 57 | logger.info("发送参数:"+messageVo.getParamStr()); 58 | TerminalParamSettingVo pojo =(TerminalParamSettingVo) GsonUtil.getObject(messageVo.getParamStr(), TerminalParamSettingVo.class); 59 | TerminalParametersSettingInfo msg = pojoToMessage.changeToerminalParametersSettigInfo(pojo); 60 | Gps指令集 directive = new Gps指令集(); 61 | directive.setSim卡号(messageVo.getPhone()); 62 | directive.set关联id(pojo.getPojoId()); 63 | directive.set消息内容(messageVo.getParamStr()); 64 | directive.set消息id(TPMSConsts.cmd_terminal_param_settings); 65 | flag = this.msgSendService.sendTerminalParamSettingMsg(messageVo.getPhone(),msg,directive); 66 | if(flag) { 67 | strResp = "消息发送成功"; 68 | }else { 69 | strResp = "消息发送失败"; 70 | } 71 | } 72 | // else if( TPMSConsts.cmd_polygon_area_settings == messageVo.getMessageId()) { 73 | // System.out.println("发送参数:"+messageVo.getParamStr()); 74 | // Gps区域 pojo =(Gps区域) GsonUtil.getObject(messageVo.getParamStr(), Gps区域.class); 75 | // PolygonSettingArea msg = pojoToMessage.changeToPolygonAreaSettigInfo(pojo); 76 | // } 77 | else if(TPMSConsts.cmd_terminal_param_query == messageVo.getMessageId()){ 78 | System.out.println("发送参数:"+messageVo.getParamStr()); 79 | // Gps指令集 directive = new Gps指令集(); 80 | // directive.setSim卡号(messageVo.getPhone()); 81 | // directive.set消息内容(messageVo.getParamStr()); 82 | // directive.set消息id(TPMSConsts.cmd_terminal_param_query); 83 | // flag = this.msgSendService.sendTerminalParamQueryMsg(messageVo.getPhone(),directive); 84 | flag = this.msgSendService.sendTerminalParamQueryMsg(messageVo.getPhone()); 85 | if(flag) { 86 | strResp = "消息发送成功"; 87 | }else { 88 | strResp = "消息发送失败"; 89 | } 90 | } 91 | else if(TPMSConsts.cmd_position_query == messageVo.getMessageId()){ 92 | System.out.println("发送参数:"+messageVo.getParamStr()); 93 | // Gps指令集 directive = new Gps指令集(); 94 | // directive.setSim卡号(messageVo.getPhone()); 95 | // directive.set消息内容(messageVo.getParamStr()); 96 | // directive.set消息id(TPMSConsts.cmd_position_query); 97 | flag = this.msgSendService.sendLocationQuery(messageVo.getPhone()); 98 | if(flag) { 99 | strResp = "消息发送成功"; 100 | }else { 101 | strResp = "消息发送失败"; 102 | } 103 | } 104 | logger.info("Server:" + strResp); 105 | bw.write(strResp); 106 | bw.flush(); 107 | bw.close(); 108 | socket.close(); 109 | logger.info("socket stop....."); 110 | } catch (Exception ex) { 111 | ex.printStackTrace(); 112 | } finally { 113 | 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/util/BaseUtil.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.util; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.DataOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.io.UnsupportedEncodingException; 8 | import java.math.BigDecimal; 9 | import java.net.HttpURLConnection; 10 | import java.net.MalformedURLException; 11 | import java.net.ProtocolException; 12 | import java.net.URL; 13 | import java.net.URLEncoder; 14 | import java.util.Date; 15 | 16 | import org.slf4j.Logger; 17 | import org.slf4j.LoggerFactory; 18 | 19 | import com.google.gson.JsonArray; 20 | import com.google.gson.JsonObject; 21 | import com.rksp.util.GsonUtil; 22 | 23 | 24 | /** 25 | * 系统共用的util类 26 | * @author cheryl 27 | * 28 | */ 29 | public class BaseUtil { 30 | private final static Logger log = LoggerFactory.getLogger(BaseUtil.class); 31 | /** 32 | * 生产终端设备的鉴权码 33 | * [终端手机号,当前日期的毫秒值] 34 | * @param terminalPhone 35 | * @return 36 | */ 37 | public static String generateAuthCode(String terminalPhone) { 38 | return terminalPhone+ new Date().getTime(); 39 | 40 | } 41 | //纠偏经纬度 42 | 43 | /** 44 | * 经度,纬度坐标转换 45 | * @param coords 坐标拼接的字符串 46 | * @param from 现在对应的坐标系 47 | * @param to 要转换的对应的坐标系 48 | * api:http://lbsyun.baidu.com/index.php?title=webapi/guide/changeposition 49 | * @return 50 | */ 51 | public static String getRealJWD(String coords,String from, String to){ 52 | String message =""; 53 | String encoding="UTF-8"; 54 | String path = "http://api.map.baidu.com/geoconv/v1/?from="+from+"&to="+to+"&ak=qePPr6rygb0n4BTYzL8C9hMC"; 55 | try{ 56 | String content = "coords="+URLEncoder.encode(coords,encoding);////在参数传递时 , 涉及需要转义的字符和汉字时需要进行编码 57 | String pmessage = urlConnReq(path ,encoding, content,"POST"); 58 | log.info("post方式:"+pmessage); 59 | JsonObject obj = GsonUtil.getJsonObject(pmessage); 60 | String status = obj.get("status").getAsString(); 61 | if(status.equals("0")) { 62 | JsonArray result = obj.get("result").getAsJsonArray(); 63 | StringBuilder str = new StringBuilder(); 64 | for(int i=0; i 12 | * 0x7d01 <====> 0x7d 13 | * 0x7d02 <====> 0x7e 14 | * 15 | * 16 | * @author hylexus 17 | * 18 | */ 19 | public class JT808ProtocolUtils { 20 | private final Logger log = LoggerFactory.getLogger(getClass()); 21 | private BitOperator bitOperator; 22 | private BCD8421Operater bcd8421Operater; 23 | 24 | public JT808ProtocolUtils() { 25 | this.bitOperator = new BitOperator(); 26 | this.bcd8421Operater = new BCD8421Operater(); 27 | } 28 | 29 | /** 30 | * 接收消息时转义
31 | * 32 | *
 33 | 	 * 0x7d01 <====> 0x7d
 34 | 	 * 0x7d02 <====> 0x7e
 35 | 	 * 
36 | * 37 | * @param bs 38 | * 要转义的字节数组 39 | * @param start 40 | * 起始索引 41 | * @param end 42 | * 结束索引 43 | * @return 转义后的字节数组 44 | * @throws Exception 45 | */ 46 | public byte[] doEscape4Receive(byte[] bs, int start, int end) throws Exception { 47 | if (start < 0 || end > bs.length) 48 | throw new ArrayIndexOutOfBoundsException("doEscape4Receive error : index out of bounds(start=" + start 49 | + ",end=" + end + ",bytes length=" + bs.length + ")"); 50 | ByteArrayOutputStream baos = null; 51 | try { 52 | baos = new ByteArrayOutputStream(); 53 | for (int i = 0; i < start; i++) { 54 | baos.write(bs[i]); 55 | } 56 | for (int i = start; i < end - 1; i++) { 57 | if (bs[i] == 0x7d && bs[i + 1] == 0x01) { 58 | baos.write(0x7d); 59 | i++; 60 | } else if (bs[i] == 0x7d && bs[i + 1] == 0x02) { 61 | baos.write(0x7e); 62 | i++; 63 | } else { 64 | baos.write(bs[i]); 65 | } 66 | } 67 | for (int i = end - 1; i < bs.length; i++) { 68 | baos.write(bs[i]); 69 | } 70 | return baos.toByteArray(); 71 | } catch (Exception e) { 72 | throw e; 73 | } finally { 74 | if (baos != null) { 75 | baos.close(); 76 | baos = null; 77 | } 78 | } 79 | } 80 | 81 | /** 82 | * 83 | * 发送消息时转义
84 | * 85 | *
 86 | 	 *  0x7e <====> 0x7d02
 87 | 	 * 
88 | * 89 | * @param bs 90 | * 要转义的字节数组 91 | * @param start 92 | * 起始索引 93 | * @param end 94 | * 结束索引 95 | * @return 转义后的字节数组 96 | * @throws Exception 97 | */ 98 | public byte[] doEscape4Send(byte[] bs, int start, int end) throws Exception { 99 | if (start < 0 || end > bs.length) 100 | throw new ArrayIndexOutOfBoundsException("doEscape4Send error : index out of bounds(start=" + start 101 | + ",end=" + end + ",bytes length=" + bs.length + ")"); 102 | ByteArrayOutputStream baos = null; 103 | try { 104 | baos = new ByteArrayOutputStream(); 105 | for (int i = 0; i < start; i++) { 106 | baos.write(bs[i]); 107 | } 108 | for (int i = start; i < end; i++) { 109 | if (bs[i] == 0x7e) { 110 | baos.write(0x7d); 111 | baos.write(0x02); 112 | } else { 113 | baos.write(bs[i]); 114 | } 115 | } 116 | for (int i = end; i < bs.length; i++) { 117 | baos.write(bs[i]); 118 | } 119 | return baos.toByteArray(); 120 | } catch (Exception e) { 121 | throw e; 122 | } finally { 123 | if (baos != null) { 124 | baos.close(); 125 | baos = null; 126 | } 127 | } 128 | } 129 | 130 | public int generateMsgBodyProps(int msgLen, int enctyptionType, boolean isSubPackage, int reversed_14_15) { 131 | // [ 0-9 ] 0000,0011,1111,1111(3FF)(消息体长度) 132 | // [10-12] 0001,1100,0000,0000(1C00)(加密类型) 133 | // [ 13_ ] 0010,0000,0000,0000(2000)(是否有子包) 134 | // [14-15] 1100,0000,0000,0000(C000)(保留位) 135 | //modify by cheryl 1024-> 4096 136 | if (msgLen >= 4096) 137 | log.warn("The max value of msgLen is 4095, but {} .", msgLen); 138 | int subPkg = isSubPackage ? 1 : 0; 139 | int ret = (msgLen & 0x3FF) | ((enctyptionType << 10) & 0x1C00) | ((subPkg << 13) & 0x2000) 140 | | ((reversed_14_15 << 14) & 0xC000); 141 | return ret & 0xffff; 142 | } 143 | 144 | public byte[] generateMsgHeader(String phone, int msgType, byte[] body, int msgBodyProps, int flowId) 145 | throws Exception { 146 | ByteArrayOutputStream baos = null; 147 | try { 148 | baos = new ByteArrayOutputStream(); 149 | // 1. 消息ID word(16) 150 | baos.write(bitOperator.integerTo2Bytes(msgType)); 151 | // 2. 消息体属性 word(16) 152 | baos.write(bitOperator.integerTo2Bytes(msgBodyProps)); 153 | // 3. 终端手机号 bcd[6] 154 | baos.write(bcd8421Operater.string2Bcd(phone)); 155 | // 4. 消息流水号 word(16),按发送顺序从 0 开始循环累加 156 | baos.write(bitOperator.integerTo2Bytes(flowId)); 157 | // 消息包封装项 此处不予考虑 158 | return baos.toByteArray(); 159 | } finally { 160 | if (baos != null) { 161 | baos.close(); 162 | } 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/server/TCPServer.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.server; 2 | 3 | import java.io.*; 4 | import java.net.*; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import cn.hylexus.jt808.common.TPMSConsts; 11 | import cn.hylexus.jt808.service.handler.TCPServerHandler; 12 | import cn.hylexus.jt808.socket.SocketThread; 13 | import cn.hylexus.jt808.util.ReadConfUtil; 14 | import io.netty.bootstrap.ServerBootstrap; 15 | import io.netty.buffer.Unpooled; 16 | import io.netty.channel.ChannelFuture; 17 | import io.netty.channel.ChannelInitializer; 18 | import io.netty.channel.ChannelOption; 19 | import io.netty.channel.EventLoopGroup; 20 | import io.netty.channel.nio.NioEventLoopGroup; 21 | import io.netty.channel.socket.SocketChannel; 22 | import io.netty.channel.socket.nio.NioServerSocketChannel; 23 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 24 | import io.netty.handler.timeout.IdleStateHandler; 25 | import io.netty.util.concurrent.Future; 26 | 27 | public class TCPServer { 28 | 29 | private Logger log = LoggerFactory.getLogger(getClass()); 30 | private volatile boolean isRunning = false; 31 | 32 | private EventLoopGroup bossGroup = null; 33 | private EventLoopGroup workerGroup = null; 34 | private int port; 35 | 36 | public TCPServer() { 37 | } 38 | 39 | public TCPServer(int port) { 40 | this(); 41 | this.port = port; 42 | } 43 | 44 | private void bind() throws Exception { 45 | this.bossGroup = new NioEventLoopGroup(); 46 | this.workerGroup = new NioEventLoopGroup(); 47 | ServerBootstrap serverBootstrap = new ServerBootstrap(); 48 | serverBootstrap.group(bossGroup, workerGroup)// 49 | .channel(NioServerSocketChannel.class) // 50 | .childHandler(new ChannelInitializer() { // 51 | @Override 52 | public void initChannel(SocketChannel ch) throws Exception { 53 | ch.pipeline().addLast("idleStateHandler", 54 | new IdleStateHandler(TPMSConsts.tcp_client_idle_minutes, 0, 0, TimeUnit.HOURS)); 55 | // ch.pipeline().addLast(new Decoder4LoggingOnly()); 56 | // 4096表示单条消息的最大长度,解码器在查找分隔符的时候,达到该长度还没找到的话会抛异常 57 | //TEST 分割符 58 | // ByteBuf s1 = Unpooled.copiedBuffer("@".getBytes()); 59 | // ByteBuf s2 = Unpooled.copiedBuffer("BB".getBytes()); 60 | // ch.pipeline().addLast( 61 | // new DelimiterBasedFrameDecoder(1024,s1, 62 | // s2)); 63 | 64 | ch.pipeline().addLast( 65 | // modify by cheryl 1024-->4096 66 | new DelimiterBasedFrameDecoder(4096, Unpooled.copiedBuffer(new byte[] { 0x7e,0x7e }), 67 | Unpooled.copiedBuffer(new byte[] { 0x7e,0x7e }))); 68 | //new byte[] { 0x7e, 0x7e } 69 | // ch.pipeline().addLast(new PackageDataDecoder()); 70 | ch.pipeline().addLast(new TCPServerHandler()); 71 | } 72 | }).option(ChannelOption.SO_BACKLOG, 0) // 73 | .childOption(ChannelOption.SO_KEEPALIVE, true); 74 | 75 | this.log.info("TCP服务启动完毕,port={}", this.port); 76 | ChannelFuture channelFuture = serverBootstrap.bind(port).sync(); 77 | 78 | channelFuture.channel().closeFuture().sync(); 79 | } 80 | 81 | public synchronized void startServer() { 82 | if (this.isRunning) { 83 | throw new IllegalStateException(this.getName() + " is already started ."); 84 | } 85 | this.isRunning = true; 86 | 87 | new Thread(() -> { 88 | try { 89 | this.bind(); 90 | } catch (Exception e) { 91 | this.log.info("TCP服务启动出错:{}", e.getMessage()); 92 | e.printStackTrace(); 93 | } 94 | }, this.getName()).start(); 95 | } 96 | 97 | public synchronized void stopServer() { 98 | if (!this.isRunning) { 99 | throw new IllegalStateException(this.getName() + " is not yet started ."); 100 | } 101 | this.isRunning = false; 102 | 103 | try { 104 | Future future = this.workerGroup.shutdownGracefully().await(); 105 | if (!future.isSuccess()) { 106 | log.error("workerGroup 无法正常停止:{}", future.cause()); 107 | } 108 | 109 | future = this.bossGroup.shutdownGracefully().await(); 110 | if (!future.isSuccess()) { 111 | log.error("bossGroup 无法正常停止:{}", future.cause()); 112 | } 113 | } catch (InterruptedException e) { 114 | 115 | e.printStackTrace(); 116 | } 117 | 118 | this.log.info("TCP服务已经停止..."); 119 | } 120 | 121 | private String getName() { 122 | return "TCP-Server"; 123 | } 124 | 125 | public static void main(String[] args) throws Exception { 126 | int port = ReadConfUtil.getGpsPort(); 127 | System.out.println("通讯服务器的端口是:"+port); 128 | TCPServer server = new TCPServer(port); 129 | server.startServer(); 130 | //创建与DPlatform-GPS的socket 131 | createSocketLisener(); 132 | // Thread.sleep(3000); 133 | // server.stopServer(); 134 | } 135 | 136 | private static void createSocketLisener() throws Exception { 137 | //新建线程类 138 | SocketThread socketThread=new SocketThread(null); 139 | //启动线程 140 | socketThread.start(); 141 | // } 142 | } 143 | 144 | } -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/vo/req/TerminalParametersSettingInfo.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.vo.req; 2 | 3 | import java.util.List; 4 | /** 5 | * 设置终端参数 6 | * @author cheryl 7 | */ 8 | public class TerminalParametersSettingInfo { 9 | // 参数项总数 10 | protected int count; 11 | //附加消息列表 12 | protected List terminalParamItemList; 13 | //附加消息中具体内容的值 14 | //终端⼼跳发送间隔,单位为(s) 15 | protected int heartbeatInterval; 16 | // 位置汇报策略,0:定时汇报;1:定距汇报;2:定时和定距汇报 17 | protected int locationReportingStrategy; 18 | //主服务器地址,IP或域名 19 | protected String serverAddress; 20 | //服务器TCP端口 21 | protected int serverPort; 22 | //休眠时汇报时间间隔,单位为秒(s),>0 23 | protected int sleepTimeReportInteval; 24 | //缺省时间汇报间隔,单位为秒(s),>0 25 | protected int defaultTimeReportInteval; 26 | //最高速度,单位为千⽶每⼩时(km/h) 27 | protected int maxSpeed; 28 | //超速持续时间,单位为秒(s) 29 | protected int overspeedDuration; 30 | //车辆⾥程表读数,1/10km 31 | protected int mileage; 32 | //车辆所在的省域ID,1~255 33 | protected int provinceId; 34 | //车辆所在的市域ID,1~255 35 | protected int cityId; 36 | //公安交通同管理部门颁发的机动车号牌 37 | protected String licensePlate; 38 | //车牌颜色,按照JT/T415—2006中5.4.12的规定 39 | protected int licensePlateColor; 40 | 41 | public List getTerminalParamItemList() { 42 | return terminalParamItemList; 43 | } 44 | 45 | public void setTerminalParamItemList(List terminalParamItemList) { 46 | this.terminalParamItemList = terminalParamItemList; 47 | } 48 | 49 | public int getCount() { 50 | return count; 51 | } 52 | 53 | public void setCount(int count) { 54 | this.count = count; 55 | } 56 | 57 | public int getHeartbeatInterval() { 58 | return heartbeatInterval; 59 | } 60 | 61 | public void setHeartbeatInterval(int heartbeatInterval) { 62 | this.heartbeatInterval = heartbeatInterval; 63 | } 64 | 65 | public String getServerAddress() { 66 | return serverAddress; 67 | } 68 | 69 | public void setServerAddress(String serverAddress) { 70 | this.serverAddress = serverAddress; 71 | } 72 | 73 | public int getServerPort() { 74 | return serverPort; 75 | } 76 | 77 | public void setServerPort(int serverPort) { 78 | this.serverPort = serverPort; 79 | } 80 | 81 | public int getSleepTimeReportInteval() { 82 | return sleepTimeReportInteval; 83 | } 84 | 85 | public void setSleepTimeReportInteval(int sleepTimeReportInteval) { 86 | this.sleepTimeReportInteval = sleepTimeReportInteval; 87 | } 88 | 89 | public int getDefaultTimeReportInteval() { 90 | return defaultTimeReportInteval; 91 | } 92 | 93 | public void setDefaultTimeReportInteval(int defaultTimeReportInteval) { 94 | this.defaultTimeReportInteval = defaultTimeReportInteval; 95 | } 96 | 97 | public int getMaxSpeed() { 98 | return maxSpeed; 99 | } 100 | 101 | public void setMaxSpeed(int maxSpeed) { 102 | this.maxSpeed = maxSpeed; 103 | } 104 | 105 | public int getOverspeedDuration() { 106 | return overspeedDuration; 107 | } 108 | 109 | public void setOverspeedDuration(int overspeedDuration) { 110 | this.overspeedDuration = overspeedDuration; 111 | } 112 | 113 | public int getMileage() { 114 | return mileage; 115 | } 116 | 117 | public void setMileage(int mileage) { 118 | this.mileage = mileage; 119 | } 120 | 121 | public int getProvinceId() { 122 | return provinceId; 123 | } 124 | 125 | public void setProvinceId(int provinceId) { 126 | this.provinceId = provinceId; 127 | } 128 | 129 | public int getCityId() { 130 | return cityId; 131 | } 132 | 133 | public void setCityId(int cityId) { 134 | this.cityId = cityId; 135 | } 136 | 137 | public String getLicensePlate() { 138 | return licensePlate; 139 | } 140 | 141 | public void setLicensePlate(String licensePlate) { 142 | this.licensePlate = licensePlate; 143 | } 144 | 145 | public int getLicensePlateColor() { 146 | return licensePlateColor; 147 | } 148 | 149 | public void setLicensePlateColor(int licensePlateColor) { 150 | this.licensePlateColor = licensePlateColor; 151 | } 152 | 153 | 154 | public int getLocationReportingStrategy() { 155 | return locationReportingStrategy; 156 | } 157 | 158 | public void setLocationReportingStrategy(int locationReportingStrategy) { 159 | this.locationReportingStrategy = locationReportingStrategy; 160 | } 161 | 162 | @Override 163 | public String toString() { 164 | return "TerminalParametersSettingInfo [count=" + count + ", terminalParamItemList=" + terminalParamItemList 165 | + ", heartbeatInterval=" + heartbeatInterval + ", locationReportingStrategy=" 166 | + locationReportingStrategy + ", serverAddress=" + serverAddress + ", serverPort=" + serverPort 167 | + ", sleepTimeReportInteval=" + sleepTimeReportInteval + ", defaultTimeReportInteval=" 168 | + defaultTimeReportInteval + ", maxSpeed=" + maxSpeed + ", overspeedDuration=" + overspeedDuration 169 | + ", mileage=" + mileage + ", provinceId=" + provinceId + ", cityId=" + cityId + ", licensePlate=" 170 | + licensePlate + ", licensePlateColor=" + licensePlateColor + "]"; 171 | } 172 | 173 | 174 | 175 | } 176 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/socket/PojoToMessage.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.socket; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.rksp.util.StringUtil; 7 | import com.sharetime.gps.pojo.Gps区域; 8 | import com.sharetime.gps.pojo.Gps终端设备; 9 | import com.sharetime.gps.vo.TerminalParamSettingVo; 10 | 11 | import cn.hylexus.jt808.common.TPMSParamterConsts; 12 | import cn.hylexus.jt808.util.BitOperator; 13 | import cn.hylexus.jt808.vo.req.PolygonParamItem; 14 | import cn.hylexus.jt808.vo.req.PolygonSettingArea; 15 | import cn.hylexus.jt808.vo.req.TerminalParamItem; 16 | import cn.hylexus.jt808.vo.req.TerminalParametersSettingInfo; 17 | 18 | public class PojoToMessage { 19 | 20 | private BitOperator bitOperator; 21 | public PojoToMessage() { 22 | bitOperator = new BitOperator(); 23 | } 24 | 25 | 26 | /** 27 | * TerminalParamSettingVo --->转换为对应的TerminalParametersSettingInfo 28 | */ 29 | public TerminalParametersSettingInfo changeToerminalParametersSettigInfo(TerminalParamSettingVo pojo) { 30 | TerminalParametersSettingInfo msg = new TerminalParametersSettingInfo(); 31 | List paramItems = new ArrayList(); 32 | if(!StringUtil.isEmpty(pojo.getHeartbeatInterval())) { 33 | changeintToByte4(pojo.getHeartbeatInterval(), TPMSParamterConsts.heartbeatInterval, paramItems); 34 | } 35 | if(!StringUtil.isEmpty(pojo.getServerAddress())) { 36 | changeStringToBytes(pojo.getServerAddress(),TPMSParamterConsts.serverAddress, paramItems); 37 | } 38 | if(!StringUtil.isEmpty(pojo.getServerPort())) { 39 | changeintToByte4(pojo.getServerPort(), TPMSParamterConsts.serverPort,paramItems); 40 | } 41 | if(!StringUtil.isEmpty(pojo.getSleepTimeReportInteval())) { 42 | changeintToByte4(pojo.getSleepTimeReportInteval(),TPMSParamterConsts.sleepTimeReportInteval, paramItems); 43 | } 44 | if(!StringUtil.isEmpty(pojo.getDefaultTimeReportInteval())) { 45 | changeintToByte4(pojo.getDefaultTimeReportInteval(), TPMSParamterConsts.defaultTimeReportInteval,paramItems); 46 | } 47 | if(!StringUtil.isEmpty(pojo.getMaxSpeed())) { 48 | changeintToByte4(pojo.getMaxSpeed(), TPMSParamterConsts.maxspeed,paramItems); 49 | } 50 | if(!StringUtil.isEmpty(pojo.getOverspeedDuration())) { 51 | changeintToByte4(pojo.getOverspeedDuration(), TPMSParamterConsts.overspeedDuration,paramItems); 52 | } 53 | if(pojo.getProvinceId() != null) { 54 | changeintToByte4(pojo.getProvinceId(), TPMSParamterConsts.provinceId,paramItems); 55 | } 56 | if(pojo.getCityId() != null) { 57 | changeintToByte4(pojo.getCityId(), TPMSParamterConsts.provinceId,paramItems); 58 | } 59 | if(pojo.getLicensePlateColor() != null) { 60 | changeintToByte1(pojo.getLicensePlateColor(), TPMSParamterConsts.licensePlateColor,paramItems); 61 | } 62 | if(!StringUtil.isEmpty(pojo.getLicensePlate())) { 63 | changeStringToBytes(pojo.getLicensePlate(), TPMSParamterConsts.licensePlate,paramItems); 64 | } 65 | msg.setTerminalParamItemList(paramItems); 66 | msg.setCount(paramItems.size()); 67 | return msg; 68 | } 69 | 70 | 71 | /** 72 | * Gps区域 --->转换为对应的PolygonSettingArea 73 | */ 74 | public PolygonSettingArea changeToPolygonAreaSettigInfo(Gps区域 pojo) { 75 | PolygonSettingArea msg = new PolygonSettingArea(); 76 | List paramItems = new ArrayList(); 77 | byte[] bytes = null; 78 | if(!StringUtil.isEmpty(pojo.get区域名称())) { 79 | } 80 | if(!StringUtil.isEmpty(pojo.get区域编码())) { 81 | } 82 | if(!StringUtil.isEmpty(pojo.get单位名称())) { 83 | } 84 | if(!StringUtil.isEmpty(pojo.get颜色标识())) { 85 | } 86 | if(!StringUtil.isEmpty(pojo.get录入人())) { 87 | } 88 | 89 | msg.setPolygonParamItemList(paramItems); 90 | msg.setCount(paramItems.size()); 91 | return msg; 92 | } 93 | 94 | private void changeintToByte4(int param, int msgId, List paramItems) { 95 | TerminalParamItem paramItem = new TerminalParamItem(); 96 | paramItem.setMsgId(msgId); 97 | byte[] bytes = this.bitOperator.integerTo4Bytes(param); 98 | paramItem.setParamValue(bytes); 99 | paramItem.setParamLength(bytes.length); 100 | paramItems.add(paramItem); 101 | } 102 | 103 | private void changeintToByte1(int param, int msgId, List paramItems) { 104 | TerminalParamItem paramItem = new TerminalParamItem(); 105 | paramItem.setMsgId(msgId); 106 | byte[] bytes = this.bitOperator.integerTo1Bytes(param); 107 | paramItem.setParamValue(bytes); 108 | paramItem.setParamLength(bytes.length); 109 | paramItems.add(paramItem); 110 | } 111 | 112 | private void changeintToByte4(String param, int msgId, List paramItems) { 113 | TerminalParamItem paramItem = new TerminalParamItem(); 114 | paramItem.setMsgId(msgId); 115 | byte[] bytes = this.bitOperator.integerTo4Bytes(Integer.parseInt(param)); 116 | paramItem.setParamValue(bytes); 117 | paramItem.setParamLength(bytes.length); 118 | paramItems.add(paramItem); 119 | } 120 | 121 | private void changeStringToBytes(String param, int msgId,List paramItems) { 122 | TerminalParamItem paramItem = new TerminalParamItem(); 123 | paramItem.setMsgId(msgId); 124 | byte[] bytes = param.getBytes(); 125 | paramItem.setParamValue(bytes); 126 | paramItem.setParamLength(bytes.length); 127 | paramItems.add(paramItem); 128 | } 129 | 130 | 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/vo/PackageData.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.vo; 2 | 3 | import java.util.Arrays; 4 | 5 | import com.alibaba.fastjson.annotation.JSONField; 6 | 7 | import io.netty.channel.Channel; 8 | 9 | public class PackageData { 10 | 11 | /** 12 | * 16byte 消息头 13 | */ 14 | protected MsgHeader msgHeader; 15 | 16 | // 消息体字节数组 17 | @JSONField(serialize=false) 18 | protected byte[] msgBodyBytes; 19 | 20 | /** 21 | * 校验码 1byte 22 | */ 23 | protected int checkSum; 24 | 25 | @JSONField(serialize=false) 26 | protected Channel channel; 27 | 28 | public MsgHeader getMsgHeader() { 29 | return msgHeader; 30 | } 31 | 32 | public void setMsgHeader(MsgHeader msgHeader) { 33 | this.msgHeader = msgHeader; 34 | } 35 | 36 | public byte[] getMsgBodyBytes() { 37 | return msgBodyBytes; 38 | } 39 | 40 | public void setMsgBodyBytes(byte[] msgBodyBytes) { 41 | this.msgBodyBytes = msgBodyBytes; 42 | } 43 | 44 | public int getCheckSum() { 45 | return checkSum; 46 | } 47 | 48 | public void setCheckSum(int checkSum) { 49 | this.checkSum = checkSum; 50 | } 51 | 52 | public Channel getChannel() { 53 | return channel; 54 | } 55 | 56 | public void setChannel(Channel channel) { 57 | this.channel = channel; 58 | } 59 | 60 | @Override 61 | public String toString() { 62 | return "PackageData [msgHeader=" + msgHeader + ", msgBodyBytes=" + Arrays.toString(msgBodyBytes) + ", checkSum=" 63 | + checkSum + ", address=" + channel + "]"; 64 | } 65 | 66 | public static class MsgHeader { 67 | // 消息ID 68 | protected int msgId; 69 | 70 | /////// ========消息体属性 71 | // byte[2-3] 72 | protected int msgBodyPropsField; 73 | // 消息体长度 74 | protected int msgBodyLength; 75 | // 数据加密方式 76 | protected int encryptionType; 77 | // 是否分包,true==>有消息包封装项 78 | protected boolean hasSubPackage; 79 | // 保留位[14-15] 80 | protected String reservedBit; 81 | /////// ========消息体属性 82 | 83 | // 终端手机号 84 | protected String terminalPhone; 85 | // 流水号 86 | protected int flowId; 87 | 88 | //////// =====消息包封装项 89 | // byte[12-15] 90 | protected int packageInfoField; 91 | // 消息包总数(word(16)) 92 | protected long totalSubPackage; 93 | // 包序号(word(16))这次发送的这个消息包是分包中的第几个消息包, 从 1 开始 94 | protected long subPackageSeq; 95 | //////// =====消息包封装项 96 | 97 | public int getMsgId() { 98 | return msgId; 99 | } 100 | 101 | public void setMsgId(int msgId) { 102 | this.msgId = msgId; 103 | } 104 | 105 | public int getMsgBodyLength() { 106 | return msgBodyLength; 107 | } 108 | 109 | public void setMsgBodyLength(int msgBodyLength) { 110 | this.msgBodyLength = msgBodyLength; 111 | } 112 | 113 | public int getEncryptionType() { 114 | return encryptionType; 115 | } 116 | 117 | public void setEncryptionType(int encryptionType) { 118 | this.encryptionType = encryptionType; 119 | } 120 | 121 | public String getTerminalPhone() { 122 | return terminalPhone; 123 | } 124 | 125 | public void setTerminalPhone(String terminalPhone) { 126 | this.terminalPhone = terminalPhone; 127 | } 128 | 129 | public int getFlowId() { 130 | return flowId; 131 | } 132 | 133 | public void setFlowId(int flowId) { 134 | this.flowId = flowId; 135 | } 136 | 137 | public boolean isHasSubPackage() { 138 | return hasSubPackage; 139 | } 140 | 141 | public void setHasSubPackage(boolean hasSubPackage) { 142 | this.hasSubPackage = hasSubPackage; 143 | } 144 | 145 | public String getReservedBit() { 146 | return reservedBit; 147 | } 148 | 149 | public void setReservedBit(String reservedBit) { 150 | this.reservedBit = reservedBit; 151 | } 152 | 153 | public long getTotalSubPackage() { 154 | return totalSubPackage; 155 | } 156 | 157 | public void setTotalSubPackage(long totalPackage) { 158 | this.totalSubPackage = totalPackage; 159 | } 160 | 161 | public long getSubPackageSeq() { 162 | return subPackageSeq; 163 | } 164 | 165 | public void setSubPackageSeq(long packageSeq) { 166 | this.subPackageSeq = packageSeq; 167 | } 168 | 169 | public int getMsgBodyPropsField() { 170 | return msgBodyPropsField; 171 | } 172 | 173 | public void setMsgBodyPropsField(int msgBodyPropsField) { 174 | this.msgBodyPropsField = msgBodyPropsField; 175 | } 176 | 177 | public void setPackageInfoField(int packageInfoField) { 178 | this.packageInfoField = packageInfoField; 179 | } 180 | 181 | public int getPackageInfoField() { 182 | return packageInfoField; 183 | } 184 | 185 | @Override 186 | public String toString() { 187 | return "MsgHeader [msgId=" + msgId + ", msgBodyPropsField=" + msgBodyPropsField + ", msgBodyLength=" 188 | + msgBodyLength + ", encryptionType=" + encryptionType + ", hasSubPackage=" + hasSubPackage 189 | + ", reservedBit=" + reservedBit + ", terminalPhone=" + terminalPhone + ", flowId=" + flowId 190 | + ", packageInfoField=" + packageInfoField + ", totalSubPackage=" + totalSubPackage 191 | + ", subPackageSeq=" + subPackageSeq + "]"; 192 | } 193 | 194 | } 195 | 196 | public static void main(String[] args) { 197 | PackageData p = new PackageData(); 198 | p.setMsgBodyBytes("000c".getBytes()); 199 | 200 | MsgHeader mh = new MsgHeader(); 201 | mh.msgId = 0100; 202 | p.setMsgHeader(mh); 203 | // mh.subPackageSeq = 013024429050; 204 | System.out.println(p.toString()); 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /src/main/test/MainTest.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.DataInputStream; 3 | import java.io.DataOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | import java.io.OutputStreamWriter; 7 | import java.io.PrintWriter; 8 | import java.io.UnsupportedEncodingException; 9 | import java.net.Socket; 10 | import java.net.UnknownHostException; 11 | import java.util.Arrays; 12 | import java.util.Calendar; 13 | import java.util.Date; 14 | import java.util.Timer; 15 | import java.util.TimerTask; 16 | 17 | import org.apache.axis2.AxisFault; 18 | import org.junit.Test; 19 | 20 | import com.rksp.util.DateUtil; 21 | import com.sharetime.gps.pojo.Gps指令集; 22 | 23 | import cn.hylexus.jt808.common.GpsServerConsts; 24 | import cn.hylexus.jt808.common.TPMSConsts; 25 | import cn.hylexus.jt808.util.HexStringUtils; 26 | import rk.stub.gps.GpsBaseSvc; 27 | import rk.stub.gps.GpsBaseSvcStub; 28 | 29 | public class MainTest { 30 | private String ENCODING = "utf-8"; 31 | 32 | // @Test 33 | // public void test() throws Exception { 34 | // GpsBaseSvc gpsBaseSvc = new GpsBaseSvcStub(GpsServerConsts.gps_server_base); 35 | // Gps指令集 directive = new Gps指令集(); 36 | // directive.setSim卡号("19855241"); 37 | // directive.set发送时间(DateUtil.date2String(new Date(), "yyyy-MM-dd HH:mm:ss")); 38 | // directive.set消息id(TPMSConsts.cmd_terminal_param_settings); 39 | // directive.set消息流水号(1); 40 | // directive.set状态("成功"); 41 | // gpsBaseSvc.createTheDirective(directive); 42 | // } 43 | 44 | @Test 45 | public void test1() { 46 | String message = "7E000200000145307999700102E57E"; 47 | byte[] bytes = HexStringUtils.hexString2Bytes(message).getBytes(); 48 | System.out.println(HexStringUtils.toHexString(bytes)); 49 | } 50 | 51 | @Test 52 | public void test() { 53 | String message = "7E000200000145307999700102E57E"; 54 | // String message = "7E0200003A014530799970010B000000000000000302405FB006B5CF08000001F400AC1711231654390104000000EDEB16000C00B2898602B716177019129900060089FFFFFFFF767E"; 55 | byte[] bytes = HexStringUtils.hexStringToByte(message); 56 | System.out.println(HexStringUtils.toHexString(bytes)); 57 | try { 58 | // Socket socket = new Socket("218.26.8.116", 76); 59 | Socket socket = new Socket("127.0.0.1", 8080); 60 | // 创建IO 61 | DataOutputStream out = new DataOutputStream(socket.getOutputStream()); 62 | DataInputStream in = new DataInputStream(socket.getInputStream()); 63 | // 向服务器端发送一条消息 64 | for (int i = 0; i < 1; i++) { 65 | out.write(bytes, 0, bytes.length); // 向输出流写入 bytes 66 | out.flush(); 67 | } 68 | System.out.println(socket.getLocalSocketAddress() + "发送" + Arrays.toString(bytes) + "完毕!"); 69 | // 获取服务端的返回信息 70 | byte[] b =new byte[1024];//定义字节为2 71 | byte[] c; 72 | int i=0; 73 | while(true) { 74 | b[i] = in.readByte(); //两个字节,遍历两次,写入b 75 | if(b[i] == 126 && i>0) { 76 | c = new byte[i+1]; 77 | System.arraycopy(b, 0, c, 0, i+1); 78 | break; 79 | } 80 | i++; 81 | } 82 | System.out.println(socket.getLocalSocketAddress()+"接受到的数据:"+HexStringUtils.toHexString(c)); 83 | out.close(); 84 | in.close(); 85 | socket.close(); 86 | } catch (UnknownHostException e) { 87 | e.printStackTrace(); 88 | } catch (IOException e) { 89 | e.printStackTrace(); 90 | } 91 | 92 | } 93 | 94 | public void testTimer() throws Exception { 95 | Calendar calendar = Calendar.getInstance(); 96 | calendar.set(Calendar.HOUR_OF_DAY, 9); 97 | calendar.set(Calendar.MINUTE, 05); 98 | calendar.set(Calendar.SECOND, 00); 99 | Date time = calendar.getTime(); 100 | 101 | // 定时器实例 102 | Timer t = null; 103 | for (int i = 0; i < 30; i++) { 104 | t = new Timer(); 105 | t.schedule(new MyTask(new Socket("218.26.12.164", 8189),i), time, 120 * 1000); // timeInterval 是一天的毫秒数,也是执行间隔 106 | // t.schedule(new MyTask(new Socket("127.0.0.1", 189),i), time, 120 * 1000); // timeInterval 是一天的毫秒数,也是执行间隔 107 | 108 | } 109 | 110 | }; 111 | 112 | static class MyTask extends java.util.TimerTask { 113 | private Socket socket; 114 | private DataOutputStream out; 115 | private DataInputStream in; 116 | private String message = ""; 117 | private int count; 118 | 119 | public MyTask(Socket socket,int i) throws Exception, IOException { 120 | this.socket = socket; 121 | // 创建IO 122 | this.out = new DataOutputStream(socket.getOutputStream()); 123 | this.in = new DataInputStream(socket.getInputStream()); 124 | this.count = i; 125 | } 126 | 127 | public void run() { 128 | // String message = "7E000200000145307999700102E57E"; 129 | String message = "7E0200003A014530799970010B000000000000000302405FB006B5CF08000001F400AC1711231654390104000000EDEB16000C00B2898602B716177019129900060089FFFFFFFF767E"; 130 | // String message = "7E0200003A01453079997000FA000000000000000102407B9C06B56D98000000000000170929141121010400000000EB16000C00B2898602B716177019129900060089FFFFFFFF477E"; 131 | byte[] bytes = HexStringUtils.hexStringToByte(message); 132 | System.out.println(socket.getLocalSocketAddress()); 133 | // 创建IO 134 | try { 135 | // 向服务器端发送一条消息 136 | for (int i = 0; i < 3; i++) { 137 | out.write(bytes, 0, bytes.length); // 向输出流写入 bytes 138 | out.flush(); 139 | } 140 | System.out.println("定时器主要执行的代码:"+"count:"+this.count+"soclet:"+socket.getLocalSocketAddress() + "发送" + Arrays.toString(bytes) + "完毕!"+new Date().toLocaleString()); 141 | // 获取服务端的返回信息 142 | byte[] b =new byte[1024];//定义字节为2 143 | byte[] c; 144 | int i=0; 145 | while(true) { 146 | b[i] = in.readByte(); //两个字节,遍历两次,写入b 147 | if(b[i] == 126 && i>0) { 148 | c = new byte[i+1]; 149 | System.arraycopy(b, 0, c, 0, i+1); 150 | break; 151 | } 152 | i++; 153 | } 154 | System.out.println(socket.getLocalSocketAddress()+"count:"+this.count+"接受到的数据:"+HexStringUtils.toHexString(c)); 155 | // out.close(); 156 | // in.close(); 157 | // socket.close(); 158 | } catch (IOException e) { 159 | // TODO Auto-generated catch block 160 | e.printStackTrace(); 161 | } 162 | 163 | } 164 | } 165 | 166 | public static void main(String[] args) { 167 | MainTest mainTest = new MainTest(); 168 | try { 169 | mainTest.testTimer(); 170 | } catch (Exception e) { 171 | // TODO Auto-generated catch block 172 | e.printStackTrace(); 173 | } 174 | } 175 | 176 | 177 | } 178 | -------------------------------------------------------------------------------- /src/main/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 82 | 83 | 84 | 85 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | cn.hylexus 6 | jt808-tcp-netty 7 | 0.0.1-SNAPSHOT 8 | jar 9 | 10 | jt808-tcp-netty 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | yyyyMMdd 16 | 4.2.0.RELEASE 17 | 18 | 19 | 20 | 21 | 22 | alimaven 23 | aliyun maven 24 | http://maven.aliyun.com/nexus/content/groups/public/ 25 | 26 | true 27 | 28 | 29 | true 30 | 31 | 32 | 33 | 34 | 35 | alimaven 36 | aliyun maven 37 | http://maven.aliyun.com/nexus/content/groups/public/ 38 | 39 | true 40 | 41 | 42 | true 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | junit 51 | junit 52 | 4.11 53 | test 54 | 55 | 56 | 57 | 58 | 59 | com.alibaba 60 | fastjson 61 | 1.2.8 62 | 63 | 64 | 65 | 66 | log4j 67 | log4j 68 | 1.2.17 69 | 70 | 71 | org.slf4j 72 | slf4j-api 73 | 1.7.5 74 | 75 | 76 | org.slf4j 77 | slf4j-log4j12 78 | 1.7.5 79 | 80 | 81 | 82 | 83 | 84 | io.netty 85 | netty-all 86 | 4.1.6.Final 87 | 88 | 89 | 90 | 91 | 92 | rk.stub 93 | stub-gps 94 | 1.0 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | rk.util 105 | rk-util 106 | 3.1.0 107 | 108 | 109 | 110 | 111 | 112 | 113 | org.apache.axis2 114 | axis2 115 | 1.7.3 116 | pom 117 | 118 | 119 | org.apache.axis2 120 | axis2-adb 121 | 1.7.3 122 | 123 | 124 | org.apache.axis2 125 | axis2-transport-http 126 | 1.7.3 127 | 128 | 129 | org.apache.axis2 130 | axis2-transport-local 131 | 1.7.3 132 | 133 | 134 | org.apache.axis2 135 | axis2-jaxws 136 | 1.7.3 137 | 138 | 139 | org.apache.axis2 140 | axis2-jibx 141 | 1.7.3 142 | 143 | 144 | org.apache.axis2 145 | axis2-kernel 146 | 1.7.3 147 | 148 | 149 | org.apache.axis2 150 | axis2-metadata 151 | 1.7.3 152 | 153 | 154 | 155 | com.google.code.gson 156 | gson 157 | 2.3.1 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | org.apache.maven.plugins 166 | maven-compiler-plugin 167 | 3.5.1 168 | 169 | 1.8 170 | 1.8 171 | UTF-8 172 | 173 | 174 | 175 | 176 | 177 | 178 | org.apache.maven.plugins 179 | maven-dependency-plugin 180 | 181 | 182 | copy-dependencies 183 | prepare-package 184 | 185 | copy-dependencies 186 | 187 | 188 | ${project.build.directory}/lib 189 | false 190 | false 191 | true 192 | 193 | 194 | 195 | 196 | 197 | 198 | org.apache.maven.plugins 199 | maven-jar-plugin 200 | 201 | 202 | 203 | jar-with-dependencies 204 | 205 | 206 | 207 | cn.hylexus.jt808.server.TCPServer 208 | true 209 | lib/ 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/service/TerminalMsgSendService.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.service; 2 | 3 | import java.util.Date; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import com.alibaba.fastjson.JSON; 9 | import com.rksp.util.DateUtil; 10 | import com.sharetime.gps.pojo.Gps指令集; 11 | import com.sharetime.gps.vo.GpsBaseCdt; 12 | 13 | import cn.hylexus.jt808.common.GpsServerConsts; 14 | import cn.hylexus.jt808.common.TPMSConsts; 15 | import cn.hylexus.jt808.server.SessionManager; 16 | import cn.hylexus.jt808.service.codec.MsgEncoder; 17 | import cn.hylexus.jt808.util.HexStringUtils; 18 | import cn.hylexus.jt808.vo.Session; 19 | import cn.hylexus.jt808.vo.req.PolygonDelArea; 20 | import cn.hylexus.jt808.vo.req.PolygonSettingArea; 21 | import cn.hylexus.jt808.vo.req.TerminalAuthenticationMsg; 22 | import cn.hylexus.jt808.vo.req.TerminalParametersSettingInfo; 23 | import cn.hylexus.jt808.vo.resp.ServerCommonRespMsgBody; 24 | import cn.hylexus.jt808.vo.resp.TerminalRegisterMsgRespBody; 25 | import io.netty.channel.Channel; 26 | import rk.stub.gps.GpsBaseSvc; 27 | import rk.stub.gps.GpsBaseSvcStub; 28 | 29 | /** 30 | * 终端消息发送处理服务 31 | * @author cheryl 32 | * 33 | */ 34 | public class TerminalMsgSendService extends BaseMsgProcessService{ 35 | 36 | private final Logger log = LoggerFactory.getLogger(getClass()); 37 | private MsgEncoder msgEncoder; 38 | private SessionManager sessionManager; 39 | 40 | public TerminalMsgSendService() { 41 | this.msgEncoder = new MsgEncoder(); 42 | this.sessionManager = SessionManager.getInstance(); 43 | } 44 | 45 | //发送终端参数查询消息 46 | public boolean sendTerminalParamQueryMsg(String phone) throws Exception { 47 | log.info("终端参数查询:"); 48 | Session session = sessionManager.findByTerminalPhone(phone); 49 | boolean sendFlag = false; 50 | if (session != null) { 51 | Channel channel = session.getChannel(); 52 | if(channel != null) { 53 | // GpsBaseSvc gpsBaseSvc = new GpsBaseSvcStub(GpsServerConsts.gps_server_base); 54 | int flowId = super.getFlowId(channel); 55 | // directive.set发送时间(DateUtil.date2String(new Date(), "yyyy-MM-dd HH:mm:ss")); 56 | // directive.set消息流水号(flowId); 57 | byte[] bs = this.msgEncoder.encode4ParamQuery(phone, flowId); 58 | log.info("终端参数查询-消息字节数组:{}",HexStringUtils.toHexString(bs)); 59 | boolean flag = super.send2Client(channel, bs); 60 | if(flag) { 61 | log.info("消息发送成功!"); 62 | // directive.set状态("成功"); 63 | sendFlag = true; 64 | if(flag) { 65 | log.info("消息发送成功!"); 66 | sendFlag = true; 67 | }else { 68 | log.info("消息发送失败!"); 69 | } 70 | }else { 71 | log.info("消息发送失败!"); 72 | // directive.set状态("失败"); 73 | } 74 | // gpsBaseSvc.createTheDirective(directive); 75 | }else { 76 | log.info("终端的通道失去链接"); 77 | } 78 | 79 | }else { 80 | log.info("终端链接已经断开"); 81 | } 82 | return sendFlag; 83 | } 84 | 85 | /** 86 | * 终端参数设置报文 87 | * @param params 88 | * @throws Exception 89 | */ 90 | public boolean sendTerminalParamSettingMsg(String phone,TerminalParametersSettingInfo msg,Gps指令集 directive) throws Exception { 91 | log.info("开始发送终端参数设置报文:"+msg.toString()); 92 | Session session = sessionManager.findByTerminalPhone(phone); 93 | boolean sendFlag = false; 94 | if (session != null) { 95 | log.info("获取到:"+phone+"的session"); 96 | Channel channel = session.getChannel(); 97 | if(channel != null) { 98 | log.info("获取到:"+phone+"的channel"); 99 | int flowId = super.getFlowId(channel); 100 | log.info("终端参数设置消息:"+msg.toString()); 101 | byte[] bs = this.msgEncoder.encode4ParamSetting(phone,msg, flowId); 102 | GpsBaseSvc gpsBaseSvc = new GpsBaseSvcStub(GpsServerConsts.gps_server_base); 103 | directive.set发送时间(DateUtil.date2String(new Date(), "yyyy-MM-dd HH:mm:ss")); 104 | directive.set消息流水号(flowId); 105 | log.info("终端参数设置-消息字节数组:{}",HexStringUtils.toHexString(bs)); 106 | boolean flag = super.send2Client(channel, bs); 107 | if(flag) { 108 | log.info("消息发送成功!"); 109 | directive.set状态("成功"); 110 | sendFlag = true; 111 | if(flag) { 112 | log.info("消息发送成功!"); 113 | sendFlag = true; 114 | }else { 115 | log.info("消息发送失败!"); 116 | } 117 | }else { 118 | log.info("消息发送失败!"); 119 | directive.set状态("失败"); 120 | } 121 | gpsBaseSvc.createTheDirective(directive); 122 | }else { 123 | log.info("终端的通道失去链接"); 124 | } 125 | }else { 126 | log.info("终端链接已经断开"); 127 | } 128 | return sendFlag; 129 | } 130 | 131 | //发送位置信息查询 132 | public boolean sendLocationQuery(String phone) throws Exception { 133 | log.info("位置信息查询:"); 134 | boolean sendFlag = false; 135 | Session session = sessionManager.findByTerminalPhone(phone); 136 | if (session != null) { 137 | Channel channel = session.getChannel(); 138 | if(channel != null) { 139 | int flowId = super.getFlowId(channel); 140 | byte[] bs = this.msgEncoder.encode4LocationQuery(phone, flowId); 141 | // GpsBaseSvc gpsBaseSvc = new GpsBaseSvcStub(GpsServerConsts.gps_server_base); 142 | // directive.set发送时间(DateUtil.date2String(new Date(), "yyyy-MM-dd HH:mm:ss")); 143 | // directive.set消息流水号(flowId); 144 | log.info("位置信息查询-消息字节数组:{}",HexStringUtils.toHexString(bs)); 145 | boolean flag = super.send2Client(channel, bs); 146 | if(flag) { 147 | log.info("消息发送成功!"); 148 | // directive.set状态("成功"); 149 | sendFlag = true; 150 | if(flag) { 151 | log.info("消息发送成功!"); 152 | sendFlag = true; 153 | }else { 154 | log.info("消息发送失败!"); 155 | } 156 | }else { 157 | log.info("消息发送失败!"); 158 | // directive.set状态("失败"); 159 | } 160 | // gpsBaseSvc.createTheDirective(directive); 161 | }else { 162 | log.info("终端的通道失去链接"); 163 | } 164 | 165 | }else { 166 | log.info("终端链接已经断开"); 167 | } 168 | return sendFlag; 169 | } 170 | 171 | /** 172 | * 设置多边形区域 173 | * @param params 174 | * @throws Exception 175 | */ 176 | public void sendPolygonParamSettingArea(String phone,String params) throws Exception { 177 | // log.info("设置多边形区域:"); 178 | // Session session = sessionManager.findByTerminalPhone(phone); 179 | // if (session != null) { 180 | // Channel channel = session.getChannel(); 181 | // if(channel != null) { 182 | // int flowId = super.getFlowId(channel); 183 | // PolygonSettingArea msg = new PolygonSettingArea(); 184 | // byte[] bs = this.msgEncoder.encode4PolygonSettingArea(phone,msg, flowId); 185 | // log.info("设置多边形区域-消息字节数组:{}",HexStringUtils.toHexString(bs)); 186 | // super.send2Client(channel, bs); 187 | // }else { 188 | // log.info("终端的通道失去链接"); 189 | // } 190 | // }else { 191 | // log.info("终端链接已经断开"); 192 | // } 193 | } 194 | 195 | /** 196 | * 删除多边形区域 197 | * @param params 198 | * @throws Exception 199 | */ 200 | public void sendPolygonParamDelArea(String phone,String params) throws Exception { 201 | // log.info("删除多边形区域:"); 202 | // Session session = sessionManager.findByTerminalPhone(phone); 203 | // if (session != null) { 204 | // Channel channel = session.getChannel(); 205 | // if(channel != null) { 206 | // int flowId = super.getFlowId(channel); 207 | // PolygonDelArea msg = new PolygonDelArea(); 208 | // byte[] bs = this.msgEncoder.encode4PolygonDelArea(phone,msg, flowId); 209 | // log.info("删除多边形区域-消息字节数组:{}",HexStringUtils.toHexString(bs)); 210 | // super.send2Client(channel, bs); 211 | // }else { 212 | // log.info("终端的通道失去链接"); 213 | // } 214 | // }else { 215 | // log.info("终端链接已经断开"); 216 | // } 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /src/main/resources/log4j.dtd: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 59 | 60 | 62 | 63 | 66 | 67 | 68 | 69 | 70 | 71 | 74 | 78 | 79 | 80 | 83 | 84 | 85 | 88 | 89 | 90 | 91 | 92 | 93 | 96 | 97 | 98 | 99 | 100 | 103 | 104 | 105 | 109 | 110 | 111 | 112 | 113 | 117 | 118 | 119 | 120 | 124 | 125 | 126 | 127 | 128 | 129 | 134 | 135 | 136 | 137 | 138 | 143 | 144 | 145 | 146 | 148 | 149 | 150 | 152 | 153 | 154 | 157 | 158 | 159 | 160 | 164 | 165 | 166 | 169 | 170 | 171 | 174 | 175 | 176 | 180 | 181 | 182 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 203 | 204 | 205 | 206 | 208 | 209 | 210 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 230 | 231 | 232 | 233 | 234 | 238 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/service/TerminalMsgProcessService.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.service; 2 | 3 | 4 | import java.util.Arrays; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import com.alibaba.fastjson.JSON; 10 | 11 | import cn.hylexus.jt808.server.SessionManager; 12 | import cn.hylexus.jt808.service.codec.MsgEncoder; 13 | import cn.hylexus.jt808.util.BaseUtil; 14 | import cn.hylexus.jt808.util.HexStringUtils; 15 | import cn.hylexus.jt808.vo.PackageData; 16 | import cn.hylexus.jt808.vo.PackageData.MsgHeader; 17 | import cn.hylexus.jt808.vo.Session; 18 | import cn.hylexus.jt808.vo.req.LocationInformationQueryResp; 19 | import cn.hylexus.jt808.vo.req.TerminalAuthenticationMsg; 20 | import cn.hylexus.jt808.vo.req.TerminalLoctionInfoReportMsg; 21 | import cn.hylexus.jt808.vo.req.TerminalParamQueryMsgResp; 22 | import cn.hylexus.jt808.vo.req.TerminalRegisterMsg; 23 | import cn.hylexus.jt808.vo.resp.ServerCommonRespMsgBody; 24 | import cn.hylexus.jt808.vo.resp.TerminalCommonRespMsg; 25 | import cn.hylexus.jt808.vo.resp.TerminalRegisterMsgRespBody; 26 | import cn.hylexus.jt808.vo.resp.TerminalCommonRespMsg.TerminalCommonRespInfo; 27 | /** 28 | * 终端消息接受的处理服务 29 | * @author cheryl 30 | * 31 | */ 32 | public class TerminalMsgProcessService extends BaseMsgProcessService { 33 | 34 | private final Logger log = LoggerFactory.getLogger(getClass()); 35 | // private final Logger weblog = LoggerFactory.getLogger("weblog"); 36 | private MsgEncoder msgEncoder; 37 | private SessionManager sessionManager; 38 | private MsgToDPlatformGpsPojoService gpsPojoService = new MsgToDPlatformGpsPojoService(); 39 | 40 | public TerminalMsgProcessService() { 41 | this.msgEncoder = new MsgEncoder(); 42 | this.sessionManager = SessionManager.getInstance(); 43 | } 44 | /** 45 | * 处理终端注册信息 46 | * @param msg 47 | * @throws Exception 48 | */ 49 | public void processRegisterMsg(TerminalRegisterMsg msg) throws Exception { 50 | log.info("终端注册:{}", JSON.toJSONString(msg, true)); 51 | final String sessionId = Session.buildId(msg.getChannel()); 52 | Session session = sessionManager.findBySessionId(sessionId); 53 | String terminalPhone = msg.getMsgHeader().getTerminalPhone(); 54 | if (session == null) { 55 | session = Session.buildSession(msg.getChannel(), terminalPhone); 56 | } 57 | session.setAuthenticated(true); 58 | session.setTerminalPhone(terminalPhone); 59 | 60 | sessionManager.put(session.getId(), session); 61 | /** 62 | * 把终端同车辆进行绑定操作 63 | * 车辆注册成功或者之前绑定过则返回鉴权码,否则返回replyCode转成String之后的 64 | */ 65 | log.info("终端注册消息:",msg.toString()); 66 | String replyCodeStr = gpsPojoService.createTerminalDevice(msg); 67 | /** 68 | * 终端注册应答消息的拼接 69 | */ 70 | TerminalRegisterMsgRespBody respMsgBody = new TerminalRegisterMsgRespBody(); 71 | byte[] replyCodeBytes = replyCodeStr.getBytes(); 72 | // System.out.println("replyCodeStr:"+replyCodeStr+"replyCodeBytes:"+Arrays.toString(replyCodeBytes)); 73 | if(replyCodeBytes.length >1) {//只有注册成功之后才会有鉴权码 74 | respMsgBody.setReplyCode(TerminalRegisterMsgRespBody.success); 75 | respMsgBody.setReplyToken(replyCodeStr); 76 | }else { 77 | respMsgBody.setReplyCode(replyCodeBytes[0]); 78 | } 79 | respMsgBody.setReplyFlowId(msg.getMsgHeader().getFlowId()); 80 | int flowId = super.getFlowId(msg.getChannel()); 81 | log.info("终端注册应答-消息:{}", respMsgBody.toString()); 82 | byte[] bs = this.msgEncoder.encode4TerminalRegisterResp(msg, respMsgBody, flowId); 83 | //add by cheryl 84 | log.info("终端注册应答-消息字节数组:{}",HexStringUtils.toHexString(bs)); 85 | super.send2Client(msg.getChannel(), bs); 86 | } 87 | 88 | /** 89 | * 处理终端位置汇报信息 90 | * @param msg 91 | * @throws Exception 92 | */ 93 | public void processTerminalLocationInfoReportMsg(TerminalLoctionInfoReportMsg msg) throws Exception { 94 | log.info("终端位置信息:{}", JSON.toJSONString(msg, true)); 95 | final String sessionId = Session.buildId(msg.getChannel()); 96 | Session session = sessionManager.findBySessionId(sessionId); 97 | String terminalPhone = msg.getMsgHeader().getTerminalPhone(); 98 | if (session == null) { 99 | session = Session.buildSession(msg.getChannel(), terminalPhone); 100 | } 101 | session.setAuthenticated(true); 102 | session.setTerminalPhone(terminalPhone); 103 | 104 | sessionManager.put(session.getId(), session); 105 | /** 106 | * 把终端位置信息添加到数据库 107 | */ 108 | byte replyCode = gpsPojoService.creatLocus(msg); 109 | 110 | final MsgHeader reqHeader = msg.getMsgHeader(); 111 | ServerCommonRespMsgBody respMsgBody = new ServerCommonRespMsgBody(reqHeader.getFlowId(), reqHeader.getMsgId(),replyCode); 112 | int flowId = super.getFlowId(msg.getChannel()); 113 | byte[] bs = this.msgEncoder.encode4ServerCommonRespMsg(msg, respMsgBody, flowId); 114 | super.send2Client(msg.getChannel(), bs); 115 | } 116 | 117 | /** 118 | * 处理终端鉴权信息 119 | * @param msg 120 | * @throws Exception 121 | */ 122 | public void processAuthMsg(TerminalAuthenticationMsg msg) throws Exception { 123 | 124 | log.info("终端鉴权:{}", JSON.toJSONString(msg, true)); 125 | 126 | final String sessionId = Session.buildId(msg.getChannel()); 127 | Session session = sessionManager.findBySessionId(sessionId); 128 | String terminalPhone = msg.getMsgHeader().getTerminalPhone(); 129 | if (session == null) { 130 | session = Session.buildSession(msg.getChannel(), terminalPhone); 131 | } 132 | session.setAuthenticated(true); 133 | session.setTerminalPhone(terminalPhone); 134 | sessionManager.put(session.getId(), session); 135 | /** 136 | * 判断终端的鉴权码是否一致 137 | */ 138 | boolean flag = gpsPojoService.getTheReplyCodeByTerminalPhone(terminalPhone,msg.getAuthCode()); 139 | 140 | ServerCommonRespMsgBody respMsgBody = new ServerCommonRespMsgBody(); 141 | if(flag) { 142 | respMsgBody.setReplyCode(ServerCommonRespMsgBody.success); 143 | }else { 144 | respMsgBody.setReplyCode(ServerCommonRespMsgBody.failure); 145 | } 146 | respMsgBody.setReplyFlowId(msg.getMsgHeader().getFlowId()); 147 | respMsgBody.setReplyId(msg.getMsgHeader().getMsgId()); 148 | int flowId = super.getFlowId(msg.getChannel()); 149 | byte[] bs = this.msgEncoder.encode4ServerCommonRespMsg(msg, respMsgBody, flowId); 150 | log.info("平台通用应答回复的消息={}",HexStringUtils.toHexString(bs)); 151 | super.send2Client(msg.getChannel(), bs); 152 | } 153 | /** 154 | * 处理终端心跳信息 155 | * @param req 156 | * @throws Exception 157 | */ 158 | public void processTerminalHeartBeatMsg(PackageData req) throws Exception { 159 | log.info("心跳信息:{}", JSON.toJSONString(req, true)); 160 | final MsgHeader reqHeader = req.getMsgHeader(); 161 | String terminalPhone = reqHeader.getTerminalPhone(); 162 | /** 163 | * 更新终端设备的最后心跳时间 164 | */ 165 | boolean flag = gpsPojoService.changeTerminalLastHeatBeart(terminalPhone); 166 | byte replyCode = ServerCommonRespMsgBody.failure; 167 | if(flag) { 168 | replyCode = ServerCommonRespMsgBody.success; 169 | } 170 | ServerCommonRespMsgBody respMsgBody = new ServerCommonRespMsgBody(reqHeader.getFlowId(), reqHeader.getMsgId(),replyCode); 171 | int flowId = super.getFlowId(req.getChannel()); 172 | byte[] bs = this.msgEncoder.encode4ServerCommonRespMsg(req, respMsgBody, flowId); 173 | super.send2Client(req.getChannel(), bs); 174 | } 175 | 176 | /** 177 | * 处理终端注销信息 178 | * @param req 179 | * @throws Exception 180 | */ 181 | public void processTerminalLogoutMsg(PackageData req) throws Exception { 182 | log.info("终端注销:{}", JSON.toJSONString(req, true)); 183 | final MsgHeader reqHeader = req.getMsgHeader(); 184 | /** 185 | * 把终端同车辆进行解绑操作 186 | * 清空车辆中终端id以及序列号,清空终端的鉴权码信息 187 | */ 188 | boolean flag = gpsPojoService.clearReplationBetweenVehicleAndTerminal(reqHeader.getTerminalPhone()); 189 | byte replyCode = ServerCommonRespMsgBody.failure; 190 | if(flag) { 191 | replyCode = ServerCommonRespMsgBody.success; 192 | } 193 | ServerCommonRespMsgBody respMsgBody = new ServerCommonRespMsgBody(reqHeader.getFlowId(), reqHeader.getMsgId(),replyCode); 194 | int flowId = super.getFlowId(req.getChannel()); 195 | byte[] bs = this.msgEncoder.encode4ServerCommonRespMsg(req, respMsgBody, flowId); 196 | super.send2Client(req.getChannel(), bs); 197 | } 198 | 199 | /** 200 | * 处理位置信息查询应答 201 | * @param msg 202 | * @throws Exception 203 | */ 204 | public void processLocationQuery(LocationInformationQueryResp msg) throws Exception { 205 | log.info("位置信息查询应答:{}", JSON.toJSONString(msg, true)); 206 | final String sessionId = Session.buildId(msg.getChannel()); 207 | Session session = sessionManager.findBySessionId(sessionId); 208 | String terminalPhone = msg.getMsgHeader().getTerminalPhone(); 209 | if (session == null) { 210 | session = Session.buildSession(msg.getChannel(), terminalPhone); 211 | } 212 | session.setAuthenticated(true); 213 | session.setTerminalPhone(terminalPhone); 214 | 215 | sessionManager.put(session.getId(), session); 216 | /** 217 | * 创建位置汇报消息 218 | */ 219 | byte replyCode = gpsPojoService.creatLocus(msg); 220 | 221 | final MsgHeader reqHeader = msg.getMsgHeader(); 222 | ServerCommonRespMsgBody respMsgBody = new ServerCommonRespMsgBody(reqHeader.getFlowId(), reqHeader.getMsgId(),replyCode); 223 | int flowId = super.getFlowId(msg.getChannel()); 224 | byte[] bs = this.msgEncoder.encode4ServerCommonRespMsg(msg, respMsgBody, flowId); 225 | super.send2Client(msg.getChannel(), bs); 226 | } 227 | 228 | 229 | /** 230 | * 处理查询终端参数应答消息 231 | * @param msg 232 | * @throws Exception 233 | */ 234 | public void processParamQueryMsgResp(TerminalParamQueryMsgResp msg) throws Exception { 235 | log.info("查询终端参数应答:{}", JSON.toJSONString(msg, true)); 236 | final MsgHeader reqHeader = msg.getMsgHeader(); 237 | /** 238 | * 更新终端中相关的参数信息 239 | */ 240 | boolean flag = gpsPojoService.updateTerminalInfo(msg); 241 | ServerCommonRespMsgBody respMsgBody = new ServerCommonRespMsgBody(reqHeader.getFlowId(), reqHeader.getMsgId(), 242 | ServerCommonRespMsgBody.success); 243 | int flowId = super.getFlowId(msg.getChannel()); 244 | byte[] bs = this.msgEncoder.encode4ServerCommonRespMsg(msg, respMsgBody, flowId); 245 | super.send2Client(msg.getChannel(), bs); 246 | } 247 | 248 | /** 249 | * 处理终端通用应答 250 | * @param msg 251 | * @throws Exception 252 | */ 253 | public void processTerminalCommonMsg(TerminalCommonRespMsg req) throws Exception { 254 | log.info("终端通用应答:{}", JSON.toJSONString(req, true)); 255 | final MsgHeader reqHeader = req.getMsgHeader(); 256 | TerminalCommonRespInfo info = req.getTerminalCommonRespInfo(); 257 | //更新对应的实体类的内容 258 | boolean replyCode = gpsPojoService.updateGpsDirective(reqHeader.getTerminalPhone(),info); 259 | byte result = ServerCommonRespMsgBody.failure ; 260 | if(replyCode) { 261 | log.info("指令更新成功!"); 262 | result = ServerCommonRespMsgBody.success; 263 | }else { 264 | log.info("指令更新失败!"); 265 | } 266 | // ServerCommonRespMsgBody respMsgBody = new ServerCommonRespMsgBody(reqHeader.getFlowId(), reqHeader.getMsgId(),result); 267 | // int flowId = super.getFlowId(req.getChannel()); 268 | // byte[] bs = this.msgEncoder.encode4TerminalCommonRespMsg(req, respMsgBody, flowId); 269 | // super.send2Client(req.getChannel(), bs); 270 | } 271 | 272 | } 273 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/util/BitOperator.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.util; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | public class BitOperator { 10 | private final Logger logger = LoggerFactory.getLogger(getClass()); 11 | /** 12 | * 把一个整形该为byte 13 | * 14 | * @param value 15 | * @return 16 | * @throws Exception 17 | */ 18 | public byte integerTo1Byte(int value) { 19 | return (byte) (value & 0xFF); 20 | } 21 | 22 | /** 23 | * 把一个整形该为1位的byte数组 24 | * 25 | * @param value 26 | * @return 27 | * @throws Exception 28 | */ 29 | public byte[] integerTo1Bytes(int value) { 30 | byte[] result = new byte[1]; 31 | result[0] = (byte) (value & 0xFF); 32 | return result; 33 | } 34 | 35 | /** 36 | * 把一个整形改为2位的byte数组 37 | * 38 | * @param value 39 | * @return 40 | * @throws Exception 41 | */ 42 | public byte[] integerTo2Bytes(int value) { 43 | byte[] result = new byte[2]; 44 | result[0] = (byte) ((value >>> 8) & 0xFF); 45 | result[1] = (byte) (value & 0xFF); 46 | return result; 47 | } 48 | 49 | /** 50 | * 把一个整形改为3位的byte数组 51 | * 52 | * @param value 53 | * @return 54 | * @throws Exception 55 | */ 56 | public byte[] integerTo3Bytes(int value) { 57 | byte[] result = new byte[3]; 58 | result[0] = (byte) ((value >>> 16) & 0xFF); 59 | result[1] = (byte) ((value >>> 8) & 0xFF); 60 | result[2] = (byte) (value & 0xFF); 61 | return result; 62 | } 63 | 64 | /** 65 | * 把一个整形改为4位的byte数组 66 | * 67 | * @param value 68 | * @return 69 | * @throws Exception 70 | */ 71 | public byte[] integerTo4Bytes(int value){ 72 | byte[] result = new byte[4]; 73 | result[0] = (byte) ((value >>> 24) & 0xFF); 74 | result[1] = (byte) ((value >>> 16) & 0xFF); 75 | result[2] = (byte) ((value >>> 8) & 0xFF); 76 | result[3] = (byte) (value & 0xFF); 77 | return result; 78 | } 79 | 80 | /** 81 | * 把byte[]转化位整形,通常为指令用 82 | * 83 | * @param value 84 | * @return 85 | * @throws Exception 86 | */ 87 | public int byteToInteger(byte[] value) { 88 | int result; 89 | if (value.length == 1) { 90 | result = oneByteToInteger(value[0]); 91 | } else if (value.length == 2) { 92 | result = twoBytesToInteger(value); 93 | } else if (value.length == 3) { 94 | result = threeBytesToInteger(value); 95 | } else if (value.length == 4) { 96 | result = fourBytesToInteger(value); 97 | } else { 98 | result = fourBytesToInteger(value); 99 | } 100 | return result; 101 | } 102 | 103 | /** 104 | * 把一个byte转化位整形,通常为指令用 0xFF=255 105 | * 106 | * @param value 107 | * @return 108 | * @throws Exception 109 | */ 110 | public int oneByteToInteger(byte value) { 111 | return (int) value & 0xFF; 112 | } 113 | 114 | public static void main(String[] args) { 115 | BitOperator b = new BitOperator(); 116 | int i = b.oneByteToInteger((byte) 49); 117 | System.out.println(i); 118 | 119 | System.out.println(255 == 0xff); 120 | 121 | System.out.println(5 | 6); 122 | } 123 | 124 | /** 125 | * 把一个2位的数组转化位整形 126 | * 127 | * @param value 128 | * @return 129 | * @throws Exception 130 | */ 131 | public int twoBytesToInteger(byte[] value) { 132 | // if (value.length < 2) { 133 | // throw new Exception("Byte array too short!"); 134 | // } 135 | int temp0 = value[0] & 0xFF; 136 | int temp1 = value[1] & 0xFF; 137 | return ((temp0 << 8) + temp1); 138 | } 139 | 140 | /** 141 | * 把一个3位的数组转化位整形 142 | * 143 | * @param value 144 | * @return 145 | * @throws Exception 146 | */ 147 | public int threeBytesToInteger(byte[] value) { 148 | int temp0 = value[0] & 0xFF; 149 | int temp1 = value[1] & 0xFF; 150 | int temp2 = value[2] & 0xFF; 151 | return ((temp0 << 16) + (temp1 << 8) + temp2); 152 | } 153 | 154 | /** 155 | * 把一个4位的数组转化位整形,通常为指令用 156 | * 157 | * @param value 158 | * @return 159 | * @throws Exception 160 | */ 161 | public int fourBytesToInteger(byte[] value) { 162 | // if (value.length < 4) { 163 | // throw new Exception("Byte array too short!"); 164 | // } 165 | int temp0 = value[0] & 0xFF; 166 | int temp1 = value[1] & 0xFF; 167 | int temp2 = value[2] & 0xFF; 168 | int temp3 = value[3] & 0xFF; 169 | return ((temp0 << 24) + (temp1 << 16) + (temp2 << 8) + temp3); 170 | } 171 | 172 | /** 173 | * 把一个4位的数组转化位整形 174 | * 175 | * @param value 176 | * @return 177 | * @throws Exception 178 | */ 179 | public long fourBytesToLong(byte[] value) throws Exception { 180 | // if (value.length < 4) { 181 | // throw new Exception("Byte array too short!"); 182 | // } 183 | int temp0 = value[0] & 0xFF; 184 | int temp1 = value[1] & 0xFF; 185 | int temp2 = value[2] & 0xFF; 186 | int temp3 = value[3] & 0xFF; 187 | return (((long) temp0 << 24) + (temp1 << 16) + (temp2 << 8) + temp3); 188 | } 189 | 190 | /** 191 | * 把一个数组转化长整形 192 | * 193 | * @param value 194 | * @return 195 | * @throws Exception 196 | */ 197 | public long bytes2Long(byte[] value) { 198 | long result = 0; 199 | int len = value.length; 200 | int temp; 201 | for (int i = 0; i < len; i++) { 202 | temp = (len - 1 - i) * 8; 203 | if (temp == 0) { 204 | result += (value[i] & 0x0ff); 205 | } else { 206 | result += (value[i] & 0x0ff) << temp; 207 | } 208 | } 209 | return result; 210 | } 211 | 212 | /** 213 | * 把一个长整形改为byte数组 214 | * 215 | * @param value 216 | * @return 217 | * @throws Exception 218 | */ 219 | public byte[] longToBytes(long value){ 220 | return longToBytes(value, 8); 221 | } 222 | 223 | /** 224 | * 把一个长整形改为byte数组 225 | * 226 | * @param value 227 | * @return 228 | * @throws Exception 229 | */ 230 | public byte[] longToBytes(long value, int len) { 231 | byte[] result = new byte[len]; 232 | int temp; 233 | for (int i = 0; i < len; i++) { 234 | temp = (len - 1 - i) * 8; 235 | if (temp == 0) { 236 | result[i] += (value & 0x0ff); 237 | } else { 238 | result[i] += (value >>> temp) & 0x0ff; 239 | } 240 | } 241 | return result; 242 | } 243 | 244 | /** 245 | * 得到一个消息ID 246 | * 247 | * @return 248 | * @throws Exception 249 | */ 250 | public byte[] generateTransactionID() throws Exception { 251 | byte[] id = new byte[16]; 252 | System.arraycopy(integerTo2Bytes((int) (Math.random() * 65536)), 0, id, 0, 2); 253 | System.arraycopy(integerTo2Bytes((int) (Math.random() * 65536)), 0, id, 2, 2); 254 | System.arraycopy(integerTo2Bytes((int) (Math.random() * 65536)), 0, id, 4, 2); 255 | System.arraycopy(integerTo2Bytes((int) (Math.random() * 65536)), 0, id, 6, 2); 256 | System.arraycopy(integerTo2Bytes((int) (Math.random() * 65536)), 0, id, 8, 2); 257 | System.arraycopy(integerTo2Bytes((int) (Math.random() * 65536)), 0, id, 10, 2); 258 | System.arraycopy(integerTo2Bytes((int) (Math.random() * 65536)), 0, id, 12, 2); 259 | System.arraycopy(integerTo2Bytes((int) (Math.random() * 65536)), 0, id, 14, 2); 260 | return id; 261 | } 262 | 263 | /** 264 | * 把IP拆分位int数组 265 | * 266 | * @param ip 267 | * @return 268 | * @throws Exception 269 | */ 270 | public int[] getIntIPValue(String ip) throws Exception { 271 | String[] sip = ip.split("[.]"); 272 | // if (sip.length != 4) { 273 | // throw new Exception("error IPAddress"); 274 | // } 275 | int[] intIP = { Integer.parseInt(sip[0]), Integer.parseInt(sip[1]), Integer.parseInt(sip[2]), 276 | Integer.parseInt(sip[3]) }; 277 | return intIP; 278 | } 279 | 280 | /** 281 | * 把byte类型IP地址转化位字符串 282 | * 283 | * @param address 284 | * @return 285 | * @throws Exception 286 | */ 287 | public String getStringIPValue(byte[] address) throws Exception { 288 | int first = this.oneByteToInteger(address[0]); 289 | int second = this.oneByteToInteger(address[1]); 290 | int third = this.oneByteToInteger(address[2]); 291 | int fourth = this.oneByteToInteger(address[3]); 292 | 293 | return first + "." + second + "." + third + "." + fourth; 294 | } 295 | 296 | /** 297 | * 合并字节数组 298 | * 299 | * @param first 300 | * @param rest 301 | * @return 302 | */ 303 | public byte[] concatAll(byte[] first, byte[]... rest) { 304 | int totalLength = first.length; 305 | for (byte[] array : rest) { 306 | if (array != null) { 307 | totalLength += array.length; 308 | } 309 | } 310 | byte[] result = Arrays.copyOf(first, totalLength); 311 | int offset = first.length; 312 | for (byte[] array : rest) { 313 | if (array != null) { 314 | System.arraycopy(array, 0, result, offset, array.length); 315 | offset += array.length; 316 | } 317 | } 318 | return result; 319 | } 320 | 321 | /** 322 | * 合并字节数组 323 | * 324 | * @param rest 325 | * @return 326 | */ 327 | public byte[] concatAll(List rest) { 328 | int totalLength = 0; 329 | for (byte[] array : rest) { 330 | if (array != null) { 331 | totalLength += array.length; 332 | } 333 | } 334 | byte[] result = new byte[totalLength]; 335 | int offset = 0; 336 | for (byte[] array : rest) { 337 | if (array != null) { 338 | System.arraycopy(array, 0, result, offset, array.length); 339 | offset += array.length; 340 | } 341 | } 342 | return result; 343 | } 344 | 345 | public float byte2Float(byte[] bs) { 346 | return Float.intBitsToFloat( 347 | (((bs[3] & 0xFF) << 24) + ((bs[2] & 0xFF) << 16) + ((bs[1] & 0xFF) << 8) + (bs[0] & 0xFF))); 348 | } 349 | 350 | public float byteBE2Float(byte[] bytes) { 351 | int l; 352 | l = bytes[0]; 353 | l &= 0xff; 354 | l |= ((long) bytes[1] << 8); 355 | l &= 0xffff; 356 | l |= ((long) bytes[2] << 16); 357 | l &= 0xffffff; 358 | l |= ((long) bytes[3] << 24); 359 | return Float.intBitsToFloat(l); 360 | } 361 | /** 362 | * 生成校验码 363 | * @param bs 364 | * @param start 365 | * @param end 366 | * @return 367 | */ 368 | public int getCheckSum4JT808(byte[] bs, int start, int end) { 369 | // logger.info("校验码生成"); 370 | if (start < 0 || end > bs.length) 371 | throw new ArrayIndexOutOfBoundsException("getCheckSum4JT808 error : index out of bounds(start=" + start 372 | + ",end=" + end + ",bytes length=" + bs.length + ")"); 373 | int cs = 0; 374 | for (int i = start; i < end; i++) { 375 | cs ^= bs[i]; 376 | // logger.info("i={},bs[i]={}", i, bs[]); 377 | } 378 | return cs; 379 | } 380 | 381 | public int getBitRange(int number, int start, int end) { 382 | if (start < 0) 383 | throw new IndexOutOfBoundsException("min index is 0,but start = " + start); 384 | if (end >= Integer.SIZE) 385 | throw new IndexOutOfBoundsException("max index is " + (Integer.SIZE - 1) + ",but end = " + end); 386 | 387 | return (number << Integer.SIZE - (end + 1)) >>> Integer.SIZE - (end - start + 1); 388 | } 389 | 390 | public int getBitAt(int number, int index) { 391 | if (index < 0) 392 | throw new IndexOutOfBoundsException("min index is 0,but " + index); 393 | if (index >= Integer.SIZE) 394 | throw new IndexOutOfBoundsException("max index is " + (Integer.SIZE - 1) + ",but " + index); 395 | 396 | return ((1 << index) & number) >> index; 397 | } 398 | 399 | public int getBitAtS(int number, int index) { 400 | String s = Integer.toBinaryString(number); 401 | return Integer.parseInt(s.charAt(index) + ""); 402 | } 403 | 404 | @Deprecated 405 | public int getBitRangeS(int number, int start, int end) { 406 | 407 | String s = Integer.toBinaryString(number); 408 | StringBuilder sb = new StringBuilder(s); 409 | while (sb.length() < Integer.SIZE) { 410 | sb.insert(0, "0"); 411 | } 412 | String tmp = sb.reverse().substring(start, end + 1); 413 | sb = new StringBuilder(tmp); 414 | return Integer.parseInt(sb.reverse().toString(), 2); 415 | } 416 | } 417 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/service/handler/TCPServerHandler.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.service.handler; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import com.rksp.util.StringUtil; 7 | 8 | import cn.hylexus.jt808.common.TPMSConsts; 9 | import cn.hylexus.jt808.server.SessionManager; 10 | import cn.hylexus.jt808.service.MsgToDPlatformGpsPojoService; 11 | import cn.hylexus.jt808.service.TerminalMsgProcessService; 12 | import cn.hylexus.jt808.service.TerminalMsgSendService; 13 | import cn.hylexus.jt808.service.codec.MsgDecoder; 14 | import cn.hylexus.jt808.util.HexStringUtils; 15 | import cn.hylexus.jt808.vo.PackageData; 16 | import cn.hylexus.jt808.vo.PackageData.MsgHeader; 17 | import cn.hylexus.jt808.vo.Session; 18 | import cn.hylexus.jt808.vo.req.LocationInformationQueryResp; 19 | import cn.hylexus.jt808.vo.req.TerminalAuthenticationMsg; 20 | import cn.hylexus.jt808.vo.req.TerminalLoctionInfoReportMsg; 21 | import cn.hylexus.jt808.vo.req.TerminalParamQueryMsgResp; 22 | import cn.hylexus.jt808.vo.req.TerminalRegisterMsg; 23 | import cn.hylexus.jt808.vo.resp.ServerCommonRespMsgBody; 24 | import cn.hylexus.jt808.vo.resp.TerminalCommonRespMsg; 25 | import io.netty.buffer.ByteBuf; 26 | import io.netty.channel.ChannelHandlerContext; 27 | import io.netty.channel.ChannelInboundHandlerAdapter; 28 | import io.netty.handler.timeout.IdleState; 29 | import io.netty.handler.timeout.IdleStateEvent; 30 | import io.netty.util.ReferenceCountUtil; 31 | 32 | public class TCPServerHandler extends ChannelInboundHandlerAdapter { // (1) 33 | 34 | private final Logger logger = LoggerFactory.getLogger(getClass()); 35 | 36 | private final SessionManager sessionManager; 37 | private final MsgDecoder decoder; 38 | private TerminalMsgProcessService msgProcessService; 39 | private MsgToDPlatformGpsPojoService msPojoService; 40 | 41 | public TCPServerHandler() { 42 | this.sessionManager = SessionManager.getInstance(); 43 | this.decoder = new MsgDecoder(); 44 | this.msgProcessService = new TerminalMsgProcessService(); 45 | this.msPojoService = new MsgToDPlatformGpsPojoService(); 46 | } 47 | 48 | @Override 49 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws InterruptedException { // (2) 50 | try { 51 | ByteBuf buf = (ByteBuf) msg; 52 | logger.info("接收到的消息长度:{}",buf.readableBytes()); 53 | if (buf.readableBytes() <= 0) { 54 | // ReferenceCountUtil.safeRelease(msg); 55 | return; 56 | } 57 | 58 | byte[] bs = new byte[buf.readableBytes()]; 59 | 60 | buf.readBytes(bs); 61 | logger.info("读完后的数据长度:{}" , buf.readableBytes()); 62 | String receiveMsg = "7E"+HexStringUtils.toHexString(bs)+"7E"; 63 | logger.info("收到的消息包:{}",receiveMsg); 64 | // 字节数据转换为针对于808消息结构的实体类 65 | PackageData pkg = this.decoder.bytes2PackageData(bs); 66 | // 引用channel,以便回送数据给硬件 67 | pkg.setChannel(ctx.channel()); 68 | logger.info("消息体中的Channel:{}" ,pkg.getChannel()); 69 | this.processPackageData(pkg,receiveMsg); 70 | } finally { 71 | release(msg); 72 | } 73 | } 74 | 75 | /** 76 | * 77 | * 处理业务逻辑 78 | * 79 | * @param packageData 80 | * 81 | */ 82 | private void processPackageData(PackageData packageData,String receiveMsg) { 83 | final MsgHeader header = packageData.getMsgHeader(); 84 | /** 85 | * 1、终端注册 (0100)2、注册应答(8100)3、注册成功 4、鉴权信息(0102)5、鉴权信息(0102) 6、鉴权应答(8001)7、定位数据(0200)8、平台通用应答(8001) 86 | * 9、查询终端参数应答(0x0104) 10、位置信息查询应答(0x0201) 87 | */ 88 | String type = "成功"; 89 | String messageType = "未知"; 90 | // 1. 终端心跳-消息体为空 ==> 平台通用应答 91 | if (TPMSConsts.msg_id_terminal_heart_beat == header.getMsgId()) { 92 | logger.info(">>>>>[终端心跳],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId()); 93 | messageType = "终端心跳"; 94 | try { 95 | this.msgProcessService.processTerminalHeartBeatMsg(packageData); 96 | logger.info("<<<<<[终端心跳],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId()); 97 | } catch (Exception e) { 98 | type="失败"; 99 | logger.error("<<<<<[终端心跳]处理错误,phone={},flowid={},err={}", header.getTerminalPhone(), header.getFlowId(), 100 | e.getMessage()); 101 | e.printStackTrace(); 102 | } 103 | 104 | } 105 | 106 | // 5. 终端鉴权 ==> 平台通用应答 107 | else if (TPMSConsts.msg_id_terminal_authentication == header.getMsgId()) { 108 | logger.info(">>>>>[终端鉴权],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId()); 109 | messageType = "终端鉴权"; 110 | try { 111 | TerminalAuthenticationMsg authenticationMsg = new TerminalAuthenticationMsg(packageData); 112 | logger.info(">>>>>[接收到的消息],authenticationMsg={}",authenticationMsg); 113 | this.msgProcessService.processAuthMsg(authenticationMsg); 114 | logger.info("<<<<<[终端鉴权],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId()); 115 | } catch (Exception e) { 116 | logger.error("<<<<<[终端鉴权]处理错误,phone={},flowid={},err={}", header.getTerminalPhone(), header.getFlowId(), 117 | e.getMessage()); 118 | type="失败"; 119 | e.printStackTrace(); 120 | } 121 | } 122 | // 6. 终端注册 ==> 终端注册应答 123 | else if (TPMSConsts.msg_id_terminal_register == header.getMsgId()) { 124 | logger.info(">>>>>[终端注册],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId()); 125 | messageType = "终端注册"; 126 | try { 127 | 128 | TerminalRegisterMsg msg = this.decoder.toTerminalRegisterMsg(packageData); 129 | this.msgProcessService.processRegisterMsg(msg); 130 | 131 | logger.info("<<<<<[终端注册],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId()); 132 | 133 | } catch (Exception e) { 134 | logger.error("<<<<<[终端注册]处理错误,phone={},flowid={},err={}", header.getTerminalPhone(), header.getFlowId(), 135 | e.getMessage()); 136 | type="失败"; 137 | e.printStackTrace(); 138 | } 139 | } 140 | // 7. 终端注销(终端注销数据消息体为空) ==> 平台通用应答 141 | else if (TPMSConsts.msg_id_terminal_log_out == header.getMsgId()) { 142 | logger.info(">>>>>[终端注销],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId()); 143 | messageType = "终端注销"; 144 | try { 145 | this.msgProcessService.processTerminalLogoutMsg(packageData); 146 | logger.info("<<<<<[终端注销],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId()); 147 | } catch (Exception e) { 148 | logger.error("<<<<<[终端注销]处理错误,phone={},flowid={},err={}", header.getTerminalPhone(), header.getFlowId(), 149 | e.getMessage()); 150 | type="失败"; 151 | e.printStackTrace(); 152 | } 153 | } 154 | // 8.定位数据(位置信息汇报) ==> 平台通用应答 155 | else if(TPMSConsts.msg_id_terminal_location_info_upload == header.getMsgId()) { 156 | logger.info(">>>>>[终端位置信息汇报],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId()); 157 | messageType = "终端位置信息汇报"; 158 | try { 159 | TerminalLoctionInfoReportMsg msg = this.decoder.toTerminalLoctionInfoReportMsg(packageData); 160 | this.msgProcessService.processTerminalLocationInfoReportMsg(msg); 161 | logger.info("<<<<<[终端位置信息汇报处理完成]"); 162 | } catch (Exception e) { 163 | logger.error("<<<<<[终端位置信息汇报]处理错误,phone={},flowid={},err={}", header.getTerminalPhone(), header.getFlowId(), 164 | e.getMessage()); 165 | type="失败"; 166 | e.printStackTrace(); 167 | } 168 | } 169 | 170 | // 9.查询终端参数应答 ==> 平台通用应答 171 | else if(TPMSConsts.msg_id_terminal_param_query_resp == header.getMsgId()) { 172 | logger.info(">>>>>[查询终端参数应答],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId()); 173 | messageType = "查询终端参数应答"; 174 | try { 175 | TerminalParamQueryMsgResp msg = this.decoder.toTerminalParamQueryMsgResp(packageData); 176 | this.msgProcessService.processParamQueryMsgResp(msg); 177 | logger.info("<<<<<[查询终端参数应答处理完成]"); 178 | } catch (Exception e) { 179 | logger.error("<<<<<[查询终端参数应答处理错误],phone={},flowid={},err={}", header.getTerminalPhone(), header.getFlowId(), 180 | e.getMessage()); 181 | type="失败"; 182 | e.printStackTrace(); 183 | } 184 | } 185 | 186 | // 10. 位置信息查询应答 ==> 平台通用应答 187 | else if (TPMSConsts.cmd_position_query_resp == header.getMsgId()) { 188 | logger.info(">>>>>[位置信息查询应答],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId()); 189 | messageType = "位置信息查询应答"; 190 | try { 191 | LocationInformationQueryResp msg = this.decoder.toLocationInformationQueryResp(packageData); 192 | this.msgProcessService.processLocationQuery(msg); 193 | logger.info("<<<<<[位置信息查询应答处理完成]"); 194 | } catch (Exception e) { 195 | logger.error("<<<<<[位置信息查询应答]处理错误,phone={},flowid={},err={}", header.getTerminalPhone(), header.getFlowId(), 196 | e.getMessage()); 197 | type="失败"; 198 | e.printStackTrace(); 199 | } 200 | 201 | } 202 | 203 | // 11.终端通用应答 ==> 平台通用应答 204 | else if (TPMSConsts.msg_id_terminal_common_resp == header.getMsgId()) { 205 | logger.info(">>>>>[终端通用应答],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId()); 206 | messageType = "终端通用应答"; 207 | try { 208 | TerminalCommonRespMsg msg = this.decoder.toTerminalCommonRespMsg(packageData); 209 | this.msgProcessService.processTerminalCommonMsg(msg); 210 | logger.info("<<<<<[终端通用应答处理完成],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId()); 211 | } catch (Exception e) { 212 | logger.error("<<<<<[终端通用应答]处理错误,phone={},flowid={},err={}", header.getTerminalPhone(), header.getFlowId(), 213 | e.getMessage()); 214 | type="失败"; 215 | e.printStackTrace(); 216 | } 217 | } 218 | // 其他情况 219 | else { 220 | logger.error(">>>>>>[未知消息类型],phone={},msgId={},package={}", header.getTerminalPhone(), header.getMsgId(), 221 | packageData); 222 | } 223 | //把接受到的报文保存到数据库中 224 | if(!"未知".equals(messageType)) { 225 | //把接收到的保存存储到数据库中 226 | String oid = msPojoService.createTheMessage(packageData,type,messageType,receiveMsg); 227 | String info = StringUtil.isEmpty(oid)?"失败":"成功"; 228 | logger.info("<<<<<[接受到的数据包消息报文"+info+"保存到数据库中],消息包={}", packageData.toString()); 229 | 230 | }else { 231 | logger.info("接收的消息类型未知,不进行保存操作。"); 232 | } 233 | } 234 | 235 | @Override 236 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4) 237 | logger.error("发生异常:{}", cause.getMessage()); 238 | cause.printStackTrace(); 239 | } 240 | 241 | @Override 242 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 243 | Session session = Session.buildSession(ctx.channel()); 244 | sessionManager.put(session.getId(), session); 245 | logger.info("终端连接:{}", session); 246 | logger.info("当前客户端数量:{}",sessionManager.toList().size()); 247 | } 248 | 249 | @Override 250 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 251 | final String sessionId = ctx.channel().id().asLongText(); 252 | Session session = sessionManager.findBySessionId(sessionId); 253 | 254 | MsgToDPlatformGpsPojoService gpsPojoService = new MsgToDPlatformGpsPojoService(); 255 | String phone = session.getTerminalPhone(); 256 | if(!StringUtil.isEmpty(phone)) { 257 | gpsPojoService.creatTerminalFacilityDropsRecord(phone);//创建终端设备掉线记录 258 | } 259 | 260 | this.sessionManager.removeBySessionId(sessionId); 261 | logger.info("终端断开连接:{}", session); 262 | logger.info("当前客户端数量:{}",sessionManager.toList().size()); 263 | ctx.channel().close(); 264 | // ctx.close(); 265 | } 266 | 267 | @Override 268 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { 269 | if (IdleStateEvent.class.isAssignableFrom(evt.getClass())) { 270 | IdleStateEvent event = (IdleStateEvent) evt; 271 | if (event.state() == IdleState.READER_IDLE) { 272 | Session session = this.sessionManager.removeBySessionId(Session.buildId(ctx.channel())); 273 | logger.error("服务器主动断开连接:{}", session); 274 | ctx.close(); 275 | } 276 | } 277 | } 278 | 279 | private void release(Object msg) { 280 | try { 281 | ReferenceCountUtil.release(msg); 282 | } catch (Exception e) { 283 | e.printStackTrace(); 284 | } 285 | } 286 | } -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/service/codec/MsgEncoder.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.service.codec; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import cn.hylexus.jt808.common.TPMSConsts; 9 | import cn.hylexus.jt808.util.BitOperator; 10 | import cn.hylexus.jt808.util.JT808ProtocolUtils; 11 | import cn.hylexus.jt808.vo.PackageData; 12 | import cn.hylexus.jt808.vo.Session; 13 | import cn.hylexus.jt808.vo.req.LocationInformationQueryResp; 14 | import cn.hylexus.jt808.vo.req.PolygonDelArea; 15 | import cn.hylexus.jt808.vo.req.PolygonParamItem; 16 | import cn.hylexus.jt808.vo.req.PolygonSettingArea; 17 | import cn.hylexus.jt808.vo.req.TerminalParamItem; 18 | import cn.hylexus.jt808.vo.req.TerminalParametersSettingInfo; 19 | import cn.hylexus.jt808.vo.req.TerminalRegisterMsg; 20 | import cn.hylexus.jt808.vo.resp.ServerCommonRespMsgBody; 21 | import cn.hylexus.jt808.vo.resp.TerminalRegisterMsgRespBody; 22 | 23 | public class MsgEncoder { 24 | private BitOperator bitOperator; 25 | private JT808ProtocolUtils jt808ProtocolUtils; 26 | private final Logger logger = LoggerFactory.getLogger(getClass()); 27 | public MsgEncoder() { 28 | this.bitOperator = new BitOperator(); 29 | this.jt808ProtocolUtils = new JT808ProtocolUtils(); 30 | } 31 | 32 | public byte[] encode4TerminalRegisterResp(TerminalRegisterMsg req, TerminalRegisterMsgRespBody respMsgBody, 33 | int flowId) throws Exception { 34 | // 消息体字节数组 35 | // logger.info("=======对终端注册应答消息进行编码======"); 36 | // logger.info("消息流水号={},响应结果={},鉴权码 ={}" ,respMsgBody.getReplyFlowId(),respMsgBody.getReplyCode(),respMsgBody.getReplyToken()); 37 | byte[] msgBody = null; 38 | // 鉴权码(STRING) 只有在成功后才有该字段 39 | if (respMsgBody.getReplyCode() == TerminalRegisterMsgRespBody.success) { 40 | msgBody = this.bitOperator.concatAll(Arrays.asList(// 41 | bitOperator.integerTo2Bytes(respMsgBody.getReplyFlowId()), // 流水号(2) 42 | new byte[] { respMsgBody.getReplyCode() }, // 结果 43 | respMsgBody.getReplyToken().getBytes(TPMSConsts.string_charset)// 鉴权码(STRING) 44 | )); 45 | } else { 46 | msgBody = this.bitOperator.concatAll(Arrays.asList(// 47 | bitOperator.integerTo2Bytes(respMsgBody.getReplyFlowId()), // 流水号(2) 48 | new byte[] { respMsgBody.getReplyCode() }// 错误代码 49 | )); 50 | } 51 | 52 | // 消息头 53 | int msgBodyProps = this.jt808ProtocolUtils.generateMsgBodyProps(msgBody.length, 0b000, false, 0); 54 | byte[] msgHeader = this.jt808ProtocolUtils.generateMsgHeader(req.getMsgHeader().getTerminalPhone(), 55 | TPMSConsts.cmd_terminal_register_resp, msgBody, msgBodyProps, flowId); 56 | byte[] headerAndBody = this.bitOperator.concatAll(msgHeader, msgBody); 57 | 58 | // 校验码 59 | int checkSum = this.bitOperator.getCheckSum4JT808(headerAndBody, 0, headerAndBody.length); 60 | // logger.info("消息体={},消息体的长度={},校验码={}", Arrays.toString(headerAndBody) , headerAndBody.length,checkSum); 61 | // 连接并且转义 62 | return this.doEncode(headerAndBody, checkSum); 63 | } 64 | 65 | // public byte[] encode4ServerCommonRespMsg(TerminalAuthenticationMsg req, 66 | // ServerCommonRespMsgBody respMsgBody, int flowId) throws Exception { 67 | public byte[] encode4ServerCommonRespMsg(PackageData req, ServerCommonRespMsgBody respMsgBody, int flowId) 68 | throws Exception { 69 | // logger.info("=======对平台通用应答消息进行编码======"); 70 | // logger.info("消息流水号={},应答id={},响应结果 ={}" ,respMsgBody.getReplyFlowId(),respMsgBody.getReplyId(),respMsgBody.getReplyCode()); 71 | 72 | byte[] msgBody = this.bitOperator.concatAll(Arrays.asList(// 73 | bitOperator.integerTo2Bytes(respMsgBody.getReplyFlowId()), // 应答流水号 74 | bitOperator.integerTo2Bytes(respMsgBody.getReplyId()), // 应答ID,对应的终端消息的ID 75 | new byte[] { respMsgBody.getReplyCode() }// 结果 76 | )); 77 | 78 | // 消息头 79 | int msgBodyProps = this.jt808ProtocolUtils.generateMsgBodyProps(msgBody.length, 0b000, false, 0); 80 | byte[] msgHeader = this.jt808ProtocolUtils.generateMsgHeader(req.getMsgHeader().getTerminalPhone(), 81 | TPMSConsts.cmd_common_resp, msgBody, msgBodyProps, flowId); 82 | byte[] headerAndBody = this.bitOperator.concatAll(msgHeader, msgBody); 83 | 84 | // 校验码 85 | int checkSum = this.bitOperator.getCheckSum4JT808(headerAndBody, 0, headerAndBody.length); 86 | // logger.info("消息体={},消息体的长度={},校验码={}", Arrays.toString(headerAndBody) , headerAndBody.length,checkSum); 87 | // 连接并且转义 88 | return this.doEncode(headerAndBody, checkSum); 89 | } 90 | 91 | /** 92 | * 终端通用应答 93 | * @param req 94 | * @param respMsgBody 95 | * @param flowId 96 | * @return 97 | * @throws Exception 98 | */ 99 | public byte[] encode4TerminalCommonRespMsg(PackageData req, ServerCommonRespMsgBody respMsgBody, int flowId) 100 | throws Exception { 101 | 102 | byte[] msgBody = this.bitOperator.concatAll(Arrays.asList(// 103 | bitOperator.integerTo2Bytes(respMsgBody.getReplyFlowId()), // 应答流水号 104 | bitOperator.integerTo2Bytes(respMsgBody.getReplyId()), // 应答ID,对应的终端消息的ID 105 | new byte[] { respMsgBody.getReplyCode() }// 结果 106 | )); 107 | 108 | // 消息头 109 | int msgBodyProps = this.jt808ProtocolUtils.generateMsgBodyProps(msgBody.length, 0b000, false, 0); 110 | byte[] msgHeader = this.jt808ProtocolUtils.generateMsgHeader(req.getMsgHeader().getTerminalPhone(), 111 | TPMSConsts.msg_id_terminal_common_resp, msgBody, msgBodyProps, flowId); 112 | byte[] headerAndBody = this.bitOperator.concatAll(msgHeader, msgBody); 113 | 114 | // 校验码 115 | int checkSum = this.bitOperator.getCheckSum4JT808(headerAndBody, 0, headerAndBody.length); 116 | // 连接并且转义 117 | return this.doEncode(headerAndBody, checkSum); 118 | } 119 | 120 | /** 121 | * 终端参数设置 122 | * @param msgBodyBytes 123 | * @param session 124 | * @return 125 | * @throws Exception 126 | */ 127 | public byte[] encode4ParamSetting(String phone,TerminalParametersSettingInfo respMsgBody, int flowId) throws Exception { 128 | // 消息头 129 | byte[] msgBodyBytes = bitOperator.integerTo1Bytes(respMsgBody.getCount()); 130 | for(TerminalParamItem item : respMsgBody.getTerminalParamItemList()) { 131 | byte[] msgValue = item.getParamValue(); 132 | msgBodyBytes = this.bitOperator.concatAll(msgBodyBytes,// 133 | bitOperator.integerTo4Bytes(item.getMsgId()), 134 | bitOperator.integerTo1Bytes(item.getParamLength()),msgValue); 135 | } 136 | int msgBodyProps = this.jt808ProtocolUtils.generateMsgBodyProps(msgBodyBytes.length, 0b000, false, 0); 137 | byte[] msgHeader = this.jt808ProtocolUtils.generateMsgHeader(phone, 138 | TPMSConsts.cmd_terminal_param_settings, msgBodyBytes, msgBodyProps, flowId); 139 | // 连接消息头和消息体 140 | byte[] headerAndBody = this.bitOperator.concatAll(msgHeader, msgBodyBytes); 141 | // 校验码 142 | int checkSum = this.bitOperator.getCheckSum4JT808(headerAndBody, 0, headerAndBody.length); 143 | // 连接并且转义 144 | return this.doEncode(headerAndBody, checkSum); 145 | } 146 | 147 | public byte[] encode4ParamSetting1(byte[] msgBodyBytes, Session session) throws Exception { 148 | // 消息头 149 | int msgBodyProps = this.jt808ProtocolUtils.generateMsgBodyProps(msgBodyBytes.length, 0b000, false, 0); 150 | byte[] msgHeader = this.jt808ProtocolUtils.generateMsgHeader(session.getTerminalPhone(), 151 | TPMSConsts.cmd_terminal_param_settings, msgBodyBytes, msgBodyProps, session.currentFlowId()); 152 | // 连接消息头和消息体 153 | byte[] headerAndBody = this.bitOperator.concatAll(msgHeader, msgBodyBytes); 154 | // 校验码 155 | int checkSum = this.bitOperator.getCheckSum4JT808(headerAndBody, 0, headerAndBody.length-1); 156 | // 连接并且转义 157 | return this.doEncode(headerAndBody, checkSum); 158 | } 159 | /** 160 | * 终端参数查询 161 | * @return 162 | */ 163 | public byte[] encode4ParamQuery(String phone, int flowId) throws Exception { 164 | logger.info("=======终端消息查询======"); 165 | byte[] msgBody = {}; 166 | // 消息头 167 | int msgBodyProps = this.jt808ProtocolUtils.generateMsgBodyProps(msgBody.length, 0b000, false, 0); 168 | byte[] msgHeader = this.jt808ProtocolUtils.generateMsgHeader(phone, 169 | TPMSConsts.cmd_terminal_param_query, msgBody, msgBodyProps, flowId); 170 | byte[] headerAndBody = this.bitOperator.concatAll(msgHeader, msgBody); 171 | 172 | // 校验码 173 | int checkSum = this.bitOperator.getCheckSum4JT808(headerAndBody, 0, headerAndBody.length); 174 | // logger.info("消息体={},消息体的长度={},校验码={}", Arrays.toString(headerAndBody) , headerAndBody.length,checkSum); 175 | // 连接并且转义 176 | return this.doEncode(headerAndBody, checkSum); 177 | } 178 | 179 | 180 | /** 181 | * 位置信息查询 182 | * @return 183 | */ 184 | public byte[] encode4LocationQuery( String phone, int flowId) throws Exception { 185 | logger.info("=======位置信息查询======"); 186 | byte[] msgBody = {}; 187 | // 消息头 188 | int msgBodyProps = this.jt808ProtocolUtils.generateMsgBodyProps(msgBody.length, 0b000, false, 0); 189 | byte[] msgHeader = this.jt808ProtocolUtils.generateMsgHeader(phone, 190 | TPMSConsts.cmd_position_query, msgBody, msgBodyProps, flowId); 191 | byte[] headerAndBody = this.bitOperator.concatAll(msgHeader, msgBody); 192 | // 校验码 193 | int checkSum = this.bitOperator.getCheckSum4JT808(headerAndBody, 0, headerAndBody.length); 194 | // 连接并且转义 195 | return this.doEncode(headerAndBody, checkSum); 196 | } 197 | 198 | /** 199 | * 设置多边形区域 200 | * @param msgBodyBytes 201 | * @param session 202 | * @return 203 | * @throws Exception 204 | */ 205 | public byte[] encode4PolygonSettingArea(String phone,PolygonSettingArea respMsgBody, int flowId) throws Exception { 206 | // 消息体 207 | byte[] msgBodyBytes = {}; 208 | // byte[] msgBodyBytes = this.bitOperator.concatAll(Arrays.asList(// 209 | // bitOperator.integerTo2Bytes(respMsgBody.getAreaID()) // 区域ID 210 | // 211 | // )); 212 | 213 | int msgBodyProps = this.jt808ProtocolUtils.generateMsgBodyProps(msgBodyBytes.length, 0b000, false, 0); 214 | // 消息头 215 | byte[] msgHeader = this.jt808ProtocolUtils.generateMsgHeader(phone, 216 | TPMSConsts.cmd_polygon_area_settings, msgBodyBytes, msgBodyProps, flowId); 217 | // 连接消息头和消息体 218 | byte[] headerAndBody = this.bitOperator.concatAll(msgHeader, msgBodyBytes); 219 | // 校验码 220 | int checkSum = this.bitOperator.getCheckSum4JT808(headerAndBody, 0, headerAndBody.length-1); 221 | // 连接并且转义 222 | return this.doEncode(headerAndBody, checkSum); 223 | } 224 | 225 | /** 226 | * 删除多边形区域 227 | * @param msgBodyBytes 228 | * @param session 229 | * @return 230 | * @throws Exception 231 | */ 232 | public byte[] encode4PolygonDelArea(String phone,PolygonDelArea respMsgBody, int flowId) throws Exception { 233 | // 消息体 234 | byte[] msgBodyBytes = {}; 235 | // byte[] msgBodyBytes = this.bitOperator.concatAll(Arrays.asList(// 236 | // bitOperator.integerTo2Bytes(respMsgBody.getAreaCount()), // 区域数 237 | // bitOperator.bytes2bytes(respMsgBody.getAreaIds())//区域ID 238 | // )); 239 | 240 | int msgBodyProps = this.jt808ProtocolUtils.generateMsgBodyProps(msgBodyBytes.length, 0b000, false, 0); 241 | // 消息头 242 | byte[] msgHeader = this.jt808ProtocolUtils.generateMsgHeader(phone, 243 | TPMSConsts.cmd_polygon_area_del, msgBodyBytes, msgBodyProps, flowId); 244 | // 连接消息头和消息体 245 | byte[] headerAndBody = this.bitOperator.concatAll(msgHeader, msgBodyBytes); 246 | // 校验码 247 | int checkSum = this.bitOperator.getCheckSum4JT808(headerAndBody, 0, headerAndBody.length-1); 248 | // 连接并且转义 249 | return this.doEncode(headerAndBody, checkSum); 250 | } 251 | 252 | private byte[] doEncode(byte[] headerAndBody, int checkSum) throws Exception { 253 | byte[] noEscapedBytes = this.bitOperator.concatAll(Arrays.asList(// 254 | new byte[] { TPMSConsts.pkg_delimiter }, // 0x7e 255 | headerAndBody, // 消息头+ 消息体 256 | bitOperator.integerTo1Bytes(checkSum), // 校验码 257 | new byte[] { TPMSConsts.pkg_delimiter }// 0x7e 258 | )); 259 | // 转义 260 | return jt808ProtocolUtils.doEscape4Send(noEscapedBytes, 1, noEscapedBytes.length - 2); 261 | } 262 | 263 | } 264 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/service/codec/MsgDecoder.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.service.codec; 2 | 3 | import java.nio.ByteBuffer; 4 | import java.util.Arrays; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import cn.hylexus.jt808.common.TPMSConsts; 10 | import cn.hylexus.jt808.util.BCD8421Operater; 11 | import cn.hylexus.jt808.util.BitOperator; 12 | import cn.hylexus.jt808.vo.PackageData; 13 | import cn.hylexus.jt808.vo.PackageData.MsgHeader; 14 | import cn.hylexus.jt808.vo.req.LocationInformationQueryResp; 15 | import cn.hylexus.jt808.vo.req.LocationInformationQueryResp.LocationInformationQueryInfo; 16 | import cn.hylexus.jt808.vo.req.TerminalLoctionInfoReportMsg; 17 | import cn.hylexus.jt808.vo.req.TerminalLoctionInfoReportMsg.TerminalLoctionInfo; 18 | import cn.hylexus.jt808.vo.req.TerminalParamQueryMsgResp; 19 | import cn.hylexus.jt808.vo.req.TerminalParamQueryMsgResp.TerminalParametersqQueryInfo; 20 | import cn.hylexus.jt808.vo.req.TerminalRegisterMsg; 21 | import cn.hylexus.jt808.vo.req.TerminalRegisterMsg.TerminalRegInfo; 22 | import cn.hylexus.jt808.vo.resp.ServerCommonRespMsgBody; 23 | import cn.hylexus.jt808.vo.resp.TerminalCommonRespMsg; 24 | import cn.hylexus.jt808.vo.resp.TerminalCommonRespMsg.TerminalCommonRespInfo; 25 | 26 | public class MsgDecoder { 27 | 28 | private static final Logger log = LoggerFactory.getLogger(MsgDecoder.class); 29 | 30 | private BitOperator bitOperator; 31 | private BCD8421Operater bcd8421Operater; 32 | 33 | public MsgDecoder() { 34 | this.bitOperator = new BitOperator(); 35 | this.bcd8421Operater = new BCD8421Operater(); 36 | } 37 | 38 | public PackageData bytes2PackageData(byte[] data) { 39 | PackageData ret = new PackageData(); 40 | 41 | // 0. 终端套接字地址信息 42 | // ret.setChannel(msg.getChannel()); 43 | 44 | // 1. 16byte 或 12byte 消息头 45 | MsgHeader msgHeader = this.parseMsgHeaderFromBytes(data); 46 | ret.setMsgHeader(msgHeader); 47 | 48 | int msgBodyByteStartIndex = 12; 49 | // 2. 消息体 50 | // 有子包信息,消息体起始字节后移四个字节:消息包总数(word(16))+包序号(word(16)) 51 | if (msgHeader.isHasSubPackage()) { 52 | msgBodyByteStartIndex = 16; 53 | } 54 | 55 | byte[] tmp = new byte[msgHeader.getMsgBodyLength()]; 56 | System.arraycopy(data, msgBodyByteStartIndex, tmp, 0, tmp.length); 57 | ret.setMsgBodyBytes(tmp); 58 | // 3. 去掉分隔符之后,最后一位就是校验码 59 | // int checkSumInPkg = 60 | // this.bitOperator.oneByteToInteger(data[data.length - 1]); 61 | int checkSumInPkg = data[data.length - 1]; 62 | //消息包中的最后以为为校验码所以此处的长度为data.length - 1 ,即只取消息头和消息体的数据 63 | int calculatedCheckSum = this.bitOperator.getCheckSum4JT808(data, 0, data.length - 1); 64 | ret.setCheckSum(checkSumInPkg); 65 | if (checkSumInPkg != calculatedCheckSum) { 66 | log.warn("检验码不一致,msgid:{},pkg:{},calculated:{}", msgHeader.getMsgId(), checkSumInPkg, calculatedCheckSum); 67 | } 68 | return ret; 69 | } 70 | /** 71 | * 解析消息头 72 | * @param data 73 | * @return 74 | */ 75 | private MsgHeader parseMsgHeaderFromBytes(byte[] data) { 76 | MsgHeader msgHeader = new MsgHeader(); 77 | 78 | // 1. 消息ID word(16) 79 | // byte[] tmp = new byte[2]; 80 | // System.arraycopy(data, 0, tmp, 0, 2); 81 | // msgHeader.setMsgId(this.bitOperator.twoBytesToInteger(tmp)); 82 | msgHeader.setMsgId(this.parseIntFromBytes(data, 0, 2)); 83 | 84 | // 2. 消息体属性 word(16)=================> 85 | // System.arraycopy(data, 2, tmp, 0, 2); 86 | // int msgBodyProps = this.bitOperator.twoBytesToInteger(tmp); 87 | int msgBodyProps = this.parseIntFromBytes(data, 2, 2); 88 | msgHeader.setMsgBodyPropsField(msgBodyProps); 89 | // [ 0-9 ] 0000,0011,1111,1111(3FF)(消息体长度) 90 | msgHeader.setMsgBodyLength(msgBodyProps & 0x1ff); 91 | // [10-12] 0001,1100,0000,0000(1C00)(加密类型) 92 | msgHeader.setEncryptionType((msgBodyProps & 0xe00) >> 10); 93 | // [ 13_ ] 0010,0000,0000,0000(2000)(是否有子包) 94 | msgHeader.setHasSubPackage(((msgBodyProps & 0x2000) >> 13) == 1); 95 | // [14-15] 1100,0000,0000,0000(C000)(保留位) 96 | msgHeader.setReservedBit(((msgBodyProps & 0xc000) >> 14) + ""); 97 | // 消息体属性 word(16)<================= 98 | 99 | // 3. 终端手机号 bcd[6] 100 | // tmp = new byte[6]; 101 | // System.arraycopy(data, 4, tmp, 0, 6); 102 | // msgHeader.setTerminalPhone(this.bcd8421Operater.bcd2String(tmp)); 103 | msgHeader.setTerminalPhone(this.parseBcdStringFromBytes(data, 4, 6)); 104 | 105 | // 4. 消息流水号 word(16) 按发送顺序从 0 开始循环累加 106 | // tmp = new byte[2]; 107 | // System.arraycopy(data, 10, tmp, 0, 2); 108 | // msgHeader.setFlowId(this.bitOperator.twoBytesToInteger(tmp)); 109 | msgHeader.setFlowId(this.parseIntFromBytes(data, 10, 2)); 110 | 111 | // 5. 消息包封装项 112 | // 有子包信息 113 | if (msgHeader.isHasSubPackage()) { 114 | // 消息包封装项字段 115 | msgHeader.setPackageInfoField(this.parseIntFromBytes(data, 12, 4)); 116 | // byte[0-1] 消息包总数(word(16)) 117 | // tmp = new byte[2]; 118 | // System.arraycopy(data, 12, tmp, 0, 2); 119 | // msgHeader.setTotalSubPackage(this.bitOperator.twoBytesToInteger(tmp)); 120 | msgHeader.setTotalSubPackage(this.parseIntFromBytes(data, 12, 2)); 121 | 122 | // byte[2-3] 包序号(word(16)) 从 1 开始 123 | // tmp = new byte[2]; 124 | // System.arraycopy(data, 14, tmp, 0, 2); 125 | // msgHeader.setSubPackageSeq(this.bitOperator.twoBytesToInteger(tmp)); 126 | msgHeader.setSubPackageSeq(this.parseIntFromBytes(data, 12, 2)); 127 | } 128 | return msgHeader; 129 | } 130 | 131 | protected String parseStringFromBytes(byte[] data, int startIndex, int lenth) { 132 | return this.parseStringFromBytes(data, startIndex, lenth, null); 133 | } 134 | 135 | private String parseStringFromBytes(byte[] data, int startIndex, int lenth, String defaultVal) { 136 | try { 137 | byte[] tmp = new byte[lenth]; 138 | System.arraycopy(data, startIndex, tmp, 0, lenth); 139 | return new String(tmp, TPMSConsts.string_charset); 140 | } catch (Exception e) { 141 | log.error("解析字符串出错:{}", e.getMessage()); 142 | e.printStackTrace(); 143 | return defaultVal; 144 | } 145 | } 146 | 147 | private String parseBcdStringFromBytes(byte[] data, int startIndex, int lenth) { 148 | return this.parseBcdStringFromBytes(data, startIndex, lenth, null); 149 | } 150 | 151 | private String parseBcdStringFromBytes(byte[] data, int startIndex, int lenth, String defaultVal) { 152 | try { 153 | byte[] tmp = new byte[lenth]; 154 | log.info("拷贝的数组长度:{},实际拷贝长度:{},开始的未知:{}",data.length,lenth,startIndex); 155 | System.arraycopy(data, startIndex, tmp, 0, lenth); 156 | return this.bcd8421Operater.bcd2String(tmp); 157 | } catch (Exception e) { 158 | log.error("解析BCD(8421码)出错:{}", e.getMessage()); 159 | e.printStackTrace(); 160 | return defaultVal; 161 | } 162 | } 163 | 164 | private int parseIntFromBytes(byte[] data, int startIndex, int length) { 165 | return this.parseIntFromBytes(data, startIndex, length, 0); 166 | } 167 | 168 | private int parseIntFromBytes(byte[] data, int startIndex, int length, int defaultVal) { 169 | try { 170 | // 字节数大于4,从起始索引开始向后处理4个字节,其余超出部分丢弃 171 | final int len = length > 4 ? 4 : length; 172 | byte[] tmp = new byte[len]; 173 | System.arraycopy(data, startIndex, tmp, 0, len); 174 | return bitOperator.byteToInteger(tmp); 175 | } catch (Exception e) { 176 | log.error("解析整数出错:{}", e.getMessage()); 177 | e.printStackTrace(); 178 | return defaultVal; 179 | } 180 | } 181 | /** 182 | * 解析终端注册信息 183 | * @param packageData 184 | * @return 185 | */ 186 | public TerminalRegisterMsg toTerminalRegisterMsg(PackageData packageData) { 187 | TerminalRegisterMsg ret = new TerminalRegisterMsg(packageData); 188 | byte[] data = ret.getMsgBodyBytes(); 189 | 190 | TerminalRegInfo body = new TerminalRegInfo(); 191 | 192 | // 1. byte[0-1] 省域ID(WORD) 193 | // 设备安装车辆所在的省域,省域ID采用GB/T2260中规定的行政区划代码6位中前两位 194 | // 0保留,由平台取默认值 195 | body.setProvinceId(this.parseIntFromBytes(data, 0, 2)); 196 | 197 | // 2. byte[2-3] 设备安装车辆所在的市域或县域,市县域ID采用GB/T2260中规定的行 政区划代码6位中后四位 198 | // 0保留,由平台取默认值 199 | body.setCityId(this.parseIntFromBytes(data, 2, 2)); 200 | 201 | // 3. byte[4-8] 制造商ID(BYTE[5]) 5 个字节,终端制造商编码 202 | // byte[] tmp = new byte[5]; 203 | body.setManufacturerId(this.parseStringFromBytes(data, 4, 5)); 204 | 205 | // 4. byte[9-16] 终端型号(BYTE[8]) 八个字节, 此终端型号 由制造商自行定义 位数不足八位的,补空格。 206 | body.setTerminalType(this.parseStringFromBytes(data, 9, 8)); 207 | 208 | // 5. byte[17-23] 终端ID(BYTE[7]) 七个字节, 由大写字母 和数字组成, 此终端 ID由制造 商自行定义 209 | body.setTerminalId(this.parseStringFromBytes(data, 17, 7)); 210 | 211 | // 6. byte[24] 车牌颜色(BYTE) 车牌颜 色按照JT/T415-2006 中5.4.12 的规定 212 | body.setLicensePlateColor(this.parseIntFromBytes(data, 24, 1)); 213 | 214 | // 7. byte[25-x] 车牌(STRING) 公安交 通管理部门颁 发的机动车号牌 215 | body.setLicensePlate(this.parseStringFromBytes(data, 25, data.length - 25)); 216 | 217 | ret.setTerminalRegInfo(body); 218 | return ret; 219 | } 220 | 221 | /** 222 | * 解析位置信息汇报 223 | * @param packageData 224 | * @return 225 | */ 226 | public TerminalLoctionInfoReportMsg toTerminalLoctionInfoReportMsg(PackageData packageData) { 227 | TerminalLoctionInfoReportMsg ret = new TerminalLoctionInfoReportMsg(packageData); 228 | byte[] data = ret.getMsgBodyBytes(); 229 | TerminalLoctionInfo body = new TerminalLoctionInfo(); 230 | 231 | // 1. byte[0-3]报警标志 (DWORD) 232 | body.setWarningFlag(this.parseIntFromBytes(data, 0, 4)); 233 | 234 | // 2. byte[4-7] 状态 235 | body.setStatus(this.parseIntFromBytes(data, 4, 4)); 236 | 237 | // 3. byte[8-11] 纬度 以度为单位的纬度值乘以 10 的 6 次方,精确到百万分之一度 238 | int latitude =this.parseIntFromBytes(data, 8, 4); 239 | body.setLatitude(latitude); 240 | 241 | // 4. byte[12-15] 经度 以度为单位的经度值乘以 10 的 6 次方,精确到百万分之一度 242 | int longitude =this.parseIntFromBytes(data, 12, 4); 243 | body.setLongitude(longitude); 244 | 245 | // 5. byte[16-17] 高程 海拔高度,单位为米(m) 246 | body.setAltitude(this.parseIntFromBytes(data, 16, 2)); 247 | 248 | // 6. byte[18-19] 速度 1/10km/h 249 | body.setSpeed(this.parseIntFromBytes(data, 18, 2)); 250 | 251 | // 7. byte[20-21] 方向 0-359,正北为 0,顺时针 252 | body.setCourse(this.parseIntFromBytes(data, 20, 2)); 253 | 254 | // 8. byte[22-27] YY-MM-DD-hh-mm-ss(GMT+8 时间) 255 | body.setTime(this.parseBcdStringFromBytes(data, 22, 6)); 256 | System.out.println(Arrays.toString(data)); 257 | //9. 附加消息 258 | int attachPosStart = 28; 259 | if(data.length > attachPosStart) { //当消息长度大于27的时候,即表示还有附加消息的时候 260 | log.info("报文中含有附加信息,数组的长度:"+data.length); 261 | int count =0; 262 | while(attachPosStart attachPosStart) { //当消息长度大于3的时候,即表示开始读取参数项列表 308 | int count =0; 309 | while(attachPosStart attachPosStart) { //当消息长度大于27的时候,即表示还有附加消息的时候 357 | log.info("报文中含有附加信息,数组的长度:"+data.length); 358 | int count =0; 359 | while(attachPosStart0 391 | body.setSleepTimeReportInteval(this.parseIntFromBytes(data, ++tempPosStart, msgLength)); 392 | }else if(0x0029 == msgId) { 393 | // 缺省时间汇报间隔,单位为秒(s),>0 394 | body.setDefaultTimeReportInteval(this.parseIntFromBytes(data, ++tempPosStart, msgLength)); 395 | }else if(0x0055 == msgId) { 396 | // 最高速度,单位为千⽶每⼩时(km/h) 397 | body.setMaxSpeed(this.parseIntFromBytes(data, ++tempPosStart, msgLength)); 398 | }else if(0x0056 == msgId) { 399 | // 超速持续时间,单位为秒(s) 400 | body.setOverspeedDuration(this.parseIntFromBytes(data, ++tempPosStart, msgLength)); 401 | }else if(0x0080 == msgId) { 402 | // 车辆⾥程表读数,1/10km 403 | body.setMileage(this.parseIntFromBytes(data, ++tempPosStart, msgLength)); 404 | }else if(0x0081 == msgId) { 405 | // 车辆所在的省域ID,1~255 406 | body.setProvinceId(this.parseIntFromBytes(data, ++tempPosStart, msgLength)); 407 | }else if(0x0082 == msgId) { 408 | // 车辆所在的市域ID,1~255 409 | body.setCityId(this.parseIntFromBytes(data, ++tempPosStart, msgLength)); 410 | }else if(0x0083 == msgId) { 411 | // 公安交通同管理部门颁发的机动车号牌 412 | body.setLicensePlate(this.parseStringFromBytes(data, ++tempPosStart, msgLength)); 413 | }else if(0x0084 == msgId) { 414 | // 车牌颜色,按照JT/T415—2006中5.4.12的规定 415 | body.setLicensePlateColor(this.parseIntFromBytes(data, ++tempPosStart, msgLength)); 416 | }else if(0x0002 == msgId) { 417 | // TCP 消息应答超时时间,单位为秒(s) 418 | body.setLocationReportingStrategy(this.parseIntFromBytes(data, ++tempPosStart, msgLength)); 419 | }else if(0x0003 == msgId) { 420 | // TCP 消息重传次数 421 | body.setLocationReportingStrategy(this.parseIntFromBytes(data, ++tempPosStart, msgLength)); 422 | }else if(0x0020 == msgId) { 423 | // 位置汇报策略 ,0:定时汇报;1:定距汇报;2:定时和定距汇报 424 | body.setLocationReportingStrategy(this.parseIntFromBytes(data, ++tempPosStart, msgLength)); 425 | }else{ 426 | ++tempPosStart; 427 | log.info("消息暂时不解析:"+msgId); 428 | } 429 | int nextPos = tempPosStart+msgLength; 430 | return nextPos; 431 | } 432 | 433 | /** 434 | * 解析终端通用应答消息 435 | * @param packageData 436 | * @return 437 | */ 438 | public TerminalCommonRespMsg toTerminalCommonRespMsg(PackageData packageData) { 439 | TerminalCommonRespMsg ret = new TerminalCommonRespMsg(packageData); 440 | byte[] data = ret.getMsgBodyBytes(); 441 | TerminalCommonRespInfo body = new TerminalCommonRespInfo(); 442 | //data[0-1] 应答流水号 WORD 对应的平台消息的流水号 443 | body.setReplyFlowId(this.parseIntFromBytes(data, 0, 2)); 444 | //data[2-3] 应答 ID WORD 对应的平台消息的 ID 445 | body.setReplyId(this.parseIntFromBytes(data, 2, 2)); 446 | //data[4] 结果 BYTE 0:成功/确认;1:失败;2:消息有误;3:不支持 447 | body.setReplyCode(data[4]); 448 | ret.setTerminalCommonRespInfo(body); 449 | return ret; 450 | } 451 | } 452 | -------------------------------------------------------------------------------- /src/main/java/cn/hylexus/jt808/service/MsgToDPlatformGpsPojoService.java: -------------------------------------------------------------------------------- 1 | package cn.hylexus.jt808.service; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.rmi.RemoteException; 5 | import java.text.SimpleDateFormat; 6 | import java.util.ArrayList; 7 | import java.util.Date; 8 | import java.util.List; 9 | 10 | import org.apache.axis2.AxisFault; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import com.rksp.util.DateUtil; 15 | import com.rksp.util.GsonUtil; 16 | import com.rksp.util.StringUtil; 17 | import com.sharetime.gps.pojo.Gps实时轨迹; 18 | import com.sharetime.gps.pojo.Gps报文; 19 | import com.sharetime.gps.pojo.Gps指令集; 20 | import com.sharetime.gps.pojo.Gps终端设备; 21 | import com.sharetime.gps.pojo.Gps终端设备掉线记录; 22 | import com.sharetime.gps.pojo.Gps车辆; 23 | import com.sharetime.gps.vo.GpsBaseCdt; 24 | import com.sharetime.gps.vo.TerminalParamSettingVo; 25 | 26 | import cn.hylexus.jt808.common.GpsServerConsts; 27 | import cn.hylexus.jt808.common.TPMSConsts; 28 | import cn.hylexus.jt808.util.BaseUtil; 29 | import cn.hylexus.jt808.util.BitOperator; 30 | import cn.hylexus.jt808.util.HexStringUtils; 31 | import cn.hylexus.jt808.vo.PackageData; 32 | import cn.hylexus.jt808.vo.PackageData.MsgHeader; 33 | import cn.hylexus.jt808.vo.req.LocationInformationQueryResp; 34 | import cn.hylexus.jt808.vo.req.TerminalLoctionInfoReportMsg; 35 | import cn.hylexus.jt808.vo.req.TerminalLoctionInfoReportMsg.TerminalLoctionInfo; 36 | import cn.hylexus.jt808.vo.req.TerminalParamQueryMsgResp; 37 | import cn.hylexus.jt808.vo.req.TerminalParamQueryMsgResp.TerminalParametersqQueryInfo; 38 | import cn.hylexus.jt808.vo.req.TerminalRegisterMsg; 39 | import cn.hylexus.jt808.vo.req.TerminalRegisterMsg.TerminalRegInfo; 40 | import cn.hylexus.jt808.vo.resp.TerminalRegisterMsgRespBody; 41 | import cn.hylexus.jt808.vo.resp.TerminalCommonRespMsg.TerminalCommonRespInfo; 42 | import rk.stub.gps.GpsBaseSvc; 43 | import rk.stub.gps.GpsBaseSvcStub; 44 | import rk.stub.gps.GpsBusinessSvc; 45 | import rk.stub.gps.GpsBusinessSvcStub; 46 | 47 | /** 48 | * 把接受到的报文信息转换为 DPlatform_GPS系统中对应的实体类 49 | * 50 | * @author cheryl 51 | * 52 | */ 53 | public class MsgToDPlatformGpsPojoService { 54 | private final static Logger logger = LoggerFactory.getLogger(MsgToDPlatformGpsPojoService.class); 55 | 56 | private static GpsBaseSvc gpsBaseSvc; 57 | private static GpsBusinessSvc gpsBusinessSvc; 58 | 59 | static { 60 | try { 61 | gpsBaseSvc = new GpsBaseSvcStub(GpsServerConsts.gps_server_base); 62 | gpsBusinessSvc = new GpsBusinessSvcStub(GpsServerConsts.gps_server_business); 63 | } catch (AxisFault e) { 64 | // TODO Auto-generated catch block 65 | e.printStackTrace(); 66 | logger.info("服务连接失败"); 67 | } 68 | } 69 | /** 70 | * 创建终端设备 TerminalRegisterMsg 终端注册信息 authCode 生成的鉴权码 71 | * 72 | * @return 73 | */ 74 | public String createTerminalDevice(TerminalRegisterMsg msg) { 75 | GpsBaseCdt cdt = new GpsBaseCdt(); 76 | TerminalRegInfo terminalRegInfo = msg.getTerminalRegInfo(); 77 | String terminalPhone = msg.getMsgHeader().getTerminalPhone(); 78 | String authCode = null;// 鉴权码 79 | boolean flag ; //操作成功标识符 80 | try { 81 | // 1、获取终端 82 | Gps终端设备 terminal = gpsBaseSvc.getTheTerminalByPhone(terminalPhone); 83 | cdt = new GpsBaseCdt(); 84 | cdt.setPlatenumber(terminalRegInfo.getLicensePlate()); 85 | // 2、获取车辆 86 | List vehicleList = gpsBaseSvc.getVehicles(cdt); 87 | // 3、判断终端是否存在 88 | if (terminal == null) { 89 | logger.error("终端没有找到"); 90 | return new String(new byte[] { TerminalRegisterMsgRespBody.terminal_not_found }); 91 | } 92 | // 4、判断车辆是否存在 93 | if (vehicleList == null || vehicleList.size() <= 0) { 94 | logger.error("没有找到对应的车辆"); 95 | return new String(new byte[] { TerminalRegisterMsgRespBody.car_not_found }); 96 | } 97 | // 5、判断车辆是否绑定过终端 98 | for (Gps车辆 tempvehicle : vehicleList) { 99 | if (!StringUtil.isEmpty(tempvehicle.get设备序列号())) { 100 | if (!tempvehicle.get设备序列号().equals(terminalRegInfo.getTerminalId().trim())) { 101 | logger.error("车辆已经被注册"); 102 | return new String(new byte[] { TerminalRegisterMsgRespBody.car_already_registered }, 103 | "UTF-8"); 104 | } else { 105 | logger.info("车辆与终端已经绑定成功,无需重复绑定"); 106 | if (terminal.get设备序列号().equals(tempvehicle.get设备序列号())) { 107 | authCode = terminal.get鉴权码(); 108 | break; 109 | } 110 | } 111 | if (!StringUtil.isEmpty(authCode)) { 112 | return authCode; 113 | } else { 114 | return new String(new byte[] { TerminalRegisterMsgRespBody.car_already_registered }, 115 | "UTF-8"); 116 | } 117 | } 118 | 119 | } 120 | 121 | // 6、判断终端是否 绑定过车辆 (终端参数设置当设置了车牌号的时候会发送终端注册的报文,从而更新终端和车辆的绑定关系) 122 | Gps车辆 vehicle = terminal.getVehicle(); 123 | List vehicles = new ArrayList(); 124 | if (vehicle != null) { 125 | if (terminalRegInfo.getLicensePlate().equals(vehicle.get车牌号())) { 126 | authCode = terminal.get鉴权码(); 127 | } else { 128 | vehicle.set设备序列号(null); 129 | vehicle.set设备id(null); 130 | vehicles.add(vehicle); 131 | for (Gps车辆 tempvehicle : vehicleList) { //如果找到报文中车牌号一样的车辆则进行绑定 132 | if (tempvehicle.get车牌号().equals(terminalRegInfo.getLicensePlate().trim())) { 133 | tempvehicle.set设备id(terminal.getOid()); 134 | tempvehicle.set设备序列号(terminal.get设备序列号()); 135 | vehicles.add(tempvehicle); 136 | flag = gpsBaseSvc.updateVehicles(vehicles); 137 | if(flag) { 138 | return terminal.get鉴权码(); 139 | }else { 140 | logger.info("车辆信息更新失败!"); 141 | return "5"; 142 | } 143 | } 144 | } 145 | } 146 | } 147 | 148 | // 7、 终端以及对应车牌号的车辆还都没有进行绑定 149 | if (StringUtil.isEmpty(terminal.get制造商ID())) { 150 | terminal.set制造商ID(terminalRegInfo.getManufacturerId().trim().trim()); 151 | } 152 | if (StringUtil.isEmpty(terminal.get设备型号())) { 153 | terminal.set设备型号(terminalRegInfo.getTerminalType().trim()); 154 | } 155 | //平台新增的时候已经写好 156 | // terminal.set设备序列号(terminalRegInfo.getTerminalId().trim()); 157 | // 鉴权码,由终端的手机号以及当前时间的毛秒之生成; 158 | authCode = BaseUtil.generateAuthCode(terminalPhone); 159 | terminal.set鉴权码(authCode); 160 | terminal.set设备状态("在线"); 161 | terminal.set设备使用状态("使用"); 162 | vehicle = vehicleList.get(0); 163 | vehicle.set设备id(terminal.getOid()); 164 | // vehicle.set设备序列号(terminalRegInfo.getTerminalId().trim()); 165 | vehicle.set设备序列号(terminal.get设备序列号()); 166 | flag = gpsBaseSvc.updateTerminalAndVehicle(vehicle, terminal); 167 | if (flag) { 168 | return authCode; 169 | } else { 170 | logger.info("车辆和终端新更新失败!"); 171 | return "5"; 172 | } 173 | 174 | } catch (RemoteException e) { 175 | logger.error(GpsServerConsts.gps_server_base + "连接失败!"); 176 | e.printStackTrace(); 177 | // 返回非正常的响应值 178 | return "5"; 179 | } catch (UnsupportedEncodingException e) { 180 | // TODO Auto-generated catch block 181 | logger.error("byte[]转换成String异常"); 182 | e.printStackTrace(); 183 | return "5"; 184 | } 185 | 186 | } 187 | 188 | /** 189 | * 创建实时轨迹---位置汇报 TerminalLoctionInfoReportMsg 位置汇报信息 190 | * 191 | * @return 192 | */ 193 | public byte creatLocus(TerminalLoctionInfoReportMsg msg) { 194 | String oid = null; 195 | TerminalLoctionInfo terminalLoctionInfo = msg.getTerminalLoctionInfo(); 196 | String phone = msg.getMsgHeader().getTerminalPhone(); 197 | try { 198 | GpsBaseCdt cdt = new GpsBaseCdt(); 199 | cdt.setSimcn(phone); 200 | List terminalDeviceList = gpsBaseSvc.getTerminals(cdt); 201 | if (terminalDeviceList == null || terminalDeviceList.size() <= 0) { 202 | logger.error("终端没有找到"); 203 | } else { 204 | Gps实时轨迹 trajectory = setEntity(terminalDeviceList, terminalLoctionInfo, phone); 205 | oid = gpsBusinessSvc.createTheTrajectory(trajectory);// 添加到数据库 206 | } 207 | 208 | if (!StringUtil.isEmpty(oid)) { 209 | return 0; 210 | } else { 211 | return 1; 212 | } 213 | 214 | } catch (RemoteException e) { 215 | logger.error(GpsServerConsts.gps_server_business + "连接失败!"); 216 | e.printStackTrace(); 217 | return 1; 218 | } 219 | } 220 | 221 | /** 222 | * 根据手机号查询终端的鉴权码,比较两者是否一致 223 | * 224 | * @param terminalPhone 225 | * @param authCode 226 | * @return 227 | */ 228 | public boolean getTheReplyCodeByTerminalPhone(String terminalPhone, String authCode) { 229 | try { 230 | GpsBaseCdt cdt = new GpsBaseCdt(); 231 | cdt.setSimcn(terminalPhone); 232 | List terminalDeviceList = gpsBaseSvc.getTerminals(cdt); 233 | if (terminalDeviceList != null && terminalDeviceList.size() > 0) { 234 | Gps终端设备 pojo = terminalDeviceList.get(0); 235 | String code = pojo.get鉴权码(); 236 | if (authCode.equals(code)) {// 鉴权码一致返回true,否则返回false 237 | if (pojo.get设备状态().equals("离线")) { 238 | pojo.set设备状态("在线"); 239 | pojo.set设备使用状态("使用"); 240 | gpsBaseSvc.updateTheTerminal(pojo); 241 | } 242 | return true; 243 | } 244 | } 245 | return false; 246 | } catch (RemoteException e) { 247 | logger.error(GpsServerConsts.gps_server_business + "axis请求失败!"); 248 | e.printStackTrace(); 249 | return false; 250 | } 251 | } 252 | 253 | /** 254 | * 保存终端通用应答消息 255 | * 256 | * @param reqHeader 257 | * @return 258 | */ 259 | public boolean updateGpsDirective(String terminalPhone, TerminalCommonRespInfo info) { 260 | boolean flag = false; 261 | try { 262 | GpsBaseCdt cdt = new GpsBaseCdt(); 263 | cdt.setMessageId(info.getReplyId()); 264 | cdt.setSimcn(terminalPhone); 265 | cdt.setFlowId(info.getReplyFlowId()); 266 | List directiveList = (List) gpsBaseSvc.getDirectives(cdt); 267 | if (directiveList != null && directiveList.size() > 0) { 268 | Gps指令集 directive = directiveList.get(0); 269 | directive.set回执时间(DateUtil.date2String(new Date(), "yyyy-MM-dd HH:mm:ss")); 270 | if (info.getReplyCode() == 0) { 271 | directive.set消息回执("成功"); 272 | flag = updateRelativePojo(gpsBaseSvc, directive); 273 | } else if (info.getReplyCode() == 1) { 274 | directive.set消息回执("失败"); 275 | } else if (info.getReplyCode() == 2) { 276 | directive.set消息回执("消息有误"); 277 | } else if (info.getReplyCode() == 3) { 278 | directive.set消息回执("不支持"); 279 | } 280 | flag = gpsBaseSvc.updateTheDirective(directive); 281 | } 282 | } catch (RemoteException e) { 283 | // TODO Auto-generated catch block 284 | e.printStackTrace(); 285 | } 286 | return flag; 287 | } 288 | 289 | /** 290 | * 接受到终端通用应答的成功报文后,执行数据库pojo类的更新操作 291 | * 292 | * @param gpsBaseSvc 293 | * @param directive 294 | * @throws RemoteException 295 | */ 296 | private boolean updateRelativePojo(GpsBaseSvc gpsBaseSvc, Gps指令集 directive) throws RemoteException { 297 | boolean flag = false; 298 | if (directive.get消息id() == TPMSConsts.cmd_terminal_param_settings) { 299 | if (StringUtil.isEmpty(directive.get消息内容())) { 300 | return flag; 301 | } 302 | TerminalParamSettingVo terminalParamSettingVo = (TerminalParamSettingVo) GsonUtil 303 | .getObject(directive.get消息内容(), TerminalParamSettingVo.class); 304 | if (terminalParamSettingVo.getType().equals("terminal")) { 305 | Gps终端设备 pojo = gpsBaseSvc.getTheTerminal(directive.get关联id()); 306 | List vehicles = new ArrayList(); 307 | if (!StringUtil.isEmpty(terminalParamSettingVo.getHeartbeatInterval())) { 308 | pojo.set终端心跳发送间隔(terminalParamSettingVo.getHeartbeatInterval()); 309 | } 310 | if (!StringUtil.isEmpty(terminalParamSettingVo.getServerAddress())) { 311 | pojo.set主服务器地址(terminalParamSettingVo.getServerAddress()); 312 | } 313 | if (!StringUtil.isEmpty(terminalParamSettingVo.getServerPort())) { 314 | pojo.set服务器TCP端口(terminalParamSettingVo.getServerPort()); 315 | } 316 | if (!StringUtil.isEmpty(terminalParamSettingVo.getDefaultTimeReportInteval())) { 317 | pojo.set缺省时间汇报间隔(terminalParamSettingVo.getDefaultTimeReportInteval()); 318 | } 319 | if (!StringUtil.isEmpty(terminalParamSettingVo.getSleepTimeReportInteval())) { 320 | pojo.set休眠时汇报时间间隔(terminalParamSettingVo.getSleepTimeReportInteval()); 321 | } 322 | if (!StringUtil.isEmpty(terminalParamSettingVo.getLicensePlate())) { 323 | String licensePlate = terminalParamSettingVo.getLicensePlate().trim(); 324 | Gps车辆 bingingVehicle = pojo.getVehicle(); 325 | logger.error("绑定的车辆信息"); 326 | logger.error("原车车辆信息:" + GsonUtil.getJSONString(bingingVehicle)); 327 | if (bingingVehicle != null) { 328 | // if(!licensePlate.equals(bingingVehicle.get车牌号())) { 329 | bingingVehicle.set设备id(null); 330 | bingingVehicle.set设备序列号(null); 331 | logger.error("新车车辆信息:" + GsonUtil.getJSONString(bingingVehicle)); 332 | vehicles.add(bingingVehicle); 333 | // } 334 | 335 | } 336 | GpsBaseCdt cdt = new GpsBaseCdt(); 337 | cdt.setPlatenumber(licensePlate); 338 | List tempVehicles = gpsBaseSvc.getVehicles(cdt); 339 | if (vehicles != null && vehicles.size() > 0) { 340 | Gps车辆 vehicle = vehicles.get(0); 341 | vehicle.set设备id(pojo.getOid()); 342 | vehicle.set设备序列号(pojo.get设备序列号()); 343 | vehicles.add(vehicle); 344 | } 345 | } 346 | if (vehicles != null && vehicles.size() > 0) { 347 | logger.error("更新车辆" + vehicles.size()); 348 | flag = gpsBaseSvc.updateVehicles(vehicles); 349 | } else { 350 | flag = gpsBaseSvc.updateTheTerminal(pojo); 351 | } 352 | } else { 353 | // Gps车辆 pojo = gpsBaseSvc.getTheVehicle(directive.get关联id()); 354 | // if(!StringUtil.isEmpty(terminalParamSettingVo.getMaxSpeed())) { 355 | // pojo.set速度阈值(terminalParamSettingVo.getMaxSpeed()); 356 | // } 357 | // if(!StringUtil.isEmpty(terminalParamSettingVo.getOverspeedDuration())) { 358 | // pojo.set超速持续时间(terminalParamSettingVo.getOverspeedDuration()); 359 | // } 360 | // if(!StringUtil.isEmpty(terminalParamSettingVo.getLicensePlate())) { 361 | // pojo.set车牌号(terminalParamSettingVo.getLicensePlate()); 362 | // } 363 | // if(!StringUtil.isEmpty(terminalParamSettingVo.getLicensePlateColor())) { 364 | // pojo.set车牌颜色(terminalParamSettingVo.getLicensePlateColor()); 365 | // } 366 | // flag = gpsBaseSvc.updateTheVehicle(pojo); 367 | } 368 | } 369 | return flag; 370 | } 371 | 372 | /** 373 | * 创建终端设备掉线记录 374 | * 375 | * @return 376 | */ 377 | public String creatTerminalFacilityDropsRecord(String phone) { 378 | try { 379 | GpsBaseCdt cdt = new GpsBaseCdt(); 380 | cdt.setSimcn(phone); 381 | List terminalDeviceList = gpsBaseSvc.getTerminals(cdt); 382 | if (terminalDeviceList == null || terminalDeviceList.size() <= 0) { 383 | logger.error("终端没有找到"); 384 | } else { 385 | // 设备掉线后修改终端设备状态为离线 386 | Gps终端设备 terminalDevice = terminalDeviceList.get(0); 387 | terminalDevice.set设备状态("离线"); 388 | terminalDevice.set设备使用状态("闲置"); 389 | gpsBaseSvc.updateTheTerminal(terminalDevice); 390 | // 终端设备掉线记录数据库表插入数据 391 | Gps终端设备掉线记录 dropsRecord = new Gps终端设备掉线记录(); 392 | dropsRecord.setSim卡号(phone); 393 | dropsRecord.set掉线时间(new Date()); 394 | dropsRecord.set设备id(terminalDevice.getOid()); 395 | dropsRecord.set设备序列号(terminalDevice.get设备序列号()); 396 | gpsBaseSvc.createTerminalFacilityDropsRecord(dropsRecord);// 添加到数据库 397 | } 398 | 399 | } catch (RemoteException e) { 400 | logger.error(GpsServerConsts.gps_server_business + "连接失败!"); 401 | e.printStackTrace(); 402 | } 403 | return null; 404 | } 405 | 406 | /** 407 | * 创建实时轨迹---位置信息查询应答 LocationInformationQueryResp 位置信息查询应答 408 | * 409 | * @return 410 | */ 411 | public byte creatLocus(LocationInformationQueryResp msg) { 412 | try { 413 | String oid = null; 414 | TerminalLoctionInfo terminalLoctionInfo = msg.getLocationInformationQueryInfo(); 415 | String phone = msg.getMsgHeader().getTerminalPhone(); 416 | GpsBaseCdt cdt = new GpsBaseCdt(); 417 | // cdt.setMessageId(TPMSConsts.cmd_position_query_resp); 418 | // cdt.setSimcn(phone); 419 | // cdt.setFlowId(msg.getLocationInformationQueryInfo().getReplyFlowId()); 420 | // List directiveList =(List) gpsBaseSvc.getDirectives(cdt); 421 | // if(directiveList !=null && directiveList.size() >0) { 422 | // Gps指令集 directive = directiveList.get(0); 423 | // directive.set回执时间(DateUtil.date2String(new Date(), "yyyy-MM-dd HH:mm:ss")); 424 | // directive.set消息回执("成功"); 425 | // boolean flag= gpsBaseSvc.updateTheDirective(directive); 426 | // if(!flag) { 427 | // logger.error("终端参数查询指令回执更新失败"); 428 | // } 429 | // } 430 | // cdt = new GpsBaseCdt(); 431 | cdt.setSimcn(phone); 432 | List terminalDeviceList = gpsBaseSvc.getTerminals(cdt); 433 | if (terminalDeviceList == null || terminalDeviceList.size() <= 0) { 434 | logger.error("终端没有找到"); 435 | } else { 436 | Gps实时轨迹 trajectory = setEntity(terminalDeviceList, terminalLoctionInfo, phone); 437 | oid = gpsBusinessSvc.createTheTrajectory(trajectory);// 添加到数据库 438 | } 439 | 440 | if (!StringUtil.isEmpty(oid)) { 441 | return 0; 442 | } else { 443 | return 1; 444 | } 445 | } catch (RemoteException e) { 446 | logger.error(GpsServerConsts.gps_server_business + "连接失败!"); 447 | e.printStackTrace(); 448 | return 1; 449 | } 450 | } 451 | 452 | /** 453 | * 实体类字段进行设置 454 | * 455 | * @return 456 | */ 457 | public Gps实时轨迹 setEntity(List terminalDeviceList, TerminalLoctionInfo terminalLoctionInfo, String phone) 458 | throws AxisFault { 459 | Gps实时轨迹 trajectory = new Gps实时轨迹(); 460 | Gps终端设备 terminalDevice = terminalDeviceList.get(0); 461 | trajectory.set设备id(terminalDevice.getOid()); 462 | trajectory.set设备序列号(terminalDevice.get设备序列号()); 463 | trajectory.setSim卡号(phone); 464 | trajectory.set报警标志(String.valueOf(terminalLoctionInfo.getWarningFlag())); 465 | trajectory.set状态(String.valueOf(terminalLoctionInfo.getStatus())); 466 | trajectory.set高程(terminalLoctionInfo.getAltitude()); 467 | trajectory.set速度(terminalLoctionInfo.getSpeed()); 468 | trajectory.set方向(terminalLoctionInfo.getCourse()); 469 | int longitude = terminalLoctionInfo.getLongitude(); 470 | int latitude = terminalLoctionInfo.getLatitude(); 471 | trajectory.set经度(longitude); 472 | trajectory.set纬度(latitude); 473 | if (longitude != 0 && latitude != 0) { 474 | double lng = longitude / Math.pow(10, 6); 475 | double lan = latitude / Math.pow(10, 6); 476 | String coords = lng + "," + lan; 477 | String message = BaseUtil.getRealJWD(coords, "1", "5"); 478 | if (!message.equals("error")) { 479 | String[] arr = message.split(","); 480 | trajectory.set纠偏经度(Double.valueOf(arr[0])); 481 | trajectory.set纠偏纬度(Double.valueOf(arr[1])); 482 | } 483 | } 484 | 485 | if (!StringUtil.isEmpty(String.valueOf(terminalLoctionInfo.getMileage()))) { 486 | trajectory.set里程(String.valueOf(terminalLoctionInfo.getMileage())); 487 | } 488 | 489 | // 获取到的字符串日期格式化 490 | String time = terminalLoctionInfo.getTime(); 491 | Date date = DateUtil.string2Date(time, "yyMMddHHmmss"); 492 | // SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 493 | // String str=sdf.format(date); 494 | trajectory.set上报时间(date); 495 | trajectory.set系统时间(DateUtil.date2String(new Date(), "yyyy-MM-dd HH:mm:ss")); 496 | return trajectory; 497 | } 498 | 499 | /** 500 | * 501 | * @param terminalPhone 502 | * @return 503 | */ 504 | public boolean changeTerminalLastHeatBeart(String terminalPhone) { 505 | boolean flag = false; 506 | try { 507 | GpsBaseCdt cdt = new GpsBaseCdt(); 508 | cdt.setSimcn(terminalPhone); 509 | List terminalDeviceList = gpsBaseSvc.getTerminals(cdt); 510 | if (terminalDeviceList == null || terminalDeviceList.size() <= 0) { 511 | logger.error("终端没有找到"); 512 | } else { 513 | Gps终端设备 pojo = terminalDeviceList.get(0); 514 | pojo.set最后心跳时间(new Date()); 515 | flag = gpsBaseSvc.updateTheTerminal(pojo); 516 | } 517 | } catch (AxisFault e) { 518 | // TODO Auto-generated catch block 519 | e.printStackTrace(); 520 | } catch (RemoteException e) { 521 | // TODO Auto-generated catch block 522 | e.printStackTrace(); 523 | } 524 | 525 | return flag; 526 | } 527 | 528 | /** 529 | * 清除终端和车辆的绑定关系 530 | */ 531 | public boolean clearReplationBetweenVehicleAndTerminal(String terminalPhone) { 532 | boolean flag = false; 533 | try { 534 | Gps终端设备 terminalDevice = gpsBaseSvc.getTheTerminalByPhone(terminalPhone); 535 | if (terminalDevice == null) { 536 | logger.error("终端没有找到"); 537 | } else { 538 | terminalDevice.set鉴权码(null); 539 | Gps车辆 vehicle = terminalDevice.getVehicle(); 540 | if (vehicle != null) { 541 | vehicle.set设备id(null); 542 | vehicle.set设备序列号(null); 543 | } 544 | flag = gpsBaseSvc.updateTerminalAndVehicle(vehicle, terminalDevice); 545 | } 546 | } catch (AxisFault e) { 547 | // TODO Auto-generated catch block 548 | e.printStackTrace(); 549 | } catch (RemoteException e) { 550 | // TODO Auto-generated catch block 551 | e.printStackTrace(); 552 | } 553 | return flag; 554 | } 555 | 556 | /** 557 | * 更新终端的参数相关的信息 558 | * 559 | * @param msg 560 | * @return 561 | */ 562 | public boolean updateTerminalInfo(TerminalParamQueryMsgResp msg) { 563 | boolean flag = false; 564 | try { 565 | GpsBaseCdt cdt = new GpsBaseCdt(); 566 | // cdt.setMessageId(TPMSConsts.cmd_terminal_param_query); 567 | // cdt.setSimcn(msg.getMsgHeader().getTerminalPhone()); 568 | // cdt.setFlowId(msg.getTerminalParametersqQueryInfo().getReplyFlowId()); 569 | // List directiveList =(List) gpsBaseSvc.getDirectives(cdt); 570 | // if(directiveList !=null && directiveList.size() >0) { 571 | // Gps指令集 directive = directiveList.get(0); 572 | // directive.set回执时间(DateUtil.date2String(new Date(), "yyyy-MM-dd HH:mm:ss")); 573 | // directive.set消息回执("成功"); 574 | // flag= gpsBaseSvc.updateTheDirective(directive); 575 | // if(!flag) { 576 | // logger.error("终端参数查询指令回执更新失败"); 577 | // } 578 | // } 579 | // cdt = new GpsBaseCdt(); 580 | cdt.setSimcn(msg.getMsgHeader().getTerminalPhone()); 581 | List terminalDeviceList = gpsBaseSvc.getTerminals(cdt); 582 | if (terminalDeviceList == null || terminalDeviceList.size() <= 0) { 583 | logger.error("终端没有找到"); 584 | } else { 585 | Gps终端设备 pojo = terminalDeviceList.get(0); 586 | TerminalParametersqQueryInfo info = msg.getTerminalParametersqQueryInfo(); 587 | String heartbeatInterval = String.valueOf(info.getHeartbeatInterval()); 588 | String serverAddress = String.valueOf(info.getServerAddress()); 589 | String serverPort = String.valueOf(info.getServerPort()); 590 | String sleepTimeReportInteval = String.valueOf(info.getSleepTimeReportInteval()); 591 | String defaultTimeReportInteval = String.valueOf(info.getDefaultTimeReportInteval()); 592 | if (!StringUtil.isEmpty(heartbeatInterval)) { 593 | pojo.set终端心跳发送间隔(heartbeatInterval); 594 | } 595 | if (!StringUtil.isEmpty(serverAddress)) { 596 | pojo.set主服务器地址(serverAddress); 597 | } 598 | if (!StringUtil.isEmpty(serverPort)) { 599 | pojo.set服务器TCP端口(serverPort); 600 | } 601 | if (!StringUtil.isEmpty(sleepTimeReportInteval)) { 602 | pojo.set休眠时汇报时间间隔(sleepTimeReportInteval); 603 | } 604 | if (!StringUtil.isEmpty(defaultTimeReportInteval)) { 605 | pojo.set缺省时间汇报间隔(defaultTimeReportInteval); 606 | } 607 | // Gps车辆 vehicle = pojo.getVehicle(); 608 | // if(vehicle!=null) { 609 | // String maxSpeed = String.valueOf(info.getMaxSpeed()); 610 | // if(!StringUtil.isEmpty(maxSpeed)) { 611 | // vehicle.set速度阈值(maxSpeed); 612 | // } 613 | // String overspeedDuration = String.valueOf(info.getOverspeedDuration()); 614 | //// if(!StringUtil.isEmpty(overspeedDuration)) { 615 | //// vehicle.set超速持续时间(overspeedDuration); 616 | //// } 617 | // flag = gpsBaseSvc.updateTerminalAndVehicle(vehicle, pojo); 618 | // }else { 619 | flag = gpsBaseSvc.updateTheTerminal(pojo); 620 | // } 621 | } 622 | } catch (AxisFault e) { 623 | // TODO Auto-generated catch block 624 | e.printStackTrace(); 625 | } catch (RemoteException e) { 626 | // TODO Auto-generated catch block 627 | e.printStackTrace(); 628 | } 629 | 630 | return flag; 631 | } 632 | 633 | /** 634 | * 保存接受到的指令消息 635 | * @param packageData 636 | * add by cheryl 2017-12-15 637 | * @return 638 | */ 639 | public String createTheMessage(PackageData packageData,String type,String messageType,String receiveMsg){ 640 | Gps报文 pojo = new Gps报文(); 641 | String oid = null; 642 | MsgHeader header = packageData.getMsgHeader(); 643 | pojo.setSim卡号(header.getTerminalPhone()); 644 | System.out.println(DateUtil.date2String(new Date(), "yyyy-MM-dd HH:mm:ss")); 645 | pojo.set消息时间(DateUtil.date2String(new Date(), "yyyy-MM-dd HH:mm:ss")); 646 | pojo.set消息类型(messageType); 647 | pojo.set消息id(header.getMsgId()); 648 | pojo.set消息流水号(header.getFlowId()); 649 | //加上消息开始和结束的标识位。 650 | pojo.set消息内容(receiveMsg); 651 | pojo.set状态(type); 652 | // pojo.set备注("消息内容中只包括消息头以及对应的消息体,不包含标识位和对应的校验码"); 653 | try { 654 | oid = gpsBaseSvc.createTheMessage(pojo); 655 | } catch (RemoteException e) { 656 | // TODO Auto-generated catch block 657 | e.printStackTrace(); 658 | logger.info("报文保存失败"); 659 | } 660 | return oid; 661 | } 662 | } 663 | --------------------------------------------------------------------------------