-
Notifications
You must be signed in to change notification settings - Fork 20
数据实体定义的最佳实践
ray.zh edited this page Nov 21, 2023
·
21 revisions
框架对于数据结构实体定义是没有限制的。 可以使用以下数据类型:
- byte/boolean/char/short/int/long/float/double
- Byte/Boolean/Char/Short/Integer/Long/Float/Double/String/UByte/UShort/UInt/ULong/UNumber
- 其他有正确定义数据格式的实体类
在实际项目使用中,一般有两种使用方式:
完整代码位于项目com.github.misterchangray.core.example
目录下
在本例中假设存在两种数据报文HeatbeatCmd
和EchoCmd
/**
* 报文头
* 一般来说为公共结构, 即每个数据都应该有此字段
*/
@MagicClass
public class Head {
@MagicField(order = 1)
private byte header;
// calcLength = true 时,此字段将会在序列化时自动填充数据实际长度
@MagicField(order = 3, calcLength = true)
private byte length;
// 假设 1=HeartbeatCmd,2=EchoCmd
@MagicField(order = 5)
private byte cmd;
// ignore setter/getter
}
/**
* 心跳报文
*
* 一般来说会周期性上报
*/
@MagicClass()
public class HeartbeatCmd {
// 这里组合使用 Head 结构
@MagicField(order = 1)
private Head head;
// 8 bytes
@MagicField(order = 3)
private long timestamp;
// 1 byte
@MagicField(order = 5)
private byte checkCode;
// ignore setter/getter
}
/**
* 指定的业务报文
*
* 一般来说,这里应该是业务报文,
* 这里假设设备端存在一个回响报文, 设备端原样返回云端下发数据
*/
@MagicClass()
public class EchoCmd {
// 这里组合使用 Head 结构
@MagicField(order = 1)
private Head head;
// string 总字节数为10
@MagicField(order = 3, size = 10)
private String body;
// 1 byte
@MagicField(order = 5)
private byte checkCode;
// ignore setter/getter
}
定义完成报文结构体后,当设备上行数据到达时,使用以下方式进行解析:
/**
* 这里是项目的启动类
*/
public class ApplicationStartup {
public static void main(String[] args) {
// 假设此处数据为设备的上行数据
byte[] deviceUploadMessage = new byte[]{};
// 以下为业务端逻辑解析建议方式
// 1. 首先应该解析报文头
Head pack = MagicByte.pack(deviceUploadMessage, Head.class);
// 2. 这里省略检查报文头逻辑
// 3. 根据报文类型解析为特定的报文格式
switch (pack.getCmd()) {
case 1:
HeartbeatCmd pack1 = MagicByte.pack(deviceUploadMessage, HeartbeatCmd.class);
doHeartbeatCmd(pack1);
break;
case 2:
EchoCmd pack2 = MagicByte.pack(deviceUploadMessage, EchoCmd.class);
doEchoCmd(pack2);
break;
// 更多的报文类型
}
}
private static void doEchoCmd(EchoCmd pack2) {
// 这里处理EchoCmd 的业务
}
private static void doHeartbeatCmd(HeartbeatCmd pack1) {
// 这里处理 HeartbeatCmd 的业务
}
}
以上是框架的建议的使用方式。其他的情况框架将会做如下处理:
- 未被
@MagicField
进行标注的字段将会被字节忽略 - 继承的属性直接被忽略。因为不支持继承。
- 未知的数据类型, 即没有自定义转换且也没有受到支持的数据类型;比如使用 Map, Object 什么的。
- 如果使用包装类型且未赋值, 则将使用原始类型默认值。
- 数组或对象为
Null
时, 将使用 0x00 进行填充。 - 如果需要计算校验和的场景,建议返回buffer然后直接附加校验和结果
-
strict=true
模式将会自动继承, 并且要求数据完整(即数据长度不匹配将不会解析); 默认false
若大家在使用过程中有疑问,可以参考右边的目录列表进行查询