protobuf實現數據交互

    最近需要對接一個第三方的廣告投放接口,感覺挺簡單的是,但是當看到技術文檔是有點懵,其中提供了一個ts_ui_api.proto文件爲api接口文件,content-type 需要爲“x-protobuf”,也沒有樣例。看到這裏你可能和我一樣protobuf是個什麼東西,是的我就是帶着這個問題去查閱了很多資料才明白protobuf是什麼東西,需求搞定了就來寫篇文章記錄一下(本文主要爲java使用),以防以後使用:

Protobuf是什麼?

          protobuf,全稱:Google Protocol Buffer,是Google開源的一種輕便高效的結構化數據存儲格式,可以用於結構化數據的串行化,也稱作序列化,主要用於數據存儲或是RPC數據交換,支持多語言(目前支持C++、JAVA、Python,go等),可拓展;

1.protobuf的優勢

  • 平臺無關,語言無關,可擴展;

  • 提供了友好的動態庫,使用簡單;

  • 解析速度快,比對應的XML快約20-100倍;

  • 序列化數據非常簡潔、緊湊,與XML相比,其序列化之後的數據量約爲1/3到1/10;

  • 生成了更容易在編程中使用的數據訪問類

2.protobuf使用

  • 根據不同平臺有相應的支持庫java支持庫:地址連接(支持maven,gradle等引用方式)

實際開發

1.定義協議文件xx.proto(如下)

syntax = "proto2";  //protobuf的編譯器版本
package cn.lp.box.advertisement; //包名
import "src/help.proto"; //引用的外部文件


enum OsType {
    UNKNOWN = 0;
    ANDROID = 1;  // Android
    IOS = 2;  // iOS
    WINDOWS = 3;
};

//message字段想到與java中的class聲明一個類
message Version {
    optional uint32 major = 1[default = 0]; //聲明一個major 字段類型的int 默認值爲0 字段標號爲1
    optional uint32 minor = 2[default = 0]; 
    optional uint32 micro = 3[default = 0]; 
};


//這個是一個枚舉類型的數據
enum UdIdType {
    MAC = 1; //聲明一個屬性值爲1
    MEDIA_ID = 2; 
};

message UdId {
    optional UdIdType id_type = 1; //聲明一個id_type 字段 類型爲UdIdType 字段標號爲1
    required id id = 2;  //聲明一個id 字段 類型爲id 字段標號爲2
};


message Size {
    optional uint32 width = 1[default = 0];  
    optional uint32 height = 2[default = 0];  
};

message Device {
    optional UdId udid = 1; //聲明一個udid 字段 類型爲UdId 字段標號爲1 
    optional Version os_version = 2; 
    required string vendor = 3[default = ""]; 
    required string model = 4[default = ""]; 
    optional Size screen_size = 5; //聲明一個screen_size 字段 類型爲Size 字段標號爲5 
}

message TsApiRequest {
   .../字段這裏就不寫了
}
message TsApiResponse{
   .../字段這裏就不寫了
}

看看是否感覺很熟悉,是的感覺還java還是不比較像,就是一些關鍵之被替換了,如class被換成了 message等 

備註:

(1).required,optional 、repeated爲protobuf中的特有修飾符,用於修飾字段具體區別如下:

 - required:該值是必須要設置的; 
 - optional :該字段可以有0個或1個值(不超過1個); 
 - repeated:該字段可以重複任意多次(包括0次),類似於C++中的list;

 根據每個修飾符不同,生成的代碼與區別的

(2).標識號:字段的標識號決定在二進制中字段的位置

2.文件轉換(將xx.proto文件轉化爲相應的平臺語言)

  • 文件轉換工具protoc,protoc是proto文件的編譯器可以將xx.proto文件編輯爲響應的文件:protoc下載地址
  • protoc安裝,沒有什麼安裝的其實就是解壓(請注意解壓路徑儘量避免誤中文)就可以使用了
  • protoc使用(cmd打開命令窗口操作):
A.切換到解壓後的bin目錄
​​​B:執行的命令
C:編輯的文件格式(cpp_out表示C++代碼,--java_out表示Java代碼,--python_out表示Python代碼,--go_out表示go代碼)
D:爲輸出文件路徑(實際文件在改路徑+.proto文件的包名路徑中)
E;爲編輯文件路徑(圖上在本目錄所以只有文件名稱)​​​​

備註:該方式爲直接切換到bin目錄執行,可以通過配置環境變量後直接在命令窗口操作(環境變量中包該解壓文件的bin目錄配置進去即可)

3.android中使用

   A.添加依賴:

compile 'com.google.protobuf:protobuf-java-util:3.6.1' 具體參考這裏(該包中已經引用了Gson引用是避免重複引入導致代碼報錯,本人已入坑)

B.將轉換後的文件按照指定的包結構複製進項目(和.proto文件中的包名路徑一直,負責文件會報錯)

C.組織數據:

TsUiApi.TsApiRequest.Builder apiRequest = TsUiApi.TsApiRequest.newBuilder();//爲請求接口時需要的數據對象

TsUiApi.UdId udId = TsUiApi.UdId.newBuilder().setIdType(TsUiApi.UdIdType.MEDIA_ID).setId("id").build();
TsUiApi.Size screenSize = TsUiApi.Size.newBuilder().setWidth(102).setHeight(56).build();
TsUiApi.Version osVersion = TsUiApi.Version.newBuilder().setMicro(0).setMajor(0).setMinor(0).build();
//獲取Device對象
TsUiApi.Device device = TsUiApi.Device.newBuilder().setVendor("data").
                .setUdid(udId)
                .setScreenSize(screenSize)
                .setOsVersion(osVersion)
                .build();

TsUiApi.Version apiVersion = TsUiApi.Version.newBuilder().setMicro(0).setMajor(1).setMinor(0).build();

 apiRequest.setDevice(device);
 apiRequest.setApiVersion(apiVersion)

//通過build方法獲取TsApiRequest 對象,tsApiRequest 將會被轉化爲  byte[] 放入請求體中傳遞
 TsUiApi.TsApiRequest tsApiRequest = apiRequest.build();


這個對象比較熟悉把,就是剛纔.proto文件中的字段

D.發送數據這個根據網絡框架不同方式不同,由於舊項目使用的是AsyncHttpClient,修改一下框架的方法才支持:

 //組織數據
        byte[] data = tsApiRequest.toByteArray();

        ByteArrayEntity httpEntity = new ByteArrayEntity(data);
        //數據整體以流的形式傳遞
        mAsyncHttpClient.post(context.getApplicationContext(), "http://jpaccess.baidu.com/api_6", httpEntity, 
                "x-protobuf", advHandler);

 

E:數據接收呢,還記得TsApiResponse類嗎:

byte[] responseBytes

TsUiApi.TsApiResponse tsApiResponse = TsUiApi.TsApiResponse.parseFrom(responseBytes);

同tsApiResponse獲取響應的值轉爲爲本地可用的數據;

 

本文就介紹到這裏,可能還有許多不足之處,希望對正在學習的您有幫助,如果您有好的建議請感謝您的反饋。

文章參考:https://blog.csdn.net/longxuanzhigu/article/details/81538748

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章