最近需要對接一個第三方的廣告投放接口,感覺挺簡單的是,但是當看到技術文檔是有點懵,其中提供了一個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打開命令窗口操作):
備註:該方式爲直接切換到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