java 利用JAX-RS快速开发RESTful 服务

JAX-RS(Java API for RESTful Web Services)同样也是JSR的一部分,详细规范定义见 https://jcp.org/en/jsr/detail?id=311 。从JAVA EE 6开始,已经内置了该技术,跟.NET中的RESTful WCF类似,只要在常规方法上使用一些简单的注解,就可以对外暴露成RESTful 服务.

一、最基础的HelloWorld (无参数)

复制代码
 1 @Path("/")
 2 public class MyService {
 3 
 4     final String XMLNS_NAMESPACE = "http://yjmyzz.cnblogs.com/rest/service";
 5     final String ROOT_NODE = "root";
 6 
 7     @GET
 8     @Path("/json/hello")
 9     @Produces(MediaType.APPLICATION_JSON)
10     public JAXBElement<String> getHelloWorldJSON() {
11         JAXBElement<String> result = new JAXBElement<String>(new QName("",
12                 ROOT_NODE), String.class, sayHelloWorld());
13         return result;
14     }
15 。。。
16
复制代码
1     private String sayHelloWorld() {
2         return "Hello JAX-RS!";
3     }

解释:
@GET 表示该服务可以直接在浏览器地址栏里访问(对应HTTP请求中的GET方法)

@Path 这里用了二次,第一次是在Class上,相当服务的基地址;第二次是在方法上,表示具体某个服务方法的URL.

此外web.xml中,还需要增加以下内容:

1     <servlet-mapping>
2         <servlet-name>javax.ws.rs.core.Application</servlet-name>
3         <url-pattern>/rest/*</url-pattern>
4     </servlet-mapping>

@Produces 表示返回消息的格式,配合MediaType.APPLICATION_JSON说明,本方法返回Json字符串格式

以上几项综合起来,最终可以用类似 http://localhost:8080/jboss-as-helloworld-rs/rest/json/hello 的地址来访问,返回的结果为:

java 利用JAX-RS快速开发RESTful 服务_第1张图片

JAXBElement<T> 类似一个包装器(Wrapper),用于将返回对象做下json/xml格式的包装,比如上图中的{root:}就是它的功劳,感兴趣的朋友,可以把返回类似改成最原始的String对比下差异.

如果需要返回XML格式,只需要把@Produces后面的MediaType.APPLICATION_JSON换成MediaType.APPLICATION_XML就行了,即:

复制代码
1     @GET
2     @Path("/xml/hello")
3     @Produces(MediaType.APPLICATION_XML)
4     public JAXBElement<String> getHelloWorldXML() {
5         JAXBElement<String> result = new JAXBElement<String>(new QName(
6                 XMLNS_NAMESPACE, ROOT_NODE), String.class, sayHelloWorld());
7         return result;
8     }
复制代码

效果如下:

java 利用JAX-RS快速开发RESTful 服务_第2张图片

 

二、带一个基本类型参数的HelloWorld

复制代码
 1     @GET
 2     @Path("/json/hi/{name}")
 3     @Produces(MediaType.APPLICATION_JSON)
 4     public JAXBElement<String> getHelloToNameJSON(@PathParam("name") String name) {
 5         JAXBElement<String> result = new JAXBElement<String>(new QName("",
 6                 ROOT_NODE), String.class, sayHelloToName(name));
 7         return result;
 8     }
 9 
10     @GET
11     @Path("/xml/hi/{name}")
12     @Produces(MediaType.APPLICATION_XML)
13     public JAXBElement<String> getHelloToNameXML(@PathParam("name") String name) {
14         JAXBElement<String> result = new JAXBElement<String>(new QName(
15                 XMLNS_NAMESPACE, ROOT_NODE), String.class, sayHelloToName(name));
16         return result;
17     }
复制代码
1     private String sayHelloToName(String name) {
2         return "Hello " + name + ",welcome to the world of JAX-RS!";
3     }

对比一下刚才的代码,有二个变化:

2.1 @Path上多了一个{name}的部分,表示url中,将允许以 /json/hi/xxx 的访问URL响应请求

2.2 方法参数前有一个 @PathParam("name") 的注解,表示如果按/json/hi/xxx的方式访问,则url中xxx的部分,会被映射到name这个参数上(说得更通俗点,就是通过解析url最后的xxx部分直接把name传进来)

运行效果如下:

java 利用JAX-RS快速开发RESTful 服务_第3张图片

java 利用JAX-RS快速开发RESTful 服务_第4张图片

 

三、返回结果为实体Bean

实际应用中,web服务返回的结果,除了基本类型,还有可能是实体Bean,先来定义一个User类

  User

代码中加的一堆@XML开头的注解,是为了在传输过程中,如果需要以XML格式传输,这些注解可以帮助完成 XML <-> Obj的转换(详情可参见JAXB相关内容

  getUserInXML & getUserInJSON

注意:这里我们没有使用JAXBElement<T>对结果进行包装,辅助方法getUser()代码如下

  getUser

运行结果如下:
java 利用JAX-RS快速开发RESTful 服务_第5张图片

java 利用JAX-RS快速开发RESTful 服务_第6张图片

当然,也可以给方法增加参数,先从最基本类型的String参数耍起:

  getUserWithStringParameter

运行结果如下:
java 利用JAX-RS快速开发RESTful 服务_第7张图片

java 利用JAX-RS快速开发RESTful 服务_第8张图片

如果加上包装器JAXBElement<User>后,返回结果会变成什么样呢? 我也很好奇,so, 嘿-喂狗!

  getUserWithWrapper

结果如下:

java 利用JAX-RS快速开发RESTful 服务_第9张图片

java 利用JAX-RS快速开发RESTful 服务_第10张图片

个中差异,请自行体会

 

四、单个String参数的实体Bean注入

web服务中方法的传入参数,不可能都是基础类型,同样也可以是实体Bean

复制代码
 1     @GET
 2     @Path("/xml/product/{name}")
 3     @Produces(MediaType.APPLICATION_XML)
 4     public Product getProductXML(@PathParam("name") Product product) {
 5         return getProductFromServer(product);
 6     }
 7 
 8     @GET
 9     @Path("/xml/product2/{name}")
10     @Produces(MediaType.APPLICATION_XML)
11     public JAXBElement<Product> getProductXML2(
12             @PathParam("name") Product product) {
13         JAXBElement<Product> result = new JAXBElement<Product>(new QName(
14                 XMLNS_NAMESPACE, ROOT_NODE), Product.class,
15                 getProductFromServer(product));
16         return result;
17     }
复制代码

这里我们用到了一个新的Bean :Product类,代码如下:

  Product Bean

先提个问题:从@Path上看,我们希望用类似 /xml/product/xxx 来请求该web方法,但是方法中的参数是一个Bean实例,而url中的xxx部分只是一个字符串,一个字符串如何被映射成一个Bean实例呢

关键在于Product中的构造函数:Product(String name) ,方法getProductXML(@PathParam("name") Product product) 被请求时,url中的xxx部分会先映射成参数name,然后name又会被传入到构造函数Product(String name)中,于是一个崭新的Product对象诞生了!(可以通过eclipse Console的输出来印证Product(String name)是否被调用)

运行结果:

java 利用JAX-RS快速开发RESTful 服务_第11张图片

eclipse的控制台里,也可以看到构造器,确实被调用了

java 利用JAX-RS快速开发RESTful 服务_第12张图片

除了利用“带参数的构造器”来实现“url参数->Bean实例”的注入,JAX-RS机制还允许使用Bean自身提供的static valueOf()方法来实现注入,再来看一下示例:

从Product派生一个子类Book:

  Book

再定义一个新方法:

  getBookXML

里面有一个辅助方法,代码如下:

  getBookFromServer

运行效果如下:

java 利用JAX-RS快速开发RESTful 服务_第13张图片

eclipse的控制台信息如下:

java 利用JAX-RS快速开发RESTful 服务_第14张图片

 

五、POST方式的Bean实例参数注入

前面提到的都是GET方式的web服务方法,GET方式能传输的数据大小有限,对于较大的参数数据,直接POST的场景更常见,下面是一个示例:

  add-book

解释一下:

又遇到了一个新的注解:@Consumes(MediaType.APPLICATION_JSON) 它表示传入的Book实例是json格式。

我们用jQuery以Ajax方式调用这个服务演示一下:

  testJsonAddBook & testXmlAddBook

运行效果如下:
java 利用JAX-RS快速开发RESTful 服务_第15张图片

java 利用JAX-RS快速开发RESTful 服务_第16张图片

 

如果断点调试ajax,可以看到传过来的json串已经映射成Bean实例了

java 利用JAX-RS快速开发RESTful 服务_第17张图片

示例源代码下载:helloworld-rs.zip

你可能感兴趣的:(Restful)