Java 将消息体转为byte数组

以下以 JT/T808-2013 版中终端通用应答消息(0x0001) 为例(该消息体结构简单,适合入门),实现消息体转 byte 数组:

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;

/**
 * JT/T808协议消息体转byte数组示例
 * 以0x0001终端通用应答消息为例,消息体结构:
 * 1. 应答流水号:2字节(无符号短整型)
 * 2. 应答ID:2字节(无符号短整型)
 * 3. 应答结果:1字节(0:成功/确认 1:失败 2:消息有误 3:不支持)
 */
public class JT808MsgBodyEncoder {

    // 字符编码:JT/T808协议规定使用GBK(此处用GBK兼容的GB2312,效果一致)
    private static final String CHARSET = "GBK";

    /**
     * 终端通用应答消息体编码
     * @param replyFlowId 应答流水号
     * @param replyMsgId 应答ID(被应答的消息ID)
     * @param replyResult 应答结果
     * @return 编码后的消息体byte数组
     */
    public static byte[] encodeTerminalGeneralReply(short replyFlowId, short replyMsgId, byte replyResult) {
        try {
            // 1. 计算消息体总长度:2(流水号) + 2(应答ID) + 1(结果) = 5字节
            int bodyLength = 2 + 2 + 1;
            ByteBuffer buffer = ByteBuffer.allocate(bodyLength);
            buffer.order(java.nio.ByteOrder.BIG_ENDIAN); // 强制大端(协议要求)

            // 2. 依次写入字段(严格按协议顺序)
            buffer.putShort(replyFlowId); // 应答流水号:2字节
            buffer.putShort(replyMsgId);  // 应答ID:2字节
            buffer.put(replyResult);      // 应答结果:1字节

            // 3. 转换为byte数组并返回
            return buffer.array();
        } catch (Exception e) {
            throw new RuntimeException("JT808消息体编码失败", e);
        }
    }

    /**
     * 扩展:字符串字段编码(如终端手机号、车牌等)
     * @param str 要编码的字符串
     * @param fixedLength 协议规定的固定长度(不足补0)
     * @return 编码后的byte数组
     */
    public static byte[] encodeString(String str, int fixedLength) {
        try {
            byte[] strBytes = str.getBytes(CHARSET);
            // 创建指定长度的数组,默认填充0
            byte[] result = new byte[fixedLength];
            // 复制字符串字节(超出则截断,不足则补0)
            System.arraycopy(strBytes, 0, result, 0, Math.min(strBytes.length, fixedLength));
            return result;
        } catch (Exception e) {
            throw new RuntimeException("字符串编码失败", e);
        }
    }

    // 测试方法
    public static void main(String[] args) {
        // 测试终端通用应答编码
        short flowId = 1234;    // 应答流水号
        short msgId = 0x0100;   // 被应答的消息ID(如0x0100终端注册)
        byte result = 0;        // 应答结果:成功

        byte[] bodyBytes = encodeTerminalGeneralReply(flowId, msgId, result);
        System.out.println("消息体byte数组长度:" + bodyBytes.length); // 输出5
        System.out.print("消息体byte数组内容:");
        for (byte b : bodyBytes) {
            System.out.printf("%02X ", b); // 十六进制输出:04 D2 01 00 00
        }

        // 测试字符串编码(如终端手机号13800138000,固定12位)
        byte[] phoneBytes = encodeString("13800138000", 12);
        System.out.println("\n手机号编码后:");
        for (byte b : phoneBytes) {
            System.out.printf("%02X ", b); // 输出:31 33 38 30 30 31 33 38 30 30 30 00
        }
    }
}

 附ByteBuffer介绍

public class ByteBufferReadWrite {
    public static void main(String[] args) {
        // ========== 第一步:写数据(编码808协议字段)==========
        ByteBuffer buffer = ByteBuffer.allocate(5); // 容量5字节
        buffer.order(ByteOrder.BIG_ENDIAN); // 808协议必须设置大端
        
        // 写入字段(对应808的0x0001消息体)
        buffer.putShort((short) 1234); // 应答流水号(2字节)
        buffer.putShort((short) 0x0100); // 应答ID(2字节)
        buffer.put((byte) 0); // 应答结果(1字节)
        
        // ========== 第二步:切换为读模式(flip())==========
        // flip()作用:limit = position; position = 0; mark = -1
        // 简单说:把“写边界”设为读的上限,指针回到起始位置
        buffer.flip();
        
        // ========== 第三步:读数据(解码808协议字段)==========
        short replyFlowId = buffer.getShort(); // 读2字节(应答流水号)
        short replyMsgId = buffer.getShort();  // 读2字节(应答ID)
        byte replyResult = buffer.get();       // 读1字节(应答结果)
        
        // 输出结果(验证读写一致性)
        System.out.println("应答流水号:" + replyFlowId); // 1234
        System.out.println("应答ID:" + Integer.toHexString(replyMsgId)); // 100
        System.out.println("应答结果:" + replyResult); // 0
        
        // ========== 重置缓冲区(重复使用)==========
        buffer.clear(); // 不是清空数据,只是重置position=0、limit=capacity
    }
}

 

posted @ 2025-12-25 17:29  都是城市惹的祸  阅读(17)  评论(0)    收藏  举报