Protobuf協議 Java & Js的配合使用

雲逸_發表於2018-09-05

Google Protocol Buffer

1.協議介紹:

Google Protocol Buffer是google 的一種資料交換的格式,它獨立於語言,獨立於平臺。google 提供了多種語言的實現:java、c#、c++、go、python、js等,每一種實現都包含了相應語言的編譯器以及庫檔案。由於它是一種二進位制的格式,比使用 xml 進行資料交換快許多。可以把它用於分散式應用之間的資料通訊或者異構環境下的資料交換。作為一種效率和相容性都很優秀的二進位制資料傳輸格式,可以用於諸如網路傳輸、配置檔案、資料儲存等諸多領域。

2.使用說明:

2.1proto檔案說明:

不管是同種語言還是不同語言,在使用Protobuf進行資料互動的時候需要統一的一個資料結構。這個資料結構使用.proto字尾,並使用proto的特殊語法進行定義。此檔案格式如下:
    syntax="proto2" //語法格式
    package tutorial; //包
    //option:可賦值非必須賦值 java_package:java包名
    option java_package = "com.example.tutorial";
    //java類名,生成com.example.tutorial.AddressBookProtos java類
    option java_outer_classname = "ProtoEntity";
    option csharp_namespace = "Google.ProtocolBuffers.Examples.AddressBook";
    //message定義所需要序列化的資料的格式。每一個Message都是一個小的資訊邏輯單元,
    //包含了一些列的name-value對。
    message Person {
      required string name = 1; //required必須賦值,是永久性的
      required int32 id = 2;        // Unique ID number for this person.
      optional string email = 3;
    enum PhoneType { //列舉
        MOBILE = 0;
        HOME = 1;
        WORK = 2;
      }
    message PhoneNumber {
        required string number = 1;
        optional PhoneType type = 2 [default = HOME];
      }
    //repeated類似陣列或集合(java裡是list)
      repeated PhoneNumber phone = 4;
    }
    //使用者資訊
    message UserInfo {
		optional string userId=1;//使用者id
    	optional string userNickname=2;//使用者暱稱
    	optional string userPicPath=3;//頭像地址
    	optional sint64 shopId=4;//商店id
    	optional string tableId=5;//桌臺id
    	optional string clearType=6;//清理型別
    	optional string orderId=7;//訂單id
    	optional sint64 tag=8;//tag
    	optional sint32 source=9[default=1];//來源 1微信 2pad
	}  
    // Our address book file is just one of these.
    message AddressBook {
      repeated Person person = 1;
    }       
複製程式碼
由於Protobuf需要在多種語言之間進行互動,所以對於proto檔案中的資料型別定義如下:

資料型別對比

2.2Java使用說明:

2.2.1在Java中使用Protobuf需要注意幾點:

1.java_package屬性:在class生成時,會在相對路徑後加上這個屬性對應的包名,在定義時需要與專案中你希望放Protobuf Class的路徑相同。
2.java_outer_classname屬性:這個屬性是在生成Class後的類名,下面包含的message都是這個class下的內部類。
3.**JSON轉換問題:**在轉換成JSON格式傳遞byte[]時需要使用對應的byte轉換方法,如果使用轉換string的方法js無法decode

2.2.2使用說明:

安裝protoc:
  1. windows:首先需要在github的protobuf開源地址下載protoc進行安裝
  2. mac:依次執行brew install automake brew install libtool brew install protobuf
protoc使用:
	protoc --java_out=src/main/java/ src/main/resources/proto/shoppingcart.proto
複製程式碼

java_out:生成的java檔案輸出目錄 後面的指定的是proto檔案的地址

2.2.3Usage:

下列使用上面2.1proto檔案中的UserInfo物件來進行舉例:

2.2.3.1建立物件:
  1. 通過build的方式建立物件:
    ProtoEntity.UserInfo proUserInfo = 	ProtoEntity.UserInfo.newBuilder().setTableId("1234").setShopId(1234).setUserId("userid").setUserNickname("測試").setTag(1234444L).build();
複製程式碼
  1. 通過被編譯後的byte[]:
    ProtoEntity.UserInfo joinRoomUserInfo = ProtoEntity.UserInfo.parseFrom(data.getData());
複製程式碼

同時Protobuf的物件parseFrom方法還有通過InputStream和ByteString物件來生成物件的方式。

2.2.3.2序列化物件:
  1. 序列化為byte[]:
    userInfo.toByteArray();
複製程式碼

同時,protobuf的每個物件也可以序列化為InputStream和ByteString等。

2.4JS使用說明:

2.4.1Protobuf.js匯入方式:

  1. 直接下載protobuf下載地址
  2. 使用npm install protobuf也可以安裝
  3. 直接貼上
   <script src="//cdn.rawgit.com/dcodeIO/protobuf.js/6.6.3/dist/protobuf.js"></script>
複製程式碼

2.4.2Usage:

2.4.2.1建立物件:
    protobuf.load("./js/proto/shoppingcart.proto", function (err, root) {
                if (err) throw err;
                var UserInfo = root.lookup("proto.UserInfo");
                var message = UserInfo.create(userinfo);
                var encodedObj = UserInfo.encode(message).finish();
複製程式碼
2.4.2.2序列化物件:
    getProtoObj("./js/proto/shoppingcart.proto", "proto.UserInfo", data, function (result) {
                console.info(result);
            });
    function getProtoObj(protoPath, objName, data, cb) {
            protobuf.load(protoPath, function (err, root) {
                if (err) throw err;
                var info = root.lookup(objName);
                var result = Uint8Array.from(JSON.parse(data).data);//此時jsProtobuf使用的是無符號byte陣列,而java序列化後是帶符號的,所以需要先進行轉換成無符號的byte陣列
                cb(info.decode(result))
            });
        }
複製程式碼

相關文章