master
剑器近 2020-11-05 10:15:09 +08:00
parent 6fa42d1706
commit 1ada42637e
1 changed files with 72 additions and 216 deletions

288
README.md
View File

@ -1,236 +1,92 @@
部标808协议快速开发包
====================
# 项目介绍
* 基于Netty实现JT/T 808部标协议的消息分发与编码解码
* 与Spring解耦合协议编码解码和Netty服务均可独立运行Android客户端同样适用
* SpringBoot 仅负责将协议暴露至Web接口目的是方便测试且为二次开发提供样例
* 最简洁、清爽、易用的部标开发框架。
一款纯粹的Java序列化框架
问题交流群:[906230542]
- **纯粹**, 严格按照字节顺序和长度写入,不产生额外的描述性信息;
- **性能**, 基于Netty的ByteBuf可使用池化内存与堆外内存提升性能
- **多版本**, 同一个Class支持多个版本的配置。
# 主要特性
* 代码足够精简,便于二次开发;
* 致敬Spring、Hibernate设计理念熟悉Web开发的同学上手极快
* 使用注解描述协议,告别繁琐的封包、解包;
* 实时兼容2011、2013、2019部标协议版本支持分包请求
* 支持JT/T1078音视频协议T/JSATL12苏标主动安防协议
* 支持异步批量处理显著提升MySQL入库性能
* 提供报文解释器(解析过程分析工具),编码解码不再抓瞎;
* 全覆盖的测试用例,稳定发版。
### 场景
- 适用于多数序列化场景,用于传输或存储对象;
- 开发初期的目的是为了解析部标、国标相关的通讯协议。
# 代码仓库
* Gitee仓库地址[https://gitee.com/yezhihao/jt808-server/tree/master](https://gitee.com/yezhihao/jt808-server/tree/master)
* Github仓库地址[https://github.com/yezhihao/jt808-server/tree/master](https://github.com/yezhihao/jt808-server/tree/master)
# 下载方式
* Gitee下载命令`git clone https://gitee.com/yezhihao/jt808-server -b master`
* Github下载命令`git clone https://github.com/yezhihao/jt808-server -b master`
# 使用说明
## 项目分为四部分:
## 1.framework核心模块不推荐修改有BUG或扩展的需求建议提交issues或联系作者
```sh
└── framework
├── codec 编码解码
├── mvc 消息分发、处理
├── netty 网络通信
├── orm 序列化相关
└── session 消息发送和会话管理
```
注解:
* @Endpoint服务接入点等价SpringMVC的 @Controller
* @Mapping定义消息ID等价SpringMVC中 @RequestMapping
* @AsyncBatch, 异步批量消息对于并发较高的消息如0x0200(位置信息汇报)使用该注解显著提升Netty和MySQL入库性能。
* @Message协议类型等价Hibernate的 @Table
* @Field属性定义等价Hibernate的 @Column
* @Fs,多版本协议支持
## 2.protocol 部标协议定义,不推荐做大量修改
```sh
└── protocol
├── basics 部标协议通用消息头,以及公共的消息定义
├── codec 部标编码解码工具
├── commons 部标协议ID工具类等
├── jsatl12 T/JSATL12 苏标协议(已完成)
├── t808 JT/T808 部标协议(已完成)
└── t1078 JT/T1078 音视频协议(已完成)
```
消息定义样例:
```java
@Message(JT808.定位数据批量上传)
public class T0704 extends AbstractMessage<Header> {
private Integer total;
private Integer type;
private List<Item> items;
@Field(index = 0, type = DataType.WORD, desc = "数据项个数")
public Integer getTotal() { return total; }
public void setTotal(Integer total) { this.total = total; }
@Field(index = 2, type = DataType.BYTE, desc = "位置数据类型 0正常位置批量汇报1盲区补报")
public Integer getType() { return type; }
public void setType(Integer type) { this.type = type; }
@Field(index = 3, type = DataType.LIST, desc = "位置汇报数据项")
public List<Item> getItems() { return items; }
public void setItems(List<Item> items) { this.items = items; this.total = items.size(); }
}
```
## 3.web 开箱即用的Demo业务需求在这个包下开发可随意修改
```sh
└── web
├── config spring 相关配置
├── component.mybatis 附赠极简的mybatis分页插件:D
├── endpoint 808消息入口所有netty进入的请求都会根据@Mapping转发到此
└── controller service mapper ... 不再赘述
```
##### 消息接入:
## 使用
```java
@Endpoint
public class JT808Endpoint {
@Autowired
private LocationService locationService;
@Autowired
private DeviceService deviceService;
public class Test {
//异步批量处理 队列大小20000 最大累积200处理一次 最大等待时间5秒
@AsyncBatch(capacity = 20000, maxElements = 200, maxWait = 5000)
@Mapping(types = 位置信息汇报, desc = "位置信息汇报")
public void 位置信息汇报(List<T0200> list) {
locationService.batchInsert(list);
public static void main(String[] args) {
//开启序列化过程分析
FieldFactory.EXPLAIN = true;
//获得多个版本的协议定义
Map<Integer, Schema<Foo>> multiVersionSchema = ProtostarUtil.getSchema(Foo.class);
//默认的版本是0
Schema<Foo> schema = multiVersionSchema.get(0);
//使用netty的Unpooled申请初始32字节的空间
ByteBuf buffer = Unpooled.buffer(32);
//将foo写入到缓冲区
schema.writeTo(buffer, foo());
String hex = ByteBufUtil.hexDump(buffer);
System.out.println(hex);
//将缓冲区的字节解析为对象
Foo foo = schema.readFrom(buffer);
System.out.println(foo);
}
@Async
@Mapping(types = 终端注册, desc = "终端注册")
public T8100 register(T0100 message, Session session) {
Header header = message.getHeader();
public static Foo foo() {
Foo foo = new Foo();
foo.setName("张三");
foo.setId(128);
foo.setDateTime(LocalDateTime.of(2020, 7, 7, 19, 23, 59));
return foo;
}
T8100 result = new T8100(session.nextSerialNo(), header.getMobileNo());
result.setSerialNo(header.getSerialNo());
public static class Foo {
String token = deviceService.register(message);
if (token != null) {
session.register(header);
private String name;
private int id;
private LocalDateTime dateTime;
result.setResultCode(T8100.Success);
result.setToken(token);
} else {
result.setResultCode(T8100.NotFoundTerminal);
@Field(index = 0, type = DataType.STRING, lengthSize = 1, desc = "名称")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Field(index = 1, type = DataType.WORD, desc = "ID")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Field(index = 3, type = DataType.BCD8421, desc = "日期")
public LocalDateTime getDateTime() {
return dateTime;
}
public void setDateTime(LocalDateTime dateTime) {
this.dateTime = dateTime;
}
return result;
}
}
```
##### 消息下发:
```java
@Controller
@RestController("terminal")
public class TerminalController {
## Maven
```xml
<dependency>
<groupId>io.github.yezhihao</groupId>
<artifactId>protostar</artifactId>
<version>1.0.0.RELEASE</version>
</dependency>
```
private MessageManager messageManager = MessageManager.getInstance();
@ApiOperation("设置终端参数")
@PostMapping("{terminalId}/parameters")
public T0001 updateParameters(@PathVariable("terminalId") String terminalId, @RequestBody List<TerminalParameter> parameters) {
T8103 request = new T8103(terminalId);
request.setItems(parameters);
T0001 response = messageManager.request(request, T0001.class);
return response;
}
}
```
##### 已集成Swagger文档启动后可访问如下地址
* Swagger UI[http://127.0.0.1:8000/swagger-ui.html](http://127.0.0.1:8000/swagger-ui.html)
* Bootstrap UI[http://127.0.0.1:8000/doc.html](http://127.0.0.1:8000/doc.html)
![Bootstrap UI](https://images.gitee.com/uploads/images/2020/0731/135035_43dfca8e_670717.png "doc2.png")
## 4.test 808协议全覆盖的测试用例以及报文解释器
* QuickStart 不依赖Spring的启动可用于Android客户端
* Beans 测试数据
* TestBeans 消息对象的封包解包
* TestHex 原始报文测试
* Elucidator 报文解释器 - 解码
* DarkRepulsor 报文解释器 - 编码
分析报文内每个属性所处的位置以及转换后的值,以便查询报文解析出错的原因
Elucidator 运行效果如下:
```
0 [0200] 消息ID: 512
2 [4061] 消息体属性: 16481
4 [01] 协议版本号: 1
5 [00000000017299841738] 终端手机号: 17299841738
15 [ffff] 流水号: 65535
0 [00000400] 报警标志: 1024
4 [00000800] 状态: 2048
8 [06eeb6ad] 纬度: 116307629
12 [02633df7] 经度: 40058359
16 [0138] 海拔: 312
18 [0003] 速度: 3
20 [0063] 方向: 99
22 [200707192359] 时间: 2020-07-07T19:23:59
0 [01] 附加信息ID: 1
1 [04] 参数值长度: 4
2 [0000000b] 参数值: {0,0,0,11}
0 [02] 附加信息ID: 2
1 [02] 参数值长度: 2
2 [0016] 参数值: {0,22}
0 [03] 附加信息ID: 3
1 [02] 参数值长度: 2
2 [0021] 参数值: {0,33}
0 [04] 附加信息ID: 4
1 [02] 参数值长度: 2
2 [002c] 参数值: {0,44}
0 [05] 附加信息ID: 5
1 [03] 参数值长度: 3
2 [373737] 参数值: {55,55,55}
0 [11] 附加信息ID: 17
1 [05] 参数值长度: 5
2 [4200000042] 参数值: {66,0,0,0,66}
0 [12] 附加信息ID: 18
1 [06] 参数值长度: 6
2 [4d0000004d4d] 参数值: {77,0,0,0,77,77}
0 [13] 附加信息ID: 19
1 [07] 参数值长度: 7
2 [00000058005858] 参数值: {0,0,0,88,0,88,88}
0 [25] 附加信息ID: 37
1 [04] 参数值长度: 4
2 [00000063] 参数值: {0,0,0,99}
0 [2a] 附加信息ID: 42
1 [02] 参数值长度: 2
2 [000a] 参数值: {0,10}
0 [2b] 附加信息ID: 43
1 [04] 参数值长度: 4
2 [00000014] 参数值: {0,0,0,20}
0 [30] 附加信息ID: 48
1 [01] 参数值长度: 1
2 [1e] 参数值: {30}
0 [31] 附加信息ID: 49
1 [01] 参数值长度: 1
2 [28] 参数值: {40}
28 [01040000000b02020016030200210402002c05033737371105420000004212064d0000004d4d1307000000580058582504000000632a02000a2b040000001430011e310128] 位置附加信息: [BytesAttribute[id=1,value={0,0,0,11}], BytesAttribute[id=2,value={0,22}], BytesAttribute[id=3,value={0,33}], BytesAttribute[id=4,value={0,44}], BytesAttribute[id=5,value={55,55,55}], BytesAttribute[id=17,value={66,0,0,0,66}], BytesAttribute[id=18,value={77,0,0,0,77,77}], BytesAttribute[id=19,value={0,0,0,88,0,88,88}], BytesAttribute[id=37,value={0,0,0,99}], BytesAttribute[id=42,value={0,10}], BytesAttribute[id=43,value={0,0,0,20}], BytesAttribute[id=48,value={30}], BytesAttribute[id=49,value={40}]]
020040610100000000017299841738ffff000004000000080006eeb6ad02633df701380003006320070719235901040000000b02020016030200210402002c05033737371105420000004212064d0000004d4d1307000000580058582504000000632a02000a2b040000001430011e31012863
```
使用发包工具模拟请求
```
7e020040610100000000017299841738ffff000004000000080006eeb6ad02633df701380003006320070719235901040000000b02020016030200210402002c05033737371105420000004212064d0000004d4d1307000000580058582504000000632a02000a2b040000001430011e310128637e
```
![使用发包工具模拟请求](https://images.gitee.com/uploads/images/2019/0705/162745_9becaf08_670717.png)
更多的例子请参考Test目录
项目会不定期进行更新建议star和watch一份您的支持是我最大的动力。