├── .gitignore ├── README.md ├── pom.xml └── src └── main ├── java └── com │ └── jt808 │ ├── client │ ├── MsgSend.java │ ├── MsgSend2.java │ └── ProcessService.java │ ├── common │ ├── MyClassificationLogAppender.java │ ├── TPMSConsts.java │ └── TerminalArgIdEnums.java │ ├── server │ ├── ChannelMap.java │ ├── LoopBuffer.java │ ├── SessionManager.java │ └── TCPServer.java │ ├── service │ ├── BaseMsgProcessService.java │ ├── TerminalMsgProcessService.java │ ├── codec │ │ ├── Decoder.java │ │ ├── Decoder4LoggingOnly.java │ │ ├── Encoder.java │ │ ├── MsgDecoder.java │ │ └── MsgEncoder.java │ └── handler │ │ └── TCPServerHandler.java │ ├── util │ ├── BCD8421Operater.java │ ├── BitOperator.java │ ├── DigitalUtils.java │ ├── HexStringUtils.java │ ├── Img2Base64Util.java │ ├── JT808ProtocolUtils.java │ ├── PhotoUtil.java │ └── TerminalArgUtils.java │ └── vo │ ├── PackageData.java │ ├── Session.java │ ├── req │ ├── CoachLoginMsg.java │ ├── CoachOrStuPhotoMsg.java │ ├── ExtendedTimekeepingTrainingMsg.java │ ├── ForbiddenState.java │ ├── GnssMsg.java │ ├── ImmediatelyTakePicturesMsg.java │ ├── LocationInfoUploadMsg.java │ ├── PhotoUploadDataMsg.java │ ├── PhotoUploadInitializesMsg.java │ ├── PlatformLoginMsg.java │ ├── StudentLoginMsg.java │ ├── StudentLoginOutMsg.java │ ├── TerminalApplyArgMsg.java │ ├── TerminalArgMsg.java │ ├── TerminalAuthenticationMsg.java │ ├── TerminalControlMsg.java │ ├── TerminalRegisterMsg.java │ ├── UpPeriodRecordMsg.java │ └── UpQueryImageMsg.java │ └── resp │ ├── CoachLoginMsgRespBody.java │ ├── QueryTerminalArgRespMsgBody.java │ ├── ServerCommonRespMsgBody.java │ ├── StudentLoginMsgRespBody.java │ ├── TerminalArgMsgRespBody.java │ └── TerminalRegisterMsgRespBody.java └── resources ├── log4j.dtd └── log4j.xml /.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 | # Eclipse Core 16 | .project 17 | 18 | # External tool builders 19 | .externalToolBuilders/ 20 | 21 | # Locally stored "Eclipse launch configurations" 22 | *.launch 23 | 24 | # CDT-specific 25 | .cproject 26 | 27 | # JDT-specific (Eclipse Java Development Tools) 28 | .classpath 29 | 30 | # Java annotation processor (APT) 31 | .factorypath 32 | 33 | # PDT-specific 34 | .buildpath 35 | 36 | # sbteclipse plugin 37 | .target 38 | 39 | # TeXlipse plugin 40 | .texlipse 41 | 42 | 43 | ### JetBrains template 44 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion 45 | 46 | *.iml 47 | 48 | ## Directory-based project format: 49 | .idea/ 50 | # if you remove the above rule, at least ignore the following: 51 | 52 | # User-specific stuff: 53 | # .idea/workspace.xml 54 | # .idea/tasks.xml 55 | # .idea/dictionaries 56 | 57 | # Sensitive or high-churn files: 58 | # .idea/dataSources.ids 59 | # .idea/dataSources.xml 60 | # .idea/sqlDataSources.xml 61 | # .idea/dynamic.xml 62 | # .idea/uiDesigner.xml 63 | 64 | # Gradle: 65 | # .idea/gradle.xml 66 | # .idea/libraries 67 | 68 | # Mongo Explorer plugin: 69 | # .idea/mongoSettings.xml 70 | 71 | ## File-based project format: 72 | *.ipr 73 | *.iws 74 | 75 | ## Plugin-specific files: 76 | 77 | # IntelliJ 78 | /out/ 79 | 80 | # mpeltonen/sbt-idea plugin 81 | .idea_modules/ 82 | 83 | # JIRA plugin 84 | atlassian-ide-plugin.xml 85 | 86 | # Crashlytics plugin (for Android Studio and IntelliJ) 87 | com_crashlytics_export_strings.xml 88 | crashlytics.properties 89 | crashlytics-build.properties 90 | 91 | 92 | ### Java template 93 | *.class 94 | 95 | # Mobile Tools for Java (J2ME) 96 | .mtj.tmp/ 97 | 98 | # Package Files # 99 | *.jar 100 | *.war 101 | *.ear 102 | 103 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 104 | hs_err_pid* 105 | 106 | 107 | /project/project/ 108 | /project/target/ 109 | /project/activator-* 110 | /logs/ 111 | /RUNNING_PID 112 | .DS_Store 113 | /target/ 114 | /workspace/ 115 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jt808-tcp-netty 2 | java 实现部标jt808协议 3 | 4 | 参考:https://blog.csdn.net/hylexus/article/details/54987786 5 | https://github.com/hylexus/jt-808-protocol 6 | -------------------------------------------------------------------------------- /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 | commons-codec 90 | commons-codec 91 | 1.11 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | org.apache.maven.plugins 102 | maven-compiler-plugin 103 | 3.5.1 104 | 105 | 1.8 106 | 1.8 107 | UTF-8 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/client/MsgSend.java: -------------------------------------------------------------------------------- 1 | package com.jt808.client; 2 | 3 | import com.jt808.server.SessionManager; 4 | import com.jt808.vo.Session; 5 | import io.netty.buffer.Unpooled; 6 | import io.netty.channel.Channel; 7 | import io.netty.channel.ChannelFuture; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | /** 12 | * @author :刘洋 13 | * 向终端发送数据,从SessionManager中获取指定终端通道 14 | */ 15 | public class MsgSend { 16 | 17 | private final Logger logger = LoggerFactory.getLogger(getClass()); 18 | private SessionManager sessionManager; 19 | 20 | public MsgSend() { 21 | this.sessionManager = SessionManager.getInstance(); 22 | } 23 | 24 | public String send(byte[] arr, String phone) { 25 | try { 26 | if (phone.length() < 16) { 27 | //手机号码长度补,全统一长度16 28 | phone = String.format("%016d", Long.parseLong(phone)); 29 | } 30 | logger.info("终端手机号:{}", phone); 31 | //跟就终端手机号获取对应的session 32 | Session session = this.sessionManager.findByTerminalPhone(phone); 33 | if(null!=session) { 34 | // Channel channel = ChannelMap.getChannelByName("000000000000123"); 35 | //获取与终端的连接通道 36 | Channel channel = session.getChannel(); 37 | //检查通道是否连通 38 | if (channel.isActive()) { 39 | //发送数据 40 | ChannelFuture future = channel.writeAndFlush(Unpooled.copiedBuffer(arr)).sync(); 41 | if (future.isSuccess()) { 42 | logger.info("发送数据成功:{}", arr); 43 | return "发送数据成功"; 44 | } else { 45 | logger.error("发送数据出错:{}", future.cause()); 46 | return "发送数据出错"; 47 | } 48 | } else { 49 | return "设备不在线"; 50 | } 51 | }else { 52 | return "设备不在线"; 53 | } 54 | } catch (InterruptedException e) { 55 | e.printStackTrace(); 56 | } 57 | return "发送数据成功"; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/client/MsgSend2.java: -------------------------------------------------------------------------------- 1 | package com.jt808.client; 2 | 3 | import com.jt808.server.SessionManager; 4 | import com.jt808.service.codec.Decoder; 5 | import com.jt808.service.codec.Encoder; 6 | import com.jt808.vo.req.PlatformLoginMsg; 7 | import com.jt808.vo.req.PlatformLoginMsg.PlatformLoginInfo; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.io.DataOutputStream; 12 | import java.io.IOException; 13 | import java.io.InputStream; 14 | import java.net.Socket; 15 | 16 | public class MsgSend2 { 17 | private Logger logger = LoggerFactory.getLogger(getClass()); 18 | private Decoder decoder; 19 | private Encoder encoder; 20 | private Socket socket; 21 | private DataOutputStream out; 22 | private InputStream is; 23 | private SessionManager sessionManager; 24 | 25 | 26 | public MsgSend2(int port, String host) throws IOException { 27 | this.decoder = new Decoder(); 28 | this.encoder = new Encoder(); 29 | this.socket = new Socket(host, port); 30 | this.out = new DataOutputStream(this.socket.getOutputStream()); 31 | this.is = this.socket.getInputStream(); 32 | this.sessionManager = SessionManager.getInstance(); 33 | } 34 | 35 | /** 36 | * 平台登录 37 | */ 38 | public void login() { 39 | try { 40 | PlatformLoginInfo info = new PlatformLoginInfo(); 41 | info.setNum("12345"); 42 | info.setPass("12341234"); 43 | info.setCode("123456"); 44 | byte[] bs = this.encoder.encode4Resp(info); 45 | logger.info("发送的数据:{}", bs); 46 | this.out.write(bs); 47 | byte[] data = new byte[1024]; 48 | this.is.read(data); 49 | logger.info("返回数据:{}", data); 50 | PlatformLoginMsg resp = this.decoder.toLoginMsg(data); 51 | int result = resp.getPlatformLoginInfo().getResult(); 52 | switch (result) { 53 | case 0: 54 | logger.info(">>>>>成功<<<<<"); 55 | break; 56 | case 1: 57 | logger.info(">>>>>ip地址不正确<<<<<"); 58 | break; 59 | case 2: 60 | logger.info(">>>>>接入码不正确<<<<<"); 61 | break; 62 | case 3: 63 | logger.info(">>>>>改平台没有注册<<<<<"); 64 | break; 65 | case 4: 66 | logger.info(">>>>>密码错误<<<<<"); 67 | break; 68 | case 5: 69 | logger.info(">>>>>资源紧张,稍后再链接(已占用)<<<<<"); 70 | break; 71 | case 9: 72 | logger.info(">>>>>其他<<<<<"); 73 | break; 74 | default: 75 | break; 76 | } 77 | } catch (Exception e) { 78 | e.printStackTrace(); 79 | } finally { 80 | close(this.socket, this.out, this.is); 81 | } 82 | } 83 | 84 | /** 85 | * 平台登出 86 | */ 87 | public void loginOut() { 88 | try { 89 | PlatformLoginMsg.PlatformLoginInfo info = new PlatformLoginMsg.PlatformLoginInfo(); 90 | info.setNum("12345"); 91 | info.setPass("12341234"); 92 | byte[] bs = this.encoder.encode4OutResp(info); 93 | logger.info("发送的数据:{}", bs); 94 | out.write(bs); 95 | } catch (Exception e) { 96 | e.printStackTrace(); 97 | } finally { 98 | close(this.socket, this.out, this.is); 99 | } 100 | } 101 | 102 | 103 | 104 | 105 | public void close(Socket socket, DataOutputStream out, InputStream is) { 106 | if (is != null) { 107 | try { 108 | is.close(); 109 | } catch (IOException e) { 110 | e.printStackTrace(); 111 | } 112 | } 113 | if (out != null) { 114 | try { 115 | out.close(); 116 | } catch (IOException e) { 117 | e.printStackTrace(); 118 | } 119 | } 120 | if (socket != null) { 121 | try { 122 | socket.close(); 123 | } catch (IOException e) { 124 | e.printStackTrace(); 125 | } 126 | } 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/client/ProcessService.java: -------------------------------------------------------------------------------- 1 | package com.jt808.client; 2 | 3 | import com.jt808.service.codec.Encoder; 4 | import com.jt808.vo.req.ForbiddenState; 5 | import com.jt808.vo.req.ImmediatelyTakePicturesMsg; 6 | import com.jt808.vo.req.TerminalApplyArgMsg; 7 | import com.jt808.vo.req.TerminalArgMsg.TerminalArg; 8 | import com.jt808.vo.req.TerminalArgMsg.TerminalArg.TerminalArgList; 9 | import com.jt808.vo.req.TerminalControlMsg; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import java.util.Date; 14 | import java.util.List; 15 | 16 | /** 17 | * @author :刘洋 18 | * 业务处理:数据组装==>>编码==>>发送==>>处理返回数据 19 | */ 20 | public class ProcessService { 21 | private Logger logger = LoggerFactory.getLogger(getClass()); 22 | private Encoder encoder; 23 | private MsgSend msgSend; 24 | 25 | public ProcessService() { 26 | this.encoder = new Encoder(); 27 | this.msgSend = new MsgSend(); 28 | } 29 | 30 | /** 31 | * 设置终端参数 需要终端参数项列表 ok 32 | * 33 | * @param lists 34 | * @return 35 | */ 36 | public String settingTerminalArg(List lists) { 37 | //lists.size()>10则分包,否则不分包 38 | int len = 10; 39 | String msg = null; 40 | TerminalArg terminalArg = new TerminalArg(); 41 | terminalArg.setArgTotal(lists.size()); 42 | //消息包总数 43 | int msgTotalNum = (int) Math.ceil(lists.size() / 10f); 44 | //包序号 45 | int packageNum = 0; 46 | try { 47 | if (lists.size() > len) { 48 | int listSize = lists.size(); 49 | int toIndex = 10; 50 | for (int i = 0; i < lists.size(); i += 10) { 51 | //作用为toIndex最后没有10条数据则剩余几条newList中就装几条 52 | if (i + 10 > listSize) { 53 | toIndex = listSize - i; 54 | } 55 | List newList = lists.subList(i, i + toIndex); 56 | terminalArg.setArgNum(newList.size()); 57 | terminalArg.setTerminalArgList(newList); 58 | packageNum++; 59 | byte[] bs = this.encoder.encode4TerminalArgResp(terminalArg, msgTotalNum, packageNum); 60 | msg = this.msgSend.send(bs, "000000000000123"); 61 | logger.info("第{}次发送{}", packageNum, msg); 62 | } 63 | } else { 64 | terminalArg.setTerminalArgList(lists); 65 | terminalArg.setArgNum(lists.size()); 66 | byte[] bs = this.encoder.encode4TerminalArgResp(terminalArg, 0, 0); 67 | msg = this.msgSend.send(bs, "000000000000123"); 68 | return msg; 69 | } 70 | } catch (Exception e) { 71 | e.printStackTrace(); 72 | } 73 | return msg; 74 | } 75 | 76 | /** 77 | * 当list为空时 78 | * 封装查寻终端参数 ok 79 | * 当list不为空时 80 | * 封装查询指定终端参数 ok 81 | * 82 | * @param argIdList 83 | */ 84 | public String queryTerminalArg(List argIdList) { 85 | try { 86 | byte[] bs = this.encoder.encode4queryTerminalArgResp(argIdList); 87 | return this.msgSend.send(bs, "000000000000123"); 88 | } catch (Exception e) { 89 | e.printStackTrace(); 90 | } 91 | return null; 92 | } 93 | 94 | /** 95 | * 临时位置跟踪 96 | * 97 | * @param interval 时间间隔 单位 s 98 | * @param validity 有效期 单位 s 99 | */ 100 | public String temporaryPositionTracking(int interval, int validity) { 101 | try { 102 | byte[] bs = this.encoder.encode4TemporaryPositionTrackingResp(interval, validity); 103 | return this.msgSend.send(bs, "000000000000123"); 104 | } catch (Exception e) { 105 | e.printStackTrace(); 106 | } 107 | return null; 108 | } 109 | 110 | /** 111 | * 命令上报学时记录 ok 112 | * 113 | * @param way 查询方式 1:按时间上传 2:按条数上传 114 | * @param startTime 查询起始时间 格式YYMMddHHmmss 115 | * @param endTime 查询终止时间 格式YYMMddHHmmss 116 | * @param num 查询条数 117 | */ 118 | public String upPeriodRecord(int way, Date startTime, Date endTime, int num) { 119 | try { 120 | byte[] bs = this.encoder.encode4UpPeriodRecordResp(way, startTime, endTime, num); 121 | return this.msgSend.send(bs, "000000000000123"); 122 | } catch (Exception e) { 123 | e.printStackTrace(); 124 | } 125 | return null; 126 | } 127 | 128 | /** 129 | * 设置计时终端应用参数 ok 130 | * 131 | * @param terminalApplyArg 132 | * @return 133 | */ 134 | public String setTerminalApplyArg(TerminalApplyArgMsg terminalApplyArg) { 135 | try { 136 | byte[] bs = this.encoder.encode4SetTerminalApplyArgMsg(terminalApplyArg); 137 | return this.msgSend.send(bs, "000000000000123"); 138 | } catch (Exception e) { 139 | e.printStackTrace(); 140 | } 141 | return null; 142 | } 143 | 144 | /** 145 | * 查询计时终端应用参数 ok 146 | * 147 | * @return 148 | */ 149 | public String queryTerminalApplyArg() { 150 | try { 151 | byte[] bs = this.encoder.encode4QueryTerminalApplyArgResp(); 152 | return this.msgSend.send(bs, "000000000000123"); 153 | } catch (Exception e) { 154 | e.printStackTrace(); 155 | } 156 | return null; 157 | } 158 | 159 | /** 160 | * 设置禁训状态 ok 161 | * 162 | * @param forbiddenState 163 | * @return 164 | */ 165 | public String setForbiddenState(ForbiddenState forbiddenState) { 166 | try { 167 | if (forbiddenState.getState() == 1) { 168 | forbiddenState.setMsg("可用"); 169 | } else { 170 | forbiddenState.setMsg("禁用"); 171 | } 172 | forbiddenState.setMsgLen(forbiddenState.getMsg().length()); 173 | byte[] bs = this.encoder.encode4setForbiddenStateMsg(forbiddenState); 174 | return this.msgSend.send(bs, "000000000000123"); 175 | } catch (Exception e) { 176 | e.printStackTrace(); 177 | } 178 | return null; 179 | } 180 | 181 | /** 182 | * 终端控制 183 | * 184 | * @param terminalControlMsg 185 | * @return 186 | */ 187 | public String terminalControl(TerminalControlMsg terminalControlMsg) { 188 | try { 189 | byte[] bs = this.encoder.encode4TerminalControlMsg(terminalControlMsg); 190 | return this.msgSend.send(bs, "000000000000123"); 191 | } catch (Exception e) { 192 | e.printStackTrace(); 193 | } 194 | return null; 195 | } 196 | 197 | /** 198 | * 位置信息查询 ok 199 | * 200 | * @return 201 | */ 202 | public String queryLocation() { 203 | try { 204 | byte[] bs = this.encoder.encode4queryLocation(); 205 | return this.msgSend.send(bs, "000000000000123"); 206 | } catch (Exception e) { 207 | e.printStackTrace(); 208 | } 209 | return null; 210 | } 211 | 212 | /** 213 | * 立即拍照 ok 214 | * @return 215 | */ 216 | public String immediatelyTakePictures(ImmediatelyTakePicturesMsg msg){ 217 | try { 218 | byte[] bs = this.encoder.encode4ImmediatelyTakePictures(msg); 219 | return this.msgSend.send(bs, "000000000000123"); 220 | } catch (Exception e) { 221 | e.printStackTrace(); 222 | } 223 | return null; 224 | } 225 | 226 | /** 227 | * 查询照片 228 | * @param way 查询方式 229 | * @param startTime 查询开始时间 230 | * @param endTime 查询结束时间 231 | * @return 232 | */ 233 | public String queryImage(int way,Date startTime, Date endTime ){ 234 | try { 235 | byte[] bs = this.encoder.encode4QueryImage(way,startTime,endTime); 236 | return this.msgSend.send(bs, "000000000000123"); 237 | } catch (Exception e) { 238 | e.printStackTrace(); 239 | } 240 | return null; 241 | } 242 | 243 | /** 244 | * 上传指定照片消息编码 245 | * @param imgNum 照片编号 246 | * @return 247 | */ 248 | public String upAppointImage(String imgNum){ 249 | try { 250 | byte[] bs = this.encoder.encode4UpAppointImage(imgNum); 251 | return this.msgSend.send(bs, "000000000000123"); 252 | } catch (Exception e) { 253 | e.printStackTrace(); 254 | } 255 | return null; 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/common/MyClassificationLogAppender.java: -------------------------------------------------------------------------------- 1 | package com.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/com/jt808/common/TPMSConsts.java: -------------------------------------------------------------------------------- 1 | package com.jt808.common; 2 | 3 | import java.nio.charset.Charset; 4 | 5 | /** 6 | * 标识位 7 | * 8 | * @author :liuyang 9 | */ 10 | public class TPMSConsts { 11 | 12 | public static final String STRING_ENCODING = "GBK"; 13 | 14 | public static final Charset STRING_CHARSET = Charset.forName(STRING_ENCODING); 15 | /** 16 | * 平台登录 17 | */ 18 | public static final int LOGIN = 0x01f0; 19 | /** 20 | * 平台登录应答 21 | */ 22 | public static final int LOGIN_RESP = 0x81f0; 23 | 24 | /** 25 | * 平台登出 26 | */ 27 | public static final int OUT = 0x01f1; 28 | //======================================================================== 29 | /** 30 | * 标识位 31 | */ 32 | public static final int PKG_DELIMITER = 0x7e; 33 | /** 34 | * 客户端发呆15分钟后,服务器主动断开连接 35 | */ 36 | public static int TCP_CLIENT_IDLE_MINUTES = 30; 37 | /** 38 | * 终端通用应答 39 | */ 40 | public static final int MSG_ID_TERMINAL_COMMON_RESP = 0x0001; 41 | /** 42 | * 终端心跳 43 | */ 44 | public static final int MSG_ID_TERMINAL_HEART_BEAT = 0x0002; 45 | /** 46 | * 终端注册 47 | */ 48 | public static final int MSG_ID_TERMINAL_REGISTER = 0x0100; 49 | /** 50 | * 终端注销 51 | */ 52 | public static final int MSG_ID_TERMINAL_LOG_OUT = 0x0003; 53 | /** 54 | * 终端鉴权 55 | */ 56 | public static final int MSG_ID_TERMINAL_AUTHENTICATION = 0x0102; 57 | /** 58 | * 位置信息汇报 59 | */ 60 | public static final int MSG_ID_TERMINAL_LOCATION_INFO_UPLOAD = 0x0200; 61 | 62 | /** 63 | * 平台通用应答 64 | */ 65 | public static final int CMD_COMMON_RESP = 0x8001; 66 | /** 67 | * 终端注册应答 68 | */ 69 | public static final int CMD_TERMINAL_REGISTER_RESP = 0x8100; 70 | /** 71 | * 设置终端参数 72 | */ 73 | public static final int CMD_TERMINAL_PARAM_SETTINGS = 0X8103; 74 | /** 75 | * 终端控制 76 | */ 77 | public static final int CMD_TERMINAL_CONTROL = 0X8105; 78 | /** 79 | * 位置信息查询 80 | */ 81 | public static final int QUERY_LOCATION_MSG = 0X8201; 82 | /** 83 | * 位置信息查询应答 84 | */ 85 | public static final int QUERY_LOCATION_RESP = 0X0201; 86 | 87 | /** 88 | * 数据下行透传 89 | */ 90 | public static final int DATA_DOWN = 0x8900; 91 | /** 92 | * 数据上行透传 93 | */ 94 | public static final int DATA_UP = 0x0900; 95 | //======================================================================== 96 | //透传消息 97 | //======================================================================== 98 | /** 99 | * 教练员登录 100 | */ 101 | public static final int COACH_LOGIN = 0x0101; 102 | /** 103 | * 教练员登录应答 104 | */ 105 | public static final int COACH_LOGIN_RESP = 0x8101; 106 | /** 107 | * 教练员登出 108 | */ 109 | public static final int COACH_LOGIN_OUT = 0x0102; 110 | /** 111 | * 教练员登出应答 112 | */ 113 | public static final int COACH_LOGIN_OUT_RESP = 0x8102; 114 | /** 115 | * 学员登录 116 | */ 117 | public static final int STU_LOGIN = 0x0201; 118 | /** 119 | * 学员登录应答 120 | */ 121 | public static final int STU_LOGIN_RESP = 0x8201; 122 | /** 123 | * 学员登出 124 | */ 125 | public static final int STU_LOGIN_OUT = 0x0202; 126 | /** 127 | * 学员登出应答 128 | */ 129 | public static final int STU_LOGIN_OUT_RESP = 0x8202; 130 | /** 131 | * 上传学时记录 132 | */ 133 | public static final int UP_PERIOD_RECORD = 0x0203; 134 | /** 135 | * 照片上传初始化 136 | */ 137 | public static final int PHOTO_UPLOAD_INITIALIZES = 0x0305; 138 | /** 139 | * 上传照片数据包 140 | */ 141 | public static final int PHOTO_UPLOAD_DATA = 0x0306; 142 | /** 143 | * 获取教练或学员照片 144 | */ 145 | public static final int COACH_OR_STU_PHOTO = 0x8207; 146 | /** 147 | * 下发教练或学员照片 148 | */ 149 | public static final int COACH_OR_STU_PHOTO_RESP = 0x0207; 150 | /** 151 | * 查询计时终端应用参数应答 152 | */ 153 | public static final int QUERY_TERMINAL_APPLY_ARG = 0x0503; 154 | /** 155 | * 设置计时终端应用参数应答 156 | */ 157 | public static final int SET_TRAINING_APPLY_ARG_RESP = 0x0501; 158 | /** 159 | * 查询终端参数应答 160 | */ 161 | public static final int MSG_ID_TERMINAL_PARAM_QUERY_RESP = 0x0104; 162 | /** 163 | * 设置禁训状态消息应答 164 | */ 165 | public static final int FORBIDDEN_STATE_RESP = 0x0502; 166 | //======================================================================== 167 | /** 168 | * 设置终端参数 169 | */ 170 | public static final int SETTING_TERMINAL_ARG = 0x8103; 171 | /** 172 | * 查询终端参数 173 | */ 174 | public static final int QUERY_TERMINAL_ARG = 0x8104; 175 | /** 176 | * 查询指定终端参数 177 | */ 178 | public static final int QUERY_APPOINT_TERMINAL_ARG = 0x8106; 179 | /** 180 | * 临时位置跟踪控制 181 | */ 182 | public static final int TEMPORARY_POSITION_TRACKING_RESP = 0x8202; 183 | /** 184 | * 命令上报学时记录 185 | */ 186 | public static final int UP_PERIOD_RECORD_RESP = 0x8205; 187 | /** 188 | * 命令上报学时记录应答 189 | */ 190 | public static final int UP_PERIOD_RECORD_ORDER_RESP = 0x0205; 191 | /** 192 | * 立即拍照 193 | */ 194 | public static final int IMMEDIATELY_TAKE_PICTURES = 0x8301; 195 | /** 196 | * 立即拍照应答 197 | */ 198 | public static final int IMMEDIATELY_TAKE_PICTURES_RESP = 0x0301; 199 | /** 200 | * 查询计时终端应用参数 201 | */ 202 | public static final int QUERY_TERMINAL_APPLY_ARG_MSG = 0x8503; 203 | /** 204 | * 设置禁训状态消息 205 | */ 206 | public static final int FORBIDDEN_STATE_MSG = 0x8502; 207 | /** 208 | * 设置计时终端应用参数 209 | */ 210 | public static final int SET_TRAINING_APPLY_ARG_MSG = 0x8501; 211 | /** 212 | * 查询照片 213 | */ 214 | public static final int QUERY_IMAGE = 0x8302; 215 | /** 216 | * 查询照片应答 217 | */ 218 | public static final int QUERY_IMAGE_RESP = 0x0302; 219 | /** 220 | * 上报照片查询结果 221 | */ 222 | public static final int UP_QUERY_IMAGE = 0x0303; 223 | /** 224 | * 上报照片查询结果应答 225 | */ 226 | public static final int UP_QUERY_IMAGE_RESP = 0x8303; 227 | /** 228 | * 上传指定照片 229 | */ 230 | public static final int UP_APPOINT_IMAGE = 0x8304; 231 | /** 232 | * 上传指定照片应答 233 | */ 234 | public static final int UP_APPOINT_IMAGE_RESP = 0x0304; 235 | 236 | 237 | } 238 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/common/TerminalArgIdEnums.java: -------------------------------------------------------------------------------- 1 | package com.jt808.common; 2 | 3 | /** 4 | * @author :刘洋 5 | */ 6 | public enum TerminalArgIdEnums { 7 | /** 8 | * 客户端心跳发送间隔 9 | */ 10 | D_0X0001(0x0001, "int", "客户端心跳发送间隔"), 11 | /** 12 | * TCP消息应答超时时间 13 | */ 14 | D_0X0002(0x0002, "int", "TCP消息应答超时时间"), 15 | /** 16 | * TCP消息重传次数 17 | */ 18 | D_0X0003(0x0003, "int", "TCP消息重传次数"), 19 | /** 20 | * 主服务器地址,ip或域名 21 | */ 22 | D_0X0013(0x0013, "String", "主服务器地址,ip或域名"), 23 | /** 24 | * 服务器TCP端口 25 | */ 26 | D_0X0018(0x0018, "int", "服务器TCP端口"), 27 | /** 28 | * 位置汇报策略:0:定时汇报,1:定距离汇报,2:定时和定距汇报 29 | */ 30 | D_0X0020(0x0020, "int", "位置汇报策略:0:定时汇报,1:定距离汇报,2:定时和定距汇报"), 31 | /** 32 | * 位置汇报方案:0:根据ACC状态,1:根据登录状态和ACC状态 33 | */ 34 | D_0X0021(0x0021, "int", "位置汇报方案:0:根据ACC状态,1:根据登录状态和ACC状态"), 35 | /** 36 | * 驾驶员未登录汇报时间间隔,单位(s) 37 | */ 38 | D_0X0022(0x0022, "int", "驾驶员未登录汇报时间间隔,单位(s)"), 39 | /** 40 | * 紧急报警时汇报时间间隔,单位(s) 41 | */ 42 | D_0X0028(0x0028, "int", "紧急报警时汇报时间间隔,单位(s)"), 43 | /** 44 | * 缺省时间汇报间隔,单位(s) 45 | */ 46 | D_0X0029(0x0029, "int", "缺省时间汇报间隔,单位(s)"), 47 | /** 48 | * 缺省距离汇报间隔,单位(m) 49 | */ 50 | D_0X002C(0x002C, "int", "缺省距离汇报间隔,单位(m)"), 51 | /** 52 | * 驾驶员未登录汇报距离间隔,单位(m) 53 | */ 54 | D_0X002D(0x002D, "int", "驾驶员未登录汇报距离间隔,单位(m)"), 55 | /** 56 | * 休眠时汇报距离间隔,单位(m) 57 | */ 58 | D_0X002E(0x002E, "int", "休眠时汇报距离间隔,单位(m)"), 59 | /** 60 | * 紧急报警时汇报距离间隔,单位(m) 61 | */ 62 | D_0X002F(0x002F, "int", "紧急报警时汇报距离间隔,单位(m)"), 63 | /** 64 | * 最高时速,单位(km/h) 65 | */ 66 | D_0X0055(0x0055, "int", "最高时速,单位(km/h)"), 67 | /** 68 | * 超速持续时间,单位(s) 69 | */ 70 | D_0X0056(0x0056, "int", "超速持续时间,单位(s)"), 71 | ; 72 | private Integer id; 73 | private String type; 74 | private String msg; 75 | 76 | TerminalArgIdEnums(Integer id, String type, String msg) { 77 | this.id = id; 78 | this.type = type; 79 | this.msg = msg; 80 | } 81 | 82 | public static String msg(int id) { 83 | if (D_0X0001.getId() == id) { 84 | return D_0X0001.getMsg(); 85 | } else if (D_0X0002.getId() == id) { 86 | return D_0X0002.getMsg(); 87 | } else if (D_0X0003.getId() == id) { 88 | return D_0X0003.getMsg(); 89 | } else if (D_0X0013.getId() == id) { 90 | return D_0X0013.getMsg(); 91 | } else if (D_0X0018.getId() == id) { 92 | return D_0X0018.getMsg(); 93 | } else if (D_0X0020.getId() == id) { 94 | return D_0X0020.getMsg(); 95 | } else if (D_0X0021.getId() == id) { 96 | return D_0X0021.getMsg(); 97 | } else if (D_0X0022.getId() == id) { 98 | return D_0X0022.getMsg(); 99 | } else if (D_0X0028.getId() == id) { 100 | return D_0X0028.getMsg(); 101 | } else if (D_0X0029.getId() == id) { 102 | return D_0X0029.getMsg(); 103 | } else if (D_0X002C.getId() == id) { 104 | return D_0X002C.getMsg(); 105 | } else if (D_0X002D.getId() == id) { 106 | return D_0X002D.getMsg(); 107 | } else if (D_0X002E.getId() == id) { 108 | return D_0X002E.getMsg(); 109 | } else if (D_0X002F.getId() == id) { 110 | return D_0X002F.getMsg(); 111 | } else if (D_0X0055.getId() == id) { 112 | return D_0X0055.getMsg(); 113 | } else if (D_0X0056.getId() == id) { 114 | return D_0X0056.getMsg(); 115 | } else { 116 | return "未知的参数ID"; 117 | } 118 | } 119 | 120 | public Integer getId() { 121 | return id; 122 | } 123 | 124 | public String getMsg() { 125 | return msg; 126 | } 127 | 128 | public String getType() { 129 | return type; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/server/ChannelMap.java: -------------------------------------------------------------------------------- 1 | package com.jt808.server; 2 | 3 | import io.netty.channel.Channel; 4 | 5 | import java.util.HashMap; 6 | 7 | public class ChannelMap { 8 | 9 | public static int channelNum = 0; 10 | private static HashMap channelHashMap = null;//应改为concurrentHashmap以解决多线程冲突 11 | 12 | public static HashMap getChannelHashMap() { 13 | return channelHashMap; 14 | } 15 | 16 | public static Channel getChannelByName(String name) { 17 | if (channelHashMap == null || channelHashMap.isEmpty()) { 18 | return null; 19 | } 20 | return channelHashMap.get(name); 21 | } 22 | 23 | public static void addChannel(String name, Channel channel) { 24 | if (channelHashMap == null) { 25 | channelHashMap = new HashMap<>(100); 26 | } 27 | channelHashMap.put(name, channel); 28 | channelNum++; 29 | } 30 | 31 | public static int removeChannelByName(String name) { 32 | if (channelHashMap.containsKey(name)) { 33 | channelHashMap.remove(name); 34 | return 0; 35 | } else { 36 | return 1; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/server/LoopBuffer.java: -------------------------------------------------------------------------------- 1 | package com.jt808.server; 2 | 3 | /** 4 | * loopBuffer 5 | */ 6 | public class LoopBuffer { 7 | private static int wp = 0; 8 | private static int rp = 0; 9 | private static int count = 0; 10 | private static int maxlen = 0; 11 | private static byte[] buff; 12 | private static LoopBuffer instance; 13 | 14 | private LoopBuffer() { 15 | } 16 | 17 | public static LoopBuffer getInstance() { 18 | if (instance == null) { 19 | synchronized (LoopBuffer.class) { 20 | if (instance == null) { 21 | instance = new LoopBuffer(1024); 22 | } 23 | } 24 | } 25 | return instance; 26 | } 27 | 28 | private LoopBuffer(int len) { 29 | wp = 0; 30 | rp = 0; 31 | count = 0; 32 | maxlen = len; 33 | buff = new byte[maxlen]; 34 | } 35 | 36 | public void write(byte[] data) { 37 | if (count + data.length > maxlen) 38 | return; 39 | 40 | int rlen = maxlen - wp; 41 | if (rlen > data.length) { 42 | System.arraycopy(data, 0, buff, wp, data.length); 43 | wp += data.length; 44 | if (wp >= maxlen) { 45 | wp %= maxlen; 46 | } 47 | } else { 48 | System.arraycopy(data, 0, buff, wp, rlen); 49 | System.arraycopy(data, rlen, buff, 0, data.length - rlen); 50 | wp = data.length - rlen; 51 | } 52 | count += data.length; 53 | } 54 | 55 | public byte[] read(int readLen) { 56 | if (readLen > count) 57 | readLen = count; 58 | 59 | byte[] rbuf = new byte[readLen]; 60 | int rlen = maxlen - rp; 61 | if (readLen < rlen) { 62 | System.arraycopy(buff, rp, rbuf, 0, readLen); 63 | } else { 64 | int len1 = maxlen - rp; 65 | System.arraycopy(buff, rp, rbuf, 0, len1); 66 | System.arraycopy(buff, 0, rbuf, len1, readLen - len1); 67 | } 68 | 69 | return rbuf; 70 | } 71 | 72 | public int count() { 73 | return count; 74 | } 75 | 76 | public void remove(int len) { 77 | if (len > count) 78 | return; 79 | count -= len; 80 | rp += len; 81 | rp %= maxlen; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/server/SessionManager.java: -------------------------------------------------------------------------------- 1 | package com.jt808.server; 2 | 3 | 4 | import com.jt808.vo.Session; 5 | 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Map.Entry; 9 | import java.util.Set; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | import java.util.function.BiConsumer; 12 | import java.util.stream.Collectors; 13 | 14 | /** 15 | * session管理器 16 | * 17 | * @author :liuyang 18 | */ 19 | public class SessionManager { 20 | 21 | private static volatile SessionManager instance = null; 22 | /** 23 | * netty生成的sessionID和Session的对应关系 24 | */ 25 | private Map sessionIdMap; 26 | /** 27 | * 终端手机号和netty生成的sessionID的对应关系 28 | */ 29 | private Map phoneMap; 30 | 31 | public static SessionManager getInstance() { 32 | if (instance == null) { 33 | synchronized (SessionManager.class) { 34 | if (instance == null) { 35 | instance = new SessionManager(); 36 | } 37 | } 38 | } 39 | return instance; 40 | } 41 | 42 | public SessionManager() { 43 | this.sessionIdMap = new ConcurrentHashMap<>(); 44 | this.phoneMap = new ConcurrentHashMap<>(); 45 | } 46 | 47 | public boolean containsKey(String sessionId) { 48 | return sessionIdMap.containsKey(sessionId); 49 | } 50 | 51 | public boolean containsSession(Session session) { 52 | return sessionIdMap.containsValue(session); 53 | } 54 | 55 | public Session findBySessionId(String id) { 56 | return sessionIdMap.get(id); 57 | } 58 | 59 | public Session findByTerminalPhone(String phone) { 60 | phone = String.format("%016d", Long.parseLong(phone)); 61 | String sessionId = this.phoneMap.get(phone); 62 | if (sessionId == null) 63 | return null; 64 | return this.findBySessionId(sessionId); 65 | } 66 | 67 | public synchronized Session put(String key, Session value) { 68 | if (value.getTerminalPhone() != null && !"".equals(value.getTerminalPhone().trim())) { 69 | String phone = value.getTerminalPhone(); 70 | phone = String.format("%016d", Long.parseLong(phone)); 71 | this.phoneMap.put(phone, value.getId()); 72 | } 73 | return sessionIdMap.put(key, value); 74 | } 75 | 76 | public synchronized Session removeBySessionId(String sessionId) { 77 | if (sessionId == null) { 78 | return null; 79 | } 80 | Session session = sessionIdMap.remove(sessionId); 81 | if (session == null) { 82 | return null; 83 | } 84 | if (session.getTerminalPhone() != null) { 85 | String phone = session.getTerminalPhone(); 86 | phone = String.format("%016d", Long.parseLong(phone)); 87 | this.phoneMap.remove(phone); 88 | } 89 | return session; 90 | } 91 | 92 | 93 | public Set keySet() { 94 | return sessionIdMap.keySet(); 95 | } 96 | 97 | public void forEach(BiConsumer action) { 98 | sessionIdMap.forEach(action); 99 | } 100 | 101 | public Set> entrySet() { 102 | return sessionIdMap.entrySet(); 103 | } 104 | 105 | public List toList() { 106 | return this.sessionIdMap.entrySet().stream().map(e -> e.getValue()).collect(Collectors.toList()); 107 | } 108 | 109 | } -------------------------------------------------------------------------------- /src/main/java/com/jt808/server/TCPServer.java: -------------------------------------------------------------------------------- 1 | package com.jt808.server; 2 | 3 | import com.jt808.common.TPMSConsts; 4 | import com.jt808.service.codec.Decoder4LoggingOnly; 5 | import com.jt808.service.handler.TCPServerHandler; 6 | import io.netty.bootstrap.ServerBootstrap; 7 | import io.netty.buffer.Unpooled; 8 | import io.netty.channel.ChannelFuture; 9 | import io.netty.channel.ChannelInitializer; 10 | import io.netty.channel.ChannelOption; 11 | import io.netty.channel.EventLoopGroup; 12 | import io.netty.channel.nio.NioEventLoopGroup; 13 | import io.netty.channel.socket.SocketChannel; 14 | import io.netty.channel.socket.nio.NioServerSocketChannel; 15 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 16 | import io.netty.handler.timeout.IdleStateHandler; 17 | import io.netty.util.concurrent.Future; 18 | import org.slf4j.Logger; 19 | import org.slf4j.LoggerFactory; 20 | 21 | import java.util.concurrent.TimeUnit; 22 | 23 | /** 24 | * tcp服务 25 | * 26 | * @author :liyang 27 | */ 28 | public class TCPServer { 29 | 30 | private Logger log = LoggerFactory.getLogger(getClass()); 31 | private volatile boolean isRunning = false; 32 | 33 | private EventLoopGroup bossGroup = null; 34 | private EventLoopGroup workerGroup = null; 35 | private int port; 36 | 37 | public TCPServer() { 38 | } 39 | 40 | public TCPServer(int port) { 41 | this(); 42 | this.port = port; 43 | } 44 | 45 | private void bind() throws Exception { 46 | this.bossGroup = new NioEventLoopGroup(); 47 | this.workerGroup = new NioEventLoopGroup(); 48 | ServerBootstrap serverBootstrap = new ServerBootstrap(); 49 | serverBootstrap.group(bossGroup, workerGroup) 50 | .channel(NioServerSocketChannel.class) 51 | .childHandler(new ChannelInitializer() { 52 | @Override 53 | public void initChannel(SocketChannel ch) throws Exception { 54 | ch.pipeline().addLast("idleStateHandler", 55 | new IdleStateHandler(TPMSConsts.TCP_CLIENT_IDLE_MINUTES, 0, 0, TimeUnit.MINUTES)); 56 | ch.pipeline().addLast(new Decoder4LoggingOnly()); 57 | // 1024表示单条消息的最大长度,解码器在查找分隔符的时候,达到该长度还没找到的话会抛异常 58 | ch.pipeline().addLast( 59 | new DelimiterBasedFrameDecoder(1024, Unpooled.copiedBuffer(new byte[]{0x7e}), 60 | Unpooled.copiedBuffer(new byte[]{0x7e, 0x7e}))); 61 | ch.pipeline().addLast(new TCPServerHandler()); 62 | } 63 | }).option(ChannelOption.SO_BACKLOG, 128) 64 | .childOption(ChannelOption.SO_KEEPALIVE, true); 65 | 66 | this.log.info("TCP服务启动完毕,port={}", this.port); 67 | ChannelFuture channelFuture = serverBootstrap.bind(port).sync(); 68 | 69 | channelFuture.channel().closeFuture().sync(); 70 | } 71 | 72 | public synchronized void startServer() { 73 | if (this.isRunning) { 74 | throw new IllegalStateException(this.getName() + " is already started ."); 75 | } 76 | this.isRunning = true; 77 | 78 | new Thread(() -> { 79 | try { 80 | this.bind(); 81 | } catch (Exception e) { 82 | this.log.info("TCP服务启动出错:{}", e.getMessage()); 83 | e.printStackTrace(); 84 | } 85 | }, this.getName()).start(); 86 | } 87 | 88 | public synchronized void stopServer() { 89 | if (!this.isRunning) { 90 | throw new IllegalStateException(this.getName() + " is not yet started ."); 91 | } 92 | this.isRunning = false; 93 | 94 | try { 95 | Future future = this.workerGroup.shutdownGracefully().await(); 96 | if (!future.isSuccess()) { 97 | log.error("workerGroup 无法正常停止:{}", future.cause()); 98 | } 99 | 100 | future = this.bossGroup.shutdownGracefully().await(); 101 | if (!future.isSuccess()) { 102 | log.error("bossGroup 无法正常停止:{}", future.cause()); 103 | } 104 | } catch (InterruptedException e) { 105 | e.printStackTrace(); 106 | } 107 | 108 | this.log.info("TCP服务已经停止..."); 109 | } 110 | 111 | private String getName() { 112 | return "TCP-Server"; 113 | } 114 | 115 | public static void main(String[] args) throws Exception { 116 | TCPServer server = new TCPServer(8879); 117 | server.startServer(); 118 | 119 | // Thread.sleep(3000); 120 | // server.stopServer(); 121 | } 122 | } -------------------------------------------------------------------------------- /src/main/java/com/jt808/service/BaseMsgProcessService.java: -------------------------------------------------------------------------------- 1 | package com.jt808.service; 2 | 3 | import com.jt808.common.TPMSConsts; 4 | import com.jt808.server.SessionManager; 5 | import com.jt808.util.BitOperator; 6 | import com.jt808.util.DigitalUtils; 7 | import com.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 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | import java.util.Arrays; 17 | 18 | /** 19 | * @author :liuyang 20 | */ 21 | public class BaseMsgProcessService { 22 | 23 | protected final Logger log = LoggerFactory.getLogger(getClass()); 24 | 25 | protected SessionManager sessionManager; 26 | private BitOperator bitOperator; 27 | 28 | public BaseMsgProcessService() { 29 | this.sessionManager = SessionManager.getInstance(); 30 | this.bitOperator = new BitOperator(); 31 | } 32 | 33 | protected ByteBuf getByteBuf(byte[] arr) { 34 | ByteBuf byteBuf = PooledByteBufAllocator.DEFAULT.directBuffer(arr.length); 35 | byteBuf.writeBytes(arr); 36 | return byteBuf; 37 | } 38 | public void send2Client(Channel channel, byte[] arr) throws InterruptedException { 39 | byte[] bs = new byte[arr.length-2]; 40 | System.arraycopy(arr,1,bs,0,bs.length); 41 | byte[] tem = this.bitOperator.concatAll(Arrays.asList( 42 | // 0x7e 43 | new byte[]{TPMSConsts.PKG_DELIMITER}, 44 | // 消息头+ 消息体 45 | DigitalUtils.transferMean(bs), 46 | // 0x7e 47 | new byte[]{TPMSConsts.PKG_DELIMITER} 48 | )); 49 | ChannelFuture future = channel.writeAndFlush(Unpooled.copiedBuffer(tem)).sync(); 50 | if (!future.isSuccess()) { 51 | log.error("发送数据出错:{}", future.cause()); 52 | }else { 53 | log.info("发送数据成功:{}",arr); 54 | } 55 | } 56 | 57 | protected int getFlowId(Channel channel, int defaultValue) { 58 | Session session = this.sessionManager.findBySessionId(Session.buildId(channel)); 59 | if (session == null) { 60 | return defaultValue; 61 | } 62 | 63 | return session.currentFlowId(); 64 | } 65 | 66 | protected int getFlowId(Channel channel) { 67 | return this.getFlowId(channel, 0); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/service/TerminalMsgProcessService.java: -------------------------------------------------------------------------------- 1 | package com.jt808.service; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.jt808.server.SessionManager; 5 | import com.jt808.service.codec.MsgEncoder; 6 | import com.jt808.vo.PackageData; 7 | import com.jt808.vo.PackageData.MsgHeader; 8 | import com.jt808.vo.Session; 9 | import com.jt808.vo.req.*; 10 | import com.jt808.vo.resp.CoachLoginMsgRespBody; 11 | import com.jt808.vo.resp.ServerCommonRespMsgBody; 12 | import com.jt808.vo.resp.StudentLoginMsgRespBody; 13 | import com.jt808.vo.resp.TerminalRegisterMsgRespBody; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | /** 21 | * 处理终端消息 22 | * 23 | * @author :刘洋 24 | */ 25 | public class TerminalMsgProcessService extends BaseMsgProcessService { 26 | 27 | private final Logger log = LoggerFactory.getLogger(getClass()); 28 | private MsgEncoder msgEncoder; 29 | private SessionManager sessionManager; 30 | 31 | public TerminalMsgProcessService() { 32 | this.msgEncoder = new MsgEncoder(); 33 | this.sessionManager = SessionManager.getInstance(); 34 | } 35 | 36 | /** 37 | * 终端注册 38 | * @param msg 39 | * @throws Exception 40 | */ 41 | public void processRegisterMsg(TerminalRegisterMsg msg) throws Exception { 42 | log.debug("终端注册:{}", JSON.toJSONString(msg, true)); 43 | 44 | final String sessionId = Session.buildId(msg.getChannel()); 45 | Session session = sessionManager.findBySessionId(sessionId); 46 | if (session == null) { 47 | session = Session.buildSession(msg.getChannel(), msg.getMsgHeader().getTerminalPhone()); 48 | } 49 | session.setAuthenticated(true); 50 | session.setTerminalPhone(msg.getMsgHeader().getTerminalPhone()); 51 | sessionManager.put(session.getId(), session); 52 | String res = "0"; 53 | TerminalRegisterMsgRespBody respMsgBody = new TerminalRegisterMsgRespBody(); 54 | //返回消息 55 | //注册应答 56 | if ("0".equals(res)) { 57 | Map map = new HashMap<>(); 58 | map.put("number", "01");//应答流水号 59 | map.put("platformCode", "12345");//平台编号 60 | map.put("institutionCode", "2000200030004000");//培训机构编号 61 | map.put("deviceCode", "3000200030004000");//计时终端编号 62 | map.put("pwd", "400010002000");//证书口令 63 | map.put("zhengshu", "312312313ffasfafsa");//终端证书 64 | respMsgBody.setReplyCode(TerminalRegisterMsgRespBody.success); 65 | respMsgBody.setReplyFlowId(msg.getMsgHeader().getFlowId()); 66 | respMsgBody.setNum(map.get("platformCode").toString()); 67 | respMsgBody.setDevnum(map.get("deviceCode").toString()); 68 | respMsgBody.setInscode(map.get("institutionCode").toString()); 69 | respMsgBody.setPass(map.get("pwd").toString()); 70 | respMsgBody.setCredential(map.get("zhengshu").toString()); 71 | } else if ("1".equals(res)) { 72 | respMsgBody.setReplyCode(TerminalRegisterMsgRespBody.car_already_registered); 73 | respMsgBody.setReplyFlowId(msg.getMsgHeader().getFlowId()); 74 | } else if ("2".equals(res)) { 75 | respMsgBody.setReplyCode(TerminalRegisterMsgRespBody.car_not_found); 76 | respMsgBody.setReplyFlowId(msg.getMsgHeader().getFlowId()); 77 | } else if ("3".equals(res)) { 78 | respMsgBody.setReplyCode(TerminalRegisterMsgRespBody.terminal_already_registered); 79 | respMsgBody.setReplyFlowId(msg.getMsgHeader().getFlowId()); 80 | } else if ("4".equals(res)) { 81 | respMsgBody.setReplyCode(TerminalRegisterMsgRespBody.terminal_not_found); 82 | respMsgBody.setReplyFlowId(msg.getMsgHeader().getFlowId()); 83 | } 84 | int flowId = super.getFlowId(msg.getChannel()); 85 | byte[] bs = this.msgEncoder.encode4TerminalRegisterResp(msg, respMsgBody, flowId); 86 | super.send2Client(msg.getChannel(), bs); 87 | } 88 | 89 | /** 90 | * 终端鉴权 91 | * @param msg 92 | * @throws Exception 93 | */ 94 | public void processAuthMsg(TerminalAuthenticationMsg msg) throws Exception { 95 | // TODO 暂时每次鉴权都成功 96 | log.debug("终端鉴权:{}", JSON.toJSONString(msg, true)); 97 | final String sessionId = Session.buildId(msg.getChannel()); 98 | Session session = sessionManager.findBySessionId(sessionId); 99 | if (session == null) { 100 | session = Session.buildSession(msg.getChannel(), msg.getMsgHeader().getTerminalPhone()); 101 | } 102 | session.setAuthenticated(true); 103 | session.setTerminalPhone(msg.getMsgHeader().getTerminalPhone()); 104 | sessionManager.put(session.getId(), session); 105 | 106 | ServerCommonRespMsgBody respMsgBody = new ServerCommonRespMsgBody(); 107 | respMsgBody.setReplyCode(ServerCommonRespMsgBody.success); 108 | respMsgBody.setReplyFlowId(msg.getMsgHeader().getFlowId()); 109 | respMsgBody.setReplyId(msg.getMsgHeader().getMsgId()); 110 | int flowId = super.getFlowId(msg.getChannel()); 111 | byte[] bs = this.msgEncoder.encode4ServerCommonRespMsg(msg, respMsgBody, flowId); 112 | super.send2Client(msg.getChannel(), bs); 113 | } 114 | 115 | /** 116 | * 心跳信息 ===>>>回复通用应答 117 | * @param req 118 | * @throws Exception 119 | */ 120 | public void processTerminalHeartBeatMsg(PackageData req) throws Exception { 121 | log.debug("心跳信息:{}", JSON.toJSONString(req, true)); 122 | final MsgHeader reqHeader = req.getMsgHeader(); 123 | ServerCommonRespMsgBody respMsgBody = new ServerCommonRespMsgBody(reqHeader.getFlowId(), reqHeader.getMsgId(), 124 | ServerCommonRespMsgBody.success); 125 | int flowId = super.getFlowId(req.getChannel()); 126 | byte[] bs = this.msgEncoder.encode4ServerCommonRespMsg(req, respMsgBody, flowId); 127 | super.send2Client(req.getChannel(), bs); 128 | } 129 | 130 | /** 131 | * 终端注销 ===>>>回复通用应答 132 | * @param req 133 | * @throws Exception 134 | */ 135 | public void processTerminalLogoutMsg(PackageData req) throws Exception { 136 | log.info("终端注销:{}", JSON.toJSONString(req, true)); 137 | final MsgHeader reqHeader = req.getMsgHeader(); 138 | ServerCommonRespMsgBody respMsgBody = new ServerCommonRespMsgBody(reqHeader.getFlowId(), reqHeader.getMsgId(), 139 | ServerCommonRespMsgBody.success); 140 | int flowId = super.getFlowId(req.getChannel()); 141 | byte[] bs = this.msgEncoder.encode4ServerCommonRespMsg(req, respMsgBody, flowId); 142 | super.send2Client(req.getChannel(), bs); 143 | } 144 | 145 | /** 146 | * 位置信息 ===>>>回复通用应答 147 | * @param req 148 | * @throws Exception 149 | */ 150 | public void processLocationInfoUploadMsg(LocationInfoUploadMsg req) throws Exception { 151 | log.debug("位置 信息:{}", JSON.toJSONString(req, true)); 152 | final MsgHeader reqHeader = req.getMsgHeader(); 153 | ServerCommonRespMsgBody respMsgBody = new ServerCommonRespMsgBody(reqHeader.getFlowId(), reqHeader.getMsgId(), 154 | ServerCommonRespMsgBody.success); 155 | int flowId = super.getFlowId(req.getChannel()); 156 | byte[] bs = this.msgEncoder.encode4ServerCommonRespMsg(req, respMsgBody, flowId); 157 | super.send2Client(req.getChannel(), bs); 158 | } 159 | 160 | /** 161 | * 教练登录 ===>>>> 教练登录应答 162 | * 163 | * @param msg 164 | * @param coachLoginMsg 165 | * @throws Exception 166 | */ 167 | public void coachLoginMsg(ExtendedTimekeepingTrainingMsg msg, CoachLoginMsg coachLoginMsg) throws Exception { 168 | log.debug("教练登录:{}", JSON.toJSONString(coachLoginMsg, true)); 169 | final String sessionId = Session.buildId(msg.getChannel()); 170 | Session session = sessionManager.findBySessionId(sessionId); 171 | if (session == null) { 172 | session = Session.buildSession(msg.getChannel(), msg.getMsgHeader().getTerminalPhone()); 173 | } 174 | session.setAuthenticated(true); 175 | session.setTerminalPhone(msg.getMsgHeader().getTerminalPhone()); 176 | sessionManager.put(session.getId(), session); 177 | //封装应答消息 178 | CoachLoginMsgRespBody respMsgBody = new CoachLoginMsgRespBody(); 179 | respMsgBody.setReplyCode(CoachLoginMsgRespBody.success); 180 | respMsgBody.setCoachnum(coachLoginMsg.getCoachnum()); 181 | if (respMsgBody.getReplyCode() == 2) { 182 | respMsgBody.setIsRead(StudentLoginMsgRespBody.yes_read); 183 | respMsgBody.setMsg("无效的教练员编号"); 184 | respMsgBody.setMsgLen(respMsgBody.getMsg().length()); 185 | } else if (respMsgBody.getReplyCode() == 3) { 186 | respMsgBody.setIsRead(StudentLoginMsgRespBody.yes_read); 187 | respMsgBody.setMsg("准教车型不符"); 188 | respMsgBody.setMsgLen(respMsgBody.getMsg().length()); 189 | } else if (respMsgBody.getReplyCode() == 9) { 190 | respMsgBody.setIsRead(StudentLoginMsgRespBody.yes_read); 191 | respMsgBody.setMsg("其他错误"); 192 | respMsgBody.setMsgLen(respMsgBody.getMsg().length()); 193 | } else { 194 | respMsgBody.setIsRead(StudentLoginMsgRespBody.no_read); 195 | respMsgBody.setMsg(""); 196 | respMsgBody.setMsgLen(respMsgBody.getMsg().length()); 197 | } 198 | byte[] bs = this.msgEncoder.encodeCoachLoginResp(msg, respMsgBody, msg.getMsgHeader().getFlowId()); 199 | super.send2Client(msg.getChannel(), bs); 200 | } 201 | 202 | /** 203 | * 教练登出 ===>>>> 教练登出应答 204 | * 205 | * @param msg 206 | * @param coachLoginMsg 207 | * @throws Exception 208 | */ 209 | public void coachLoginOutMsg(ExtendedTimekeepingTrainingMsg msg, CoachLoginMsg coachLoginMsg) throws Exception { 210 | log.debug("教练登出:{}", JSON.toJSONString(coachLoginMsg, true)); 211 | final String sessionId = Session.buildId(msg.getChannel()); 212 | Session session = sessionManager.findBySessionId(sessionId); 213 | if (session == null) { 214 | session = Session.buildSession(msg.getChannel(), msg.getMsgHeader().getTerminalPhone()); 215 | } 216 | session.setAuthenticated(true); 217 | session.setTerminalPhone(msg.getMsgHeader().getTerminalPhone()); 218 | sessionManager.put(session.getId(), session); 219 | String coachnum = coachLoginMsg.getCoachnum(); 220 | byte[] bs = this.msgEncoder.encodeCoachLoginOutResp(msg, coachnum, msg.getMsgHeader().getFlowId()); 221 | super.send2Client(msg.getChannel(), bs); 222 | 223 | } 224 | 225 | /** 226 | * 学员登录 ===>>>> 学员登录应答 227 | * 228 | * @param msg 229 | * @param studentLoginMsg 230 | * @throws Exception 231 | */ 232 | public void studentLoginMsg(ExtendedTimekeepingTrainingMsg msg, StudentLoginMsg studentLoginMsg) throws Exception { 233 | log.debug("学员登录:{}", JSON.toJSONString(studentLoginMsg, true)); 234 | final String sessionId = Session.buildId(msg.getChannel()); 235 | Session session = sessionManager.findBySessionId(sessionId); 236 | if (session == null) { 237 | session = Session.buildSession(msg.getChannel(), msg.getMsgHeader().getTerminalPhone()); 238 | } 239 | session.setAuthenticated(true); 240 | session.setTerminalPhone(msg.getMsgHeader().getTerminalPhone()); 241 | sessionManager.put(session.getId(), session); 242 | //封装应答消息 243 | StudentLoginMsgRespBody respMsgBody = new StudentLoginMsgRespBody(); 244 | respMsgBody.setReplyCode(StudentLoginMsgRespBody.success); 245 | respMsgBody.setStuhnum(studentLoginMsg.getStunum()); 246 | respMsgBody.setTotalHours(800); 247 | respMsgBody.setFinishHours(600); 248 | respMsgBody.setTotalMileage(100.5f); 249 | respMsgBody.setFinishMileage(80.6f); 250 | if (respMsgBody.getReplyCode() == 2) { 251 | respMsgBody.setIsRead(StudentLoginMsgRespBody.yes_read); 252 | respMsgBody.setMsg("无效的学员编号"); 253 | respMsgBody.setMsgLen(respMsgBody.getMsg().length()); 254 | } else if (respMsgBody.getReplyCode() == 3) { 255 | respMsgBody.setIsRead(StudentLoginMsgRespBody.yes_read); 256 | respMsgBody.setMsg("禁止登录的学员"); 257 | respMsgBody.setMsgLen(respMsgBody.getMsg().length()); 258 | } else if (respMsgBody.getReplyCode() == 4) { 259 | respMsgBody.setIsRead(StudentLoginMsgRespBody.yes_read); 260 | respMsgBody.setMsg("区域外教学提醒"); 261 | respMsgBody.setMsgLen(respMsgBody.getMsg().length()); 262 | } else if (respMsgBody.getReplyCode() == 5) { 263 | respMsgBody.setIsRead(StudentLoginMsgRespBody.yes_read); 264 | respMsgBody.setMsg("准教车型与培训车型不符"); 265 | respMsgBody.setMsgLen(respMsgBody.getMsg().length()); 266 | } else if (respMsgBody.getReplyCode() == 9) { 267 | respMsgBody.setIsRead(StudentLoginMsgRespBody.yes_read); 268 | respMsgBody.setMsg("其他错误"); 269 | respMsgBody.setMsgLen(respMsgBody.getMsg().length()); 270 | } else { 271 | respMsgBody.setIsRead(StudentLoginMsgRespBody.no_read); 272 | respMsgBody.setMsg(""); 273 | respMsgBody.setMsgLen(respMsgBody.getMsg().length()); 274 | } 275 | byte[] bs = this.msgEncoder.encodeStuLoginResp(msg, respMsgBody, msg.getMsgHeader().getFlowId()); 276 | super.send2Client(msg.getChannel(), bs); 277 | } 278 | 279 | /** 280 | * 学员登出 ===>>>> 学员登出应答 281 | * 282 | * @param msg 283 | * @param studentLoginMsg 284 | * @throws Exception 285 | */ 286 | public void studentLoginOutMsg(ExtendedTimekeepingTrainingMsg msg, StudentLoginOutMsg studentLoginMsg) throws Exception { 287 | log.debug("学员登出:{}", JSON.toJSONString(studentLoginMsg, true)); 288 | final String sessionId = Session.buildId(msg.getChannel()); 289 | Session session = sessionManager.findBySessionId(sessionId); 290 | if (session == null) { 291 | session = Session.buildSession(msg.getChannel(), msg.getMsgHeader().getTerminalPhone()); 292 | } 293 | session.setAuthenticated(true); 294 | session.setTerminalPhone(msg.getMsgHeader().getTerminalPhone()); 295 | sessionManager.put(session.getId(), session); 296 | String stunum = studentLoginMsg.getStunum(); 297 | byte[] bs = this.msgEncoder.encodeStuLoginOutResp(msg, stunum, msg.getMsgHeader().getFlowId()); 298 | super.send2Client(msg.getChannel(), bs); 299 | } 300 | 301 | /** 302 | * 上报学时记录 =====>>>>> 通用应答 303 | * @param msg 304 | * @param upPeriodRecordMsg 305 | * @throws Exception 306 | */ 307 | public void upPeriodRecordMsg(ExtendedTimekeepingTrainingMsg msg, UpPeriodRecordMsg upPeriodRecordMsg) throws Exception{ 308 | final String sessionId = Session.buildId(msg.getChannel()); 309 | Session session = sessionManager.findBySessionId(sessionId); 310 | if (session == null) { 311 | session = Session.buildSession(msg.getChannel(), msg.getMsgHeader().getTerminalPhone()); 312 | } 313 | session.setAuthenticated(true); 314 | session.setTerminalPhone(msg.getMsgHeader().getTerminalPhone()); 315 | sessionManager.put(session.getId(), session); 316 | final MsgHeader reqHeader = msg.getMsgHeader(); 317 | ServerCommonRespMsgBody respMsgBody = new ServerCommonRespMsgBody(reqHeader.getFlowId(), reqHeader.getMsgId(), 318 | ServerCommonRespMsgBody.success); 319 | int flowId = super.getFlowId(msg.getChannel()); 320 | byte[] bs = this.msgEncoder.encode4ServerCommonRespMsg(msg, respMsgBody, flowId); 321 | super.send2Client(msg.getChannel(), bs); 322 | } 323 | 324 | /** 325 | * 照片上传初始化 326 | * @param msg 327 | * @param photoUploadInitializesMsg 328 | * @throws Exception 329 | */ 330 | public void photoUploadInitializesMsg(ExtendedTimekeepingTrainingMsg msg, PhotoUploadInitializesMsg photoUploadInitializesMsg) throws Exception{ 331 | log.debug("照片上传初始化:{}", JSON.toJSONString(photoUploadInitializesMsg, true)); 332 | final String sessionId = Session.buildId(msg.getChannel()); 333 | Session session = sessionManager.findBySessionId(sessionId); 334 | if (session == null) { 335 | session = Session.buildSession(msg.getChannel(), msg.getMsgHeader().getTerminalPhone()); 336 | } 337 | session.setAuthenticated(true); 338 | session.setTerminalPhone(msg.getMsgHeader().getTerminalPhone()); 339 | sessionManager.put(session.getId(), session); 340 | int code = 0; 341 | byte[] bs = this.msgEncoder.encodePhotoUploadInitializesResp(msg, code, msg.getMsgHeader().getFlowId()); 342 | super.send2Client(msg.getChannel(), bs); 343 | } 344 | 345 | /** 346 | * 上传照片数据包 347 | * @param msg 348 | * @param photoUploadDataMsg 349 | * @throws Exception 350 | */ 351 | public void photoUploadDataMsg(ExtendedTimekeepingTrainingMsg msg, PhotoUploadDataMsg photoUploadDataMsg)throws Exception { 352 | final String sessionId = Session.buildId(msg.getChannel()); 353 | Session session = sessionManager.findBySessionId(sessionId); 354 | if (session == null) { 355 | session = Session.buildSession(msg.getChannel(), msg.getMsgHeader().getTerminalPhone()); 356 | } 357 | session.setAuthenticated(true); 358 | session.setTerminalPhone(msg.getMsgHeader().getTerminalPhone()); 359 | sessionManager.put(session.getId(), session); 360 | //通用应答 361 | final MsgHeader reqHeader = msg.getMsgHeader(); 362 | ServerCommonRespMsgBody respMsgBody = new ServerCommonRespMsgBody(reqHeader.getFlowId(), reqHeader.getMsgId(), 363 | ServerCommonRespMsgBody.success); 364 | int flowId = super.getFlowId(msg.getChannel()); 365 | byte[] bs = this.msgEncoder.encode4ServerCommonRespMsg(msg, respMsgBody, flowId); 366 | super.send2Client(msg.getChannel(), bs); 367 | } 368 | 369 | /** 370 | * 上报照片查询结果应答 371 | * @param msg 372 | * @param upQueryImageMsg 373 | * @throws Exception 374 | */ 375 | public void upQueryImageMsg(ExtendedTimekeepingTrainingMsg msg, UpQueryImageMsg upQueryImageMsg) throws Exception{ 376 | final String sessionId = Session.buildId(msg.getChannel()); 377 | Session session = sessionManager.findBySessionId(sessionId); 378 | if (session == null) { 379 | session = Session.buildSession(msg.getChannel(), msg.getMsgHeader().getTerminalPhone()); 380 | } 381 | session.setAuthenticated(true); 382 | session.setTerminalPhone(msg.getMsgHeader().getTerminalPhone()); 383 | sessionManager.put(session.getId(), session); 384 | int code = upQueryImageMsg.getReplyCode(); 385 | byte[] bs = this.msgEncoder.encodeUpQueryImageResp(msg, code, msg.getMsgHeader().getFlowId()); 386 | super.send2Client(msg.getChannel(), bs); 387 | } 388 | /** 389 | * 获取教练或学员照片 === 应答 390 | * @param msg 391 | * @param data 392 | * @throws Exception 393 | */ 394 | public void coachOrStuPhotoMsg(ExtendedTimekeepingTrainingMsg msg, byte[] data) throws Exception{ 395 | final String sessionId = Session.buildId(msg.getChannel()); 396 | Session session = sessionManager.findBySessionId(sessionId); 397 | if (session == null) { 398 | session = Session.buildSession(msg.getChannel(), msg.getMsgHeader().getTerminalPhone()); 399 | } 400 | session.setAuthenticated(true); 401 | session.setTerminalPhone(msg.getMsgHeader().getTerminalPhone()); 402 | sessionManager.put(session.getId(), session); 403 | //消息包总数 404 | int msgTotalNum = (int) Math.ceil(data.length / 768f); 405 | //包序号 406 | int packageNum = 0; 407 | int len =768; 408 | if(data.length>768){ 409 | for(int i=0;idata.length){ 413 | len = data.length-(i*768); 414 | } 415 | byte[] tem = new byte[len]; 416 | System.arraycopy(data,i*768,tem,0,tem.length); 417 | byte[] bs = this.msgEncoder.encodeCoachOrStuPhotoResp(msg, msgTotalNum,packageNum,tem.length,tem, msg.getMsgHeader().getFlowId()); 418 | super.send2Client(msg.getChannel(), bs); 419 | } 420 | }else { 421 | byte[] bs = this.msgEncoder.encodeCoachOrStuPhotoResp(msg, 0,0,data.length,data, msg.getMsgHeader().getFlowId()); 422 | super.send2Client(msg.getChannel(), bs); 423 | } 424 | 425 | } 426 | } 427 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/service/codec/Decoder.java: -------------------------------------------------------------------------------- 1 | package com.jt808.service.codec; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.jt808.common.TPMSConsts; 5 | import com.jt808.util.BCD8421Operater; 6 | import com.jt808.util.BitOperator; 7 | import com.jt808.vo.PackageData; 8 | import com.jt808.vo.req.PlatformLoginMsg; 9 | import com.jt808.vo.resp.TerminalArgMsgRespBody; 10 | import com.jt808.vo.resp.TerminalArgMsgRespBody.TerminalArgMsg; 11 | import com.jt808.vo.resp.TerminalArgMsgRespBody.TerminalArgMsg.TerminalArgList; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | /** 16 | * 客户端消息解码器 17 | */ 18 | public class Decoder { 19 | private static final Logger log = LoggerFactory.getLogger(MsgDecoder.class); 20 | 21 | private BitOperator bitOperator; 22 | private BCD8421Operater bcd8421Operater; 23 | 24 | public Decoder() { 25 | this.bitOperator = new BitOperator(); 26 | this.bcd8421Operater = new BCD8421Operater(); 27 | } 28 | 29 | /** 30 | * 数据包 31 | * 32 | * @param data 33 | * @return PackageData 34 | */ 35 | public PackageData bytes2PackageData(byte[] data) { 36 | PackageData ret = new PackageData(); 37 | // 1. 16byte 或 20byte 消息头 38 | PackageData.MsgHeader msgHeader = this.parseMsgHeaderFromBytes(data); 39 | ret.setMsgHeader(msgHeader); 40 | 41 | int msgBodyByteStartIndex = 16; 42 | // 2. 消息体 43 | // 有子包信息,消息体起始字节后移四个字节:消息包总数(word(16))+包序号(word(16)) 44 | if (msgHeader.isHasSubPackage()) { 45 | msgBodyByteStartIndex = 20; 46 | } 47 | byte[] tmp = new byte[msgHeader.getMsgBodyLength()]; 48 | System.arraycopy(data, msgBodyByteStartIndex, tmp, 0, tmp.length); 49 | ret.setMsgBodyBytes(tmp); 50 | 51 | // 3. 去掉分隔符之后,最后一位就是校验码 52 | int checkSumInPkg = data[data.length - 1]; 53 | int calculatedCheckSum = this.bitOperator.getCheckSum4JT808(data, 0, data.length - 1); 54 | ret.setCheckSum(checkSumInPkg); 55 | if (checkSumInPkg != calculatedCheckSum) { 56 | log.warn("检验码不一致,msgid:{},pkg:{},calculated:{}", msgHeader.getMsgId(), checkSumInPkg, calculatedCheckSum); 57 | } 58 | return ret; 59 | } 60 | 61 | /** 62 | * 消息头 63 | * 64 | * @param data 65 | * @return 66 | */ 67 | private PackageData.MsgHeader parseMsgHeaderFromBytes(byte[] data) { 68 | PackageData.MsgHeader msgHeader = new PackageData.MsgHeader(); 69 | 70 | // 1. 消息ID word(16) 71 | msgHeader.setMsgId(this.parseIntFromBytes(data, 1, 2)); 72 | // 2. 消息体属性 word(16)=================> 73 | int msgBodyProps = this.parseIntFromBytes(data, 3, 2); 74 | msgHeader.setMsgBodyPropsField(msgBodyProps); 75 | // [ 0-9 ] 0000,0011,1111,1111(3FF)(消息体长度) 76 | msgHeader.setMsgBodyLength(msgBodyProps & 0x3ff); 77 | // [10-12] 0001,1100,0000,0000(1C00)(加密类型) 78 | msgHeader.setEncryptionType((msgBodyProps & 0x1c00) >> 10); 79 | // [ 13_ ] 0010,0000,0000,0000(2000)(是否有子包) 80 | msgHeader.setHasSubPackage(((msgBodyProps & 0x2000) >> 13) == 1); 81 | // [14-15] 1100,0000,0000,0000(C000)(保留位) 82 | msgHeader.setReservedBit(((msgBodyProps & 0xc000) >> 14) + ""); 83 | // 消息体属性 word(16)<================= 84 | // 3. 终端手机号 bcd[6] 85 | msgHeader.setTerminalPhone(this.parseBcdStringFromBytes(data, 5, 8)); 86 | // 4. 消息流水号 word(16) 按发送顺序从 0 开始循环累加 87 | msgHeader.setFlowId(this.parseIntFromBytes(data, 13, 2)); 88 | // 5. 消息包封装项 89 | // 有子包信息 90 | if (msgHeader.isHasSubPackage()) { 91 | // 消息包封装项字段 92 | msgHeader.setPackageInfoField(this.parseIntFromBytes(data, 16, 4)); 93 | // byte[0-1] 消息包总数(word(16)) 94 | msgHeader.setTotalSubPackage(this.parseIntFromBytes(data, 16, 2)); 95 | // byte[2-3] 包序号(word(16)) 从 1 开始 96 | msgHeader.setSubPackageSeq(this.parseIntFromBytes(data, 18, 2)); 97 | } 98 | return msgHeader; 99 | } 100 | 101 | protected String parseStringFromBytes(byte[] data, int startIndex, int lenth) { 102 | return this.parseStringFromBytes(data, startIndex, lenth, null); 103 | } 104 | 105 | private String parseStringFromBytes(byte[] data, int startIndex, int lenth, String defaultVal) { 106 | try { 107 | byte[] tmp = new byte[lenth]; 108 | System.arraycopy(data, startIndex, tmp, 0, lenth); 109 | return new String(tmp, TPMSConsts.STRING_CHARSET); 110 | } catch (Exception e) { 111 | log.error("解析字符串出错:{}", e.getMessage()); 112 | e.printStackTrace(); 113 | return defaultVal; 114 | } 115 | } 116 | 117 | private String parseBcdStringFromBytes(byte[] data, int startIndex, int lenth) { 118 | return this.parseBcdStringFromBytes(data, startIndex, lenth, null); 119 | } 120 | 121 | private String parseBcdStringFromBytes(byte[] data, int startIndex, int lenth, String defaultVal) { 122 | try { 123 | byte[] tmp = new byte[lenth]; 124 | System.arraycopy(data, startIndex, tmp, 0, lenth); 125 | return this.bcd8421Operater.bcd2String(tmp); 126 | } catch (Exception e) { 127 | log.error("解析BCD(8421码)出错:{}", e.getMessage()); 128 | e.printStackTrace(); 129 | return defaultVal; 130 | } 131 | } 132 | 133 | private int parseIntFromBytes(byte[] data, int startIndex, int length) { 134 | return this.parseIntFromBytes(data, startIndex, length, 0); 135 | } 136 | 137 | private int parseIntFromBytes(byte[] data, int startIndex, int length, int defaultVal) { 138 | try { 139 | // 字节数大于4,从起始索引开始向后处理4个字节,其余超出部分丢弃 140 | final int len = length > 4 ? 4 : length; 141 | byte[] tmp = new byte[len]; 142 | System.arraycopy(data, startIndex, tmp, 0, len); 143 | return bitOperator.byteToInteger(tmp); 144 | } catch (Exception e) { 145 | log.error("解析整数出错:{}", e.getMessage()); 146 | e.printStackTrace(); 147 | return defaultVal; 148 | } 149 | } 150 | 151 | /** 152 | * 终端注册消息应答 153 | * 154 | * @param bs 155 | * @return 156 | */ 157 | public PlatformLoginMsg toLoginMsg(byte[] bs) { 158 | PackageData packageData = this.bytes2PackageData(bs); 159 | PlatformLoginMsg ret = new PlatformLoginMsg(packageData); 160 | PlatformLoginMsg.PlatformLoginInfo body = new PlatformLoginMsg.PlatformLoginInfo(); 161 | byte[] data = ret.getMsgBodyBytes(); 162 | log.debug("注册应答:{}", JSON.toJSONString(data, true)); 163 | body.setResult(this.parseIntFromBytes(data, 0, 1)); 164 | ret.setPlatformLoginInfo(body); 165 | return ret; 166 | } 167 | 168 | /** 169 | * 查询终端参数应答 170 | * @param bs 171 | * @return 172 | */ 173 | public TerminalArgMsgRespBody toTerminalArgMsg(byte[] bs) { 174 | PackageData packageData = this.bytes2PackageData(bs); 175 | TerminalArgMsgRespBody ret = new TerminalArgMsgRespBody(packageData); 176 | byte[] data = ret.getMsgBodyBytes(); 177 | TerminalArgMsg body = new TerminalArgMsg(); 178 | TerminalArgList terminalArgList = new TerminalArgList(); 179 | //应答流水号 180 | body.setReplyFlowId(this.parseIntFromBytes(data,0,2)); 181 | //应答参数个数 182 | body.setArgNum(this.parseIntFromBytes(data,2,1)); 183 | //包参数个数 184 | body.setPakNum(this.parseIntFromBytes(data,3,1)); 185 | //参数列表项 186 | //参数id 187 | terminalArgList.setArgId(this.parseIntFromBytes(data,4,4)); 188 | terminalArgList.setArgLen(this.parseIntFromBytes(data,8,1)); 189 | terminalArgList.setArg(this.parseStringFromBytes(data,9,data.length-9)); 190 | body.setTerminalArgList(terminalArgList); 191 | ret.setTerminalArgMsg(body); 192 | return ret; 193 | } 194 | 195 | /** 196 | * 命令上报学时记录应答消息 197 | * @param bs 198 | * @return 199 | */ 200 | public Integer toUpPeriodRecordMsg(byte[] bs) { 201 | PackageData packageData = this.bytes2PackageData(bs); 202 | byte[] data = packageData.getMsgBodyBytes(); 203 | return this.parseIntFromBytes(data,0,1); 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/service/codec/Decoder4LoggingOnly.java: -------------------------------------------------------------------------------- 1 | package com.jt808.service.codec; 2 | 3 | import com.jt808.util.HexStringUtils; 4 | import io.netty.buffer.ByteBuf; 5 | import io.netty.buffer.Unpooled; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.handler.codec.ByteToMessageDecoder; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * 该解码器只是为了自己日志所用,没其他作用.
15 | * 最终删除 16 | * 17 | * @author hylexus 18 | * 19 | */ 20 | public class Decoder4LoggingOnly extends ByteToMessageDecoder { 21 | 22 | private final Logger log = LoggerFactory.getLogger(getClass()); 23 | private final Logger weblog = LoggerFactory.getLogger("weblog"); 24 | 25 | @Override 26 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { 27 | String hex = buf2Str(in); 28 | log.info("ip={},hex = {}", ctx.channel().remoteAddress(), hex); 29 | weblog.info("ip={},hex = {}", ctx.channel().remoteAddress(), hex); 30 | 31 | ByteBuf buf = Unpooled.buffer(); 32 | while (in.isReadable()) { 33 | buf.writeByte(in.readByte()); 34 | } 35 | out.add(buf); 36 | } 37 | 38 | private String buf2Str(ByteBuf in) { 39 | byte[] dst = new byte[in.readableBytes()]; 40 | in.getBytes(0, dst); 41 | return HexStringUtils.toHexString(dst); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/util/BCD8421Operater.java: -------------------------------------------------------------------------------- 1 | package com.jt808.util; 2 | 3 | public class BCD8421Operater { 4 | 5 | /** 6 | * BCD字节数组===>String 7 | * 8 | * @param bytes 9 | * @return 十进制字符串 10 | */ 11 | public String bcd2String(byte[] bytes) { 12 | StringBuilder temp = new StringBuilder(bytes.length * 2); 13 | for (int i = 0; i < bytes.length; i++) { 14 | // 高四位 15 | temp.append((bytes[i] & 0xf0) >>> 4); 16 | // 低四位 17 | temp.append(bytes[i] & 0x0f); 18 | } 19 | return temp.toString().substring(0, 1).equalsIgnoreCase("0") ? temp.toString().substring(1) : temp.toString(); 20 | } 21 | 22 | /** 23 | * 字符串==>BCD字节数组 24 | * 25 | * @param str 26 | * @return BCD字节数组 27 | */ 28 | public byte[] string2Bcd(String str) { 29 | // 奇数,前补零 30 | if ((str.length() & 0x1) == 1) { 31 | str = "0" + str; 32 | } 33 | 34 | byte ret[] = new byte[str.length() / 2]; 35 | byte bs[] = str.getBytes(); 36 | for (int i = 0; i < ret.length; i++) { 37 | byte high = ascII2Bcd(bs[2 * i]); 38 | byte low = ascII2Bcd(bs[2 * i + 1]); 39 | // TODO 只遮罩BCD低四位? 40 | ret[i] = (byte) ((high << 4) | low); 41 | System.out.print(ret[i]+","); 42 | } 43 | return ret; 44 | } 45 | /** 46 | * 字符串==>BCD字节数组 47 | * 48 | * @param hex 49 | * @return BCD字节数组 50 | */ 51 | public byte[] hexStringToByte(String hex) { 52 | // 奇数,前补零 53 | if ((hex.length() & 0x1) == 1) { 54 | hex = "0" + hex; 55 | } 56 | int len = (hex.length() / 2); 57 | byte[] result = new byte[len]; 58 | char[] achar = hex.toCharArray(); 59 | for (int i = 0; i < len; i++) { 60 | int pos = i * 2; 61 | result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1])); 62 | } 63 | return result; 64 | } 65 | private int toByte(char c) { 66 | byte b = (byte) "0123456789ABCDEF".indexOf(c); 67 | return b; 68 | } 69 | 70 | 71 | private byte ascII2Bcd(byte asc) { 72 | if ((asc >= '0') && (asc <= '9')) 73 | return (byte) (asc - '0'); 74 | else if ((asc >= 'A') && (asc <= 'F')) 75 | return (byte) (asc - 'A' + 10); 76 | else if ((asc >= 'a') && (asc <= 'f')) 77 | return (byte) (asc - 'a' + 10); 78 | else 79 | return (byte) (asc - 48); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/util/BitOperator.java: -------------------------------------------------------------------------------- 1 | package com.jt808.util; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | public class BitOperator { 7 | 8 | /** 9 | * 把一个整形该为byte 10 | * 11 | * @param value 12 | * @return 13 | * @throws Exception 14 | */ 15 | public byte integerTo1Byte(int value) { 16 | return (byte) (value & 0xFF); 17 | } 18 | 19 | /** 20 | * 把一个整形该为1位的byte数组 21 | * 22 | * @param value 23 | * @return 24 | * @throws Exception 25 | */ 26 | public byte[] integerTo1Bytes(int value) { 27 | byte[] result = new byte[1]; 28 | result[0] = (byte) (value & 0xFF); 29 | return result; 30 | } 31 | 32 | /** 33 | * 把一个整形改为2位的byte数组 34 | * 35 | * @param value 36 | * @return 37 | * @throws Exception 38 | */ 39 | public byte[] integerTo2Bytes(int value) { 40 | byte[] result = new byte[2]; 41 | result[0] = (byte) ((value >>> 8) & 0xFF); 42 | result[1] = (byte) (value & 0xFF); 43 | return result; 44 | } 45 | 46 | /** 47 | * 把一个整形改为3位的byte数组 48 | * 49 | * @param value 50 | * @return 51 | * @throws Exception 52 | */ 53 | public byte[] integerTo3Bytes(int value) { 54 | byte[] result = new byte[3]; 55 | result[0] = (byte) ((value >>> 16) & 0xFF); 56 | result[1] = (byte) ((value >>> 8) & 0xFF); 57 | result[2] = (byte) (value & 0xFF); 58 | return result; 59 | } 60 | 61 | /** 62 | * 把一个整形改为4位的byte数组 63 | * 64 | * @param value 65 | * @return 66 | * @throws Exception 67 | */ 68 | public byte[] integerTo4Bytes(int value){ 69 | byte[] result = new byte[4]; 70 | result[0] = (byte) ((value >>> 24) & 0xFF); 71 | result[1] = (byte) ((value >>> 16) & 0xFF); 72 | result[2] = (byte) ((value >>> 8) & 0xFF); 73 | result[3] = (byte) (value & 0xFF); 74 | return result; 75 | } 76 | 77 | /** 78 | * 把byte[]转化位整形,通常为指令用 79 | * 80 | * @param value 81 | * @return 82 | * @throws Exception 83 | */ 84 | public int byteToInteger(byte[] value) { 85 | int result; 86 | if (value.length == 1) { 87 | result = oneByteToInteger(value[0]); 88 | } else if (value.length == 2) { 89 | result = twoBytesToInteger(value); 90 | } else if (value.length == 3) { 91 | result = threeBytesToInteger(value); 92 | } else if (value.length == 4) { 93 | result = fourBytesToInteger(value); 94 | } else { 95 | result = fourBytesToInteger(value); 96 | } 97 | return result; 98 | } 99 | 100 | /** 101 | * 把一个byte转化位整形,通常为指令用 102 | * 103 | * @param value 104 | * @return 105 | * @throws Exception 106 | */ 107 | public int oneByteToInteger(byte value) { 108 | return (int) value & 0xFF; 109 | } 110 | 111 | /** 112 | * 把一个2位的数组转化位整形 113 | * 114 | * @param value 115 | * @return 116 | * @throws Exception 117 | */ 118 | public int twoBytesToInteger(byte[] value) { 119 | // if (value.length < 2) { 120 | // throw new Exception("Byte array too short!"); 121 | // } 122 | int temp0 = value[0] & 0xFF; 123 | int temp1 = value[1] & 0xFF; 124 | return ((temp0 << 8) + temp1); 125 | } 126 | 127 | /** 128 | * 把一个3位的数组转化位整形 129 | * 130 | * @param value 131 | * @return 132 | * @throws Exception 133 | */ 134 | public int threeBytesToInteger(byte[] value) { 135 | int temp0 = value[0] & 0xFF; 136 | int temp1 = value[1] & 0xFF; 137 | int temp2 = value[2] & 0xFF; 138 | return ((temp0 << 16) + (temp1 << 8) + temp2); 139 | } 140 | 141 | /** 142 | * 把一个4位的数组转化位整形,通常为指令用 143 | * 144 | * @param value 145 | * @return 146 | * @throws Exception 147 | */ 148 | public int fourBytesToInteger(byte[] value) { 149 | // if (value.length < 4) { 150 | // throw new Exception("Byte array too short!"); 151 | // } 152 | int temp0 = value[0] & 0xFF; 153 | int temp1 = value[1] & 0xFF; 154 | int temp2 = value[2] & 0xFF; 155 | int temp3 = value[3] & 0xFF; 156 | return ((temp0 << 24) + (temp1 << 16) + (temp2 << 8) + temp3); 157 | } 158 | 159 | /** 160 | * 把一个4位的数组转化位整形 161 | * 162 | * @param value 163 | * @return 164 | * @throws Exception 165 | */ 166 | public long fourBytesToLong(byte[] value) throws Exception { 167 | // if (value.length < 4) { 168 | // throw new Exception("Byte array too short!"); 169 | // } 170 | int temp0 = value[0] & 0xFF; 171 | int temp1 = value[1] & 0xFF; 172 | int temp2 = value[2] & 0xFF; 173 | int temp3 = value[3] & 0xFF; 174 | return (((long) temp0 << 24) + (temp1 << 16) + (temp2 << 8) + temp3); 175 | } 176 | 177 | /** 178 | * 把一个数组转化长整形 179 | * 180 | * @param value 181 | * @return 182 | * @throws Exception 183 | */ 184 | public long bytes2Long(byte[] value) { 185 | long result = 0; 186 | int len = value.length; 187 | int temp; 188 | for (int i = 0; i < len; i++) { 189 | temp = (len - 1 - i) * 8; 190 | if (temp == 0) { 191 | result += (value[i] & 0x0ff); 192 | } else { 193 | result += (value[i] & 0x0ff) << temp; 194 | } 195 | } 196 | return result; 197 | } 198 | 199 | /** 200 | * 把一个长整形改为byte数组 201 | * 202 | * @param value 203 | * @return 204 | * @throws Exception 205 | */ 206 | public byte[] longToBytes(long value){ 207 | return longToBytes(value, 8); 208 | } 209 | 210 | /** 211 | * 把一个长整形改为byte数组 212 | * 213 | * @param value 214 | * @return 215 | * @throws Exception 216 | */ 217 | public byte[] longToBytes(long value, int len) { 218 | byte[] result = new byte[len]; 219 | int temp; 220 | for (int i = 0; i < len; i++) { 221 | temp = (len - 1 - i) * 8; 222 | if (temp == 0) { 223 | result[i] += (value & 0x0ff); 224 | } else { 225 | result[i] += (value >>> temp) & 0x0ff; 226 | } 227 | } 228 | return result; 229 | } 230 | 231 | /** 232 | * 得到一个消息ID 233 | * 234 | * @return 235 | * @throws Exception 236 | */ 237 | public byte[] generateTransactionID() throws Exception { 238 | byte[] id = new byte[16]; 239 | System.arraycopy(integerTo2Bytes((int) (Math.random() * 65536)), 0, id, 0, 2); 240 | System.arraycopy(integerTo2Bytes((int) (Math.random() * 65536)), 0, id, 2, 2); 241 | System.arraycopy(integerTo2Bytes((int) (Math.random() * 65536)), 0, id, 4, 2); 242 | System.arraycopy(integerTo2Bytes((int) (Math.random() * 65536)), 0, id, 6, 2); 243 | System.arraycopy(integerTo2Bytes((int) (Math.random() * 65536)), 0, id, 8, 2); 244 | System.arraycopy(integerTo2Bytes((int) (Math.random() * 65536)), 0, id, 10, 2); 245 | System.arraycopy(integerTo2Bytes((int) (Math.random() * 65536)), 0, id, 12, 2); 246 | System.arraycopy(integerTo2Bytes((int) (Math.random() * 65536)), 0, id, 14, 2); 247 | return id; 248 | } 249 | 250 | /** 251 | * 把IP拆分位int数组 252 | * 253 | * @param ip 254 | * @return 255 | * @throws Exception 256 | */ 257 | public int[] getIntIPValue(String ip) throws Exception { 258 | String[] sip = ip.split("[.]"); 259 | // if (sip.length != 4) { 260 | // throw new Exception("error IPAddress"); 261 | // } 262 | int[] intIP = { Integer.parseInt(sip[0]), Integer.parseInt(sip[1]), Integer.parseInt(sip[2]), 263 | Integer.parseInt(sip[3]) }; 264 | return intIP; 265 | } 266 | 267 | /** 268 | * 把byte类型IP地址转化位字符串 269 | * 270 | * @param address 271 | * @return 272 | * @throws Exception 273 | */ 274 | public String getStringIPValue(byte[] address) throws Exception { 275 | int first = this.oneByteToInteger(address[0]); 276 | int second = this.oneByteToInteger(address[1]); 277 | int third = this.oneByteToInteger(address[2]); 278 | int fourth = this.oneByteToInteger(address[3]); 279 | 280 | return first + "." + second + "." + third + "." + fourth; 281 | } 282 | 283 | /** 284 | * 合并字节数组 285 | * 286 | * @param first 287 | * @param rest 288 | * @return 289 | */ 290 | public byte[] concatAll(byte[] first, byte[]... rest) { 291 | int totalLength = first.length; 292 | for (byte[] array : rest) { 293 | if (array != null) { 294 | totalLength += array.length; 295 | } 296 | } 297 | byte[] result = Arrays.copyOf(first, totalLength); 298 | int offset = first.length; 299 | for (byte[] array : rest) { 300 | if (array != null) { 301 | System.arraycopy(array, 0, result, offset, array.length); 302 | offset += array.length; 303 | } 304 | } 305 | return result; 306 | } 307 | 308 | /** 309 | * 合并字节数组 310 | * 311 | * @param rest 312 | * @return 313 | */ 314 | public byte[] concatAll(List rest) { 315 | int totalLength = 0; 316 | for (byte[] array : rest) { 317 | if (array != null) { 318 | totalLength += array.length; 319 | } 320 | } 321 | byte[] result = new byte[totalLength]; 322 | int offset = 0; 323 | for (byte[] array : rest) { 324 | if (array != null) { 325 | System.arraycopy(array, 0, result, offset, array.length); 326 | offset += array.length; 327 | } 328 | } 329 | return result; 330 | } 331 | 332 | public float byte2Float(byte[] bs) { 333 | return Float.intBitsToFloat( 334 | (((bs[3] & 0xFF) << 24) + ((bs[2] & 0xFF) << 16) + ((bs[1] & 0xFF) << 8) + (bs[0] & 0xFF))); 335 | } 336 | 337 | public float byteBE2Float(byte[] bytes) { 338 | int l; 339 | l = bytes[0]; 340 | l &= 0xff; 341 | l |= ((long) bytes[1] << 8); 342 | l &= 0xffff; 343 | l |= ((long) bytes[2] << 16); 344 | l &= 0xffffff; 345 | l |= ((long) bytes[3] << 24); 346 | return Float.intBitsToFloat(l); 347 | } 348 | 349 | public int getCheckSum4JT808(byte[] bs, int start, int end) { 350 | if (start < 0 || end > bs.length) 351 | throw new ArrayIndexOutOfBoundsException("getCheckSum4JT808 error : index out of bounds(start=" + start 352 | + ",end=" + end + ",bytes length=" + bs.length + ")"); 353 | int cs = 0; 354 | for (int i = start; i < end; i++) { 355 | cs ^= bs[i]; 356 | } 357 | return cs; 358 | } 359 | 360 | public int getBitRange(int number, int start, int end) { 361 | if (start < 0) 362 | throw new IndexOutOfBoundsException("min index is 0,but start = " + start); 363 | if (end >= Integer.SIZE) 364 | throw new IndexOutOfBoundsException("max index is " + (Integer.SIZE - 1) + ",but end = " + end); 365 | 366 | return (number << Integer.SIZE - (end + 1)) >>> Integer.SIZE - (end - start + 1); 367 | } 368 | 369 | public int getBitAt(int number, int index) { 370 | if (index < 0) 371 | throw new IndexOutOfBoundsException("min index is 0,but " + index); 372 | if (index >= Integer.SIZE) 373 | throw new IndexOutOfBoundsException("max index is " + (Integer.SIZE - 1) + ",but " + index); 374 | 375 | return ((1 << index) & number) >> index; 376 | } 377 | 378 | public int getBitAtS(int number, int index) { 379 | String s = Integer.toBinaryString(number); 380 | return Integer.parseInt(s.charAt(index) + ""); 381 | } 382 | 383 | @Deprecated 384 | public int getBitRangeS(int number, int start, int end) { 385 | String s = Integer.toBinaryString(number); 386 | StringBuilder sb = new StringBuilder(s); 387 | while (sb.length() < Integer.SIZE) { 388 | sb.insert(0, "0"); 389 | } 390 | String tmp = sb.reverse().substring(start, end + 1); 391 | sb = new StringBuilder(tmp); 392 | return Integer.parseInt(sb.reverse().toString(), 2); 393 | } 394 | 395 | /** 396 | * 浮点转换为字节 397 | * 398 | * @param f 399 | * @return 400 | */ 401 | public byte[] float2byte(float f) { 402 | 403 | // 把float转换为byte[] 404 | int fbit = Float.floatToIntBits(f); 405 | 406 | byte[] b = new byte[4]; 407 | for (int i = 0; i < 4; i++) { 408 | b[i] = (byte) (fbit >> (24 - i * 8)); 409 | } 410 | 411 | // 翻转数组 412 | int len = b.length; 413 | // 建立一个与源数组元素类型相同的数组 414 | byte[] dest = new byte[len]; 415 | // 为了防止修改源数组,将源数组拷贝一份副本 416 | System.arraycopy(b, 0, dest, 0, len); 417 | byte temp; 418 | // 将顺位第i个与倒数第i个交换 419 | for (int i = 0; i < len / 2; ++i) { 420 | temp = dest[i]; 421 | dest[i] = dest[len - i - 1]; 422 | dest[len - i - 1] = temp; 423 | } 424 | 425 | return dest; 426 | 427 | } 428 | 429 | /** 430 | * 字节转换为浮点 431 | * 432 | * @param b 字节(至少4个字节) 433 | * @param index 开始位置 434 | * @return 435 | */ 436 | public float byte2float(byte[] b, int index) { 437 | int l; 438 | l = b[index + 0]; 439 | l &= 0xff; 440 | l |= ((long) b[index + 1] << 8); 441 | l &= 0xffff; 442 | l |= ((long) b[index + 2] << 16); 443 | l &= 0xffffff; 444 | l |= ((long) b[index + 3] << 24); 445 | return Float.intBitsToFloat(l); 446 | } 447 | 448 | public static void main(String [] arg){ 449 | byte [] bytes ={0,90}; 450 | System.out.println(new BitOperator().twoBytesToInteger(bytes)); 451 | } 452 | 453 | } 454 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/util/DigitalUtils.java: -------------------------------------------------------------------------------- 1 | package com.jt808.util; 2 | 3 | public class DigitalUtils { 4 | //转义,若检验码、消息头以及消息体中出现125则要进行转义。125后紧跟一个2转为126,125后紧跟一个1转为125 5 | public static byte[] meanTransfer(byte[] original) { 6 | byte[] bytes = {}; 7 | for (int i = 0; i < original.length; i++) { 8 | if (original[i] == 125) { 9 | if (original[i + 1] == 1) { 10 | byte[] mean = {125}; 11 | bytes = mergeBytes(bytes, mean); 12 | } else if (original[i + 1] == 2) { 13 | byte[] mean = {126}; 14 | bytes = mergeBytes(bytes, mean); 15 | } 16 | } else if ((original[i] == 1 || original[i] == 2) && original[i - 1] == 125) { 17 | byte[] mean = {}; 18 | bytes = mergeBytes(bytes, mean); 19 | } else { 20 | byte[] mean = {original[i]}; 21 | bytes = mergeBytes(bytes, mean); 22 | } 23 | } 24 | return bytes; 25 | } 26 | 27 | 28 | //转义,标识位为126,若检验码、消息头以及消息体中出现126则要进行转义。126转为125后紧跟一个2,125转为125后紧跟一个1 29 | public static byte[] transferMean(byte[] original) { 30 | byte[] bytes = {}; 31 | for (int i = 0; i < original.length; i++) { 32 | if (original[i] == 126) { 33 | byte[] mean = {125, 2}; 34 | bytes = mergeBytes(bytes, mean); 35 | 36 | } else if (original[i] == 125) { 37 | byte[] mean = {125, 1}; 38 | bytes = mergeBytes(bytes, mean); 39 | } else { 40 | byte[] mean = {original[i]}; 41 | bytes = mergeBytes(bytes, mean); 42 | } 43 | } 44 | return bytes; 45 | } 46 | 47 | /** 48 | * 组合byte数组 49 | * 50 | * @param bs 51 | * @return 52 | */ 53 | public static byte[] mergeBytes(byte[]... bs) { 54 | int length = 0; 55 | for (byte[] bs2 : bs) { 56 | length += bs2.length; 57 | } 58 | // 请求数组长度 59 | byte[] result = new byte[length]; 60 | int curLength = 0; 61 | for (byte[] b : bs) { 62 | System.arraycopy(b, 0, result, curLength, b.length); 63 | curLength += b.length; 64 | } 65 | return result; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/util/HexStringUtils.java: -------------------------------------------------------------------------------- 1 | package com.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 | public static void main(String[] args) { 54 | String s = "abc你好"; 55 | String hex = toHexString(s.getBytes()); 56 | String decode = hexString2Bytes(hex); 57 | System.out.println("原字符串:" + s); 58 | System.out.println("十六进制字符串:" + hex); 59 | System.out.println("还原:" + decode); 60 | } 61 | } -------------------------------------------------------------------------------- /src/main/java/com/jt808/util/Img2Base64Util.java: -------------------------------------------------------------------------------- 1 | package com.jt808.util; 2 | 3 | import org.apache.commons.codec.binary.Base64; 4 | 5 | import java.io.*; 6 | 7 | /** 8 | * @author :liuyang 9 | */ 10 | public class Img2Base64Util { 11 | 12 | /** 13 | * 将图片转换成Base64编码 14 | * 15 | * @param imgFile 待处理图片 16 | * @return 17 | */ 18 | public static String getImgStr(String imgFile) { 19 | //将图片文件转化为字节数组字符串,并对其进行Base64编码处理 20 | 21 | 22 | InputStream in = null; 23 | byte[] data = null; 24 | //读取图片字节数组 25 | try { 26 | in = new FileInputStream(imgFile); 27 | data = new byte[in.available()]; 28 | in.read(data); 29 | in.close(); 30 | } catch (IOException e) { 31 | e.printStackTrace(); 32 | } 33 | return new String(Base64.encodeBase64(data)); 34 | } 35 | 36 | /** 37 | * 对字节数组字符串进行Base64解码并生成图片 38 | * 39 | * @param imgStr 图片数据 40 | * @param imgFilePath 保存图片全路径地址 41 | * @return 42 | */ 43 | public static boolean generateImage(String imgStr, String imgFilePath) { 44 | // 45 | if (imgStr == null) //图像数据为空 46 | return false; 47 | 48 | try { 49 | //Base64解码 50 | byte[] b = Base64.decodeBase64(imgStr); 51 | for (int i = 0; i < b.length; ++i) { 52 | if (b[i] < 0) {//调整异常数据 53 | b[i] += 256; 54 | } 55 | } 56 | //生成jpeg图片 57 | 58 | OutputStream out = new FileOutputStream(imgFilePath); 59 | out.write(b); 60 | out.flush(); 61 | out.close(); 62 | return true; 63 | } catch (Exception e) { 64 | return false; 65 | } 66 | } 67 | 68 | /** 69 | * 图片字节数组生成图片 70 | * @param b 图片字节数组 71 | * @param imgFilePath 保存路径 72 | * @return 73 | */ 74 | public static boolean generateImage(byte[] b,String imgFilePath) { 75 | try { 76 | //生成jpeg图片 77 | OutputStream out = new FileOutputStream(imgFilePath); 78 | out.write(b); 79 | out.flush(); 80 | out.close(); 81 | return true; 82 | } catch (Exception e) { 83 | return false; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/util/JT808ProtocolUtils.java: -------------------------------------------------------------------------------- 1 | package com.jt808.util; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.io.ByteArrayOutputStream; 7 | 8 | /** 9 | * JT808协议转义工具类 10 | * 11 | *
 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 | if (msgLen >= 1024) 136 | log.warn("The max value of msgLen is 1023, but {} .", msgLen); 137 | int subPkg = isSubPackage ? 1 : 0; 138 | int ret = (msgLen & 0x3FF) | ((enctyptionType << 10) & 0x1C00) | ((subPkg << 13) & 0x2000) 139 | | ((reversed_14_15 << 14) & 0xC000); 140 | return ret & 0xffff; 141 | } 142 | public byte[] generateMsgHeader(String phone, int msgType, byte[] body, int msgBodyProps, int flowId,int msgTotalNum,int packageNum) 143 | throws Exception { 144 | ByteArrayOutputStream baos = null; 145 | try { 146 | baos = new ByteArrayOutputStream(); 147 | //0.协议版本号 148 | baos.write(bitOperator.integerTo1Byte(128)); 149 | // 1. 消息ID word(16) 150 | baos.write(bitOperator.integerTo2Bytes(msgType)); 151 | // 2. 消息体属性 word(16) 152 | baos.write(bitOperator.integerTo2Bytes(msgBodyProps)); 153 | // 3. 终端手机号 bcd[8] 154 | baos.write(bcd8421Operater.string2Bcd(phone)); 155 | // 4. 消息流水号 word(16),按发送顺序从 0 开始循环累加 156 | baos.write(bitOperator.integerTo2Bytes(flowId)); 157 | //5.预留 158 | baos.write(bitOperator.integerTo1Byte(0)); 159 | // 6.消息包封装项 160 | if(msgTotalNum>0 && packageNum>0){ 161 | //消息总包数 162 | baos.write(bitOperator.integerTo2Bytes(msgTotalNum)); 163 | //包序号 164 | baos.write(bitOperator.integerTo2Bytes(packageNum)); 165 | } 166 | return baos.toByteArray(); 167 | } finally { 168 | if (baos != null) { 169 | baos.close(); 170 | } 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/util/PhotoUtil.java: -------------------------------------------------------------------------------- 1 | package com.jt808.util; 2 | 3 | import javax.imageio.ImageIO; 4 | import java.awt.*; 5 | import java.awt.geom.AffineTransform; 6 | import java.awt.image.AffineTransformOp; 7 | import java.awt.image.BufferedImage; 8 | import java.io.ByteArrayOutputStream; 9 | import java.io.File; 10 | import java.io.IOException; 11 | 12 | /** 13 | * Created by Administrator on 2018/12/3. 14 | */ 15 | 16 | /** 17 | * 裁剪、缩放图片工具类 18 | * 19 | */ 20 | public class PhotoUtil { 21 | 22 | /** 23 | * 缩放图片方法 24 | * @param srcImageFile 要缩放的图片路径 25 | * @param result 缩放后的图片路径 26 | * @param height 目标高度像素 27 | * @param width 目标宽度像素 28 | * @param bb 是否补白 29 | */ 30 | public final static void scale(String srcImageFile, String result, int height, int width, boolean bb) { 31 | try { 32 | double ratio = 0.0; // 缩放比例 33 | File f = new File(srcImageFile); 34 | BufferedImage bi = ImageIO.read(f); 35 | //bi.SCALE_SMOOTH 选择图像平滑度比缩放速度具有更高优先级的图像缩放算法。 36 | Image itemp = bi.getScaledInstance(width, height, BufferedImage.SCALE_SMOOTH); 37 | // 计算比例 38 | if ((bi.getHeight() > height) || (bi.getWidth() > width)) { 39 | double ratioHeight = (new Integer(height)).doubleValue()/ bi.getHeight(); 40 | double ratioWhidth = (new Integer(width)).doubleValue()/ bi.getWidth(); 41 | if(ratioHeight>ratioWhidth){ 42 | ratio= ratioWhidth; 43 | }else{ 44 | ratio= ratioHeight; 45 | } 46 | AffineTransformOp op = new AffineTransformOp(AffineTransform//仿射转换 47 | .getScaleInstance(ratio, ratio), null);//返回表示剪切变换的变换 48 | itemp = op.filter(bi, null);//转换源 BufferedImage 并将结果存储在目标 BufferedImage 中。 49 | } 50 | if (bb) {//补白 51 | BufferedImage image = new BufferedImage(width, height, 52 | BufferedImage.TYPE_INT_RGB);//构造一个类型为预定义图像类型之一的 BufferedImage。 53 | Graphics2D g = image.createGraphics();//创建一个 Graphics2D,可以将它绘制到此 BufferedImage 中。 54 | g.setColor(Color.white);//控制颜色 55 | g.fillRect(0, 0, width, height);// 使用 Graphics2D 上下文的设置,填充 Shape 的内部区域。 56 | if (width == itemp.getWidth(null)) { 57 | g.drawImage(itemp, 0, (height - itemp.getHeight(null)) / 2, 58 | itemp.getWidth(null), itemp.getHeight(null), 59 | Color.white, null); 60 | } 61 | else{ 62 | g.drawImage(itemp, (width - itemp.getWidth(null)) / 2, 0, 63 | itemp.getWidth(null), itemp.getHeight(null), 64 | Color.white, null);} 65 | g.dispose(); 66 | itemp = image; 67 | } 68 | ImageIO.write((BufferedImage) itemp, "JPEG", new File(result)); //输出压缩图片 69 | } catch (IOException e) { 70 | e.printStackTrace(); 71 | } 72 | } 73 | 74 | /** 75 | * 裁剪图片方法 76 | * @param bufferedImage 图像源 77 | * @param startX 裁剪开始x坐标 78 | * @param startY 裁剪开始y坐标 79 | * @param endX 裁剪结束x坐标 80 | * @param endY 裁剪结束y坐标 81 | * @return 82 | */ 83 | public static BufferedImage cropImage(BufferedImage bufferedImage, int startX, int startY, int endX, int endY) { 84 | int width = bufferedImage.getWidth(); 85 | int height = bufferedImage.getHeight(); 86 | if (startX == -1) { 87 | startX = 0; 88 | } 89 | if (startY == -1) { 90 | startY = 0; 91 | } 92 | if (endX == -1) { 93 | endX = width - 1; 94 | } 95 | if (endY == -1) { 96 | endY = height - 1; 97 | } 98 | BufferedImage result = new BufferedImage(endX - startX, endY - startY, 4); 99 | for (int x = startX; x < endX; ++x) { 100 | for (int y = startY; y < endY; ++y) { 101 | int rgb = bufferedImage.getRGB(x, y); 102 | result.setRGB(x - startX, y - startY, rgb); 103 | } 104 | } 105 | return result; 106 | } 107 | 108 | 109 | public final static byte[] scale(String srcImageFile, int height, int width, boolean bb) { 110 | try { 111 | double ratio = 0.0; // 缩放比例 112 | File f = new File(srcImageFile); 113 | BufferedImage bi = ImageIO.read(f); 114 | //bi.SCALE_SMOOTH 选择图像平滑度比缩放速度具有更高优先级的图像缩放算法。 115 | Image itemp = bi.getScaledInstance(width, height, BufferedImage.SCALE_SMOOTH); 116 | // 计算比例 117 | if ((bi.getHeight() > height) || (bi.getWidth() > width)) { 118 | double ratioHeight = (new Integer(height)).doubleValue()/ bi.getHeight(); 119 | double ratioWhidth = (new Integer(width)).doubleValue()/ bi.getWidth(); 120 | if(ratioHeight>ratioWhidth){ 121 | ratio= ratioWhidth; 122 | }else{ 123 | ratio= ratioHeight; 124 | } 125 | AffineTransformOp op = new AffineTransformOp(AffineTransform//仿射转换 126 | .getScaleInstance(ratio, ratio), null);//返回表示剪切变换的变换 127 | itemp = op.filter(bi, null);//转换源 BufferedImage 并将结果存储在目标 BufferedImage 中。 128 | } 129 | if (bb) {//补白 130 | BufferedImage image = new BufferedImage(width, height, 131 | BufferedImage.TYPE_INT_RGB);//构造一个类型为预定义图像类型之一的 BufferedImage。 132 | Graphics2D g = image.createGraphics();//创建一个 Graphics2D,可以将它绘制到此 BufferedImage 中。 133 | g.setColor(Color.white);//控制颜色 134 | g.fillRect(0, 0, width, height);// 使用 Graphics2D 上下文的设置,填充 Shape 的内部区域。 135 | if (width == itemp.getWidth(null)) { 136 | g.drawImage(itemp, 0, (height - itemp.getHeight(null)) / 2, 137 | itemp.getWidth(null), itemp.getHeight(null), 138 | Color.white, null); 139 | } 140 | else{ 141 | g.drawImage(itemp, (width - itemp.getWidth(null)) / 2, 0, 142 | itemp.getWidth(null), itemp.getHeight(null), 143 | Color.white, null);} 144 | g.dispose(); 145 | itemp = image; 146 | } 147 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 148 | //输出压缩图片 149 | ImageIO.write((BufferedImage) itemp, "JPEG", out); 150 | return out.toByteArray(); 151 | } catch (IOException e) { 152 | e.printStackTrace(); 153 | } 154 | return null; 155 | } 156 | public static void main(String[] args) throws IOException { 157 | String path="D:/student.jpg"; //输入图片 测试要在C盘放一张图片1.jpg 158 | PhotoUtil.scale("D://img//11.jpg","D:/yasuo.jpg", 160, 120, true);//等比例缩放 输出缩放图片 159 | 160 | /*File newfile=new File("D:/yasuo.jpg"); 161 | BufferedImage bufferedimage=ImageIO.read(newfile); 162 | int width = bufferedimage.getWidth(); 163 | int height = bufferedimage.getHeight(); 164 | //目标将图片裁剪成 宽240,高160 165 | if (width > 240) { 166 | *//*开始x坐标 开始y坐标 结束x坐标 结束y坐标*//* 167 | bufferedimage=photoUtil.cropImage(bufferedimage,(int) ((width - 240) / 2),0,(int) (width - (width-240) / 2),(int) (height) 168 | ); 169 | if (height > 320) { 170 | bufferedimage=photoUtil.cropImage(bufferedimage,0,(int) ((height - 320) / 2),240,(int) (height - (height - 320) / 2) 171 | ); 172 | } 173 | }else{ 174 | if (height > 320) { 175 | bufferedimage=photoUtil.cropImage(bufferedimage,0,(int) ((height - 320) / 2),(int) (width),(int) (height - (height - 320) / 2) 176 | ); 177 | } 178 | } 179 | ImageIO.write(bufferedimage, "jpg", new File("D:/caijian.jpg")); //输出裁剪图片*/ 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/util/TerminalArgUtils.java: -------------------------------------------------------------------------------- 1 | package com.jt808.util; 2 | 3 | import com.jt808.common.TPMSConsts; 4 | import com.jt808.common.TerminalArgIdEnums; 5 | import com.jt808.service.codec.MsgDecoder; 6 | import com.jt808.vo.req.TerminalArgMsg.TerminalArg.TerminalArgList; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | /** 11 | * @author :刘洋 12 | */ 13 | public class TerminalArgUtils { 14 | private static final Logger log = LoggerFactory.getLogger(MsgDecoder.class); 15 | private BitOperator bitOperator; 16 | 17 | public TerminalArgUtils() { 18 | this.bitOperator = new BitOperator(); 19 | } 20 | 21 | /** 22 | * 终端参数项编码 23 | * 24 | * @param argId 25 | * @param str 26 | * @return 27 | */ 28 | public byte[] terminalArgToByte(int argId, String str) { 29 | byte[] arg = argToByte(argId, str); 30 | byte[] bs = this.bitOperator.concatAll( 31 | bitOperator.integerTo4Bytes(argId), 32 | bitOperator.integerTo1Bytes(arg.length), 33 | arg); 34 | return bs; 35 | } 36 | 37 | /** 38 | * 终端参数项解码 39 | * 40 | * @param bs 41 | * @return 42 | */ 43 | public TerminalArgList byteToTerminalArg(byte[] bs) { 44 | TerminalArgList body = new TerminalArgList(); 45 | body.setArgId(this.parseIntFromBytes(bs, 0, 4)); 46 | body.setArgLen(this.parseIntFromBytes(bs, 4, 1)); 47 | if (TerminalArgIdEnums.D_0X0013.getId() == body.getArgId()) { 48 | body.setArg(this.parseStringFromBytes(bs, 5, body.getArgLen())); 49 | } else { 50 | body.setArg(String.valueOf(this.parseIntFromBytes(bs, 5, 4))); 51 | } 52 | body.setMsg(TerminalArgIdEnums.msg(body.getArgId())); 53 | return body; 54 | } 55 | 56 | 57 | /** 58 | * 根据参数id 转换参数 59 | * 60 | * @param argId 参数id 61 | * @param str 参数 62 | * @return 63 | */ 64 | public byte[] argToByte(int argId, String str) { 65 | byte[] arg = null; 66 | if (TerminalArgIdEnums.D_0X0013.getId() == argId) { 67 | arg = str.getBytes(TPMSConsts.STRING_CHARSET); 68 | } else { 69 | arg = this.bitOperator.integerTo4Bytes(Integer.valueOf(str)); 70 | } 71 | return arg; 72 | } 73 | 74 | /** 75 | * byte[] 转 int 76 | * 77 | * @param data 78 | * @param startIndex 79 | * @param length 80 | * @return 81 | */ 82 | private int parseIntFromBytes(byte[] data, int startIndex, int length) { 83 | return this.parseIntFromBytes(data, startIndex, length, 0); 84 | } 85 | 86 | /** 87 | * byte[] 转 int 88 | * 89 | * @param data 90 | * @param startIndex 91 | * @param length 92 | * @param defaultVal 93 | * @return 94 | */ 95 | private int parseIntFromBytes(byte[] data, int startIndex, int length, int defaultVal) { 96 | try { 97 | // 字节数大于4,从起始索引开始向后处理4个字节,其余超出部分丢弃 98 | final int len = length > 4 ? 4 : length; 99 | byte[] tmp = new byte[len]; 100 | System.arraycopy(data, startIndex, tmp, 0, len); 101 | return bitOperator.byteToInteger(tmp); 102 | } catch (Exception e) { 103 | log.error("解析整数出错:{}", e.getMessage()); 104 | e.printStackTrace(); 105 | return defaultVal; 106 | } 107 | } 108 | 109 | /** 110 | * byte[] String 111 | * 112 | * @param data 113 | * @param startIndex 114 | * @param lenth 115 | * @return 116 | */ 117 | protected String parseStringFromBytes(byte[] data, int startIndex, int lenth) { 118 | return this.parseStringFromBytes(data, startIndex, lenth, null); 119 | } 120 | 121 | /** 122 | * byte[] 转 String 123 | * 124 | * @param data 125 | * @param startIndex 126 | * @param lenth 127 | * @param defaultVal 128 | * @return 129 | */ 130 | private String parseStringFromBytes(byte[] data, int startIndex, int lenth, String defaultVal) { 131 | try { 132 | byte[] tmp = new byte[lenth]; 133 | System.arraycopy(data, startIndex, tmp, 0, lenth); 134 | return new String(tmp, TPMSConsts.STRING_CHARSET); 135 | } catch (Exception e) { 136 | log.error("解析字符串出错:{}", e.getMessage()); 137 | e.printStackTrace(); 138 | return defaultVal; 139 | } 140 | } 141 | 142 | public static void main(String []arg){ 143 | log.info("{}",new TerminalArgUtils().terminalArgToByte(0x0018,"88889")); 144 | log.info("{}",new TerminalArgUtils().byteToTerminalArg(new byte[]{0, 0, 0, 24, 4, 0, 1, 91, 57})); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/PackageData.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import io.netty.channel.Channel; 5 | 6 | import java.util.Arrays; 7 | 8 | public class PackageData { 9 | 10 | /** 11 | * 16byte 消息头 12 | */ 13 | protected MsgHeader msgHeader; 14 | 15 | // 消息体字节数组 16 | @JSONField(serialize=false) 17 | protected byte[] msgBodyBytes; 18 | 19 | /** 20 | * 校验码 1byte 21 | */ 22 | protected int checkSum; 23 | 24 | @JSONField(serialize=false) 25 | protected Channel channel; 26 | 27 | public MsgHeader getMsgHeader() { 28 | return msgHeader; 29 | } 30 | 31 | public void setMsgHeader(MsgHeader msgHeader) { 32 | this.msgHeader = msgHeader; 33 | } 34 | 35 | public byte[] getMsgBodyBytes() { 36 | return msgBodyBytes; 37 | } 38 | 39 | public void setMsgBodyBytes(byte[] msgBodyBytes) { 40 | this.msgBodyBytes = msgBodyBytes; 41 | } 42 | 43 | public int getCheckSum() { 44 | return checkSum; 45 | } 46 | 47 | public void setCheckSum(int checkSum) { 48 | this.checkSum = checkSum; 49 | } 50 | 51 | public Channel getChannel() { 52 | return channel; 53 | } 54 | 55 | public void setChannel(Channel channel) { 56 | this.channel = channel; 57 | } 58 | 59 | @Override 60 | public String toString() { 61 | return "PackageData [msgHeader=" + msgHeader + ", msgBodyBytes=" + Arrays.toString(msgBodyBytes) + ", checkSum=" 62 | + checkSum + ", address=" + channel + "]"; 63 | } 64 | 65 | public static class MsgHeader { 66 | // 消息ID 67 | protected int msgId; 68 | 69 | /////// ========消息体属性 70 | // byte[2-3] 71 | protected int msgBodyPropsField; 72 | // 消息体长度 73 | protected int msgBodyLength; 74 | // 数据加密方式 75 | protected int encryptionType; 76 | // 是否分包,true==>有消息包封装项 77 | protected boolean hasSubPackage; 78 | // 保留位[14-15] 79 | protected String reservedBit; 80 | /////// ========消息体属性 81 | 82 | // 终端手机号 83 | protected String terminalPhone; 84 | // 流水号 85 | protected int flowId; 86 | 87 | //////// =====消息包封装项 88 | // byte[12-15] 89 | protected int packageInfoField; 90 | // 消息包总数(word(16)) 91 | protected long totalSubPackage; 92 | // 包序号(word(16))这次发送的这个消息包是分包中的第几个消息包, 从 1 开始 93 | protected long subPackageSeq; 94 | //////// =====消息包封装项 95 | 96 | public int getMsgId() { 97 | return msgId; 98 | } 99 | 100 | public void setMsgId(int msgId) { 101 | this.msgId = msgId; 102 | } 103 | 104 | public int getMsgBodyLength() { 105 | return msgBodyLength; 106 | } 107 | 108 | public void setMsgBodyLength(int msgBodyLength) { 109 | this.msgBodyLength = msgBodyLength; 110 | } 111 | 112 | public int getEncryptionType() { 113 | return encryptionType; 114 | } 115 | 116 | public void setEncryptionType(int encryptionType) { 117 | this.encryptionType = encryptionType; 118 | } 119 | 120 | public String getTerminalPhone() { 121 | return terminalPhone; 122 | } 123 | 124 | public void setTerminalPhone(String terminalPhone) { 125 | this.terminalPhone = terminalPhone; 126 | } 127 | 128 | public int getFlowId() { 129 | return flowId; 130 | } 131 | 132 | public void setFlowId(int flowId) { 133 | this.flowId = flowId; 134 | } 135 | 136 | public boolean isHasSubPackage() { 137 | return hasSubPackage; 138 | } 139 | 140 | public void setHasSubPackage(boolean hasSubPackage) { 141 | this.hasSubPackage = hasSubPackage; 142 | } 143 | 144 | public String getReservedBit() { 145 | return reservedBit; 146 | } 147 | 148 | public void setReservedBit(String reservedBit) { 149 | this.reservedBit = reservedBit; 150 | } 151 | 152 | public long getTotalSubPackage() { 153 | return totalSubPackage; 154 | } 155 | 156 | public void setTotalSubPackage(long totalPackage) { 157 | this.totalSubPackage = totalPackage; 158 | } 159 | 160 | public long getSubPackageSeq() { 161 | return subPackageSeq; 162 | } 163 | 164 | public void setSubPackageSeq(long packageSeq) { 165 | this.subPackageSeq = packageSeq; 166 | } 167 | 168 | public int getMsgBodyPropsField() { 169 | return msgBodyPropsField; 170 | } 171 | 172 | public void setMsgBodyPropsField(int msgBodyPropsField) { 173 | this.msgBodyPropsField = msgBodyPropsField; 174 | } 175 | 176 | public void setPackageInfoField(int packageInfoField) { 177 | this.packageInfoField = packageInfoField; 178 | } 179 | 180 | public int getPackageInfoField() { 181 | return packageInfoField; 182 | } 183 | 184 | @Override 185 | public String toString() { 186 | return "MsgHeader [msgId=" + msgId + ", msgBodyPropsField=" + msgBodyPropsField + ", msgBodyLength=" 187 | + msgBodyLength + ", encryptionType=" + encryptionType + ", hasSubPackage=" + hasSubPackage 188 | + ", reservedBit=" + reservedBit + ", terminalPhone=" + terminalPhone + ", flowId=" + flowId 189 | + ", packageInfoField=" + packageInfoField + ", totalSubPackage=" + totalSubPackage 190 | + ", subPackageSeq=" + subPackageSeq + "]"; 191 | } 192 | 193 | } 194 | 195 | } 196 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/Session.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo; 2 | 3 | import io.netty.channel.Channel; 4 | 5 | import java.net.SocketAddress; 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/com/jt808/vo/req/CoachLoginMsg.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | import com.jt808.vo.PackageData; 4 | 5 | /** 6 | * @Author :刘洋 7 | * 教练登录消息 8 | */ 9 | public class CoachLoginMsg extends ExtendedTimekeepingTrainingMsg{ 10 | //教练编号 byte[16] 11 | private String coachnum; 12 | //教练身份证 byte[18] 13 | private String idcard; 14 | //准教车型 byte[2] 15 | private String teachpermitted; 16 | //Gnss数据包byte[28] 17 | private GnssMsg gnss; 18 | 19 | public CoachLoginMsg(){} 20 | 21 | public CoachLoginMsg(PackageData packageData){ 22 | super(packageData); 23 | } 24 | 25 | 26 | public String getCoachnum() { 27 | return coachnum; 28 | } 29 | 30 | public void setCoachnum(String coachnum) { 31 | this.coachnum = coachnum; 32 | } 33 | 34 | public String getIdcard() { 35 | return idcard; 36 | } 37 | 38 | public void setIdcard(String idcard) { 39 | this.idcard = idcard; 40 | } 41 | 42 | public String getTeachpermitted() { 43 | return teachpermitted; 44 | } 45 | 46 | public void setTeachpermitted(String teachpermitted) { 47 | this.teachpermitted = teachpermitted; 48 | } 49 | 50 | public GnssMsg getGnss() { 51 | return gnss; 52 | } 53 | 54 | public void setGnss(GnssMsg gnss) { 55 | this.gnss = gnss; 56 | } 57 | 58 | @Override 59 | public String toString() { 60 | return "CoachLoginMsg{" + 61 | "coachnum='" + coachnum + '\'' + 62 | ", idcard='" + idcard + '\'' + 63 | ", teachpermitted='" + teachpermitted + '\'' + 64 | ", gnss=" + gnss + 65 | '}'; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/req/CoachOrStuPhotoMsg.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | import com.jt808.vo.PackageData; 4 | 5 | public class CoachOrStuPhotoMsg extends ExtendedTimekeepingTrainingMsg { 6 | /** 7 | * 类型:0:教练,1:学员 8 | * byte 9 | */ 10 | private int type; 11 | /** 12 | * 教练或学员编号 13 | * byte[16] 14 | */ 15 | private String num; 16 | 17 | public CoachOrStuPhotoMsg() { 18 | } 19 | 20 | public CoachOrStuPhotoMsg(PackageData packageData) { 21 | super(packageData); 22 | } 23 | 24 | public int getType() { 25 | return type; 26 | } 27 | 28 | public void setType(int type) { 29 | this.type = type; 30 | } 31 | 32 | public String getNum() { 33 | return num; 34 | } 35 | 36 | public void setNum(String num) { 37 | this.num = num; 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "CoachOrStuPhotoMsg{" + 43 | "type=" + type + 44 | ", num='" + num + '\'' + 45 | '}'; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/req/ExtendedTimekeepingTrainingMsg.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import com.jt808.vo.PackageData; 5 | 6 | import java.util.Arrays; 7 | 8 | /** 9 | * 扩展计时培训消息 10 | */ 11 | public class ExtendedTimekeepingTrainingMsg extends PackageData { 12 | 13 | private ExtendedTimekeepingTrainingInfo extendedTimekeepingTrainingInfo; 14 | 15 | public ExtendedTimekeepingTrainingMsg() { 16 | } 17 | 18 | public ExtendedTimekeepingTrainingMsg(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 ExtendedTimekeepingTrainingInfo getExtendedTimekeepingTrainingInfo() { 27 | return extendedTimekeepingTrainingInfo; 28 | } 29 | 30 | public void setExtendedTimekeepingTrainingInFo(ExtendedTimekeepingTrainingInfo extendedTimekeepingTrainingInfo) { 31 | this.extendedTimekeepingTrainingInfo = extendedTimekeepingTrainingInfo; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "ExtendedTimekeepingTrainingMsg{" + 37 | "extendedTimekeepingTrainingInfo=" + extendedTimekeepingTrainingInfo + 38 | ", msgHeader=" + msgHeader + 39 | ", msgBodyBytes=" + Arrays.toString(msgBodyBytes) + 40 | ", checkSum=" + checkSum + 41 | ", channel=" + channel + 42 | '}'; 43 | } 44 | 45 | public static class ExtendedTimekeepingTrainingInfo{ 46 | //透传消息id 为功能号+消息编号 word byte[0-2] 47 | private int ospfId; 48 | /** 49 | * 扩展消息属性 bit0 表示消息失效类型,应答中也应附带此内容 0:实时消息,1:补传消息 50 | * bit1 表示应答属性,0:不需要应答,1:需要应答 51 | * bit4-7 表示加密算法,0:未加密,1:SHA1,2:SHA256;其他保留 52 | * word byte[2-4] 53 | */ 54 | private int bodyPropsField; 55 | //驾培包序号 word byte[4-6] 56 | private int numOrder; 57 | //计时终端编号byte[16] byte[6-22] 58 | private String terminalId; 59 | //数据长度 word byte[22-24]数据长度为n,没有数据则为0 60 | private int dataLen; 61 | //数据内容byte[n] byte[24-(24+n)] 62 | @JSONField(serialize=false) 63 | private byte[] dataContent; 64 | //校验串 byte[(24+n)-x] 采用2048位证书时,长度为256byte,平台发送的扩展消息无此字段 65 | private String checkSum; 66 | 67 | public ExtendedTimekeepingTrainingInfo() { 68 | } 69 | 70 | public int getOspfId() { 71 | return ospfId; 72 | } 73 | 74 | public void setOspfId(int ospfId) { 75 | this.ospfId = ospfId; 76 | } 77 | 78 | public int getBodyPropsField() { 79 | return bodyPropsField; 80 | } 81 | 82 | public void setBodyPropsField(int bodyPropsField) { 83 | this.bodyPropsField = bodyPropsField; 84 | } 85 | 86 | public int getNumOrder() { 87 | return numOrder; 88 | } 89 | 90 | public void setNumOrder(int numOrder) { 91 | this.numOrder = numOrder; 92 | } 93 | 94 | public String getTerminalId() { 95 | return terminalId; 96 | } 97 | 98 | public void setTerminalId(String terminalId) { 99 | this.terminalId = terminalId; 100 | } 101 | 102 | public int getDataLen() { 103 | return dataLen; 104 | } 105 | 106 | public void setDataLen(int dataLen) { 107 | this.dataLen = dataLen; 108 | } 109 | 110 | public byte[] getDataContent() { 111 | return dataContent; 112 | } 113 | 114 | public void setDataContent(byte[] dataContent) { 115 | this.dataContent = dataContent; 116 | } 117 | 118 | public String getCheckSum() { 119 | return checkSum; 120 | } 121 | 122 | public void setCheckSum(String checkSum) { 123 | this.checkSum = checkSum; 124 | } 125 | 126 | @Override 127 | public String toString() { 128 | return "ExtendedTimekeepingTrainingInFo{" + 129 | "ospfId=" + ospfId + 130 | ", bodyPropsField=" + bodyPropsField + 131 | ", numOrder=" + numOrder + 132 | ", terminalId='" + terminalId + '\'' + 133 | ", dataLen=" + dataLen + 134 | ", dataContent=" + Arrays.toString(dataContent) + 135 | ", checkSum=" + checkSum + 136 | '}'; 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/req/ForbiddenState.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | import com.jt808.vo.PackageData; 4 | 5 | public class ForbiddenState extends ExtendedTimekeepingTrainingMsg { 6 | /** 7 | * 执行结果 byte 8 | */ 9 | private int replyCode; 10 | /** 11 | * 禁训状态 byte 12 | */ 13 | private int state; 14 | /** 15 | * 提示消息长度 byte 16 | */ 17 | private int msgLen; 18 | /** 19 | * 提示消息内容 string 20 | */ 21 | private String msg; 22 | 23 | 24 | public ForbiddenState() { 25 | } 26 | 27 | public ForbiddenState(PackageData packageData) { 28 | super(packageData); 29 | } 30 | 31 | 32 | public ForbiddenState(int replyCode, int state, int msgLen, String msg) { 33 | this.replyCode = replyCode; 34 | this.state = state; 35 | this.msgLen = msgLen; 36 | this.msg = msg; 37 | } 38 | 39 | public ForbiddenState(PackageData packageData, int replyCode, int state, int msgLen, String msg) { 40 | super(packageData); 41 | this.replyCode = replyCode; 42 | this.state = state; 43 | this.msgLen = msgLen; 44 | this.msg = msg; 45 | } 46 | 47 | public int getReplyCode() { 48 | return replyCode; 49 | } 50 | 51 | public void setReplyCode(int replyCode) { 52 | this.replyCode = replyCode; 53 | } 54 | 55 | public int getState() { 56 | return state; 57 | } 58 | 59 | public void setState(int state) { 60 | this.state = state; 61 | } 62 | 63 | public int getMsgLen() { 64 | return msgLen; 65 | } 66 | 67 | public void setMsgLen(int msgLen) { 68 | this.msgLen = msgLen; 69 | } 70 | 71 | public String getMsg() { 72 | return msg; 73 | } 74 | 75 | public void setMsg(String msg) { 76 | this.msg = msg; 77 | } 78 | 79 | @Override 80 | public String toString() { 81 | return "ForbiddenState{" + 82 | "replyCode=" + replyCode + 83 | ", state=" + state + 84 | ", msgLen=" + msgLen + 85 | ", msg='" + msg + '\'' + 86 | '}'; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/req/GnssMsg.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | 6 | public class GnssMsg { 7 | //位置基本信息数据 8 | /** 9 | * 报警标识 10 | * byte [0-4] (DWORD(32)) 11 | */ 12 | private int warningFlagField; 13 | /** 14 | * byte[4-8] 状态(DWORD(32)) 15 | */ 16 | private int statusField; 17 | /** 18 | * byte[8-12] 纬度(DWORD(32)) 19 | */ 20 | private float latitude; 21 | /** 22 | * byte[12-16] 经度(DWORD(32)) 23 | */ 24 | private float longitude; 25 | /** 26 | * byte [16-18]行驶记录速度 (WORD)1/10km/h 27 | */ 28 | private float runSpeed; 29 | /** 30 | * byte[18-20] 卫星定位速度(WORD) 1/10km/h 31 | */ 32 | private float satelliteSpeed; 33 | /** 34 | * byte[20-22] 方向(WORD) 0-359,正北为 0,顺时针 35 | */ 36 | private int direction; 37 | /** 38 | * byte[22-x] 时间(BCD[6]) YY-MM-DD-hh-mm-ss 39 | * GMT+8 时间,本标准中之后涉及的时间均采用此时区 40 | */ 41 | private Date time; 42 | 43 | private List attachLocation; 44 | 45 | public GnssMsg() { 46 | } 47 | 48 | 49 | public int getWarningFlagField() { 50 | return warningFlagField; 51 | } 52 | 53 | public void setWarningFlagField(int warningFlagField) { 54 | this.warningFlagField = warningFlagField; 55 | } 56 | 57 | public int getStatusField() { 58 | return statusField; 59 | } 60 | 61 | public void setStatusField(int statusField) { 62 | this.statusField = statusField; 63 | } 64 | 65 | public float getLatitude() { 66 | return latitude; 67 | } 68 | 69 | public void setLatitude(float latitude) { 70 | this.latitude = latitude; 71 | } 72 | 73 | public float getLongitude() { 74 | return longitude; 75 | } 76 | 77 | public void setLongitude(float longitude) { 78 | this.longitude = longitude; 79 | } 80 | 81 | public float getRunSpeed() { 82 | return runSpeed; 83 | } 84 | 85 | public void setRunSpeed(float runSpeed) { 86 | this.runSpeed = runSpeed; 87 | } 88 | 89 | public float getSatelliteSpeed() { 90 | return satelliteSpeed; 91 | } 92 | 93 | public void setSatelliteSpeed(float satelliteSpeed) { 94 | this.satelliteSpeed = satelliteSpeed; 95 | } 96 | 97 | public int getDirection() { 98 | return direction; 99 | } 100 | 101 | public void setDirection(int direction) { 102 | this.direction = direction; 103 | } 104 | 105 | public Date getTime() { 106 | return time; 107 | } 108 | 109 | public void setTime(Date time) { 110 | this.time = time; 111 | } 112 | 113 | public List getAttachLocation() { 114 | return attachLocation; 115 | } 116 | 117 | public void setAttachLocation(List attachLocation) { 118 | this.attachLocation = attachLocation; 119 | } 120 | 121 | @Override 122 | public String toString() { 123 | return "GnssMsg{" + 124 | "warningFlagField=" + warningFlagField + 125 | ", statusField=" + statusField + 126 | ", latitude=" + latitude + 127 | ", longitude=" + longitude + 128 | ", runSpeed=" + runSpeed + 129 | ", satelliteSpeed=" + satelliteSpeed + 130 | ", direction=" + direction + 131 | ", time=" + time + 132 | ", attachLocation=" + attachLocation + 133 | '}'; 134 | } 135 | 136 | public static class AttachLocation{ 137 | /** 138 | * 位置附加信息 byte 139 | */ 140 | private int msgId; 141 | /** 142 | * 附加信息长度 byte 143 | */ 144 | private int msgLen; 145 | /** 146 | * 附加消息 dword word 147 | */ 148 | private int msg; 149 | 150 | public AttachLocation() { 151 | } 152 | 153 | public int getMsgId() { 154 | return msgId; 155 | } 156 | 157 | public void setMsgId(int msgId) { 158 | this.msgId = msgId; 159 | } 160 | 161 | public int getMsgLen() { 162 | return msgLen; 163 | } 164 | 165 | public void setMsgLen(int msgLen) { 166 | this.msgLen = msgLen; 167 | } 168 | 169 | public int getMsg() { 170 | return msg; 171 | } 172 | 173 | public void setMsg(int msg) { 174 | this.msg = msg; 175 | } 176 | 177 | @Override 178 | public String toString() { 179 | return "AttachLocation{" + 180 | "msgId=" + msgId + 181 | ", msgLen=" + msgLen + 182 | ", msg=" + msg + 183 | '}'; 184 | } 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/req/ImmediatelyTakePicturesMsg.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | import com.jt808.vo.PackageData; 4 | 5 | public class ImmediatelyTakePicturesMsg extends ExtendedTimekeepingTrainingMsg { 6 | /** 7 | * 执行结果 byte 8 | */ 9 | private int replyCode; 10 | /** 11 | * 上传模式 byte 12 | */ 13 | private int model; 14 | /** 15 | * 摄像头通道号 byte 16 | */ 17 | private int aisle; 18 | /** 19 | * 图片尺寸 byte 20 | */ 21 | private int size; 22 | 23 | public ImmediatelyTakePicturesMsg() { 24 | } 25 | 26 | public ImmediatelyTakePicturesMsg(PackageData packageData) { 27 | super(packageData); 28 | } 29 | 30 | public int getReplyCode() { 31 | return replyCode; 32 | } 33 | 34 | public void setReplyCode(int replyCode) { 35 | this.replyCode = replyCode; 36 | } 37 | 38 | public int getModel() { 39 | return model; 40 | } 41 | 42 | public void setModel(int model) { 43 | this.model = model; 44 | } 45 | 46 | public int getAisle() { 47 | return aisle; 48 | } 49 | 50 | public void setAisle(int aisle) { 51 | this.aisle = aisle; 52 | } 53 | 54 | public int getSize() { 55 | return size; 56 | } 57 | 58 | public void setSize(int size) { 59 | this.size = size; 60 | } 61 | 62 | @Override 63 | public String toString() { 64 | return "ImmediatelyTakePicturesMsg{" + 65 | "replyCode=" + replyCode + 66 | ", model=" + model + 67 | ", aisle=" + aisle + 68 | ", size=" + size + 69 | '}'; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/req/LocationInfoUploadMsg.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | 4 | import com.jt808.vo.PackageData; 5 | 6 | import java.util.Date; 7 | 8 | /** 9 | * 位置信息汇报消息 10 | * 11 | * @author hylexus 12 | * 13 | */ 14 | public class LocationInfoUploadMsg extends PackageData { 15 | // 报警标识 16 | // byte [0-4] (DWORD(32)) 17 | private int warningFlagField; 18 | // byte[4-8] 状态(DWORD(32)) 19 | private int statusField; 20 | // byte[8-12] 纬度(DWORD(32)) 21 | private float latitude; 22 | // byte[12-16] 经度(DWORD(32)) 23 | private float longitude; 24 | // byte [16-18]行驶记录速度 (WORD)1/10km/h 25 | private int runSpeed; 26 | // byte[18-20] 卫星定位速度(WORD) 1/10km/h 27 | private int satelliteSpeed; 28 | // byte[20-22] 方向(WORD) 0-359,正北为 0,顺时针 29 | private int direction; 30 | // byte[22-x] 时间(BCD[6]) YY-MM-DD-hh-mm-ss 31 | // GMT+8 时间,本标准中之后涉及的时间均采用此时区 32 | private Date time; 33 | 34 | public LocationInfoUploadMsg() { 35 | } 36 | 37 | public LocationInfoUploadMsg(PackageData packageData) { 38 | this(); 39 | this.channel = packageData.getChannel(); 40 | this.checkSum = packageData.getCheckSum(); 41 | this.msgBodyBytes = packageData.getMsgBodyBytes(); 42 | this.msgHeader = packageData.getMsgHeader(); 43 | } 44 | 45 | 46 | 47 | 48 | 49 | public int getWarningFlagField() { 50 | return warningFlagField; 51 | } 52 | 53 | public void setWarningFlagField(int warningFlagField) { 54 | this.warningFlagField = warningFlagField; 55 | } 56 | 57 | public int getStatusField() { 58 | return statusField; 59 | } 60 | 61 | public void setStatusField(int statusField) { 62 | this.statusField = statusField; 63 | } 64 | 65 | public float getLatitude() { 66 | return latitude; 67 | } 68 | 69 | public void setLatitude(float latitude) { 70 | this.latitude = latitude; 71 | } 72 | 73 | public float getLongitude() { 74 | return longitude; 75 | } 76 | 77 | public void setLongitude(float longitude) { 78 | this.longitude = longitude; 79 | } 80 | 81 | public int getRunSpeed() { 82 | return runSpeed; 83 | } 84 | 85 | public void setRunSpeed(int runSpeed) { 86 | this.runSpeed = runSpeed; 87 | } 88 | 89 | public int getSatelliteSpeed() { 90 | return satelliteSpeed; 91 | } 92 | 93 | public void setSatelliteSpeed(int satelliteSpeed) { 94 | this.satelliteSpeed = satelliteSpeed; 95 | } 96 | 97 | public int getDirection() { 98 | return direction; 99 | } 100 | 101 | public void setDirection(int direction) { 102 | this.direction = direction; 103 | } 104 | 105 | public Date getTime() { 106 | return time; 107 | } 108 | 109 | public void setTime(Date time) { 110 | this.time = time; 111 | } 112 | 113 | @Override 114 | public String toString() { 115 | return "LocationInfoUploadMsg{" + 116 | "warningFlagField=" + warningFlagField + 117 | ", statusField=" + statusField + 118 | ", latitude=" + latitude + 119 | ", longitude=" + longitude + 120 | ", runSpeed=" + runSpeed + 121 | ", satelliteSpeed=" + satelliteSpeed + 122 | ", direction=" + direction + 123 | ", time=" + time + 124 | '}'; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/req/PhotoUploadDataMsg.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | import com.jt808.vo.PackageData; 4 | 5 | public class PhotoUploadDataMsg extends ExtendedTimekeepingTrainingMsg { 6 | /** 7 | * 照片编号 byte[10] 8 | */ 9 | private String photoNum; 10 | /** 11 | * 照片数据 bytr[n] 12 | */ 13 | private String photoData; 14 | 15 | public PhotoUploadDataMsg() { 16 | } 17 | 18 | public PhotoUploadDataMsg(PackageData packageData) { 19 | super(packageData); 20 | } 21 | 22 | public PhotoUploadDataMsg(String photoNum, String photoData) { 23 | this.photoNum = photoNum; 24 | this.photoData = photoData; 25 | } 26 | 27 | public PhotoUploadDataMsg(PackageData packageData, String photoNum, String photoData) { 28 | super(packageData); 29 | this.photoNum = photoNum; 30 | this.photoData = photoData; 31 | } 32 | 33 | public String getPhotoNum() { 34 | return photoNum; 35 | } 36 | 37 | public void setPhotoNum(String photoNum) { 38 | this.photoNum = photoNum; 39 | } 40 | 41 | public String getPhotoData() { 42 | return photoData; 43 | } 44 | 45 | public void setPhotoData(String photoData) { 46 | this.photoData = photoData; 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return "PhotoUploadDataMsg{" + 52 | "photoNum='" + photoNum + '\'' + 53 | ", photoData='" + photoData + '\'' + 54 | '}'; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/req/PhotoUploadInitializesMsg.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | import com.jt808.vo.PackageData; 4 | 5 | public class PhotoUploadInitializesMsg extends ExtendedTimekeepingTrainingMsg { 6 | /** 7 | * 照片编号 byte[10] 8 | */ 9 | private String photoNum; 10 | /** 11 | * 学员编号 byte[16] 12 | */ 13 | private String stunum; 14 | /** 15 | * 上传模式 byte 16 | */ 17 | private int upMode; 18 | /** 19 | * 摄像头通道号 byte 20 | */ 21 | private int cameraChannelNumber; 22 | /** 23 | * 图片尺寸 byte 24 | */ 25 | private int photoSize; 26 | /** 27 | * 发起图片的事件类型 byte 28 | */ 29 | private int photoType; 30 | /** 31 | * 总包数 word 2 32 | */ 33 | private int totalPackage; 34 | /** 35 | * 照片数据大小 dword 4 位 36 | */ 37 | private int photoDataSize; 38 | /** 39 | * 课堂id dword 4 位 40 | */ 41 | private int classRoomId; 42 | /** 43 | * 卫星定位数据包 byte[28] 44 | */ 45 | private GnssMsg gnss; 46 | /** 47 | * 人脸识别置信度 byte 0-100数值越大置信度越高 48 | */ 49 | private int confidenceCoefficient; 50 | 51 | public PhotoUploadInitializesMsg() { 52 | } 53 | 54 | public PhotoUploadInitializesMsg(PackageData packageData) { 55 | super(packageData); 56 | } 57 | 58 | 59 | 60 | public String getPhotoNum() { 61 | return photoNum; 62 | } 63 | 64 | public void setPhotoNum(String photoNum) { 65 | this.photoNum = photoNum; 66 | } 67 | 68 | public String getStunum() { 69 | return stunum; 70 | } 71 | 72 | public void setStunum(String stunum) { 73 | this.stunum = stunum; 74 | } 75 | 76 | public int getUpMode() { 77 | return upMode; 78 | } 79 | 80 | public void setUpMode(int upMode) { 81 | this.upMode = upMode; 82 | } 83 | 84 | public int getCameraChannelNumber() { 85 | return cameraChannelNumber; 86 | } 87 | 88 | public void setCameraChannelNumber(int cameraChannelNumber) { 89 | this.cameraChannelNumber = cameraChannelNumber; 90 | } 91 | 92 | public int getPhotoSize() { 93 | return photoSize; 94 | } 95 | 96 | public void setPhotoSize(int photoSize) { 97 | this.photoSize = photoSize; 98 | } 99 | 100 | public int getPhotoType() { 101 | return photoType; 102 | } 103 | 104 | public void setPhotoType(int photoType) { 105 | this.photoType = photoType; 106 | } 107 | 108 | public int getTotalPackage() { 109 | return totalPackage; 110 | } 111 | 112 | public void setTotalPackage(int totalPackage) { 113 | this.totalPackage = totalPackage; 114 | } 115 | 116 | public int getPhotoDataSize() { 117 | return photoDataSize; 118 | } 119 | 120 | public void setPhotoDataSize(int photoDataSize) { 121 | this.photoDataSize = photoDataSize; 122 | } 123 | 124 | public int getClassRoomId() { 125 | return classRoomId; 126 | } 127 | 128 | public void setClassRoomId(int classRoomId) { 129 | this.classRoomId = classRoomId; 130 | } 131 | 132 | public GnssMsg getGnss() { 133 | return gnss; 134 | } 135 | 136 | public void setGnss(GnssMsg gnss) { 137 | this.gnss = gnss; 138 | } 139 | 140 | public int getConfidenceCoefficient() { 141 | return confidenceCoefficient; 142 | } 143 | 144 | public void setConfidenceCoefficient(int confidenceCoefficient) { 145 | this.confidenceCoefficient = confidenceCoefficient; 146 | } 147 | 148 | @Override 149 | public String toString() { 150 | return "PhotoUploadInitializesMsg{" + 151 | "photoNum='" + photoNum + '\'' + 152 | ", stunum='" + stunum + '\'' + 153 | ", upMode=" + upMode + 154 | ", cameraChannelNumber=" + cameraChannelNumber + 155 | ", photoSize=" + photoSize + 156 | ", photoType=" + photoType + 157 | ", totalPackage=" + totalPackage + 158 | ", photoDataSize=" + photoDataSize + 159 | ", classRoomId=" + classRoomId + 160 | ", gnss=" + gnss + 161 | ", confidenceCoefficient=" + confidenceCoefficient + 162 | '}'; 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/req/PlatformLoginMsg.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | import com.jt808.vo.PackageData; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * @author :liuyang 9 | * 平台登录请求 10 | */ 11 | public class PlatformLoginMsg extends PackageData { 12 | 13 | private PlatformLoginInfo platformLoginInfo; 14 | 15 | public PlatformLoginMsg(PackageData packageData) { 16 | this(); 17 | this.channel = packageData.getChannel(); 18 | this.checkSum = packageData.getCheckSum(); 19 | this.msgBodyBytes = packageData.getMsgBodyBytes(); 20 | this.msgHeader = packageData.getMsgHeader(); 21 | } 22 | 23 | public PlatformLoginMsg() { 24 | } 25 | 26 | public PlatformLoginInfo getPlatformLoginInfo() { 27 | return platformLoginInfo; 28 | } 29 | 30 | public void setPlatformLoginInfo(PlatformLoginInfo platformLoginInfo) { 31 | this.platformLoginInfo = platformLoginInfo; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "PlatformLoginResp{" + 37 | "platformLoginInfo=" + platformLoginInfo + 38 | ", msgHeader=" + msgHeader + 39 | ", msgBodyBytes=" + Arrays.toString(msgBodyBytes) + 40 | ", checkSum=" + checkSum + 41 | ", channel=" + channel + 42 | '}'; 43 | } 44 | 45 | public static class PlatformLoginInfo { 46 | //平台编号 byte[5] 47 | private String num; 48 | //密码 byte[8] 49 | private String pass; 50 | //接入码 dword 51 | 52 | private String code; 53 | //应答结果 发送时不复制 54 | private int result; 55 | 56 | public PlatformLoginInfo() { 57 | } 58 | 59 | public String getNum() { 60 | return num; 61 | } 62 | 63 | public void setNum(String num) { 64 | this.num = num; 65 | } 66 | 67 | public String getPass() { 68 | return pass; 69 | } 70 | 71 | public void setPass(String pass) { 72 | this.pass = pass; 73 | } 74 | 75 | public String getCode() { 76 | return code; 77 | } 78 | 79 | public void setCode(String code) { 80 | this.code = code; 81 | } 82 | 83 | public int getResult() { 84 | return result; 85 | } 86 | 87 | public void setResult(int result) { 88 | this.result = result; 89 | } 90 | 91 | @Override 92 | public String toString() { 93 | return "PlatformLoginInfo{" + 94 | "num='" + num + '\'' + 95 | ", pass='" + pass + '\'' + 96 | ", code='" + code + '\'' + 97 | '}'; 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/req/StudentLoginMsg.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | import com.jt808.vo.PackageData; 4 | 5 | /** 6 | * @author :liuyang 7 | * 学员登录消息 8 | */ 9 | public class StudentLoginMsg extends ExtendedTimekeepingTrainingMsg { 10 | //学员编号 byte[16] 11 | private String stunum; 12 | //当前教练编号 byte[16] 13 | private String coachnum; 14 | //培训课程BCD[5] 15 | private String curriculum; 16 | //课堂id dword 4 位 17 | private int classRoomId; 18 | //Gnss数据包byte[28] 19 | private GnssMsg gnss; 20 | 21 | public StudentLoginMsg() { 22 | } 23 | 24 | public StudentLoginMsg(PackageData packageData) { 25 | super(packageData); 26 | } 27 | 28 | 29 | 30 | public String getStunum() { 31 | return stunum; 32 | } 33 | 34 | public void setStunum(String stunum) { 35 | this.stunum = stunum; 36 | } 37 | 38 | public String getCoachnum() { 39 | return coachnum; 40 | } 41 | 42 | public void setCoachnum(String coachnum) { 43 | this.coachnum = coachnum; 44 | } 45 | 46 | public String getCurriculum() { 47 | return curriculum; 48 | } 49 | 50 | public void setCurriculum(String curriculum) { 51 | this.curriculum = curriculum; 52 | } 53 | 54 | public int getClassRoomId() { 55 | return classRoomId; 56 | } 57 | 58 | public void setClassRoomId(int classRoomId) { 59 | this.classRoomId = classRoomId; 60 | } 61 | 62 | public GnssMsg getGnss() { 63 | return gnss; 64 | } 65 | 66 | public void setGnss(GnssMsg gnss) { 67 | this.gnss = gnss; 68 | } 69 | 70 | @Override 71 | public String toString() { 72 | return "StudentLoginMsg{" + 73 | "stunum='" + stunum + '\'' + 74 | ", coachnum='" + coachnum + '\'' + 75 | ", curriculum='" + curriculum + '\'' + 76 | ", classRoomId=" + classRoomId + 77 | ", gnss=" + gnss + 78 | '}'; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/req/StudentLoginOutMsg.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | import com.jt808.vo.PackageData; 4 | 5 | public class StudentLoginOutMsg extends ExtendedTimekeepingTrainingMsg { 6 | //学员编号 byte[16] 7 | private String stunum; 8 | //登出时间 BCD[6] YYMMddHHmmss 9 | private String outTime; 10 | //学员该次登录总时间 word 2位 11 | private int loginTotalTime; 12 | //学员该次登录总里程 word 2位 13 | private float loginTotalMileage; 14 | //课堂id dword 4 位 15 | private int classRoomId; 16 | //Gnss数据包byte[28] 17 | private GnssMsg gnss; 18 | 19 | public StudentLoginOutMsg() { 20 | } 21 | 22 | public StudentLoginOutMsg(PackageData packageData) { 23 | super(packageData); 24 | } 25 | 26 | 27 | 28 | public String getStunum() { 29 | return stunum; 30 | } 31 | 32 | public void setStunum(String stunum) { 33 | this.stunum = stunum; 34 | } 35 | 36 | public String getOutTime() { 37 | return outTime; 38 | } 39 | 40 | public void setOutTime(String outTime) { 41 | this.outTime = outTime; 42 | } 43 | 44 | public int getLoginTotalTime() { 45 | return loginTotalTime; 46 | } 47 | 48 | public void setLoginTotalTime(int loginTotalTime) { 49 | this.loginTotalTime = loginTotalTime; 50 | } 51 | 52 | public float getLoginTotalMileage() { 53 | return loginTotalMileage; 54 | } 55 | 56 | public void setLoginTotalMileage(float loginTotalMileage) { 57 | this.loginTotalMileage = loginTotalMileage; 58 | } 59 | 60 | public int getClassRoomId() { 61 | return classRoomId; 62 | } 63 | 64 | public void setClassRoomId(int classRoomId) { 65 | this.classRoomId = classRoomId; 66 | } 67 | 68 | public GnssMsg getGnss() { 69 | return gnss; 70 | } 71 | 72 | public void setGnss(GnssMsg gnss) { 73 | this.gnss = gnss; 74 | } 75 | 76 | @Override 77 | public String toString() { 78 | return "StudentLoginOutMsg{" + 79 | "stunum='" + stunum + '\'' + 80 | ", outTime='" + outTime + '\'' + 81 | ", loginTotalTime=" + loginTotalTime + 82 | ", loginTotalMileage=" + loginTotalMileage + 83 | ", classRoomId=" + classRoomId + 84 | ", gnss=" + gnss + 85 | '}'; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/req/TerminalApplyArgMsg.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | import com.jt808.vo.PackageData; 4 | 5 | public class TerminalApplyArgMsg extends ExtendedTimekeepingTrainingMsg { 6 | /** 7 | * 参数编号 byte 8 | */ 9 | private int argNum; 10 | /** 11 | * 定时拍照时间间隔 byte 12 | */ 13 | private int timedPhotoIntervals; 14 | /** 15 | * 照片上传设置 byte 16 | */ 17 | private int photoUploadSettings; 18 | /** 19 | * 是否报读附加消息 byte 20 | */ 21 | private int isRead; 22 | /** 23 | * 熄火后停止学时计时的延时时间 byte 24 | */ 25 | private int delayedTime; 26 | /** 27 | * 熄火后Gnss数据包上传间隔 word 28 | */ 29 | private int gnssUpInterval; 30 | /** 31 | * 熄火后教练自动登出的延时时间 word 32 | */ 33 | private int coachLoginDelayedTime; 34 | /** 35 | * 重新验证身份时间 word 36 | */ 37 | private int revalidate; 38 | /** 39 | * 教练跨校教学 byte 40 | */ 41 | private int acrossSchoolTeaching; 42 | /** 43 | * 学员跨校学习 44 | */ 45 | private int acrossSchoolLearning; 46 | 47 | public TerminalApplyArgMsg() { 48 | } 49 | 50 | public TerminalApplyArgMsg(PackageData packageData) { 51 | super(packageData); 52 | } 53 | 54 | public TerminalApplyArgMsg(int argNum, int timedPhotoIntervals, int photoUploadSettings, int isRead, int delayedTime, int gnssUpInterval, int coachLoginDelayedTime, int revalidate, int acrossSchoolTeaching, int acrossSchoolLearning) { 55 | this.argNum = argNum; 56 | this.timedPhotoIntervals = timedPhotoIntervals; 57 | this.photoUploadSettings = photoUploadSettings; 58 | this.isRead = isRead; 59 | this.delayedTime = delayedTime; 60 | this.gnssUpInterval = gnssUpInterval; 61 | this.coachLoginDelayedTime = coachLoginDelayedTime; 62 | this.revalidate = revalidate; 63 | this.acrossSchoolTeaching = acrossSchoolTeaching; 64 | this.acrossSchoolLearning = acrossSchoolLearning; 65 | } 66 | 67 | public TerminalApplyArgMsg(PackageData packageData, int argNum, int timedPhotoIntervals, int photoUploadSettings, int isRead, int delayedTime, int gnssUpInterval, int coachLoginDelayedTime, int revalidate, int acrossSchoolTeaching, int acrossSchoolLearning) { 68 | super(packageData); 69 | this.argNum = argNum; 70 | this.timedPhotoIntervals = timedPhotoIntervals; 71 | this.photoUploadSettings = photoUploadSettings; 72 | this.isRead = isRead; 73 | this.delayedTime = delayedTime; 74 | this.gnssUpInterval = gnssUpInterval; 75 | this.coachLoginDelayedTime = coachLoginDelayedTime; 76 | this.revalidate = revalidate; 77 | this.acrossSchoolTeaching = acrossSchoolTeaching; 78 | this.acrossSchoolLearning = acrossSchoolLearning; 79 | } 80 | 81 | public int getArgNum() { 82 | return argNum; 83 | } 84 | 85 | public void setArgNum(int argNum) { 86 | this.argNum = argNum; 87 | } 88 | 89 | public int getTimedPhotoIntervals() { 90 | return timedPhotoIntervals; 91 | } 92 | 93 | public void setTimedPhotoIntervals(int timedPhotoIntervals) { 94 | this.timedPhotoIntervals = timedPhotoIntervals; 95 | } 96 | 97 | public int getPhotoUploadSettings() { 98 | return photoUploadSettings; 99 | } 100 | 101 | public void setPhotoUploadSettings(int photoUploadSettings) { 102 | this.photoUploadSettings = photoUploadSettings; 103 | } 104 | 105 | public int getIsRead() { 106 | return isRead; 107 | } 108 | 109 | public void setIsRead(int isRead) { 110 | this.isRead = isRead; 111 | } 112 | 113 | public int getDelayedTime() { 114 | return delayedTime; 115 | } 116 | 117 | public void setDelayedTime(int delayedTime) { 118 | this.delayedTime = delayedTime; 119 | } 120 | 121 | public int getGnssUpInterval() { 122 | return gnssUpInterval; 123 | } 124 | 125 | public void setGnssUpInterval(int gnssUpInterval) { 126 | this.gnssUpInterval = gnssUpInterval; 127 | } 128 | 129 | public int getCoachLoginDelayedTime() { 130 | return coachLoginDelayedTime; 131 | } 132 | 133 | public void setCoachLoginDelayedTime(int coachLoginDelayedTime) { 134 | this.coachLoginDelayedTime = coachLoginDelayedTime; 135 | } 136 | 137 | public int getRevalidate() { 138 | return revalidate; 139 | } 140 | 141 | public void setRevalidate(int revalidate) { 142 | this.revalidate = revalidate; 143 | } 144 | 145 | public int getAcrossSchoolTeaching() { 146 | return acrossSchoolTeaching; 147 | } 148 | 149 | public void setAcrossSchoolTeaching(int acrossSchoolTeaching) { 150 | this.acrossSchoolTeaching = acrossSchoolTeaching; 151 | } 152 | 153 | public int getAcrossSchoolLearning() { 154 | return acrossSchoolLearning; 155 | } 156 | 157 | public void setAcrossSchoolLearning(int acrossSchoolLearning) { 158 | this.acrossSchoolLearning = acrossSchoolLearning; 159 | } 160 | 161 | @Override 162 | public String toString() { 163 | return "QueryTerminalApplyArgRespBody{" + 164 | "argNum=" + argNum + 165 | ", timedPhotoIntervals=" + timedPhotoIntervals + 166 | ", photoUploadSettings=" + photoUploadSettings + 167 | ", isRead=" + isRead + 168 | ", delayedTime=" + delayedTime + 169 | ", gnssUpInterval=" + gnssUpInterval + 170 | ", coachLoginDelayedTime=" + coachLoginDelayedTime + 171 | ", revalidate=" + revalidate + 172 | ", acrossSchoolTeaching=" + acrossSchoolTeaching + 173 | ", acrossSchoolLearning=" + acrossSchoolLearning + 174 | '}'; 175 | } 176 | 177 | } 178 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/req/TerminalArgMsg.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | import com.jt808.vo.PackageData; 4 | 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | public class TerminalArgMsg extends PackageData { 9 | 10 | private TerminalArg terminalArg; 11 | 12 | public TerminalArgMsg() { 13 | } 14 | 15 | public TerminalArgMsg(PackageData packageData) { 16 | this(); 17 | this.channel = packageData.getChannel(); 18 | this.checkSum = packageData.getCheckSum(); 19 | this.msgBodyBytes = packageData.getMsgBodyBytes(); 20 | this.msgHeader = packageData.getMsgHeader(); 21 | } 22 | 23 | public TerminalArg getTerminalArg() { 24 | return terminalArg; 25 | } 26 | 27 | public void setTerminalArg(TerminalArg terminalArg) { 28 | this.terminalArg = terminalArg; 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return "TerminalArgMsg{" + 34 | "terminalArg=" + terminalArg + 35 | ", msgHeader=" + msgHeader + 36 | ", msgBodyBytes=" + Arrays.toString(msgBodyBytes) + 37 | ", checkSum=" + checkSum + 38 | ", channel=" + channel + 39 | '}'; 40 | } 41 | 42 | public static class TerminalArg { 43 | /** 44 | * 参数总数 byte[1] 45 | */ 46 | private int argTotal; 47 | /** 48 | * 分包参数个数(本数据包包含的参数个数) byte[1] 49 | */ 50 | private int argNum; 51 | /** 52 | * 参数列表项 53 | */ 54 | private List terminalArgList; 55 | 56 | public TerminalArg() { 57 | } 58 | 59 | public int getArgTotal() { 60 | return argTotal; 61 | } 62 | 63 | public void setArgTotal(int argTotal) { 64 | this.argTotal = argTotal; 65 | } 66 | 67 | public int getArgNum() { 68 | return argNum; 69 | } 70 | 71 | public void setArgNum(int argNum) { 72 | this.argNum = argNum; 73 | } 74 | 75 | public List getTerminalArgList() { 76 | return terminalArgList; 77 | } 78 | 79 | public void setTerminalArgList(List terminalArgList) { 80 | this.terminalArgList = terminalArgList; 81 | } 82 | 83 | @Override 84 | public String toString() { 85 | return "TerminalArg{" + 86 | "argTotal=" + argTotal + 87 | ", argNum=" + argNum + 88 | ", terminalArgList=" + terminalArgList + 89 | '}'; 90 | } 91 | 92 | public static class TerminalArgList { 93 | //参数id DWORD[4] 94 | private int argId; 95 | //参数长度 BYTE[1] 96 | private int argLen; 97 | //参数值 98 | private String arg; 99 | //参数说明 100 | private String msg; 101 | 102 | public TerminalArgList() { 103 | } 104 | 105 | public int getArgId() { 106 | return argId; 107 | } 108 | 109 | public void setArgId(int argId) { 110 | this.argId = argId; 111 | } 112 | 113 | public int getArgLen() { 114 | return argLen; 115 | } 116 | 117 | public void setArgLen(int argLen) { 118 | this.argLen = argLen; 119 | } 120 | 121 | public String getArg() { 122 | return arg; 123 | } 124 | 125 | public void setArg(String arg) { 126 | this.arg = arg; 127 | } 128 | 129 | public String getMsg() { 130 | return msg; 131 | } 132 | 133 | public void setMsg(String msg) { 134 | this.msg = msg; 135 | } 136 | 137 | @Override 138 | public String toString() { 139 | return "TerminalArgList{" + 140 | "argId=" + argId + 141 | ", argLen=" + argLen + 142 | ", arg='" + arg + '\'' + 143 | ", msg='" + msg + '\'' + 144 | '}'; 145 | } 146 | } 147 | 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/req/TerminalAuthenticationMsg.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | import com.jt808.common.TPMSConsts; 4 | import com.jt808.vo.PackageData; 5 | 6 | /** 7 | * 终端鉴权消息 8 | * 9 | * @author hylexus 10 | * 11 | */ 12 | public class TerminalAuthenticationMsg extends PackageData { 13 | //时间戳 14 | private int timestamp; 15 | //鉴权密文 16 | private String authCode; 17 | 18 | public TerminalAuthenticationMsg() { 19 | } 20 | 21 | public TerminalAuthenticationMsg(PackageData packageData) { 22 | this(); 23 | this.channel = packageData.getChannel(); 24 | this.checkSum = packageData.getCheckSum(); 25 | this.msgBodyBytes = packageData.getMsgBodyBytes(); 26 | this.msgHeader = packageData.getMsgHeader(); 27 | this.authCode = new String(packageData.getMsgBodyBytes(), TPMSConsts.STRING_CHARSET); 28 | } 29 | 30 | public void setAuthCode(String authCode) { 31 | this.authCode = authCode; 32 | } 33 | 34 | public String getAuthCode() { 35 | return authCode; 36 | } 37 | 38 | public int getTimestamp() { 39 | return timestamp; 40 | } 41 | 42 | public void setTimestamp(int timestamp) { 43 | this.timestamp = timestamp; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return "TerminalAuthenticationMsg{" + 49 | "timestamp=" + timestamp + 50 | ", authCode='" + authCode + '\'' + 51 | '}'; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/req/TerminalControlMsg.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | import com.jt808.vo.PackageData; 4 | 5 | /** 6 | * @author :liuyang 7 | * 终端控制 8 | */ 9 | public class TerminalControlMsg extends PackageData { 10 | /** 11 | * 命令字 byte 12 | */ 13 | private int commandWord; 14 | /** 15 | * 命令参数 16 | */ 17 | private CommandParameter commandParameter; 18 | 19 | public TerminalControlMsg() { 20 | } 21 | 22 | public TerminalControlMsg(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 int getCommandWord() { 31 | return commandWord; 32 | } 33 | 34 | public void setCommandWord(int commandWord) { 35 | this.commandWord = commandWord; 36 | } 37 | 38 | public CommandParameter getCommandParameter() { 39 | return commandParameter; 40 | } 41 | 42 | public void setCommandParameter(CommandParameter commandParameter) { 43 | this.commandParameter = commandParameter; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return "TerminalControlMsg{" + 49 | "commandWord=" + commandWord + 50 | ", commandParameter=" + commandParameter + 51 | '}'; 52 | } 53 | 54 | public static class CommandParameter{ 55 | /** 56 | * 连接控制 byte 57 | */ 58 | private int linkControl; 59 | /** 60 | * 拨号点名称 string 61 | */ 62 | private String dialName; 63 | /** 64 | * 拨号用户名 string 65 | */ 66 | private String dialUserName; 67 | /** 68 | * 拨号密码 string 69 | */ 70 | private String dialPassWord; 71 | /** 72 | * 地址 string 73 | */ 74 | private String address; 75 | /** 76 | * TCP端口 word 77 | */ 78 | private int tcpPort; 79 | /** 80 | * UDP端口 word 81 | */ 82 | private int udpPort; 83 | /** 84 | * 制造商id byte[5] 85 | */ 86 | private String manufacturerId; 87 | /** 88 | * 监管平台鉴权码 string 89 | */ 90 | private String authCode; 91 | /** 92 | * 硬件版本 string 93 | */ 94 | private String hardwareVersion; 95 | /** 96 | * 固件版本 string 97 | */ 98 | private String firmwareVersion; 99 | /** 100 | * URL地址 string 101 | */ 102 | private String url; 103 | /** 104 | * 连接到指定服务器时限 单位:min word 105 | */ 106 | private int timeLimit; 107 | 108 | public CommandParameter() { 109 | } 110 | 111 | public int getLinkControl() { 112 | return linkControl; 113 | } 114 | 115 | public void setLinkControl(int linkControl) { 116 | this.linkControl = linkControl; 117 | } 118 | 119 | public String getDialName() { 120 | return dialName; 121 | } 122 | 123 | public void setDialName(String dialName) { 124 | this.dialName = dialName; 125 | } 126 | 127 | public String getDialUserName() { 128 | return dialUserName; 129 | } 130 | 131 | public void setDialUserName(String dialUserName) { 132 | this.dialUserName = dialUserName; 133 | } 134 | 135 | public String getDialPassWord() { 136 | return dialPassWord; 137 | } 138 | 139 | public void setDialPassWord(String dialPassWord) { 140 | this.dialPassWord = dialPassWord; 141 | } 142 | 143 | public String getAddress() { 144 | return address; 145 | } 146 | 147 | public void setAddress(String address) { 148 | this.address = address; 149 | } 150 | 151 | public int getTcpPort() { 152 | return tcpPort; 153 | } 154 | 155 | public void setTcpPort(int tcpPort) { 156 | this.tcpPort = tcpPort; 157 | } 158 | 159 | public int getUdpPort() { 160 | return udpPort; 161 | } 162 | 163 | public void setUdpPort(int udpPort) { 164 | this.udpPort = udpPort; 165 | } 166 | 167 | public String getManufacturerId() { 168 | return manufacturerId; 169 | } 170 | 171 | public void setManufacturerId(String manufacturerId) { 172 | this.manufacturerId = manufacturerId; 173 | } 174 | 175 | public String getAuthCode() { 176 | return authCode; 177 | } 178 | 179 | public void setAuthCode(String authCode) { 180 | this.authCode = authCode; 181 | } 182 | 183 | public String getHardwareVersion() { 184 | return hardwareVersion; 185 | } 186 | 187 | public void setHardwareVersion(String hardwareVersion) { 188 | this.hardwareVersion = hardwareVersion; 189 | } 190 | 191 | public String getFirmwareVersion() { 192 | return firmwareVersion; 193 | } 194 | 195 | public void setFirmwareVersion(String firmwareVersion) { 196 | this.firmwareVersion = firmwareVersion; 197 | } 198 | 199 | public String getUrl() { 200 | return url; 201 | } 202 | 203 | public void setUrl(String url) { 204 | this.url = url; 205 | } 206 | 207 | public int getTimeLimit() { 208 | return timeLimit; 209 | } 210 | 211 | public void setTimeLimit(int timeLimit) { 212 | this.timeLimit = timeLimit; 213 | } 214 | 215 | @Override 216 | public String toString() { 217 | return "CommandParameter{" + 218 | "linkControl=" + linkControl + 219 | ", dialName='" + dialName + '\'' + 220 | ", dialUserName='" + dialUserName + '\'' + 221 | ", dialPassWord='" + dialPassWord + '\'' + 222 | ", address='" + address + '\'' + 223 | ", tcpPort=" + tcpPort + 224 | ", udpPort=" + udpPort + 225 | ", manufacturerId='" + manufacturerId + '\'' + 226 | ", authCode='" + authCode + '\'' + 227 | ", hardwareVersion='" + hardwareVersion + '\'' + 228 | ", firmwareVersion='" + firmwareVersion + '\'' + 229 | ", url='" + url + '\'' + 230 | ", timeLimit=" + timeLimit + 231 | '}'; 232 | } 233 | } 234 | 235 | } 236 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/req/TerminalRegisterMsg.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | import com.jt808.vo.PackageData; 4 | 5 | import java.util.Arrays; 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 | private String imei; 58 | /** 59 | * 60 | * 车牌颜色(BYTE) 车牌颜色,按照 JT/T415-2006 的 5.4.12 未上牌时,取值为0
61 | * 0===未上车牌
62 | * 1===蓝色
63 | * 2===黄色
64 | * 3===黑色
65 | * 4===白色
66 | * 9===其他 67 | */ 68 | private int licensePlateColor; 69 | // 车牌(STRING) 公安交 通管理部门颁 发的机动车号牌 70 | private String licensePlate; 71 | 72 | public TerminalRegInfo() { 73 | } 74 | 75 | public int getProvinceId() { 76 | return provinceId; 77 | } 78 | 79 | public void setProvinceId(int provinceId) { 80 | this.provinceId = provinceId; 81 | } 82 | 83 | public int getCityId() { 84 | return cityId; 85 | } 86 | 87 | public void setCityId(int cityId) { 88 | this.cityId = cityId; 89 | } 90 | 91 | public String getManufacturerId() { 92 | return manufacturerId; 93 | } 94 | 95 | public void setManufacturerId(String manufacturerId) { 96 | this.manufacturerId = manufacturerId; 97 | } 98 | 99 | public String getTerminalType() { 100 | return terminalType; 101 | } 102 | 103 | public void setTerminalType(String terminalType) { 104 | this.terminalType = terminalType; 105 | } 106 | 107 | public String getTerminalId() { 108 | return terminalId; 109 | } 110 | 111 | public void setTerminalId(String terminalId) { 112 | this.terminalId = terminalId; 113 | } 114 | 115 | public String getImei() { 116 | return imei; 117 | } 118 | 119 | public void setImei(String imei) { 120 | this.imei = imei; 121 | } 122 | 123 | public int getLicensePlateColor() { 124 | return licensePlateColor; 125 | } 126 | 127 | public void setLicensePlateColor(int licensePlate) { 128 | this.licensePlateColor = licensePlate; 129 | } 130 | 131 | public String getLicensePlate() { 132 | return licensePlate; 133 | } 134 | 135 | public void setLicensePlate(String licensePlate) { 136 | this.licensePlate = licensePlate; 137 | } 138 | 139 | @Override 140 | public String toString() { 141 | return "TerminalRegInfo{" + 142 | "provinceId=" + provinceId + 143 | ", cityId=" + cityId + 144 | ", manufacturerId='" + manufacturerId + '\'' + 145 | ", terminalType='" + terminalType + '\'' + 146 | ", terminalId='" + terminalId + '\'' + 147 | ", imei='" + imei + '\'' + 148 | ", licensePlateColor=" + licensePlateColor + 149 | ", licensePlate='" + licensePlate + '\'' + 150 | '}'; 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/req/UpPeriodRecordMsg.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | import com.jt808.vo.PackageData; 4 | 5 | public class UpPeriodRecordMsg extends ExtendedTimekeepingTrainingMsg { 6 | /** 7 | * 学时记录编号 byte[26] 8 | */ 9 | private String recordNum; 10 | /** 11 | * 上报类型 byte 12 | */ 13 | private int upType; 14 | /** 15 | * 学员编号 byte[16] 16 | */ 17 | private String stunum; 18 | /** 19 | * 教练编号 byte[16] 20 | */ 21 | private String coachnum; 22 | /** 23 | * 课堂id dword 4 位 24 | */ 25 | private int classRoomId; 26 | /** 27 | * 记录产生时间 BCD[3] 28 | * HHmmss 29 | */ 30 | private String recordTime; 31 | /** 32 | * 培训课程BCD[5] 33 | */ 34 | private String curriculum; 35 | /** 36 | * 记录状态 BYTE 37 | * 0正常记录,1异常记录 38 | */ 39 | private int state; 40 | /** 41 | * 最大速度 WORD 42 | */ 43 | private int speed; 44 | /** 45 | * 里程 WORD 46 | */ 47 | private int mileage; 48 | /** 49 | * Gnss数据包byte[28] 50 | */ 51 | private GnssMsg gnss; 52 | 53 | public UpPeriodRecordMsg() { 54 | } 55 | 56 | public UpPeriodRecordMsg(PackageData packageData) { 57 | super(packageData); 58 | } 59 | 60 | 61 | public String getRecordNum() { 62 | return recordNum; 63 | } 64 | 65 | public void setRecordNum(String recordNum) { 66 | this.recordNum = recordNum; 67 | } 68 | 69 | public int getUpType() { 70 | return upType; 71 | } 72 | 73 | public void setUpType(int upType) { 74 | this.upType = upType; 75 | } 76 | 77 | public String getStunum() { 78 | return stunum; 79 | } 80 | 81 | public void setStunum(String stunum) { 82 | this.stunum = stunum; 83 | } 84 | 85 | public String getCoachnum() { 86 | return coachnum; 87 | } 88 | 89 | public void setCoachnum(String coachnum) { 90 | this.coachnum = coachnum; 91 | } 92 | 93 | public int getClassRoomId() { 94 | return classRoomId; 95 | } 96 | 97 | public void setClassRoomId(int classRoomId) { 98 | this.classRoomId = classRoomId; 99 | } 100 | 101 | public String getRecordTime() { 102 | return recordTime; 103 | } 104 | 105 | public void setRecordTime(String recordTime) { 106 | this.recordTime = recordTime; 107 | } 108 | 109 | public String getCurriculum() { 110 | return curriculum; 111 | } 112 | 113 | public void setCurriculum(String curriculum) { 114 | this.curriculum = curriculum; 115 | } 116 | 117 | public int getState() { 118 | return state; 119 | } 120 | 121 | public void setState(int state) { 122 | this.state = state; 123 | } 124 | 125 | public int getSpeed() { 126 | return speed; 127 | } 128 | 129 | public void setSpeed(int speed) { 130 | this.speed = speed; 131 | } 132 | 133 | public int getMileage() { 134 | return mileage; 135 | } 136 | 137 | public void setMileage(int mileage) { 138 | this.mileage = mileage; 139 | } 140 | 141 | public GnssMsg getGnss() { 142 | return gnss; 143 | } 144 | 145 | public void setGnss(GnssMsg gnss) { 146 | this.gnss = gnss; 147 | } 148 | 149 | @Override 150 | public String toString() { 151 | return "UpPeriodRecordMsg{" + 152 | "recordNum='" + recordNum + '\'' + 153 | ", upType=" + upType + 154 | ", stunum='" + stunum + '\'' + 155 | ", coachnum='" + coachnum + '\'' + 156 | ", classRoomId=" + classRoomId + 157 | ", recordTime='" + recordTime + '\'' + 158 | ", curriculum='" + curriculum + '\'' + 159 | ", state=" + state + 160 | ", speed=" + speed + 161 | ", mileage=" + mileage + 162 | ", gnss=" + gnss + 163 | '}'; 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/req/UpQueryImageMsg.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.req; 2 | 3 | import com.jt808.vo.PackageData; 4 | 5 | import java.util.List; 6 | 7 | public class UpQueryImageMsg extends ExtendedTimekeepingTrainingMsg { 8 | /** 9 | * 应答代码 10 | */ 11 | private Integer replyCode; 12 | /** 13 | * 是否上报结束 byte 14 | */ 15 | private Integer isUpEnd; 16 | /** 17 | * 符合条件的照片总数 byte 18 | */ 19 | private Integer imgTotal; 20 | /** 21 | * 此次发送的照片数目 byte 22 | */ 23 | private Integer sendImgNum; 24 | /** 25 | * 照片编号 byte[10] 26 | */ 27 | private List imgNum; 28 | 29 | public UpQueryImageMsg() { 30 | } 31 | 32 | public UpQueryImageMsg(PackageData packageData) { 33 | super(packageData); 34 | } 35 | 36 | public Integer getReplyCode() { 37 | return replyCode; 38 | } 39 | 40 | public void setReplyCode(Integer replyCode) { 41 | this.replyCode = replyCode; 42 | } 43 | 44 | public Integer getIsUpEnd() { 45 | return isUpEnd; 46 | } 47 | 48 | public void setIsUpEnd(Integer isUpEnd) { 49 | this.isUpEnd = isUpEnd; 50 | } 51 | 52 | public Integer getImgTotal() { 53 | return imgTotal; 54 | } 55 | 56 | public void setImgTotal(Integer imgTotal) { 57 | this.imgTotal = imgTotal; 58 | } 59 | 60 | public Integer getSendImgNum() { 61 | return sendImgNum; 62 | } 63 | 64 | public void setSendImgNum(Integer sendImgNum) { 65 | this.sendImgNum = sendImgNum; 66 | } 67 | 68 | public List getImgNum() { 69 | return imgNum; 70 | } 71 | 72 | public void setImgNum(List imgNum) { 73 | this.imgNum = imgNum; 74 | } 75 | 76 | @Override 77 | public String toString() { 78 | return "UpQueryImageMsg{" + 79 | "replyCode=" + replyCode + 80 | ", isUpEnd=" + isUpEnd + 81 | ", imgTotal=" + imgTotal + 82 | ", sendImgNum=" + sendImgNum + 83 | ", imgNum=" + imgNum + 84 | '}'; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/resp/CoachLoginMsgRespBody.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.resp; 2 | 3 | public class CoachLoginMsgRespBody { 4 | public static final byte success = 1; 5 | public static final byte invalid_trainer_number = 2; 6 | public static final byte must_teach_models_does_not = 3; 7 | public static final byte other_errors = 9; 8 | 9 | public static final byte all_read = 0; 10 | public static final byte yes_read = 1; 11 | public static final byte no_read = 2; 12 | // byte[0-1] 应答流水号(WORD) 对应的终端注册消息的流水号 13 | private int replyFlowId; 14 | /*** 15 | * byte 登录结果(BYTE)
16 | * 1:成功
17 | * 2:无效的教练员编号
18 | * 3:准教车型不符
19 | * 9:其他错误
20 | **/ 21 | private byte replyCode; 22 | // byte[16] 教练编号 23 | private String coachnum; 24 | /** 25 | * 是否报读附加消息 26 | * 0:根据全局设置决定是否报读 27 | * 1:需要报读 28 | * 2:不必报读 29 | */ 30 | private byte isRead; 31 | //附加消息长度 32 | private int msgLen; 33 | //附加消息 34 | private String msg; 35 | 36 | public CoachLoginMsgRespBody() { 37 | } 38 | 39 | public int getReplyFlowId() { 40 | return replyFlowId; 41 | } 42 | 43 | public void setReplyFlowId(int replyFlowId) { 44 | this.replyFlowId = replyFlowId; 45 | } 46 | 47 | public byte getReplyCode() { 48 | return replyCode; 49 | } 50 | 51 | public void setReplyCode(byte replyCode) { 52 | this.replyCode = replyCode; 53 | } 54 | 55 | public String getCoachnum() { 56 | return coachnum; 57 | } 58 | 59 | public void setCoachnum(String coachnum) { 60 | this.coachnum = coachnum; 61 | } 62 | 63 | public byte getIsRead() { 64 | return isRead; 65 | } 66 | 67 | public void setIsRead(byte isRead) { 68 | this.isRead = isRead; 69 | } 70 | 71 | public int getMsgLen() { 72 | return msgLen; 73 | } 74 | 75 | public void setMsgLen(int msgLen) { 76 | this.msgLen = msgLen; 77 | } 78 | 79 | public String getMsg() { 80 | return msg; 81 | } 82 | 83 | public void setMsg(String msg) { 84 | this.msg = msg; 85 | } 86 | 87 | @Override 88 | public String toString() { 89 | return "CoachLoginMsgRespBody{" + 90 | "replyFlowId=" + replyFlowId + 91 | ", replyCode=" + replyCode + 92 | ", coachnum='" + coachnum + '\'' + 93 | ", isRead=" + isRead + 94 | ", msgLen=" + msgLen + 95 | ", msg='" + msg + '\'' + 96 | '}'; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/resp/QueryTerminalArgRespMsgBody.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.resp; 2 | 3 | import com.jt808.vo.PackageData; 4 | import com.jt808.vo.req.TerminalArgMsg.TerminalArg.TerminalArgList; 5 | 6 | import java.util.List; 7 | 8 | public class QueryTerminalArgRespMsgBody extends PackageData { 9 | // byte[0-1] 应答流水号(WORD) 对应的终端注册消息的流水号 10 | private int replyFlowId; 11 | /** 12 | * 应答参数个数 byte[1] 13 | */ 14 | private int argTotal; 15 | /** 16 | * 包参数个数(本数据包包含的参数个数) byte[1] 17 | */ 18 | private int argNum; 19 | /** 20 | * 参数列表项 21 | */ 22 | private List terminalArgList; 23 | 24 | public QueryTerminalArgRespMsgBody() { 25 | } 26 | 27 | public QueryTerminalArgRespMsgBody(PackageData packageData) { 28 | this(); 29 | this.channel = packageData.getChannel(); 30 | this.checkSum = packageData.getCheckSum(); 31 | this.msgBodyBytes = packageData.getMsgBodyBytes(); 32 | this.msgHeader = packageData.getMsgHeader(); 33 | } 34 | 35 | public QueryTerminalArgRespMsgBody(int replyFlowId, int argTotal, int argNum, List terminalArgList) { 36 | this.replyFlowId = replyFlowId; 37 | this.argTotal = argTotal; 38 | this.argNum = argNum; 39 | this.terminalArgList = terminalArgList; 40 | } 41 | 42 | public int getReplyFlowId() { 43 | return replyFlowId; 44 | } 45 | 46 | public void setReplyFlowId(int replyFlowId) { 47 | this.replyFlowId = replyFlowId; 48 | } 49 | 50 | public int getArgTotal() { 51 | return argTotal; 52 | } 53 | 54 | public void setArgTotal(int argTotal) { 55 | this.argTotal = argTotal; 56 | } 57 | 58 | public int getArgNum() { 59 | return argNum; 60 | } 61 | 62 | public void setArgNum(int argNum) { 63 | this.argNum = argNum; 64 | } 65 | 66 | public List getTerminalArgList() { 67 | return terminalArgList; 68 | } 69 | 70 | public void setTerminalArgList(List terminalArgList) { 71 | this.terminalArgList = terminalArgList; 72 | } 73 | 74 | @Override 75 | public String toString() { 76 | return "QueryTerminalArgRespMsgBody{" + 77 | "replyFlowId=" + replyFlowId + 78 | ", argTotal=" + argTotal + 79 | ", argNum=" + argNum + 80 | ", terminalArgList=" + terminalArgList + 81 | '}'; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/resp/ServerCommonRespMsgBody.java: -------------------------------------------------------------------------------- 1 | package com.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/com/jt808/vo/resp/StudentLoginMsgRespBody.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.resp; 2 | 3 | public class StudentLoginMsgRespBody { 4 | public static final byte success = 1; 5 | public static final byte invalid_stu_number = 2; 6 | public static final byte ban_stu_login = 3; 7 | public static final byte external_instruction_reminder = 4; 8 | public static final byte must_teach_models_and_training_model_does_not = 5; 9 | public static final byte other_errors = 9; 10 | 11 | 12 | public static final byte yes_read = 1; 13 | public static final byte no_read = 0; 14 | // byte[0-1] 应答流水号(WORD) 对应的终端注册消息的流水号 15 | private int replyFlowId; 16 | /*** 17 | * byte 登录结果(BYTE)
18 | * 1:成功
19 | * 2:无效的学员编号
20 | * 3:禁止登录的学员
21 | * 4:区域外教学提醒
22 | * 5:准教车型与培训车型不符
23 | * 9:其他错误
24 | **/ 25 | private byte replyCode; 26 | // byte[16] 学员编号 27 | private String stuhnum; 28 | //总培训学时 word 2位 单位min 29 | private int totalHours; 30 | //当前培训部分已完成学时 word 2位 单位min 31 | private int finishHours; 32 | //总培训里程 word 2位 单位1/10km 33 | private float totalMileage; 34 | //当前培训部分已完成里程 word 2位 单位1/10km 35 | private float finishMileage; 36 | /** 37 | * 是否报读附加消息 38 | * 1:需要报读 39 | * 0:不必报读 40 | */ 41 | private byte isRead; 42 | //附加消息长度 43 | private int msgLen; 44 | //附加消息 45 | private String msg; 46 | 47 | public StudentLoginMsgRespBody() { 48 | } 49 | 50 | public int getReplyFlowId() { 51 | return replyFlowId; 52 | } 53 | 54 | public void setReplyFlowId(int replyFlowId) { 55 | this.replyFlowId = replyFlowId; 56 | } 57 | 58 | public byte getReplyCode() { 59 | return replyCode; 60 | } 61 | 62 | public void setReplyCode(byte replyCode) { 63 | this.replyCode = replyCode; 64 | } 65 | 66 | public String getStuhnum() { 67 | return stuhnum; 68 | } 69 | 70 | public void setStuhnum(String stuhnum) { 71 | this.stuhnum = stuhnum; 72 | } 73 | 74 | public int getTotalHours() { 75 | return totalHours; 76 | } 77 | 78 | public void setTotalHours(int totalHours) { 79 | this.totalHours = totalHours; 80 | } 81 | 82 | public int getFinishHours() { 83 | return finishHours; 84 | } 85 | 86 | public void setFinishHours(int finishHours) { 87 | this.finishHours = finishHours; 88 | } 89 | 90 | public float getTotalMileage() { 91 | return totalMileage; 92 | } 93 | 94 | public void setTotalMileage(float totalMileage) { 95 | this.totalMileage = totalMileage; 96 | } 97 | 98 | public float getFinishMileage() { 99 | return finishMileage; 100 | } 101 | 102 | public void setFinishMileage(float finishMileage) { 103 | this.finishMileage = finishMileage; 104 | } 105 | 106 | public byte getIsRead() { 107 | return isRead; 108 | } 109 | 110 | public void setIsRead(byte isRead) { 111 | this.isRead = isRead; 112 | } 113 | 114 | public int getMsgLen() { 115 | return msgLen; 116 | } 117 | 118 | public void setMsgLen(int msgLen) { 119 | this.msgLen = msgLen; 120 | } 121 | 122 | public String getMsg() { 123 | return msg; 124 | } 125 | 126 | public void setMsg(String msg) { 127 | this.msg = msg; 128 | } 129 | 130 | @Override 131 | public String toString() { 132 | return "StudentLoginMsgRespBody{" + 133 | "replyFlowId=" + replyFlowId + 134 | ", replyCode=" + replyCode + 135 | ", stuhnum='" + stuhnum + '\'' + 136 | ", totalHours=" + totalHours + 137 | ", finishHours=" + finishHours + 138 | ", totalMileage=" + totalMileage + 139 | ", finishMileage=" + finishMileage + 140 | ", isRead=" + isRead + 141 | ", msgLen=" + msgLen + 142 | ", msg='" + msg + '\'' + 143 | '}'; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/resp/TerminalArgMsgRespBody.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.resp; 2 | 3 | import com.jt808.vo.PackageData; 4 | 5 | import java.util.Arrays; 6 | 7 | public class TerminalArgMsgRespBody extends PackageData { 8 | 9 | private TerminalArgMsg terminalArgMsg; 10 | 11 | public TerminalArgMsgRespBody() { 12 | } 13 | 14 | public TerminalArgMsgRespBody(PackageData packageData) { 15 | this(); 16 | this.channel = packageData.getChannel(); 17 | this.checkSum = packageData.getCheckSum(); 18 | this.msgBodyBytes = packageData.getMsgBodyBytes(); 19 | this.msgHeader = packageData.getMsgHeader(); 20 | } 21 | 22 | public TerminalArgMsg getTerminalArgMsg() { 23 | return terminalArgMsg; 24 | } 25 | 26 | public void setTerminalArgMsg(TerminalArgMsg terminalArgMsg) { 27 | this.terminalArgMsg = terminalArgMsg; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return "TerminalArgMsgRespBody{" + 33 | "terminalArgMsg=" + terminalArgMsg + 34 | ", msgHeader=" + msgHeader + 35 | ", msgBodyBytes=" + Arrays.toString(msgBodyBytes) + 36 | ", checkSum=" + checkSum + 37 | ", channel=" + channel + 38 | '}'; 39 | } 40 | 41 | public static class TerminalArgMsg { 42 | /** 43 | * 应答流水号 WORD BYTE[2] 44 | */ 45 | private int replyFlowId; 46 | /** 47 | * 应答参数个数 BYTE[1] 48 | */ 49 | private int argNum; 50 | /** 51 | * 包参数个数 BYTE[1] 52 | */ 53 | private int pakNum; 54 | /** 55 | * 参数列表项 56 | */ 57 | private TerminalArgList terminalArgList; 58 | 59 | public TerminalArgMsg() { 60 | } 61 | 62 | public int getReplyFlowId() { 63 | return replyFlowId; 64 | } 65 | 66 | public void setReplyFlowId(int replyFlowId) { 67 | this.replyFlowId = replyFlowId; 68 | } 69 | 70 | public int getArgNum() { 71 | return argNum; 72 | } 73 | 74 | public void setArgNum(int argNum) { 75 | this.argNum = argNum; 76 | } 77 | 78 | public int getPakNum() { 79 | return pakNum; 80 | } 81 | 82 | public void setPakNum(int pakNum) { 83 | this.pakNum = pakNum; 84 | } 85 | 86 | public TerminalArgList getTerminalArgList() { 87 | return terminalArgList; 88 | } 89 | 90 | public void setTerminalArgList(TerminalArgList terminalArgList) { 91 | this.terminalArgList = terminalArgList; 92 | } 93 | 94 | @Override 95 | public String toString() { 96 | return "TerminalArgMsg{" + 97 | "replyFlowId=" + replyFlowId + 98 | ", argNum=" + argNum + 99 | ", pakNum=" + pakNum + 100 | ", terminalArgList=" + terminalArgList + 101 | '}'; 102 | } 103 | 104 | public static class TerminalArgList { 105 | //参数id DWORD[4] 106 | private int argId; 107 | //参数长度 BYTE[1] 108 | private int argLen; 109 | //参数值 110 | private String arg; 111 | 112 | public TerminalArgList() { 113 | } 114 | 115 | public int getArgId() { 116 | return argId; 117 | } 118 | 119 | public void setArgId(int argId) { 120 | this.argId = argId; 121 | } 122 | 123 | public int getArgLen() { 124 | return argLen; 125 | } 126 | 127 | public void setArgLen(int argLen) { 128 | this.argLen = argLen; 129 | } 130 | 131 | public String getArg() { 132 | return arg; 133 | } 134 | 135 | public void setArg(String arg) { 136 | this.arg = arg; 137 | } 138 | 139 | @Override 140 | public String toString() { 141 | return "TerminalArgList{" + 142 | "argId=" + argId + 143 | ", argLen=" + argLen + 144 | ", arg='" + arg + '\'' + 145 | '}'; 146 | } 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/main/java/com/jt808/vo/resp/TerminalRegisterMsgRespBody.java: -------------------------------------------------------------------------------- 1 | package com.jt808.vo.resp; 2 | 3 | //终端注册应答 4 | public class TerminalRegisterMsgRespBody { 5 | 6 | public static final byte success = 0; 7 | public static final byte car_already_registered = 1; 8 | public static final byte car_not_found = 2; 9 | public static final byte terminal_already_registered = 3; 10 | public static final byte terminal_not_found = 4; 11 | // byte[0-1] 应答流水号(WORD) 对应的终端注册消息的流水号 12 | private int replyFlowId; 13 | /*** 14 | * byte[2] 结果(BYTE)
15 | * 0:成功
16 | * 1:车辆已被注册
17 | * 2:数据库中无该车辆
18 | * 3:终端已被注册
19 | * 4:数据库中无该终端
20 | **/ 21 | private byte replyCode; 22 | // byte[3-x] 鉴权码(STRING) 只有在成功后才有该字段 23 | private String replyToken; 24 | //平台编号 25 | private String num; 26 | //培训机构编号 27 | private String inscode; 28 | //计时终端编号 29 | private String devnum; 30 | //证书口令 31 | private String pass; 32 | //终端证书 33 | private String credential; 34 | public TerminalRegisterMsgRespBody() { 35 | } 36 | 37 | public int getReplyFlowId() { 38 | return replyFlowId; 39 | } 40 | 41 | public void setReplyFlowId(int flowId) { 42 | this.replyFlowId = flowId; 43 | } 44 | 45 | public byte getReplyCode() { 46 | return replyCode; 47 | } 48 | 49 | public void setReplyCode(byte code) { 50 | this.replyCode = code; 51 | } 52 | 53 | public String getReplyToken() { 54 | return replyToken; 55 | } 56 | 57 | public void setReplyToken(String token) { 58 | this.replyToken = token; 59 | } 60 | 61 | public String getNum() { 62 | return num; 63 | } 64 | 65 | public void setNum(String num) { 66 | this.num = num; 67 | } 68 | 69 | public String getInscode() { 70 | return inscode; 71 | } 72 | 73 | public void setInscode(String inscode) { 74 | this.inscode = inscode; 75 | } 76 | 77 | public String getDevnum() { 78 | return devnum; 79 | } 80 | 81 | public void setDevnum(String devnum) { 82 | this.devnum = devnum; 83 | } 84 | 85 | public String getCredential() { 86 | return credential; 87 | } 88 | 89 | public void setCredential(String credential) { 90 | this.credential = credential; 91 | } 92 | 93 | public String getPass() { 94 | return pass; 95 | } 96 | 97 | public void setPass(String pass) { 98 | this.pass = pass; 99 | } 100 | 101 | @Override 102 | public String toString() { 103 | return "TerminalRegisterMsgRespBody{" + 104 | "replyFlowId=" + replyFlowId + 105 | ", replyCode=" + replyCode + 106 | ", replyToken='" + replyToken + '\'' + 107 | ", num='" + num + '\'' + 108 | ", inscode='" + inscode + '\'' + 109 | ", devnum='" + devnum + '\'' + 110 | ", pass='" + pass + '\'' + 111 | ", credential='" + credential + '\'' + 112 | '}'; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /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/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 | 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 | --------------------------------------------------------------------------------