JAX-RS 方式的 RESTful Web Service 开发

Web Service 目前在风格上有两大类,一个是基于 SOAP 协议,一个是彻底遵循 HTTP 协议规范的RESTful 风格。 SOAP 方式的 web service 已经很成熟了,应用也很广,已经成为 Web Service 的工业标准。不过 RESTful Web Service 如今势头愈来愈猛,特别是其灵活性以及与 Ajax 的完美结合,让人爱不释手,颇有必要了解一下。 RESTful 就是一种架构风格,是对 HTTP 协议的彻底遵循。像是人们经历了无止境的对 HTTP 引伸、扩展之路后的一种回归,让 web service 开发者从新作回 HTTP 协议的信徒。 RESTful 倡导用 HTTP 协议中的 verb 与实际数据操做的增删改查相对应,如 HTTP 中的 PUT 、 GET 、 POST 、DELETE 分别对应 web 系统中数据的改、查、增、删的操做。固然 RESTful 支持的 http verb 还不只限于上述 4 个,还有像其余的 HEAD,OPTION ……等,不过上述 4 个已经够咱们平常使用了。java

目前 Web Service 的框架不少,不过我只用过 CXF ,因此我仍是以 apache-cxf2.2.2 为例介绍一下 RESTful Web Service 的开发。web

比较常见的 RESTful Web Service 的发布有 JAX-RS 风格、 Provider 方式、 Servlet 方式、 HTTPBinding ,也许还有其余方式,不过我只知道这些了。总的感受最偷懒的方式是采用 Servlet 方式发布 Web Service ,说是 Web Service 发布,其实就是转换下对 Servlet 的认识, Servlet 自己就支持对 HTTP 请求中各类动做的支持,因此 Servlet 原生就是一种 RESTful Web Service 。不过这种方式我以为有些不够时尚。 Povider 的方式我了解了一下,须要实现 Provider 接口,感受很受拘束。正在我对 RESTful 丧失兴趣的时候,发现了 JAX-RS 风格, JAX-RS 就像是一个清纯 MM ,服务端配置完成,并且配置很是的清秀。并且也很是的平易近人,客户端调用方式很灵活。接下来我就把她介绍给你们。spring

1.      环境搭建apache

在本示例中采用了 Web Project 的方式, Web 工程创建的过程就再也不赘述了,只列举一下环境须要的 jar包。以下:json

下面是我本地工程中的 jar ,仅供参考。api

环境信息

注:若是要在 RESTful 服务中直接返回 json 数据格式的话, jsr311-api-1.0.jar 必不可少。浏览器

2.      服务开发服务器

咱们以简单的一个客户信息服务为例进行介绍。服务的业务实现你们不用太在乎,关注服务开发的过程就行了。架构

2.1   开门见山app

首先咱们先构造一个客户的 VO 。

package com.harvey.cxf.demo.rest.rs.vo;  
  
import javax.xml.bind.annotation.XmlAccessType;  
import javax.xml.bind.annotation.XmlAccessorType;  
import javax.xml.bind.annotation.XmlRootElement;  
  
@XmlRootElement(name = "Customer")  
@XmlAccessorType(XmlAccessType.FIELD)  
public class Customer {  
    private long id;  
    private String name;  
  
    public long getId() {  
        return id;  
    }  
  
  
    public void setId(long id) {  
        this.id = id;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
}

接下来以 CustomerService 做为客户服务的实现类

先以最多见的查询某一客户信息为例,以下:

@Path("/")  
public class CustomerService {  
    ……  
   //普通路径参数方式GET请求  
    @GET  
    @Path("/customers/{id}")  
    public Customer getCustomer(@PathParam("id") String id) {  
        ……  
    }  
}

假设咱们的服务最终发布地址为 http://127.0.0.1:8080/customerservice 的话,若是要查询某一客户的信息的话,咱们只需发送 GET 请求 http://127.0.0.1:8080/customerservice/customers/123 ,或者直接在浏览器中输入该 url就可直接访问该服务。其中 url 中传入的 123 会自动适配到服务中的 {id} 参数。这样一个简单的处理 GET 请求的RESTful Web service 就开发完了。

2.2 参数处理

在上面的例子中咱们看到, client 在服务请求时传递参数是经过的请求路径的方式传入的。如以前的http://127.0.0.1:8080/customerservice/customers/123 , 客户 ID123 做为了路径一部分。对应的服务器端的参数配置采用了 @PathParam ( "id" ) String id 。 
除了支持路径传递的方式以外,咱们还能够在请求时的查询参数中指定。好比仍是查询某一客户的信息,server 端代码能够以下:

……  
@GET  
    @Path("/customers/getCustomerById")  
    public Customer getCustomerByQueryString(@QueryParam("id") String id){  
       ……  
    }

此时该服务访问 url 则为:

http://127.0.0.1:8080/customerservice/customers/getCustomerById?id=123

说着这,也许会有听众要问了(也许没人问):以前提到的都是简单参数,这个容易,那么对于一些复杂bean 参数该怎么处理呢?

这个问题问得好,接下来我就举例说明下。说例子以前再重复一遍啊,看例子时千万不要纠结于代码的业务逻辑,只看技术实现方式。

……  
@GET  
    @Path("/customers/getCust")  
    public Customer getCustomer(@QueryParam("")Customer cust) {  
        ……  
}

这个例子中须要传入以前声明的客户信息类做为参数。参数处理方式为 QueryParam ,因此这时候咱们访问url 格式相似如下:

http://127.0.0.1:8080/customerservice/customers/getCust?id=123&name=xiaoming

若是参数 bean 还包括其余属性,用 & 符号依次追加就行了。还一般的 web 访问没什么区别。

若是你以为上述用查询字串的方式不够个性的话,能够采用另一种: @MatrixParam

Server 端代码以下:

……  
@GET  
    @Path("/customers/getCustByMat")  
    public Customer getCustomerByMat(@MatrixParam("")Customer cust) {  
        ……  
}

这时候咱们再访问时就能够用下面的形式了:

http://127.0.0.1:8080/customerservice/customers/getCustByMat;id=123;name=xiaoming

若是 cusmomer 还有其余属性,直接在后面追加就能够了,参数之间用 ; 分隔 .

以上咱们用到的参数虽然采用的处理方式的注解各不相同,可是都是有注解的。接下来出场的这个就属于特殊人物了。有请 body 参数出场……

……  
@POST  
    @Path("/addCustomer")  
    public Customer addCustomer(String body) {  
    ……  
}

这个 body 参数是 JAX-RS 中比较特殊的,它前面没有任何注解,它表明的是请求的 body 内容或者请求的inputstream ,自动解析映射为字符串参数。由于以前咱们的例子都是 GET 请求,消息中是没有 body 的,因此细心的听众可能会发现咱们此次的服务的 verb 配置为了 @POST 。

2.3 请求、应答数据格式

以前的示例中咱们的方法都返回了 Customer ,可是咱们的系统是一个 RESTful web service 啊,客户端接收到的确定是一个 HTTP 的 response 消息,那么返回的 Customer 是怎样的一个消息内容呢?

默认状况下 reponse 消息的 Customer 会以 xml 的格式返回。相似于:

<Customer><id>123</id><name>skdjl</name></Customer>

客户端调用 server 端服务,获得上述的 xml 字串结果,而后进行后续处理。

既然这说的默认状况,言外之意就是说还有不少其余状况了,不过须要配置一下。就不得不说下@Produces注解了。@Produces就是表示server端返回的数据格式类型,具体包括application/xml, application/json, application/text……,其实就是咱们常见的web端的content-type中的类型。若是咱们设置为application/json,天然返回的数据格式为json形式。另外一个注解:@Consumes,就是与@Produces相对应的。@Consumes是设定的客户端发送的请求数据的格式,对应支持的类型与@Produces相同。具体配置以下:

……  
@POST  
    @Path("/addCustomerUseBean")  
    @Produces("application/json")  
    @Consumes("application/xml")  
    public Customer addCustomerUseBean(Customer cust) {  
        ……  
    }

 这个例子的意思是客户端传入 Customer 做为参数,传递格式为 xml 风格, server 端应答的数据格式为json 风格。咱们固然也能够在类注解中加入 @Produces 和 @Consumes 做为服务总体的 request 和 response风格,具体服务方法若是不设定的话采用类的 @Produces 和 @Consumes 的设定。

3        服务配置

服务开发完成以后,咱们要作的就是把服务发布出去。发布方式也很灵活,能够采用编码的方式,也能够和spring 结合用配置的方式。在下面的例子中咱们采用后者。配置的内容再也不作过多的解释,你们看一下就能明白。

3.1   web.xml 的配置

<?xml version="1.0" encoding="UTF-8"?>  
  
<web-app version="2.4"  
         xmlns="http://java.sun.com/xml/ns/j2ee"  
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee  
         http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">  
  
         <display-name>DEMO</display-name>  
         <context-param>  
                   <param-name>contextConfigLocation</param-name>  
                   <param-value>classpath*:/applicationContext*.xml</param-value>  
         </context-param>  
  
         <listener>  
                  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
         </listener>  
  
         <listener>  
         <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>  
         </listener>  
  
         <servlet>  
                 <servlet-name>CXFServlet</servlet-name>  
                 <servlet-class>  
                          org.apache.cxf.transport.servlet.CXFServlet  
                 </servlet-class>  
                 <load-on-startup>1</load-on-startup>  
          </servlet>  
  
         <servlet-mapping>  
                 <servlet-name>CXFServlet</servlet-name>  
                 <url-pattern>/services/*</url-pattern>  
          </servlet-mapping>  
  
  <welcome-file-list>  
    <welcome-file>index.jsp</welcome-file>  
  </welcome-file-list>  
</web-app>

3.2   spring 配置文件

<?xml version="1.0" encoding="UTF-8"?>  
  
<beans  
         xmlns="http://www.springframework.org/schema/beans"  
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
         xmlns:aop="http://www.springframework.org/schema/aop"  
         xmlns:cxf="http://cxf.apache.org/core"  
    xmlns:jaxws="http://cxf.apache.org/jaxws"  
    xmlns:jaxrs="http://cxf.apache.org/jaxrs"  
  
         xsi:schemaLocation="  
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
         http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd  
         http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd  
         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">  
  
         <import resource="classpath:META-INF/cxf/cxf.xml" />  
         <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />  
         <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />  
         <import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml"/>  
  
   <jaxrs:server id="customerService" address="/customerservice">  
                   <jaxrs:serviceBeans>  
          <ref bean="customerServiceBean"/>  
        </jaxrs:serviceBeans>  
   </jaxrs:server>  
   <bean id="customerServiceBean" class="com.harvey.cxf.demo.rest.rs.server.CustomerService"/>  
</beans>

而后启动咱们的 web 程序,服务就发布完成了。能够在浏览器中敲入:

http://127.0.0.1:8080/customerservice/customers/1 测试服务是否正常。

从上面的例子也许你能发现,咱们虽然是作的RESTful的例子,可是具体提供的服务verb中不少都是带有动做的成分好比getCustomer,addCustomer等等,这些词汇的存在预示着咱们的服务虽然采用了RESTful的技术,可是并无遵循ROA(面向资源的架构)的理念,真正的ROA信徒看到上面的例子可能会很是不爽。由于毕竟RESTful和ROA才是两小无猜。不过正如前面提到的,你们值关注技术实现就行了。

4        客户端调用

咱们的服务发布完成了,接下来咱们能够作一个测试 client 程序进行 测试。对于 RESTful 的调用方式不少,能够用 java 的 Connect 方式,也能够用 apche 的 httpclint ,另外还能够用 cxf 提供的 WebClient 进行,等等。后面的 client 代码中分别采用几种调用方式,在这里咱们没必要拘泥,能够任意选用本身熟悉的方式。

相关文章
相关标签/搜索