扁平化写法示例
2024年3月24日小于 1 分钟
扁平化写法示例
提示
- 在阅读本文之前,建议先阅读 协议格式说明
- 所谓的 扁平化写法 就是不用单独封装
Header
和Body
,而是直接将Header
和Body
的数据写在同一个实体类中
实体类定义
Rust 命名风格
@Setter
@Getter
@ToString
public class RustStyleDebugEntity02Flatten {
// region 消息头
// byte[0-2) 消息ID word(16)
@Preset.RustStyle.u16
private int msgId;
// byte[2-4) 消息体属性 word(16)
@Preset.RustStyle.u16
private int msgBodyProps;
// byte[4] 协议版本号
@Preset.RustStyle.u8
private byte protocolVersion;
// byte[5-15) 终端手机号或设备ID bcd[10]
@Preset.RustStyle.str(charset = XtreamConstants.CHARSET_NAME_BCD_8421, length = 10)
private String terminalId;
// byte[15-17) 消息流水号 word(16)
@Preset.RustStyle.u16
private int msgSerialNo;
// byte[17-21) 消息包封装项
@Preset.RustStyle.u32(condition = "hasSubPackage()")
private Long subPackageInfo;
// endregion 消息头
// region 消息体
// 报警标志 DWORD(4)
@Preset.RustStyle.u32
private long alarmFlag;
// 状态 DWORD(4)
@Preset.RustStyle.u32
private long status;
// 纬度 DWORD(4)
@Preset.RustStyle.u32
private long latitude;
// 经度 DWORD(4)
@Preset.RustStyle.u32
private long longitude;
// 高程 WORD(2)
@Preset.RustStyle.u16
private int altitude;
// 高程 WORD(2)
@Preset.RustStyle.u16
private int speed;
// 方向 WORD(2)
@Preset.RustStyle.u16
private int direction;
// 时间 BCD[6] yyMMddHHmmss
@Preset.RustStyle.str(charset = XtreamConstants.CHARSET_NAME_BCD_8421, length = 6)
private String time;
// 长度:消息体长度减去前面的 28 字节
@Preset.RustStyle.list(lengthExpression = "msgBodyLength() - 28")
private List<ExtraItem> extraItems;
// endregion 消息体
// 校验码
@Preset.RustStyle.i8
private byte checkSum;
// bit[0-9] 0000,0011,1111,1111(3FF)(消息体长度)
public int msgBodyLength() {
return msgBodyProps & 0x3ff;
}
// bit[13] 0010,0000,0000,0000(2000)(是否有子包)
public boolean hasSubPackage() {
// return ((msgBodyProperty & 0x2000) >> 13) == 1;
return (msgBodyProps & 0x2000) > 0;
}
@Setter
@Getter
@ToString
public static class ExtraItem {
// 附加信息ID BYTE(1~255)
@Preset.RustStyle.u8
private short id;
// 附加信息长度 BYTE(1~255)
@Preset.RustStyle.u8
private short contentLength;
// 附加信息内容 BYTE[N]
@Preset.RustStyle.byte_array(lengthExpression = "getContentLength()")
private byte[] content;
public ExtraItem() {
}
public ExtraItem(short id, short length, byte[] content) {
this.id = id;
this.contentLength = length;
this.content = content;
}
}
}
原始命名风格
@Setter
@Getter
@ToString
public class RawStyleDebugEntity02Flatten {
// region 消息头
// byte[0-2) 消息ID word(16)
@XtreamField(length = 2)
private int msgId;
// byte[2-4) 消息体属性 word(16)
@XtreamField(length = 2)
private int msgBodyProps;
// byte[4] 协议版本号
@XtreamField(length = 1)
private byte protocolVersion;
// byte[5-15) 终端手机号或设备ID bcd[10]
@XtreamField(charset = XtreamConstants.CHARSET_NAME_BCD_8421, length = 10)
private String terminalId;
// byte[15-17) 消息流水号 word(16)
@XtreamField(length = 2)
private int msgSerialNo;
// byte[17-21) 消息包封装项
@XtreamField(condition = "hasSubPackage()")
private Long subPackageInfo;
// endregion 消息头
// region 消息体
// 报警标志 DWORD(4)
@XtreamField(length = 4)
private long alarmFlag;
// 状态 DWORD(4)
@XtreamField(length = 4)
private long status;
// 纬度 DWORD(4)
@XtreamField(length = 4)
private long latitude;
// 经度 DWORD(4)
@XtreamField(length = 4)
private long longitude;
// 高程 WORD(2)
@XtreamField(length = 2)
private int altitude;
// 高程 WORD(2)
@XtreamField(length = 2)
private int speed;
// 方向 WORD(2)
@XtreamField(length = 2)
private int direction;
// 时间 BCD[6] yyMMddHHmmss
@XtreamField(charset = XtreamConstants.CHARSET_NAME_BCD_8421, length = 6)
private String time;
// 长度:消息体长度减去前面的 28 字节
@XtreamField(dataType = BeanPropertyMetadata.FiledDataType.sequence, lengthExpression = "msgBodyLength() - 28")
private List<ExtraItem> extraItems;
// endregion 消息体
// 校验码
@XtreamField(length = 1)
private byte checkSum;
// bit[0-9] 0000,0011,1111,1111(3FF)(消息体长度)
public int msgBodyLength() {
return msgBodyProps & 0x3ff;
}
// bit[13] 0010,0000,0000,0000(2000)(是否有子包)
public boolean hasSubPackage() {
// return ((msgBodyProperty & 0x2000) >> 13) == 1;
return (msgBodyProps & 0x2000) > 0;
}
@Setter
@Getter
@ToString
public static class ExtraItem {
// 附加信息ID BYTE(1~255)
@XtreamField(length = 1)
private short id;
// 附加信息长度 BYTE(1~255)
@XtreamField(length = 1)
private short contentLength;
// 附加信息内容 BYTE[N]
@XtreamField(dataType = BeanPropertyMetadata.FiledDataType.basic, lengthExpression = "getContentLength()")
private byte[] content;
public ExtraItem() {
}
public ExtraItem(short id, short length, byte[] content) {
this.id = id;
this.contentLength = length;
this.content = content;
}
}
}
JT/T 808 命名风格
@Setter
@Getter
@ToString
public class JtStyleDebugEntity02Flatten {
// region 消息头
// byte[0-2) 消息ID word(16)
@Preset.JtStyle.Word
private int msgId;
// byte[2-4) 消息体属性 word(16)
@Preset.JtStyle.Word
private int msgBodyProps;
// byte[4] 协议版本号
@Preset.JtStyle.Byte
private byte protocolVersion;
// byte[5-15) 终端手机号或设备ID bcd[10]
@Preset.JtStyle.Bcd(length = 10)
private String terminalId;
// byte[15-17) 消息流水号 word(16)
@Preset.JtStyle.Word
private int msgSerialNo;
// byte[17-21) 消息包封装项
@Preset.JtStyle.Dword(condition = "hasSubPackage()")
private Long subPackageInfo;
// endregion 消息头
// region 消息体
// 报警标志 DWORD(4)
@Preset.JtStyle.Dword
private long alarmFlag;
// 状态 DWORD(4)
@Preset.JtStyle.Dword
private long status;
// 纬度 DWORD(4)
@Preset.JtStyle.Dword
private long latitude;
// 经度 DWORD(4)
@Preset.JtStyle.Dword
private long longitude;
// 高程 WORD(2)
@Preset.JtStyle.Word
private int altitude;
// 高程 WORD(2)
@Preset.JtStyle.Word
private int speed;
// 方向 WORD(2)
@Preset.JtStyle.Word
private int direction;
// 时间 BCD[6] yyMMddHHmmss
@Preset.JtStyle.Bcd(length = 6)
private String time;
// 长度:消息体长度减去前面的 28 字节
@Preset.JtStyle.List(lengthExpression = "msgBodyLength() - 28")
private List<ExtraItem> extraItems;
// endregion 消息体
// 校验码
@Preset.JtStyle.Byte
private byte checkSum;
// bit[0-9] 0000,0011,1111,1111(3FF)(消息体长度)
public int msgBodyLength() {
return msgBodyProps & 0x3ff;
}
// bit[13] 0010,0000,0000,0000(2000)(是否有子包)
public boolean hasSubPackage() {
// return ((msgBodyProperty & 0x2000) >> 13) == 1;
return (msgBodyProps & 0x2000) > 0;
}
@Setter
@Getter
@ToString
public static class ExtraItem {
// 附加信息ID BYTE(1~255)
@Preset.JtStyle.Byte
private short id;
// 附加信息长度 BYTE(1~255)
@Preset.JtStyle.Byte
private short contentLength;
// 附加信息内容 BYTE[N]
@Preset.JtStyle.Bytes(lengthExpression = "getContentLength()")
private byte[] content;
public ExtraItem() {
}
public ExtraItem(short id, short length, byte[] content) {
this.id = id;
this.contentLength = length;
this.content = content;
}
}
}
反序列化
public class EntityDecodeTest {
@Test
void testDecode() {
final EntityCodec entityCodec = EntityCodec.DEFAULT;
// buffer 中存储的是要反序列化的数据(这里写死用来演示)
final String hexString = "0200402a01000000000139111122220063000000580000006f01dc9a0707456246231d029a005a240322222633010400001a0a02020058030200595b";
final ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer().writeBytes(XtreamBytes.decodeHex(hexString));
try {
final JtStyleDebugEntity02Flatten entity = entityCodec.decode(JtStyleDebugEntity02Flatten.class, buffer);
System.out.println(entity);
} finally {
buffer.release();
}
}
}
序列化
public class EntityEncodeTest {
@Test
void testEncode() {
final EntityCodec entityCodec = EntityCodec.DEFAULT;
final ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer();
try {
final JtStyleDebugEntity02Flatten instance = new JtStyleDebugEntity02Flatten();
// TODO 省略属性赋值
// instance.setXxx(someValue);
// instance.setMsgId(someValue);
// ...
// 将 instance 的数据序列化到 buffer 中
entityCodec.encode(instance, buffer);
// 使用 buffer
System.out.println(ByteBufUtil.hexDump(buffer));
} finally {
buffer.release();
}
}
}