Jersey系列文章:html
Jersey框架一:Jersey RESTful WebService框架簡介java
Jersey框架三:Jersey對HTTPS的支持正則表達式
開發RESTful WebService意味着支持在多種媒體類型以及抽象底層的客戶端-服務器通訊細節,若是沒有一個好的工具包可用,這將是一個困難的任務apache
爲了簡化使用Java開發RESTful WebService及其客戶端,一個輕量級的標準被提出:JAX-RS APIapi
Jersey RESTful WebService框架是一個開源的、產品級別的JAVA框架,支持JAX-RS API而且是一個JAX-RS(JSR 311和 JSR 339)的參考實現安全
Jersey不單單是一個JAX-RS的參考實現,Jersey提供本身的API,其API繼承自JAX-RS,提供更多的特性和功能以進一步簡化RESTful service和客戶端的開發服務器
Maven版本:3.1.0app
Jersey版本:1.18框架
JDK版本:1.7.0_65
一,服務端
Maven配置以下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>JERSEY_SERVER</groupId> <artifactId>JERSEY_SERVER</artifactId> <version>1.0</version> <dependencies> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-server</artifactId> <version>1.18</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-grizzly2</artifactId> <version>1.18</version> </dependency> </dependencies> </project>
首先介紹幾個註解:
@Path
用來爲資源類或方法定義URI,固然除了靜態URI也支持動態URI
@Path("service") public class MyResource { @Path("{sub_path}") @GET public String getResource(@PathParam("sub_path") String resourceName) { ......
若是此時客戶端請求的URI爲http://127.0.0.1:10000/service/sean,則sub_path的值爲sean
@PathParam用來將請求URI的一部分做爲方法參數傳入方法中
對URI的動態部分,能夠自定義校驗正則表達式,若是請求參數校驗失敗,容器返回404 Not Found
@Path("{sub_path:[A-Z]*}")
@GET
代表被註解的方法響應HTTP GET請求,@POST、@PUT和@DELETE同理
@Consumes
定義請求的媒體類型,若是不指定,則容器默承認接受任意媒體類型,容器負責確認被調用的方法可接受HTTP請求的媒體類型,不然返回415 Unsupported Media Type
方法級註解將覆蓋類級註解
@Produces
定義響應媒體類型,若是不指定,則容器默承認接受任意媒體類型,容器負責確認被調用的方法可返回HTTP請求能夠接受媒體類型,不然返回406 Not Acceptable
方法級註解將覆蓋類級註解
@QueryParam
public String getResource( @DefaultValue("Just a test!") @QueryParam("desc") String description) { ...... }
若是請求URI中包含desc參數,例如:http://127.0.0.1:10000/service/sean?desc=123456,則desc參數的值將會賦給方法的參數description,不然方法參數description的值將爲@DefaultValue註解定義的默認值
@Context
將信息注入請求或響應相關的類,可注入的類有:Application,UriInfo,Request,HttpHeaders和SecurityContext
@Singleton和@PerRequest
默認狀況下,資源類的生命週期是per-request,也就是系統會爲每一個匹配資源類URI的請求建立一個實例,這樣的效率很低,能夠對資源類使用@Singleton註解,這樣在應用範圍內,只會建立資源類的一個實例
服務端程序以下:
package com.sean; import java.io.IOException; import java.net.URI; import java.util.Iterator; import javax.ws.rs.Consumes; import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Request; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import org.glassfish.grizzly.http.server.HttpServer; import com.sun.jersey.api.container.grizzly2.GrizzlyServerFactory; import com.sun.jersey.api.core.PackagesResourceConfig; import com.sun.jersey.api.core.ResourceConfig; import com.sun.jersey.spi.resource.Singleton; @Singleton @Path("service") public class MyResource { @Path("{sub_path:[a-zA-Z0-9]*}") @GET @Consumes({MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON}) @Produces(MediaType.TEXT_PLAIN) public String getResourceName( @PathParam("sub_path") String resourceName, @DefaultValue("Just a test!") @QueryParam("desc") String description, @Context Request request, @Context UriInfo uriInfo, @Context HttpHeaders httpHeader) { System.out.println(this.hashCode()); // 將HTTP請求打印出來 System.out.println("****** HTTP request ******"); StringBuilder strBuilder = new StringBuilder(); strBuilder.append(request.getMethod() + " "); strBuilder.append(uriInfo.getRequestUri().toString() + " "); strBuilder.append("HTTP/1.1[\\r\\n]"); System.out.println(strBuilder.toString()); MultivaluedMap<String, String> headers = httpHeader.getRequestHeaders(); Iterator<String> iterator = headers.keySet().iterator(); while(iterator.hasNext()){ String headName = iterator.next(); System.out.println(headName + ":" + headers.get(headName) + "[\\r\\n]"); } System.out.println("[\\r\\n]"); String responseStr =resourceName + "[" + description + "]"; return responseStr; } public static void main(String[] args) { URI uri = UriBuilder.fromUri("http://127.0.0.1").port(10000).build(); ResourceConfig rc = new PackagesResourceConfig("com.sean"); try { HttpServer server = GrizzlyServerFactory.createHttpServer(uri, rc); server.start(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (NullPointerException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } try { Thread.sleep(1000*1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
二,客戶端
Maven配置以下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>JERSEY_CLIENT</groupId> <artifactId>JERSEY_CLIENT</artifactId> <version>1.0</version> <dependencies> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> <version>1.18</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-grizzly2</artifactId> <version>1.18</version> </dependency> </dependencies> </project>
客戶端程序以下:
package com.sean; import java.net.URI; import java.util.Iterator; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.UriBuilder; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.WebResource; import com.sun.jersey.api.client.config.ClientConfig; import com.sun.jersey.api.client.config.DefaultClientConfig; public class JerseyClient { public static void main(String[] args) { // 要使用Jersey Client API,必須首先建立Client的實例 // 有如下兩種建立Client實例的方式 // 方式一 ClientConfig cc = new DefaultClientConfig(); cc.getProperties().put(ClientConfig.PROPERTY_CONNECT_TIMEOUT, 10*1000); // Client實例很消耗系統資源,須要重用 // 建立web資源,建立請求,接受響應都是線程安全的 // 因此Client實例和WebResource實例能夠在多個線程間安全的共享 Client client = Client.create(cc); // 方式二 // Client client = Client.create(); // client.setConnectTimeout(10*1000); // client.getProperties().put(ClientConfig.PROPERTY_CONNECT_TIMEOUT, 10*1000); // WebResource將會繼承Client中timeout的配置 WebResource resource = client.resource("http://127.0.0.1:10000/service/sean?desc=description"); String str = resource .accept(MediaType.TEXT_PLAIN) .type(MediaType.TEXT_PLAIN) .get(String.class); System.out.println("String:" + str); URI uri = UriBuilder.fromUri("http://127.0.0.1/service/sean").port(10000) .queryParam("desc", "description").build(); resource = client.resource(uri); //header方法可用來添加HTTP頭 ClientResponse response = resource.header("auth", "123456") .accept(MediaType.TEXT_PLAIN) .type(MediaType.TEXT_PLAIN) .get(ClientResponse.class); // 將HTTP響應打印出來 System.out.println("****** HTTP response ******"); StringBuilder strBuilder = new StringBuilder(); strBuilder.append("HTTP/1.1 "); strBuilder.append(response.getStatus() + " "); strBuilder.append(response.getStatusInfo() + "[\\r\\n]"); System.out.println(strBuilder.toString()); MultivaluedMap<String, String> headers = response.getHeaders(); Iterator<String> iterator = headers.keySet().iterator(); while(iterator.hasNext()){ String headName = iterator.next(); System.out.println(headName + ":" + headers.get(headName) + "[\\r\\n]"); } System.out.println("[\\r\\n]"); System.out.println(response.getEntity(String.class) + "[\\r\\n]"); } }
服務端日誌以下:
二月 06, 2015 4:33:33 下午 com.sun.jersey.api.core.PackagesResourceConfig init INFO: Scanning for root resource and provider classes in the packages: com.sean 二月 06, 2015 4:33:33 下午 com.sun.jersey.api.core.ScanningResourceConfig logClasses INFO: Root resource classes found: class com.sean.Test class com.sean.MyResource 二月 06, 2015 4:33:33 下午 com.sun.jersey.api.core.ScanningResourceConfig init INFO: No provider classes found. 二月 06, 2015 4:33:33 下午 com.sun.jersey.server.impl.application.WebApplicationImpl _initiate INFO: Initiating Jersey application, version 'Jersey: 1.18 11/22/2013 01:21 AM' 二月 06, 2015 4:33:34 下午 org.glassfish.grizzly.http.server.NetworkListener start INFO: Started listener bound to [127.0.0.1:10000] 二月 06, 2015 4:33:34 下午 org.glassfish.grizzly.http.server.HttpServer start INFO: [HttpServer] Started. 1814260800 ****** HTTP request ****** GET http://127.0.0.1:10000/service/sean?desc=description HTTP/1.1[\r\n] accept:[text/plain][\r\n] content-type:[text/plain][\r\n] user-agent:[Java/1.7.0_65][\r\n] host:[127.0.0.1:10000][\r\n] connection:[keep-alive][\r\n] [\r\n] 1814260800 ****** HTTP request ****** GET http://127.0.0.1:10000/service/sean?desc=description HTTP/1.1[\r\n] auth:[123456][\r\n] accept:[text/plain][\r\n] content-type:[text/plain][\r\n] user-agent:[Java/1.7.0_65][\r\n] host:[127.0.0.1:10000][\r\n] connection:[keep-alive][\r\n] [\r\n]
客戶端日誌以下:
String:sean[description]
****** HTTP response ******
HTTP/1.1 200 OK[\r\n]
Transfer-Encoding:[chunked][\r\n]
Date:[Fri, 06 Feb 2015 08:33:38 GMT][\r\n]
Content-Type:[text/plain][\r\n]
[\r\n]
sean[description][\r\n]