我使用的是Maven Project,所以
1。第一步加入Maven Dependency。
<dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-server</artifactId> <version>1.10</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> <version>1.10</version> </dependency> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>2.4.1</version> </dependency>
2。 然后,加入ant plugin来帮助我们产生protobuf 的java bean。
<build> <plugins> <plugin> <artifactId>maven-antrun-plugin</artifactId> <executions> <execution> <id>generate-sources</id> <phase>generate-sources</phase> <goals> <goal>run</goal> </goals> <configuration> <tasks> <mkdir dir='target/generated-sources' /> <exec executable='protoc'> <arg value='--java_out=target/generated-sources' /> <arg value='src/main/resources/addressbook.proto' /> </exec> </tasks> <sourceRoot>target/generated-sources</sourceRoot> </configuration> </execution> </executions> </plugin> </plugins> <pluginManagement> <plugins> <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.--> <plugin> <groupId>org.eclipse.m2e</groupId> <artifactId>lifecycle-mapping</artifactId> <version>1.0.0</version> <configuration> <lifecycleMappingMetadata> <pluginExecutions> <pluginExecution> <pluginExecutionFilter> <groupId> org.apache.maven.plugins </groupId> <artifactId> maven-antrun-plugin </artifactId> <versionRange>[1.3,)</versionRange> <goals> <goal>run</goal> </goals> </pluginExecutionFilter> <action> <ignore></ignore> </action> </pluginExecution> </pluginExecutions> </lifecycleMappingMetadata> </configuration> </plugin> </plugins> </pluginManagement> </build>
3。 创建addressbook.proto文件
package tutorial; option java_package = "com.sampullara.jaxrsprotobuf.tutorial"; 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; }
4。 运行mvn generate-sources命令来生成AddressBookProtos.java文件。
5。创建rest server端代码AddressBookService.java
package com.sampullara; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import com.sampullara.jaxrsprotobuf.tutorial.AddressBookProtos; @Path("/person") public class AddressBookService { @GET @Produces("application/x-protobuf") public AddressBookProtos.Person getPerson() { return AddressBookProtos.Person.newBuilder() .setId(1) .setName("Sam") .setEmail("[email protected]") .addPhone(AddressBookProtos.Person.PhoneNumber.newBuilder() .setNumber("415-555-1212") .setType(AddressBookProtos.Person.PhoneType.MOBILE) .build()) .build(); } @POST @Consumes("application/x-protobuf") @Produces("application/x-protobuf") public AddressBookProtos.Person reflect(AddressBookProtos.Person person) { return person; } }
6。创建ProtobufProviders.java文件处理protobuf对象序列化。
package com.sampullara; import com.google.protobuf.GeneratedMessage; import com.google.protobuf.Message; import javax.ws.rs.Consumes; import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.MessageBodyReader; import javax.ws.rs.ext.MessageBodyWriter; import javax.ws.rs.ext.Provider; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.Map; import java.util.WeakHashMap; /** * These providers implement the conversion of protobuf objects to and from their serialized form over the wire. * * User: sam * Date: Dec 27, 2008 * Time: 3:13:17 PM */ public class ProtobufProviders { @Provider @Consumes("application/x-protobuf") public static class ProtobufMessageBodyReader implements MessageBodyReader<Message> { public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return Message.class.isAssignableFrom(type); } public Message readFrom(Class<Message> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { try { Method newBuilder = type.getMethod("newBuilder"); GeneratedMessage.Builder builder = (GeneratedMessage.Builder) newBuilder.invoke(type); return builder.mergeFrom(entityStream).build(); } catch (Exception e) { throw new WebApplicationException(e); } } } @Provider @Produces("application/x-protobuf") public static class ProtobufMessageBodyWriter implements MessageBodyWriter<Message> { public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return Message.class.isAssignableFrom(type); } private Map<Object, byte[]> buffer = new WeakHashMap<Object, byte[]>(); public long getSize(Message m, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { m.writeTo(baos); } catch (IOException e) { return -1; } byte[] bytes = baos.toByteArray(); buffer.put(m, bytes); return bytes.length; } public void writeTo(Message m, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { entityStream.write(buffer.remove(m)); } } }
7。创建服务器
package com.sampullara; import java.io.IOException; import java.net.URI; import javax.ws.rs.core.UriBuilder; import com.sun.net.httpserver.HttpServer; import com.sun.jersey.api.container.httpserver.HttpServerFactory; import com.sun.jersey.api.core.PackagesResourceConfig; import com.sun.jersey.api.core.ResourceConfig; public class Main { public static final URI BASE_URI = UriBuilder.fromUri("http://localhost/").port(9998).build(); public static HttpServer createServer(URI uri) throws IOException { ResourceConfig rc = new PackagesResourceConfig("com.sampullara"); return HttpServerFactory.create(uri, rc); } }
8。编写客户端代码
package com.sampullara; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import junit.framework.TestCase; import com.sampullara.ProtobufProviders.ProtobufMessageBodyReader; import com.sampullara.ProtobufProviders.ProtobufMessageBodyWriter; import com.sampullara.jaxrsprotobuf.tutorial.AddressBookProtos; //import com.sun.grizzly.http.SelectorThread; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.UniformInterfaceException; import com.sun.jersey.api.client.WebResource; import com.sun.jersey.api.client.config.ClientConfig; import com.sun.jersey.api.client.config.DefaultClientConfig; import com.sun.net.httpserver.HttpServer; /** * TODO: Edit this * <p/> * User: sam * Date: Dec 27, 2008 * Time: 5:10:58 PM */ public class MainTest extends TestCase { private HttpServer server; private WebResource r; @Override protected void setUp() throws Exception { super.setUp(); //start the Grizzly web container and create the client server = Main.createServer(Main.BASE_URI); server.start(); ClientConfig cc = new DefaultClientConfig(); cc.getClasses().add(ProtobufMessageBodyReader.class); cc.getClasses().add(ProtobufMessageBodyWriter.class); Client c = Client.create(cc); r = c.resource(Main.BASE_URI); } @Override protected void tearDown() throws Exception { super.tearDown(); server.stop(0); } public void testUsingJerseyClient() { WebResource wr = r.path("person"); AddressBookProtos.Person p = null; try { p = wr.get(AddressBookProtos.Person.class); } catch (UniformInterfaceException e) { e.printStackTrace(); } assertEquals("Sam", p.getName()); AddressBookProtos.Person p2 = wr.type("application/x-protobuf").post(AddressBookProtos.Person.class, p); assertEquals(p, p2); } public void testUsingURLConnection() throws IOException { AddressBookProtos.Person person; { URL url = new URL("http://localhost:9998/person"); URLConnection urlc = url.openConnection(); urlc.setDoInput(true); urlc.setRequestProperty("Accept", "application/x-protobuf"); person = AddressBookProtos.Person.newBuilder().mergeFrom(urlc.getInputStream()).build(); assertEquals("Sam", person.getName()); } { URL url = new URL("http://localhost:9998/person"); HttpURLConnection urlc = (HttpURLConnection) url.openConnection(); urlc.setDoInput(true); urlc.setDoOutput(true); urlc.setRequestMethod("POST"); urlc.setRequestProperty("Accept", "application/x-protobuf"); urlc.setRequestProperty("Content-Type", "application/x-protobuf"); person.writeTo(urlc.getOutputStream()); AddressBookProtos.Person person2 = AddressBookProtos.Person.newBuilder().mergeFrom(urlc.getInputStream()).build(); assertEquals(person, person2); } } }