使用JAX-RS构建web服务
前面介绍了REST和JAX-RS的基本概念,本文将以jersey为例,举例说明rest的实际使用方法。
Jersey 是 JAX-RS 的参考实现,Jersey1是JAX-RS的参考实现,Jersey2是JAX-RS2的参考实现。Jersey包含三个主要部分。
- 核心服务器(Core Server):通过提供 JSR 311 中标准化的注释和 API 标准化,您可以用直观的方式开发 RESTful Web 服务。
- 核心客户端(Core Client):Jersey 客户端 API 帮助您与 REST 服务轻松通信。
- 集成(Integration):Jersey 还提供可以轻松集成 Spring、Guice、Apache Abdera 的库。
基于jersey开发rest的流程如下:
- 引入jersey的jar包,https://jersey.java.net/
通过注解的方式定义rest service类,核心的部分如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34@Path("/library")
public class LibraryServiceImpl implements LibraryService {
@GET
@Path("books")
@Override
public String getBooks() {
return "books";
}
@Override
@GET
@Path("/book/{isbn}")
@Produces(MediaType.APPLICATION_JSON)
public Book getBook(@PathParam("isbn") ISBN id) {//ISBN需要带一个String参数的构造方法
Book book = new Book();
book.setId(id);
book.setName("java book");
return book;
}
@Override
@POST
@Path("/book")
public Response addBook(Book book) {//实体参数
System.out.println("name:" + book.getName());
System.out.println("id:" + book.getId().getIsbn());
return Response.ok().build();
}
@DELETE
@Path("/book")
public void removeBook(@QueryParam("id") String id) {
System.out.println("remove id:" + id);
}
}在上述rest service中,可以通过GET方式访问project-path/library/books获取图书馆的所有书籍,以GET方式访问project-path/library/book/123获取ISBN的id为123的书的信息,其中请求头中的Accept类型需包含application/json类型的,url中的123将作为isbn的值,getBook(ISBN id)的参数值即为isbn的值。
在上述实例中,各个资源的URI命名都是名词,且通过请求方式来进行区分请求的资源,如addBook(Book book)和remobeBook(String id)方法虽然请求的URI相同,但是一个是POST一个是DELETE方式,这样就能通过请求方法来简单的辨别出rest service的功能。此外,上述的Book实体需要在类上添加
@XmlRootElement
,ISBN作为参数需要带有一个String类型的构造函数或者一个包含接收单个字符串参数的valueOf静态方法。添加web.xml配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21<web-app>
<servlet>
<servlet-name>JerseyFirstServlet</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<!-- <init-param>
设置REST资源所在的包(可选)
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.tony.jersey.service</param-value>
</init-param> -->
<!--
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.tony.jersey.service.MyApplication</param-value>
</init-param> -->
</servlet>
<servlet-mapping>
<servlet-name>JerseyFirstServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>添加rest的servlet,url-pattern可以添加前缀,如果配置成
service/* ,那么上述的getBooks()方法的URL将变为…/service/library/books。还可以设置REST资源所在的包,这样只有这些包能够被当做rest service。
此外,还有其他的配置方法,如自定义Application类,用来注册service和provider,这样能够更灵活的控制service。通过这种方式实现的,需要在web.xml中添加javax.ws.rs.Application
参数的配置,或者在自定义的Application类中添加@ApplicationPath
注解。用注解方式来实现就可以不用web.xml配置了。- 客户端调用rest service
jersey提供了客户端API,可以方便的调用service。当然,在JAX-RS2中,也提供了客户端的API。通过jersey的客户端API调用方式如下:1
2
3
4
5Client c = Client.create();
WebResource r = c.resource("http://localhost:8080/rest-jersey-demo/library...");
ClientResponse response = r.get(ClientResponse.class);
int status = response.getStatus();
String entity = response.getEntity(String.class);
当然,jersey还可以和spring集成,要和spring集成,只需要添加一个jersey-spring的包,并修改web.xml中配置的servlet类为com.sun.jersey.spi.spring.container.servlet.SpringServlet
,很简单吧。
jersey2的包名和jersey1不一样,且jersey2提供了jax-rs2的实现,有异步调用、过滤器拦截器等功能,本文不详细介绍,下文将给出一个实例的地址,写的实例托管在bitbucket中,bitbucket也是国外的,不过在国内访问速度相对于github速度快些,且bitbucket还提供免费的私有仓库(无仓库个数限制,一个仓库最大容量1G,最大协作人数5人)。
最后,给出本实例的代码地址:
- jersey1的一个实例:https://bitbucket.org/tony404/rest-resteasy-demo
- jersey2的一个实例:https://bitbucket.org/tony404/rest-jersey2-demo
- jersey与spring的整合:https://bitbucket.org/tony404/rest-jersey-spring-demo
- resteasy的一个简单实例:https://bitbucket.org/tony404/rest-resteasy-demo