日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

spring 项目中集成 Protocol Buffers 示例

發(fā)布時間:2024/4/17 编程问答 57 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring 项目中集成 Protocol Buffers 示例 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

http://blog.csdn.net/fangzhangsc2006/article/details/8687388

本文適用于了解spring框架,同時想在spring項目中使用Protocol Buffers(以下簡稱PB)的讀者。

本文標(biāo)題為《spring 項目中集成 Protocol Buffers 示例》,意思當(dāng)然是教讀者如何將PB配置到spring項目中去,但事實上在spring項目中使用PB無需任何配置,命該題目的用意也是讓正在苦苦尋找配置方式的朋友在此止步,因為當(dāng)初我也是這樣。

什么是PB?以下為PB官網(wǎng)的描述。

譯為:PB是一種高效的且可擴展的結(jié)構(gòu)化數(shù)據(jù)編碼方案。Google將其用在內(nèi)部的幾乎所有的RPC協(xié)議和文件格式。

通俗的講PB是一個不錯的序列化和反序列化方案,其采用二進制編碼方案,效率比xml、json高。將PB用在文件存儲、網(wǎng)絡(luò)傳輸都是不錯的選擇。為什么這么說?

比如我們需要在服務(wù)器與客戶端之間傳輸一些結(jié)構(gòu)化的數(shù)據(jù)(對象、結(jié)構(gòu)體),我們怎么去序列化和反序列化呢?你可能想到了以下方案:

1.使用Java Serialization。但這是依賴于java語言的,客戶端和服務(wù)器采用不同的語言實現(xiàn)時就不好辦了,而且Java Serialization公認(rèn)的有一些問題。

2.定義自己的格式,比如約定“第幾個字節(jié)表示內(nèi)容長度”、“第幾個字節(jié)表示數(shù)據(jù)類型”、“某某符號表示分隔符”等等,很明顯這只能適用于一些數(shù)據(jù)格式很簡單的場合。

3.使用xml或者json。首先xml的臃腫是大家都詬病的。另外xml和json的樹形結(jié)構(gòu)使用起來也是比較繁瑣的,肯定是不及類使用起來簡單。不過他們還是有一個PB不具備的優(yōu)點,那就是數(shù)據(jù)的自描述性。如果這一點是你看重的,那么xml和json還是可以成為被選擇的理由。

說了這么多,到底PB怎么用呢?下面我將以在springMVC項目中使用PB為示例介紹其基本用法。其實PB不依賴于任何平臺或框架,原則上只要語言支持就可以,目前支持Java、C++、Python。

一、下載

去【PB官網(wǎng)】下載編譯器。

去【maven中央庫】搜索并下載PB的jar包。


二、定義.proto文件

約定數(shù)據(jù)格式,然后用PB的語法將其定義為.proto文件。這里使用官網(wǎng)的例子。

[java]?view plaincopy
  • package?tutorial;??
  • ??
  • //這里聲明輸出的java的包名??
  • option?java_package?=?"com.example.tutorial";??
  • //這里聲明輸出的java的類名??
  • option?java_outer_classname?=?"AddressBookProtos";??
  • ??
  • message?Person?{??
  • ??required?string?name?=?1;??
  • ??required?int32?id?=?2;??
  • ??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?PhoneNumber?phone?=?4;??
  • }??
  • ??
  • message?AddressBook?{??
  • ??repeated?Person?person?=?1;??
  • }??
  • 說明:

    1.上面的例子是定義一個電話薄,電話薄AddressBook包含多個Person,一個Person有name等屬性,還有多個PhoneNumber,一個PhoneNumber有PhoneType枚舉……

    2.可以看出.proto文件中除了可以定義基本的數(shù)據(jù)類型,比如int32、string,還可以嵌套使用自定義的類型,比如AddressBook中使用Person類型。

    3.屬性聲明前的required、optional、repeated分別表示必須賦值、可為空、集合。


    三、編譯

    使用之前下載的編譯器編譯.proto文件,命令格式為:

    protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/addressbook.proto 如果將編譯器protoc.exe放到和.proto文件一起,輸出目錄為當(dāng)前路徑的話編譯命令可以簡化為:

    protoc.exe --java_out=. addressbook.proto

    輸出路徑參數(shù)“.”表示當(dāng)前目錄。

    編譯完成后當(dāng)前目錄下生成了com\example\tutorial\AddressBookProtos.java文件。然后我們就可以直接使用這個代碼文件了。


    四、server端使用

    在springMVC項目中加入PB的jar包,除此之外沒有任何的配置

    將生產(chǎn)的代碼文件AddressBookProtos.java拷到項目中,包名要一致。

    在controller層中通過request拿到inputstream對象,然后通過PB對象的靜態(tài)方法parseFrom()就可從輸入流中反序列化出PB實例。

    如果向客戶端返回PB對象,則通過PB實例的writeTo()方法,參數(shù)為OutputStream。

    例子代碼:

    [java]?view plaincopy
  • import?java.io.IOException;??
  • import?java.io.InputStream;??
  • import?java.io.OutputStream;??
  • import?javax.servlet.http.HttpServletRequest;??
  • import?javax.servlet.http.HttpServletResponse;??
  • import?org.springframework.stereotype.Controller;??
  • import?org.springframework.web.bind.annotation.RequestMapping;??
  • import?com.example.tutorial.AddressBookProtos.AddressBook;??
  • import?com.example.tutorial.AddressBookProtos.Person;??
  • ??
  • /**?
  • ?*?@author?shannon?
  • ?*?
  • ?*/??
  • @Controller??
  • @RequestMapping("/pbtest")??
  • public?class?TestController?{??
  • ????@RequestMapping("upload")??
  • ????public?void?upload(HttpServletRequest?request,?HttpServletResponse?response)?throws?IOException?{??
  • ????????InputStream?inputStream?=?request.getInputStream();??
  • ????????AddressBook?addressBook?=?AddressBook.parseFrom(inputStream);??
  • ????????inputStream.close();??
  • ????????System.out.println(addressBook);??
  • ????}??
  • ??????
  • ????@RequestMapping("download")??
  • ????public?void?download(HttpServletResponse?response)?throws?IOException{??
  • ????????Person?john?=?Person.newBuilder()??
  • ????????????????.setId(1234)??
  • ????????????????.setName("John?Doe")??
  • ????????????????.setEmail("jdoe@example.com")??
  • ????????????????.addPhone(??
  • ??????????????????Person.PhoneNumber.newBuilder()??
  • ????????????????????.setNumber("555-4321")??
  • ????????????????????.setType(Person.PhoneType.HOME))??
  • ????????????????.build();??
  • ????????AddressBook?addressBook?=?AddressBook.newBuilder().addPerson(john).build();??
  • ????????response.setContentType("application/x-protobuf");??
  • ????????OutputStream?outputStream?=?response.getOutputStream();??
  • ????????addressBook.writeTo(outputStream);??
  • ????????outputStream.flush();??
  • ????????outputStream.close();??
  • ????}??
  • }??
  • 說明:upload接口和download接口分別是上傳和下載電話薄。


    五、client端使用

    在客戶端工程中加入PB的jar包,拷入代碼文件AddressBookProtos.java。
    下面的例子模擬客戶端向服務(wù)器發(fā)送和接收電話薄。

    如下:

    [java]?view plaincopy
  • package?test;??
  • ??
  • import?java.io.IOException;??
  • import?java.io.InputStream;??
  • import?java.io.OutputStream;??
  • import?java.net.HttpURLConnection;??
  • import?java.net.URL;??
  • import?com.example.tutorial.AddressBookProtos.AddressBook;??
  • import?com.example.tutorial.AddressBookProtos.Person;??
  • ??
  • /**?
  • ?*??
  • ?*?@author?shannon?
  • ?*/??
  • public?class?PBClientTest?{??
  • ??????
  • ????public?static?void?main(String[]?args)?throws?IOException?{??
  • ????????String?url?=?"http://www.example.com/pbtest/upload.pb";??
  • ????????upload(url);??
  • ????????String?url2?=?"http://www.example.com/pbtest/download.pb";??
  • ????????download(url2);??
  • ????}??
  • ??????
  • ????public?static?void?upload(String?url)?throws?IOException?{??
  • ????????Person?john?=?Person.newBuilder()??
  • ????????.setId(1234)??
  • ????????.setName("John?Doe")??
  • ????????.setEmail("jdoe@example.com")??
  • ????????.addPhone(??
  • ??????????Person.PhoneNumber.newBuilder()??
  • ????????????.setNumber("555-4321")??
  • ????????????.setType(Person.PhoneType.HOME))??
  • ????????.build();??
  • ????????AddressBook?addressBook?=?AddressBook.newBuilder().addPerson(john).build();??
  • ????????byte[]?content?=?addressBook.toByteArray();??
  • ??????????
  • ????????URL?targetUrl?=?new?URL(url);??
  • ????????HttpURLConnection?connection?=?(HttpURLConnection)?targetUrl.openConnection();??
  • ????????connection.setDoOutput(true);??
  • ????????connection.setDoInput(true);??
  • ????????connection.setRequestProperty("Content-Type",?"application/x-protobuf");??
  • ????????connection.setRequestProperty("Accept",?"application/x-protobuf");??
  • ????????connection.setRequestMethod("POST");??
  • ????????connection.setRequestProperty("Connect-Length",?Integer.toString(content.length));??
  • ????????connection.setFixedLengthStreamingMode(content.length);??
  • ????????OutputStream?outputStream?=?connection.getOutputStream();??
  • ????????outputStream.write(content);??
  • ????????outputStream.flush();??
  • ????????outputStream.close();??
  • ????}??
  • ??????
  • ????public?static?void?download(String?url)?throws?IOException?{??????????
  • ????????URL?target?=?new?URL(url);??
  • ????????HttpURLConnection?conn?=?(HttpURLConnection)?target.openConnection();??
  • ????????conn.setDoOutput(true);??
  • ????????conn.setDoInput(true);??
  • ????????conn.setRequestMethod("GET");??
  • ????????conn.setRequestProperty("Content-Type",?"application/x-protobuf");??
  • ????????conn.setRequestProperty("Accept",?"application/x-protobuf");??
  • ????????conn.connect();??
  • ????????//?check?response?code??
  • ????????int?code?=?conn.getResponseCode();??
  • ????????System.out.println("code:"?+?code);??
  • ????????System.out.println(conn.getContent());??
  • ????????boolean?success?=?(code?>=?200)?&&?(code?<?300);??
  • ??????????
  • ????????InputStream?in?=?success???conn.getInputStream()?:?conn.getErrorStream();??
  • ????????AddressBook?addressBook?=?AddressBook.parseFrom(in);??
  • ????????in.close();??
  • ????????System.out.println(addressBook);??
  • ????}??
  • }??
  • 說明:

    1.客戶端為普通的java project就可以了。

    2.我這里的url的后綴為.pb,這要依照server端的web.xml配置,可以配置為其他的,比如.html


    六、總結(jié)

    上面的例子演示了如何序列化和反序列PB對象,其實就是調(diào)用PB對象自身提供的方法,比如parseFrom、writeTo。可以看出PB的使用的確是很方便的。通過一個方法就可以將二進制數(shù)據(jù)轉(zhuǎn)為對象。

    什么?你連轉(zhuǎn)換對象的方法都不想調(diào)?那就參考【我的另一篇博客】客吧!


    參考:

    【PB官網(wǎng)】:http://code.google.com/p/protobuf/

    【maven中央庫】:http://search.maven.org/

    【我的另一篇博客】:http://blog.csdn.net/fangzhangsc2006/article/details/8687415


    總結(jié)

    以上是生活随笔為你收集整理的spring 项目中集成 Protocol Buffers 示例的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。