|
Jersey系列文章:
Jersey框架一:Jersey RESTful WebService框架簡(jiǎn)介
Jersey框架二:Jersey對(duì)JSON的支持
Jersey框架三:Jersey對(duì)HTTPS的支持
開(kāi)發(fā)RESTful WebService意味著支持在多種媒體類(lèi)型以及抽象底層的客戶(hù)端-服務(wù)器通信細(xì)節(jié),如果沒(méi)有一個(gè)好的工具包可用,這將是一個(gè)困難的任務(wù)
為了簡(jiǎn)化使用Java開(kāi)發(fā)RESTful WebService及其客戶(hù)端,一個(gè)輕量級(jí)的標(biāo)準(zhǔn)被提出:JAX-RS API
Jersey RESTful WebService框架是一個(gè)開(kāi)源的、產(chǎn)品級(jí)別的JAVA框架,支持JAX-RS API并且是一個(gè)JAX-RS(JSR 311和 JSR 339)的參考實(shí)現(xiàn)
Jersey不僅僅是一個(gè)JAX-RS的參考實(shí)現(xiàn),Jersey提供自己的API,其API繼承自JAX-RS,提供更多的特性和功能以進(jìn)一步簡(jiǎn)化RESTful service和客戶(hù)端的開(kāi)發(fā)
Maven版本:3.1.0
Jersey版本:1.18
JDK版本:1.7.0_65
一,服務(wù)端
Maven配置如下:
- <project xmlns="http://maven./POM/4.0.0"
- xmlns:xsi="http://www./2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven./POM/4.0.0
- http://maven./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>
首先介紹幾個(gè)注解:
@Path
用來(lái)為資源類(lèi)或方法定義URI,當(dāng)然除了靜態(tài)URI也支持動(dòng)態(tài)URI
- @Path("service")
- public class MyResource {
- @Path("{sub_path}")
- @GET
- public String getResource(@PathParam("sub_path") String resourceName) {
- ......
如果此時(shí)客戶(hù)端請(qǐng)求的URI為http://127.0.0.1:10000/service/sean,則sub_path的值為sean
@PathParam用來(lái)將請(qǐng)求URI的一部分作為方法參數(shù)傳入方法中
對(duì)URI的動(dòng)態(tài)部分,可以自定義校驗(yàn)正則表達(dá)式,如果請(qǐng)求參數(shù)校驗(yàn)失敗,容器返回404 Not Found
- @Path("{sub_path:[A-Z]*}")
@GET
表明被注解的方法響應(yīng)HTTP GET請(qǐng)求,@POST、@PUT和@DELETE同理
@Consumes
定義請(qǐng)求的媒體類(lèi)型,如果不指定,則容器默認(rèn)可接受任意媒體類(lèi)型,容器負(fù)責(zé)確認(rèn)被調(diào)用的方法可接受HTTP請(qǐng)求的媒體類(lèi)型,否則返回415 Unsupported Media Type
方法級(jí)注解將覆蓋類(lèi)級(jí)注解
@Produces
定義響應(yīng)媒體類(lèi)型,如果不指定,則容器默認(rèn)可接受任意媒體類(lèi)型,容器負(fù)責(zé)確認(rèn)被調(diào)用的方法可返回HTTP請(qǐng)求可以接受媒體類(lèi)型,否則返回406 Not Acceptable
方法級(jí)注解將覆蓋類(lèi)級(jí)注解
@QueryParam
- public String getResource(
- @DefaultValue("Just a test!") @QueryParam("desc") String description) {
- ......
- }
如果請(qǐng)求URI中包含desc參數(shù),例如:http://127.0.0.1:10000/service/sean?desc=123456,則desc參數(shù)的值將會(huì)賦給方法的參數(shù)description,否則方法參數(shù)description的值將為@DefaultValue注解定義的默認(rèn)值
@Context
將信息注入請(qǐng)求或響應(yīng)相關(guān)的類(lèi),可注入的類(lèi)有:Application,UriInfo,Request,HttpHeaders和SecurityContext
@Singleton和@PerRequest
默認(rèn)情況下,資源類(lèi)的生命周期是per-request,也就是系統(tǒng)會(huì)為每個(gè)匹配資源類(lèi)URI的請(qǐng)求創(chuàng)建一個(gè)實(shí)例,這樣的效率很低,可以對(duì)資源類(lèi)使用@Singleton注解,這樣在應(yīng)用范圍內(nèi),只會(huì)創(chuàng)建資源類(lèi)的一個(gè)實(shí)例
服務(wù)端程序如下:
- 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請(qǐng)求打印出來(lái)
- 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();
- }
- }
- }
二,客戶(hù)端
Maven配置如下:
- <project xmlns="http://maven./POM/4.0.0"
- xmlns:xsi="http://www./2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven./POM/4.0.0
- http://maven./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>
客戶(hù)端程序如下:
- 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,必須首先創(chuàng)建Client的實(shí)例
- // 有以下兩種創(chuàng)建Client實(shí)例的方式
-
- // 方式一
- ClientConfig cc = new DefaultClientConfig();
- cc.getProperties().put(ClientConfig.PROPERTY_CONNECT_TIMEOUT, 10*1000);
- // Client實(shí)例很消耗系統(tǒng)資源,需要重用
- // 創(chuàng)建web資源,創(chuàng)建請(qǐng)求,接受響應(yīng)都是線(xiàn)程安全的
- // 所以Client實(shí)例和WebResource實(shí)例可以在多個(gè)線(xiàn)程間安全的共享
- Client client = Client.create(cc);
-
- // 方式二
- // Client client = Client.create();
- // client.setConnectTimeout(10*1000);
- // client.getProperties().put(ClientConfig.PROPERTY_CONNECT_TIMEOUT, 10*1000);
-
- // WebResource將會(huì)繼承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方法可用來(lái)添加HTTP頭
- ClientResponse response = resource.header("auth", "123456")
- .accept(MediaType.TEXT_PLAIN)
- .type(MediaType.TEXT_PLAIN)
- .get(ClientResponse.class);
- // 將HTTP響應(yīng)打印出來(lái)
- 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]");
- }
- }
服務(wù)端日志如下:
- 二月 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]
客戶(hù)端日志如下:
- 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]
|