Jersey框架一:Jersey RESTful WebService框架简介
Jersey系列文章:
Jersey框架一:Jersey RESTful WebService框架简介
开发RESTful WebService意味着支持在多种媒体类型以及抽象底层的客户端-服务器通信细节,如果没有一个好的工具包可用,这将是一个困难的任务
为了简化使用JAVA开发RESTful WebService及其客户端,一个轻量级的标准被提出:JAX-RS API
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.0
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
-
"service")(
-
public class MyResource {
-
"{sub_path}")(
-
-
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;
-
-
-
"service")(
-
public class MyResource {
-
-
"{sub_path:[a-zA-Z0-9]*}")(
-
-
-
-
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]