Skip to content

java protobuf ​

生成代码 ​

shell
protoc --java_out=\src\main\java ChatPacket.proto

解析二进制数据 ​

使用 ChatPacket 生成和解析二进制数据的两个实例 ​

下面是两个实例,展示如何使用 ChatPacket 类生成二进制数据并将其解析回 ChatPacket 对象。可以将这些实例直接应用到的 Java 项目中。

实例 1:生成二进制数据 ​

在这个实例中,我们将创建一个 ChatPacket 对象并将其序列化为二进制数据(字节数组)。

代码示例 ​

java
package nexus.io.im.protobuf;

import nexus.io.im.protobuf.ChatPacketOuter.ChatPacket;
import nexus.io.im.protobuf.ChatPacketOuter.CommandType;

public class ChatPacketBinaryExample {
  public static void main(String[] args) {
    // 创建一个 ChatPacket 对象
    ChatPacket chatPacket = ChatPacket.newBuilder().setCmd(CommandType.COMMAND_CHAT_REQ).
        setSequence(1234567890L).
        //
        setFrom("user123").setTo("user456").setToken("abcdefg")
        //
        .setCreateTime(1725338896411L).build();

    // 将 ChatPacket 对象序列化为二进制数据
    byte[] binaryData = chatPacket.toByteArray();

    // 输出二进制数据长度
    System.out.println("Serialized binary data length: " + binaryData.length);
  }
}
Serialized binary data length: 42

解释 ​

  • ChatPacket.newBuilder():使用生成的 ChatPacket 类的 Builder 模式创建一个新的 ChatPacket 对象。
  • .toByteArray():将 ChatPacket 对象序列化为字节数组(二进制数据)。
  • 输出:输出二进制数据的长度。

实例 2:解析二进制数据 ​

这个实例展示了如何将二进制数据反序列化回 ChatPacket 对象。

代码示例 ​

java
package nexus.io.im.protobuf;

import nexus.io.im.protobuf.ChatPacketOuter.ChatPacket;
import nexus.io.im.protobuf.ChatPacketOuter.CommandType;
import com.google.protobuf.InvalidProtocolBufferException;

public class ChatPacketBinaryParsingExample {
  public static void main(String[] args) {

    // 创建一个 ChatPacket 对象
    ChatPacket chatPacketFrom = ChatPacket.newBuilder().setCmd(CommandType.COMMAND_CHAT_REQ).setSequence(1234567890L).
    //
        setFrom("user123").setTo("user456").setToken("abcdefg")
        //
        .setCreateTime(1725338896411L).build();

    // 将 ChatPacket 对象序列化为二进制数据
    byte[] binaryData = chatPacketFrom.toByteArray();

    try {
      // 从二进制数据解析出 ChatPacket 对象
      ChatPacket chatPacket = ChatPacket.parseFrom(binaryData);

      // 输出解析后的 ChatPacket 对象
      System.out.println("Parsed ChatPacket: ");
      System.out.println("cmd: " + chatPacket.getCmd());
      System.out.println("sequence: " + chatPacket.getSequence());
      System.out.println("from: " + chatPacket.getFrom());
      System.out.println("to: " + chatPacket.getTo());
      System.out.println("token: " + chatPacket.getToken());
      System.out.println("createTime: " + chatPacket.getCreateTime());
    } catch (InvalidProtocolBufferException e) {
      e.printStackTrace();
    }
  }
}
Parsed ChatPacket:
cmd: COMMAND_CHAT_REQ
sequence: 1234567890
from: user123
to: user456
token: abcdefg
createTime: 1725338896411

解释 ​

  • ChatPacket.parseFrom(binaryData):使用 parseFrom 方法将字节数组反序列化为 ChatPacket 对象。
  • 错误处理:捕获 InvalidProtocolBufferException 异常,该异常在二进制数据不符合 ChatPacket 格式时抛出。
  • 输出:输出解析后的 ChatPacket 对象的内容。

总结 ​

  • 生成二进制数据:通过调用 toByteArray() 方法将 ChatPacket 对象序列化为字节数组。
  • 解析二进制数据:通过调用 ChatPacket.parseFrom() 方法将字节数组反序列化回 ChatPacket 对象。

通过这两个实例,可以将 ChatPacket 对象与二进制数据互相转换,从而方便地在网络传输、数据存储等场景中使用 Protobuf 的高效序列化与反序列化特性。

生成 JSON 数据 ​

使用 ChatPacket 生成 JSON 数据 ​

要将 ChatPacket 对象转换为 JSON 字符串,可以使用 Protobuf 提供的 JsonFormat 类。下面是一个详细的示例,展示如何将 ChatPacket 对象序列化为 JSON 数据。

步骤:将 Protobuf 对象转换为 JSON 字符串 ​

  1. 确保包含 Protobuf Java 库:确保项目中已经包含 Protobuf Java 运行时库和 protobuf-java-util 工具库,因为 JsonFormat 类在 protobuf-java-util 库中。

    如果使用 Maven,添加以下依赖(假设已经添加过了):

    xml
    <dependency>
      <groupId>com.google.protobuf</groupId>
      <artifactId>protobuf-java</artifactId>
      <version>4.28.0-RC2</version> <!-- 选择与您的 .proto 语法兼容的版本 -->
    </dependency>
    <dependency>
      <groupId>com.google.protobuf</groupId>
      <artifactId>protobuf-java-util</artifactId>
      <version>4.28.0-RC2</version>
    </dependency>
  2. 导入所需的类:

    java
    import com.google.protobuf.util.JsonFormat;
    import nexus.io.im.protobuf.ChatPacketOuter.ChatPacket;
    import com.google.protobuf.InvalidProtocolBufferException;
  3. 将 ChatPacket 对象转换为 JSON 字符串:

    使用 JsonFormat.Printer 类将 ChatPacket 对象转换为 JSON 字符串。

    java
    public String convertChatPacketToJson(ChatPacket chatPacket) throws InvalidProtocolBufferException {
      // 使用 JsonFormat 创建 Printer
      JsonFormat.Printer printer = JsonFormat.printer().includingDefaultValueFields();
      // 将 ChatPacket 对象转换为 JSON 字符串
      return printer.print(chatPacket);
    }

    注意:includingDefaultValueFields() 方法可以在 JSON 中包括所有字段的默认值。


示例代码 ​

以下是一个完整示例,展示如何将 ChatPacket 对象转换为 JSON 字符串。

Java 代码 ​

java
package nexus.io.im.protobuf;

import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.util.JsonFormat;
import nexus.io.im.protobuf.ChatPacketOuter.ChatMessage;
import nexus.io.im.protobuf.ChatPacketOuter.ChatPacket;
import nexus.io.im.protobuf.ChatPacketOuter.CommandType;
import nexus.io.im.protobuf.ChatPacketOuter.TextContent;

public class ChatPacketToJsonExample {

  public static String convertChatPacketToJson(ChatPacket chatPacket) throws InvalidProtocolBufferException {
    // 使用 JsonFormat 创建 Printer
    JsonFormat.Printer printer = JsonFormat.printer();
    // 将 ChatPacket 对象转换为 JSON 字符串
    return printer.print(chatPacket);
  }

  public static void main(String[] args) {
    // 创建一个 ChatPacket 对象
    TextContent textContent = nexus.io.im.protobuf.ChatPacketOuter.TextContent.newBuilder()
        //
        .setText("Hello, world!").build();

    ChatMessage chatMessage = nexus.io.im.protobuf.ChatPacketOuter.ChatMessage.newBuilder()
        //
        .setMsgType("text").setTextContent(textContent).build();

    ChatPacket chatPacket = ChatPacket.newBuilder()
        //
        .setCmd(CommandType.COMMAND_CHAT_REQ)
        //
        .setSequence(1234567890L)
        //
        .setFrom("user123")
        //
        .setTo("user456")
        //
        .setToken("abcdefg")
        //
        .setCreateTime(1725338896411L)
        //
        .setChatMessage(chatMessage).build();

    try {
      // 将 ChatPacket 对象转换为 JSON 字符串
      String jsonString = convertChatPacketToJson(chatPacket);
      System.out.println("Generated JSON data: " + jsonString);
    } catch (InvalidProtocolBufferException e) {
      e.printStackTrace();
    }
  }
}

输出 ​

运行上述代码,输出将类似于以下 JSON 字符串:

json
{
  "cmd": "COMMAND_CHAT_REQ",
  "sequence": "1234567890",
  "from": "user123",
  "to": "user456",
  "createTime": "1725338896411",
  "token": "abcdefg",
  "chatMessage": {
    "msgType": "text",
    "textContent": {
      "text": "Hello, world!"
    }
  }
}

解释 ​

  • JsonFormat.printer():使用 JsonFormat 的 printer() 方法创建一个 JSON 打印器。
  • printer.print(chatPacket):将 ChatPacket 对象序列化为 JSON 字符串。

总结 ​

通过使用 Protobuf 提供的 JsonFormat 工具类,可以方便地将 ChatPacket 对象转换为 JSON 字符串。这有助于在客户端和服务器之间进行数据交换时,保持数据的可读性和可移植性。

解析 JSON 数据 ​

在 Java 应用中,当从客户端接收到 JSON 字符串时,可以利用 Protobuf 提供的内置 JSON 解析功能,将其转换为由 .proto 文件生成的 ChatPacketOuter.ChatPacket 类的实例。Protobuf 提供了 JsonFormat 类,可以方便地实现 JSON 与 Protobuf 对象之间的转换。

使用 Protobuf 的 JsonFormat 将 JSON 字符串解析为 ChatPacket 对象

以下是实现这一转换的步骤以及示例代码。

步骤:将 JSON 字符串解析为 Protobuf 对象 ​

  1. 确保包含 Protobuf Java 库:首先需要在项目中添加 Protobuf Java 运行时库。
    如果使用 Maven,可以添加以下依赖:

    xml
    <dependency>
      <groupId>com.google.protobuf</groupId>
      <artifactId>protobuf-java</artifactId>
      <version>4.28.0-RC2</version> <!-- 选择与您的 .proto 语法兼容的版本 -->
    </dependency>
     <dependency>
       <groupId>com.google.protobuf</groupId>
       <artifactId>protobuf-java-util</artifactId>
       <version>4.28.0-RC2</version>
     </dependency>
  2. 导入所需的类:

    java
    import com.google.protobuf.util.JsonFormat;
    import nexus.io.im.protobuf.ChatPacketOuter.ChatPacket;
    import com.google.protobuf.InvalidProtocolBufferException;
  3. 解析 JSON 字符串为 Protobuf 对象:
    使用 JsonFormat.Parser 类将 JSON 字符串解析为 ChatPacket 对象。

    java
    public ChatPacket parseJsonToChatPacket(String jsonString) throws InvalidProtocolBufferException {
      ChatPacket.Builder builder = ChatPacket.newBuilder();
      JsonFormat.Parser parser = JsonFormat.parser().ignoringUnknownFields();
      parser.merge(jsonString, builder);
      return builder.build();
    }

    注意:使用 ignoringUnknownFields() 方法可以忽略 JSON 中与 Protobuf 不匹配的字段。


示例代码 ​

以下是一个完整示例,展示如何将 JSON 字符串转换为 ChatPacket 对象。

示例 JSON 字符串 ​

json
{
  "cmd": 11,
  "sequence": 1234567890,
  "from": "user123",
  "to": "user456",
  "token": "abcdefg",
  "createTime": 1725338896411,
  "body": {
    "msgType": "text",
    "textContent": {
      "text": "Hello, world!"
    }
  }
}

Java 代码 ​

java
package nexus.io.im.protobuf;
import com.google.protobuf.util.JsonFormat;
import nexus.io.im.protobuf.ChatPacketOuter.ChatPacket;
import com.google.protobuf.InvalidProtocolBufferException;

public class ChatPacketParser {

  public static ChatPacket parseJsonToChatPacket(String jsonString) throws InvalidProtocolBufferException {
    // 创建 ChatPacket 的 builder
    ChatPacket.Builder builder = ChatPacket.newBuilder();

    // 创建 JsonFormat 解析器
    JsonFormat.Parser parser = JsonFormat.parser().ignoringUnknownFields();

    // 将 JSON 字符串解析到 builder 中
    parser.merge(jsonString, builder);

    // 构建 ChatPacket 对象
    return builder.build();
  }

  public static void main(String[] args) {
    String jsonString = "{\n" +
        "  \"cmd\": 11,\n" +
        "  \"sequence\": 1234567890,\n" +
        "  \"from\": \"user123\",\n" +
        "  \"to\": \"user456\",\n" +
        "  \"token\": \"abcdefg\",\n" +
        "  \"createTime\": 1725338896411,\n" +
        "  \"body\": {\n" +
        "    \"msgType\": \"text\",\n" +
        "    \"textContent\": {\n" +
        "      \"text\": \"Hello, world!\"\n" +
        "    }\n" +
        "  }\n" +
        "}";

    try {
      ChatPacket chatPacket = parseJsonToChatPacket(jsonString);
      System.out.println("Parsed ChatPacket: " + chatPacket);
    } catch (InvalidProtocolBufferException e) {
      e.printStackTrace();
    }
  }
}

解释 ​

  • Builder 模式:Protobuf 使用 Builder 模式来构建消息对象,因此首先要创建一个 ChatPacket.Builder 实例。
  • JsonFormat.Parser:创建一个解析器实例,并配置忽略未知字段。
  • 解析:使用 parser.merge(jsonString, builder) 方法将 JSON 字符串解析到 builder 中。
  • 构建对象:通过 builder.build() 获得不可变的 ChatPacket 对象。

重要注意事项 ​

  1. JSON 字段名称:JSON 字段名称必须与 Protobuf 字段名称匹配。Protobuf 会将字段名称转换为小驼峰命名法(lowerCamelCase)。
  2. Oneof 字段处理:body 在 .proto 文件中定义为 oneof,因此在 JSON 中 body 字段下只能存在一种消息类型。
  3. 枚举:在 Protobuf 中,枚举可以通过名称或整数值来指定。
  4. 错误处理:要处理 InvalidProtocolBufferException 异常,如果 JSON 不符合 Protobuf 模式会抛出此异常。
  5. 未知字段:使用 ignoringUnknownFields() 来忽略 JSON 中未在 Protobuf 消息中定义的字段。

解析不同消息类型的 JSON ​

如果 body 字段中包含不同类型的消息,如文本消息或图片消息,确保在 JSON 中正确指定 msgType 及相应的内容。例如,对于图片消息:

json
{
  "cmd": 11,
  "sequence": 1234567890,
  "from": "user123",
  "to": "user456",
  "token": "abcdefg",
  "createTime": 1725338896411,
  "body": {
    "msgType": "image",
    "imageContent": {
      "url": "http://example.com/image.png",
      "width": 800,
      "height": 600,
      "format": "png"
    }
  }
}

结论 ​

通过利用 Protobuf 的 JsonFormat 类,可以轻松地将 JSON 字符串解析为 Protobuf 对象。请确保 JSON 结构与 Protobuf 消息定义一致,尤其要注意字段名称和 oneof 字段。这样可以实现高效、类型安全的消息处理。


参考文档 ​

MIT Licensed