扁平化写法示例
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 short 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()")
@Preset.RustStyle.u32(conditions = @Expression(spel = "hasSubPackage()", mvel = "self.hasSubPackage()", aviator = "self.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")
@Preset.RustStyle.list(lengthExpressions = @Expression(spel = "msgBodyLength() - 28", mvel = "self.msgBodyLength() - 28", aviator = "self.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;
}
// for Aviator
@SuppressWarnings("unused")
public int getMsgBodyLength() {
return msgBodyProps & 0x3ff;
}
// bit[13] 0010,0000,0000,0000(2000)(是否有子包)
public boolean hasSubPackage() {
// return ((msgBodyProperty & 0x2000) >> 13) == 1;
return (msgBodyProps & 0x2000) > 0;
}
// for Aviator
@SuppressWarnings("unused")
public boolean isHasSubPackage() {
// 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()")
@Preset.RustStyle.byte_array(lengthExpressions = @Expression(spel = "getContentLength()", mvel = "self.getContentLength()", aviator = "self.contentLength"))
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, signedness = NumberSignedness.UNSIGNED)
private int msgId;
// byte[2-4) 消息体属性 word(16)
@XtreamField(length = 2, signedness = NumberSignedness.UNSIGNED)
private int msgBodyProps;
// byte[4] 协议版本号
@XtreamField(length = 1, signedness = NumberSignedness.UNSIGNED)
private short 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, signedness = NumberSignedness.UNSIGNED)
private int msgSerialNo;
// byte[17-21) 消息包封装项
// @XtreamField(condition = "hasSubPackage()", length = 4, signedness = NumberSignedness.UNSIGNED)
@XtreamField(conditions = @Expression(spel = "hasSubPackage()", mvel = "self.hasSubPackage()", aviator = "self.hasSubPackage"), length = 4, signedness = NumberSignedness.UNSIGNED)
private Long subPackageInfo;
// endregion 消息头
// region 消息体
// 报警标志 DWORD(4)
@XtreamField(length = 4, signedness = NumberSignedness.UNSIGNED)
private long alarmFlag;
// 状态 DWORD(4)
@XtreamField(length = 4, signedness = NumberSignedness.UNSIGNED)
private long status;
// 纬度 DWORD(4)
@XtreamField(length = 4, signedness = NumberSignedness.UNSIGNED)
private long latitude;
// 经度 DWORD(4)
@XtreamField(length = 4, signedness = NumberSignedness.UNSIGNED)
private long longitude;
// 高程 WORD(2)
@XtreamField(length = 2, signedness = NumberSignedness.UNSIGNED)
private int altitude;
// 高程 WORD(2)
@XtreamField(length = 2, signedness = NumberSignedness.UNSIGNED)
private int speed;
// 方向 WORD(2)
@XtreamField(length = 2, signedness = NumberSignedness.UNSIGNED)
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")
@XtreamField(dataType = BeanPropertyMetadata.FiledDataType.sequence, lengthExpressions = @Expression(spel = "msgBodyLength() - 28", mvel = "self.msgBodyLength() - 28", aviator = "self.msgBodyLength - 28"))
private List<ExtraItem> extraItems;
// endregion 消息体
// 校验码
@XtreamField(length = 1, signedness = NumberSignedness.UNSIGNED)
private short checkSum;
// bit[0-9] 0000,0011,1111,1111(3FF)(消息体长度)
public int msgBodyLength() {
return msgBodyProps & 0x3ff;
}
// for Aviator
@SuppressWarnings("unused")
public int getMsgBodyLength() {
return msgBodyProps & 0x3ff;
}
// bit[13] 0010,0000,0000,0000(2000)(是否有子包)
public boolean hasSubPackage() {
// return ((msgBodyProperty & 0x2000) >> 13) == 1;
return (msgBodyProps & 0x2000) > 0;
}
// for Aviator
@SuppressWarnings("unused")
public boolean isHasSubPackage() {
// return ((msgBodyProperty & 0x2000) >> 13) == 1;
return (msgBodyProps & 0x2000) > 0;
}
@Setter
@Getter
@ToString
public static class ExtraItem {
// 附加信息ID BYTE(1~255)
@XtreamField(length = 1, signedness = NumberSignedness.UNSIGNED)
private short id;
// 附加信息长度 BYTE(1~255)
@XtreamField(length = 1, signedness = NumberSignedness.UNSIGNED)
private short contentLength;
// 附加信息内容 BYTE[N]
// @XtreamField(dataType = BeanPropertyMetadata.FiledDataType.basic, lengthExpression = "getContentLength()")
@XtreamField(dataType = BeanPropertyMetadata.FiledDataType.basic, lengthExpressions = @Expression(spel = "getContentLength()", mvel = "self.getContentLength()", aviator = "self.contentLength"))
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 short 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()")
@Preset.JtStyle.Dword(conditions = @Expression(spel = "hasSubPackage()", mvel = "self.hasSubPackage()", aviator = "self.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")
@Preset.JtStyle.List(lengthExpressions = @Expression(spel = "msgBodyLength() - 28", mvel = "self.msgBodyLength() - 28", aviator = "self.msgBodyLength - 28"))
private List<ExtraItem> extraItems;
// endregion 消息体
// 校验码
@Preset.JtStyle.Byte
private short checkSum;
// bit[0-9] 0000,0011,1111,1111(3FF)(消息体长度)
public int msgBodyLength() {
return msgBodyProps & 0x3ff;
}
// for Aviator
@SuppressWarnings("unused")
public int getMsgBodyLength() {
return msgBodyProps & 0x3ff;
}
// bit[13] 0010,0000,0000,0000(2000)(是否有子包)
public boolean hasSubPackage() {
// return ((msgBodyProperty & 0x2000) >> 13) == 1;
return (msgBodyProps & 0x2000) > 0;
}
// for Aviator
@SuppressWarnings("unused")
public boolean isHasSubPackage() {
// 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()")
@Preset.JtStyle.Bytes(lengthExpressions = @Expression(spel = "getContentLength()", mvel = "self.getContentLength()", aviator = "self.contentLength"))
private byte[] content;
@XtreamEntityCreator
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();
}
}
}