spring 项目中集成 Protocol Buffers 示例
2014-06-15 17:16
225 查看
http://blog.csdn.net/fangzhangsc2006/article/details/8687388
本文适用于了解spring框架,同时想在spring项目中使用Protocol Buffers(以下简称PB)的读者。
本文标题为《spring 项目中集成 Protocol Buffers 示例》,意思当然是教读者如何将PB配置到spring项目中去,但事实上在spring项目中使用PB无需任何配置,命该题目的用意也是让正在苦苦寻找配置方式的朋友在此止步,因为当初我也是这样。
什么是PB?以下为PB官网的描述。
译为:PB是一种高效的且可扩展的结构化数据编码方案。Google将其用在内部的几乎所有的RPC协议和文件格式。
通俗的讲PB是一个不错的序列化和反序列化方案,其采用二进制编码方案,效率比xml、json高。将PB用在文件存储、网络传输都是不错的选择。为什么这么说?
比如我们需要在服务器与客户端之间传输一些结构化的数据(对象、结构体),我们怎么去序列化和反序列化呢?你可能想到了以下方案:
1.使用Java Serialization。但这是依赖于java语言的,客户端和服务器采用不同的语言实现时就不好办了,而且Java Serialization公认的有一些问题。
2.定义自己的格式,比如约定“第几个字节表示内容长度”、“第几个字节表示数据类型”、“某某符号表示分隔符”等等,很明显这只能适用于一些数据格式很简单的场合。
3.使用xml或者json。首先xml的臃肿是大家都诟病的。另外xml和json的树形结构使用起来也是比较繁琐的,肯定是不及类使用起来简单。不过他们还是有一个PB不具备的优点,那就是数据的自描述性。如果这一点是你看重的,那么xml和json还是可以成为被选择的理由。
说了这么多,到底PB怎么用呢?下面我将以在springMVC项目中使用PB为示例介绍其基本用法。其实PB不依赖于任何平台或框架,原则上只要语言支持就可以,目前支持Java、C++、Python。
一、下载
去【PB官网】下载编译器。
去【maven中央库】搜索并下载PB的jar包。
二、定义.proto文件
约定数据格式,然后用PB的语法将其定义为.proto文件。这里使用官网的例子。
[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文件中除了可以定义基本的数据类型,比如int32、string,还可以嵌套使用自定义的类型,比如AddressBook中使用Person类型。
3.属性声明前的required、optional、repeated分别表示必须赋值、可为空、集合。
三、编译
使用之前下载的编译器编译.proto文件,命令格式为:
如果将编译器protoc.exe放到和.proto文件一起,输出目录为当前路径的话编译命令可以简化为:
protoc.exe --java_out=. addressbook.proto
输出路径参数“.”表示当前目录。
编译完成后当前目录下生成了com\example\tutorial\AddressBookProtos.java文件。然后我们就可以直接使用这个代码文件了。
四、server端使用
在springMVC项目中加入PB的jar包,除此之外没有任何的配置。
将生产的代码文件AddressBookProtos.java拷到项目中,包名要一致。
在controller层中通过request拿到inputstream对象,然后通过PB对象的静态方法parseFrom()就可从输入流中反序列化出PB实例。
如果向客户端返回PB对象,则通过PB实例的writeTo()方法,参数为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。
下面的例子模拟客户端向服务器发送和接收电话薄。
如下:
[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
六、总结
上面的例子演示了如何序列化和反序列PB对象,其实就是调用PB对象自身提供的方法,比如parseFrom、writeTo。可以看出PB的使用的确是很方便的。通过一个方法就可以将二进制数据转为对象。
什么?你连转换对象的方法都不想调?那就参考【我的另一篇博客】客吧!
参考:
【PB官网】:http://code.google.com/p/protobuf/
【maven中央库】:http://search.maven.org/
【我的另一篇博客】:/article/9212447.html
本文适用于了解spring框架,同时想在spring项目中使用Protocol Buffers(以下简称PB)的读者。
本文标题为《spring 项目中集成 Protocol Buffers 示例》,意思当然是教读者如何将PB配置到spring项目中去,但事实上在spring项目中使用PB无需任何配置,命该题目的用意也是让正在苦苦寻找配置方式的朋友在此止步,因为当初我也是这样。
什么是PB?以下为PB官网的描述。
译为:PB是一种高效的且可扩展的结构化数据编码方案。Google将其用在内部的几乎所有的RPC协议和文件格式。
通俗的讲PB是一个不错的序列化和反序列化方案,其采用二进制编码方案,效率比xml、json高。将PB用在文件存储、网络传输都是不错的选择。为什么这么说?
比如我们需要在服务器与客户端之间传输一些结构化的数据(对象、结构体),我们怎么去序列化和反序列化呢?你可能想到了以下方案:
1.使用Java Serialization。但这是依赖于java语言的,客户端和服务器采用不同的语言实现时就不好办了,而且Java Serialization公认的有一些问题。
2.定义自己的格式,比如约定“第几个字节表示内容长度”、“第几个字节表示数据类型”、“某某符号表示分隔符”等等,很明显这只能适用于一些数据格式很简单的场合。
3.使用xml或者json。首先xml的臃肿是大家都诟病的。另外xml和json的树形结构使用起来也是比较繁琐的,肯定是不及类使用起来简单。不过他们还是有一个PB不具备的优点,那就是数据的自描述性。如果这一点是你看重的,那么xml和json还是可以成为被选择的理由。
说了这么多,到底PB怎么用呢?下面我将以在springMVC项目中使用PB为示例介绍其基本用法。其实PB不依赖于任何平台或框架,原则上只要语言支持就可以,目前支持Java、C++、Python。
一、下载
去【PB官网】下载编译器。
去【maven中央库】搜索并下载PB的jar包。
二、定义.proto文件
约定数据格式,然后用PB的语法将其定义为.proto文件。这里使用官网的例子。
[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文件中除了可以定义基本的数据类型,比如int32、string,还可以嵌套使用自定义的类型,比如AddressBook中使用Person类型。
3.属性声明前的required、optional、repeated分别表示必须赋值、可为空、集合。
三、编译
使用之前下载的编译器编译.proto文件,命令格式为:
protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/addressbook.proto
如果将编译器protoc.exe放到和.proto文件一起,输出目录为当前路径的话编译命令可以简化为:
protoc.exe --java_out=. addressbook.proto
输出路径参数“.”表示当前目录。
编译完成后当前目录下生成了com\example\tutorial\AddressBookProtos.java文件。然后我们就可以直接使用这个代码文件了。
四、server端使用
在springMVC项目中加入PB的jar包,除此之外没有任何的配置。
将生产的代码文件AddressBookProtos.java拷到项目中,包名要一致。
在controller层中通过request拿到inputstream对象,然后通过PB对象的静态方法parseFrom()就可从输入流中反序列化出PB实例。
如果向客户端返回PB对象,则通过PB实例的writeTo()方法,参数为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。
下面的例子模拟客户端向服务器发送和接收电话薄。
如下:
[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
六、总结
上面的例子演示了如何序列化和反序列PB对象,其实就是调用PB对象自身提供的方法,比如parseFrom、writeTo。可以看出PB的使用的确是很方便的。通过一个方法就可以将二进制数据转为对象。
什么?你连转换对象的方法都不想调?那就参考【我的另一篇博客】客吧!
参考:
【PB官网】:http://code.google.com/p/protobuf/
【maven中央库】:http://search.maven.org/
【我的另一篇博客】:/article/9212447.html
相关文章推荐
- Activiti环境配置、项目搭建、与Spring集成、简单示例
- spring 项目中集成 Protocol Buffers 示例
- Activiti环境配置、项目搭建、与Spring集成、简单示例
- 分享一个sprng mvc+spring+mabatis 框架集成的项目示例
- Activiti环境配置、项目搭建、与Spring集成、简单示例
- Activiti环境配置、项目搭建、与Spring集成、简单示例
- Log4j学习笔记(2)_log4j配置示例&Spring集成log4j
- spring 集成的项目,Properties配置文件外移
- 在Eclipse和STS集成Cloud Foundry开发环境,spring + MongoDB 示例代码演示部署(一)
- 在Eclipse和STS集成Cloud Foundry开发环境,spring + MongoDB 示例代码演示部署(二)
- MyBatis与Spring集成示例——MyBatis学习笔记之五 推荐
- MyBatis与Spring集成示例
- 简单的spring-data集成mongoDB项目,实现crud的功能
- 单点登录cas与权限管理框架shiro集成------spring项目方式
- spring程序示例(SpringDemo项目)
- spring集成memcache 示例一
- spring集成memcache 示例二
- Hibernate与Spring集成示例 推荐
- A 项目 实战 (二)Spring 与 Struts 集成
- spring 集成的项目,Properties配置文件外移