最近公司有個項目需要和c++做信息交換,現在流行比較流行http+protobuf方式,一是比較簡單學習成本低,二是信息的壓縮比例比較好,節省帶寬。
經過調研spring 4.1以后開始支持protobuf HttpMessageConverter 詳細的配置如下:
- pom.xml配置:
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>com.googlecode.protobuf-java-format</groupId>
<artifactId>protobuf-java-format</artifactId>
<version>1.2</version>
</dependency>
還有要引入spring核心包及spring mvc包 版本4.1.6.RELEASE,如果不知道怎么引入,百度一下
配置portoc插件,也可以不用這個插件,得需要自己用protoc.exe生產java文件
<plugin>
<groupId>com.google.protobuf.tools</groupId>
<artifactId>maven-protoc-plugin</artifactId>
<version>0.1.10</version>
<executions>
<execution>
<id>generate-sources</id>
<goals>
<goal>compile</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<protoSourceRoot>${basedir}/src/main/proto/</protoSourceRoot>
<includes>
<param>**/*.proto</param>
</includes>
</configuration>
</execution>
</executions>
<configuration>
<protocExecutable>D:/dev/protoc.exe</protocExecutable><!--protoc.exe文件地址,使用2.5版本-->
</configuration>
</plugin>
- springmvc-servlet.xml配置
<mvc:annotation-driven>
<mvc:message-converters>
<!--看了一下源碼,客戶端請求類型必須設置成application/x-protobuf采用用這個類來解析實體
<bean class="org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter">
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
- user.proto文件,目錄/src/main/proto/和protoc插件配置路徑保持一致,如果不想用插件可以自己用protoc.exe生成java文件,可以參見protobuf使用
package com.my.pb;
option java_package = "com.my.pb";
option java_outer_classname = "UserProto";
message User {
optional int64 id = 1;
optional string name = 2;
message PhoneNumber {
required string number = 1;
}
repeated PhoneNumber phone = 4;
}
- controller類
@Controller
public class ProtobufController{
@RequestMapping(value = "/proto/write1",method= RequestMethod.POST)
public ResponseEntity<UserProto.User> protoWrite1(RequestEntity<UserProto.User> requestEntity) {
//System.out.println("server===\n");
UserProto.User user = requestEntity.getBody();
System.out.println("server===\n" + user);
return ResponseEntity.ok(user);
}
}
- 客戶端測試代碼,使用Apache的httpclient進行測試
@Test
public void testWrite() throws IOException {
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(baseUri+"/proto/write1");
UserProto.User user = UserProto.User.newBuilder().setId(1).setName("zhangsan").addPhone(UserProto.User.PhoneNumber.newBuilder().setNumber("18611163408")).build();//構造
ByteArrayInputStream inputStream = new ByteArrayInputStream(user.toByteArray());
InputStreamEntity inputStreamEntity = new InputStreamEntity(inputStream);
//這兩行很重要的,是告訴springmvc客戶端請求和響應的類型,指定application/x-protobuf類型,spring會用ProtobufHttpMessageConverter類來解析請求和響應的實體
httpPost.addHeader("Content-Type","application/x-protobuf");
httpPost.addHeader("Accept", "application/x-protobuf");
httpPost.setEntity(inputStreamEntity);
CloseableHttpResponse response2 = httpclient.execute(httpPost);
try {
System.out.println(response2.getStatusLine());
HttpEntity entity2 = response2.getEntity();
ByteArrayOutputStream buf = new ByteArrayOutputStream();
entity2.writeTo(buf);
System.out.println(new String(buf.toByteArray())+"#################");
UserProto.User user2 = UserProto.User.parseFrom(buf.toByteArray());
System.out.println(user2);
} finally {
response2.close();
}
}
- 總結:
當時調試的時候試了很多次,響應總是被轉成xml類型,最后看了源碼才發現客戶端要設置httpPost.addHeader("Accept", "application/x-protobuf");
其實也可以自己實現HttpMessageConverter,也不是很麻煩,本人比較懶,有現成的東西不太愛閉門造車輪。
參考文獻:
http://jinnianshilongnian.iteye.com/blog/2107205
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/
