天天看點

protobuf 3.5 java使用介紹(二)protobuf 3.5 java使用介紹(二)

protobuf 3.5 java使用介紹(二)

上一篇遺留了兩個問題:

  • 1,資料模型中有可能會出現數組格式,而數組裡面是一個其他的模型,這個怎麼來做?
  • 2,建構資料消息的時候,通常會有一個頭,一個體;根據頭中定義的資料類型不同,體裡面的資料模型也不相同,這個又該怎麼處理?

模型數組

假如我們需要一個"路徑"的模型,路徑由很多個"點"組成,同時在路徑中還有一些其它的屬性資訊,其中類型為定義好的幾個值。

1,首先,定義一個"pint":

syntax = "proto3";

package iot.adsb.vip;

message point{
    double lon = 2; //經度
    double lat = 3; //緯度
}
           

2,然後,定義"path"

syntax = "proto3";

import "point.proto";

package iot.adsb.vip;

message path
{
    enum typeEnum {
        COMMUTE = 0;  //通勤
        DUTY = 1;     //工作
    }
    string id = 1;   
    string name = 2; //名稱
    typeEnum type = 3; //類型
    repeated point geometry = 4; //點集合
}
           

好了,這樣兩個protobuf的檔案就滿足了我們的要求,生成一下代碼看看。

3,進入proto檔案所在的檔案夾,執行

protoc --java_out=. *.proto
           

然後可以在目前檔案夾下看到生成好的java代碼

4,下面,我們來使用一下生成好的模型測試一下

Point.point.Builder point_builder1 = Point.point.newBuilder();
        point_builder1.setLat(101.11);
        point_builder1.setLon(39.11);
        Point.point point1 = point_builder1.build();
        System.out.println(point1.toString());
        System.out.println("===== 建構point1模型結束 =====");

        Point.point.Builder point_builder2 = Point.point.newBuilder();
        point_builder2.setLat(101.11);
        point_builder2.setLon(39.11);
        Point.point point2 = point_builder2.build();
        System.out.println(point1.toString());
        System.out.println("===== 建構point2模型結束 =====");

        Path.path.Builder pathBuilder = Path.path.newBuilder();
        pathBuilder.setId("1");
        pathBuilder.setName("路徑");
        pathBuilder.setType(Path.path.typeEnum.DUTY);

        pathBuilder.addGeometry(0, point1);
        pathBuilder.addGeometry(1, point2);
        Path.path path = pathBuilder.build();
        System.out.println(path.toString());
        System.out.println("===== 建構path模型結束 =====");

        System.out.println("===== 轉成json對象開始 =====");
        String jsonFormatM = "";
        try {
            jsonFormatM = JsonFormat.printer().print(path);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(jsonFormatM.toString());
        System.out.println("json資料大小:" + jsonFormatM.getBytes().length);
        System.out.println("===== 轉成json對象結束 =====");

           

結果如下:

Connected to the target VM, address: '127.0.0.1:52895', transport: 'socket'
lon: 39.11
lat: 101.11

===== 建構point1模型結束 =====
lon: 39.11
lat: 101.11

===== 建構point2模型結束 =====
id: "1"
name: "\350\267\257\345\276\204"
type: DUTY
geometry {
  lon: 39.11
  lat: 101.11
}
geometry {
  lon: 39.11
  lat: 101.11
}

===== 建構path模型結束 =====
===== 轉成json對象開始 =====
{
  "id": "1",
  "name": "路徑",
  "type": "DUTY",
  "geometry": [{
    "lon": 39.11,
    "lat": 101.11
  }, {
    "lon": 39.11,
    "lat": 101.11
  }]
}
json資料大小:155
===== 轉成json對象結束 =====
Disconnected from the target VM, address: '127.0.0.1:52895', transport: 'socket'

Process finished with exit code 0


           

消息頭/體結構

通常在做實際項目的時候,消息是需要用信封做一下封裝便于業務的處理和一些業務無關的資訊(例如:ID,加密資訊等)存放。消息體根據消息類型是不同的資料類型。

實作這個的方式其實很簡單,protobuf對象可以序列化成byte數組,然後,在信封的模型裡定義一個 bytes 類型的字段用于存放消息體即可。

1,如下定義消息信封:

syntax = "proto3";

import "point.proto";

package iot.adsb.vip;

message msg
{
  string mid = 1;
  string type = 2;
  bytes data = 3; //資料内容
}

           

2,按照上面的方法,生成JAVA模型

3,測試一下

public static void main(String[] args) {
        // 消息體為 Point
        Point.point.Builder point_builder1 = Point.point.newBuilder();
        point_builder1.setLat(101.11);
        point_builder1.setLon(39.11);
        Point.point point1 = point_builder1.build();
        System.out.println(point1.toString());
        System.out.println("===== 建構point1模型結束 =====");

        // 建構消息
        Msg.msg.Builder msgBuilder = Msg.msg.newBuilder();
        msgBuilder.setMid("1");
        msgBuilder.setType("PATH");
        msgBuilder.setData(point1.toByteString());

        Msg.msg msg = msgBuilder.build();
        System.out.println(msg.toString());
        System.out.println("===== 建構msg模型結束 =====");

        byte[] msgBytes = msg.toByteArray();

        // 解析消息
        try {
            Msg.msg msgParse = Msg.msg.parseFrom(msgBytes);
            System.out.println(msgParse.toString());
            System.out.println("===== 反序列化msg模型結束 =====");

            System.out.println("PATH取值");
            System.out.println(msgParse.getMid());
            System.out.println(msgParse.getType());

            switch (msgParse.getType()) {
                case "PATH":
                    System.out.println("PATH消息");
                    Point.point pointParse = Point.point.parseFrom(msgParse.getData());
                    System.out.println(pointParse.toString());
                    System.out.println("===== 反序列化point模型結束 =====");
                    System.out.println("Point取值");
                    System.out.println("緯度:" + pointParse.getLat());
                    System.out.println("經度:" + pointParse.getLon());
                    break;
                case "":
                    break;
            }

        } catch (InvalidProtocolBufferException ex) {
            System.out.println(ex);
        }
    }
           

測試結果

Connected to the target VM, address: '127.0.0.1:49427', transport: 'socket'
lon: 39.11
lat: 101.11

===== 建構point1模型結束 =====
mid: "1"
type: "PATH"
data: "\021\256G\341z\024\216C@\031\327\243p=\nGY@"

===== 建構msg模型結束 =====
mid: "1"
type: "PATH"
data: "\021\256G\341z\024\216C@\031\327\243p=\nGY@"

===== 反序列化msg模型結束 =====
PATH取值
1
PATH
PATH消息
lon: 39.11
lat: 101.11

===== 反序列化point模型結束 =====
Point取值
緯度:101.11
經度:39.11
Disconnected from the target VM, address: '127.0.0.1:49427', transport: 'socket'

Process finished with exit code 0

           

代碼下載下傳位址

上一篇