在spring中构建基于jax-RS(即rest风格)的webservice

参考:http://my.oschina.net/huangyong/blog/294324 和http://www.ibm.com/developerworks/cn/opensource/os-restfulwebservices/index.html

今天我们将视角集中在 REST 上,它是继 SOAP 以后,另一种广泛使用的 Web 服务。与 SOAP 不同,REST 并没有 WSDL 的概念,也没有叫做“信封”的东西,因为 REST 主张用一种简单粗暴的方式来表达数据,传递的数据格式可以是 JSON 格式,也可以是 XML 格式,这完全由您来决定。

REST 全称是 Representational State Transfer(表述性状态转移),它是 Roy Fielding 博士在 2000 年写的一篇关于软件架构风格的论文,此文一出,震撼四方!许多知名互联网公司开始采用这种轻量级 Web 服务,大家习惯将其称为 RESTful Web Services ,或简称 REST 服务 。

那么 REST 到底是什么呢?

REST 本质上是使用 URL 来访问资源的一种方式。总所周知,URL 就是我们平常使用的请求地址了,其中包括两部分: 请求方式 与 请求路径 ,比较常见的请求方式是 GET 与 POST,但在 REST 中又提出了其它几种其它类型的请求方式,汇总起来有六种:GET、POST、PUT、DELETE、HEAD、OPTIONS。尤其是前四种,正好与 CRUD(增删改查)四种操作相对应:GET(查)、POST(增)、PUT(改)、DELETE(删),这正是 REST 的奥妙所在!

实际上,REST 是一个“无状态”的架构模式,因为在任何时候都可以由客户端发出请求到服务端,最终返回自己想要的数据。也就是说,服务端将内部资源发布 REST 服务,客户端通过 URL 来访问这些资源,这不就是 SOA 所提倡的“面向服务”的思想吗?所以,REST 也被人们看做是一种轻量级的 SOA 实现技术,因此在企业级应用与互联网应用中都得到了广泛使用。

在 Java 的世界里,有一个名为 JAX-RS 的规范,它就是用来实现 REST 服务的,目前已经发展到了 2.0 版本,也就是 JSR-339 规范,如果您想深入研究 REST,请深入阅读此规范。

JAX-RS 规范目前有以下几种比较流行的实现技术:

今天我们用CXF的规范:

1. 在spring基础上使用 CXF 发布与调用 REST 服务

第一步:添加 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>com.jimmy</groupId>
  <artifactId>mywebservice</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<mybatis.version>3.2.1</mybatis.version>

<org.aspectj-version>1.6.9</org.aspectj-version>
<commons-util.version>1.0-SNAPSHOT</commons-util.version>
<junit.version>4.7</junit.version>
<javax.servlet.api.version>3.0.1</javax.servlet.api.version>
<commons.logging.version>1.1.1</commons.logging.version>
<commons.collections.version>3.2.1</commons.collections.version>
<javax.mail.version>1.4</javax.mail.version>
<spring.version>4.1.4.RELEASE</spring.version>
<log4j.version>1.2.17</log4j.version>
<jsp-api.version>2.0</jsp-api.version>
<jackson-mapper-asl.version>1.9.3</jackson-mapper-asl.version>
<jackson-core-asl.version>1.9.3</jackson-core-asl.version>
<jackson.version>2.4.1</jackson.version>
<commons.lang.version>2.6</commons.lang.version>
<com.google.code.gson.version>1.7.1</com.google.code.gson.version>
<commons.io.version>2.1</commons.io.version>
<commons.fileupload.version>1.2.1</commons.fileupload.version>
<spring-mock.version>2.0.8</spring-mock.version>
<velocity.version>1.7</velocity.version>
<velocity-tools.version>2.0</velocity-tools.version>
<commons.collections.version>3.2.1</commons.collections.version>
<mysql.connector.java.version>5.1.10</mysql.connector.java.version>
<commons.jexl.version>1.1</commons.jexl.version>
<commons.dbcp.version>1.2.2</commons.dbcp.version>
<hsqldb.version>2.2.8</hsqldb.version>
<jsp-api.version>2.0</jsp-api.version>
<json-rpc.version>1.0</json-rpc.version>
<java.version>1.7</java.version>
<com.google.code.gson.version>2.3.1</com.google.code.gson.version>
<cxf.version>2.2.3</cxf.version>
</properties>

<dependencies>

《!--这两个是jax-rs的包--》
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0-m02</version>
</dependency>
 <dependency>
        <groupId>javax.ws.rs</groupId>
        <artifactId>jsr311-api</artifactId>
        <version>1.1</version>
    </dependency>


    <dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-frontend-jaxrs</artifactId>
  <version>${cxf.version}</version>
</dependency>
《!--这是cxf框架的包--》
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http</artifactId>
        <version>${cxf.version}</version>
    </dependency>
     <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-mapper-asl</artifactId>
            <version>1.9.2</version>
        </dependency>
        


    <!--  
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http</artifactId>
        <version>${cxf.version}</version>
    </dependency>
    -->
        <!-- Jetty is needed if you're are not using the CXFServlet
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http-jetty</artifactId>
        <version>${cxf.version}</version>
    </dependency>
     -->
      <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxws</artifactId>
        <version>${cxf.version}</version>
    </dependency>

《!--这是jaxb用的的包--因为jaxrs:server 配置里面用到"org.codehaus.jackson.jaxrs.JacksonJsonProvider"  --

        <dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-jaxrs</artifactId>
    <version>1.9.13</version>
</dependency>


<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.12</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${com.google.code.gson.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons.io.version}</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>${commons.dbcp.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>${jsp-api.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons.fileupload.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>

《!-- 这是spring的包,开始没加 spring-core老报错--》
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-mock</artifactId>
<version>${spring-mock.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
。。。
</build>
</project>

在web.xml里面添加CXF支持:

<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.properties</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<context-param>
<param-name>portalExecutorCorePoolSize</param-name>
<param-value>1024</param-value>
</context-param>
<!-- 
<filter>
<filter-name>delegatingFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>userLoginFilter</param-value>
</init-param>
</filter>


<filter-mapping>
<filter-name>delegatingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
-->
<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>
<servlet>
   <servlet-name>springmvc</servlet-name>             
   <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
   <init-param>
       <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-mvc.xml</param-value>
   </init-param>
</servlet>
<servlet-mapping>
   <servlet-name>springmvc</servlet-name>
   <url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet>    
        <servlet-name>CXFServlet</servlet-name>    
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>    
        <load-on-startup>2</load-on-startup>    
    </servlet>    
    <servlet-mapping>    
        <servlet-name>CXFServlet</servlet-name>    
        <url-pattern>/webservice/*</url-pattern>    
    </servlet-mapping>


在applicationContext.xml(位于resourse下面)添加cxf支持:

<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:jaxws="http://cxf.apache.org/jaxws"    
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
    http://www.springframework.org/schema/context  
    http://www.springframework.org/schema/context/spring-context-2.5.xsd
     http://cxf.apache.org/jaxws 
    http://cxf.apache.org/schemas/jaxws.xsd"
default-lazy-init="true">
<!--  这四个必须导入,否则报错,这是已经存在的了-->
<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"></import>

<!--  这是自己手写的,位于resourse下面-->
<import resource="classpath:rest-webservice.xml"/>
 
<!-- 自动扫描 -->
<context:annotation-config />
<context:component-scan base-package="com.jimmy.mywebservice">
</context:component-scan>

<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 数据源配置 dbcp 
<bean id="jade.dataSource.com.topshare.airshuttle.dao" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${driverClassName}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>

<property name="timeBetweenEvictionRunsMillis" value="3600000"></property>

<property name="minEvictableIdleTimeMillis" value="3600000"></property>
</bean>
-->

</beans>


第二步:定义一个 REST 服务接口:


先定义实体类:

package com.jimmy.mywebservice.bean;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement 
public class User {
private String userName;  
   private String emailId;  
 
   @XmlAttribute  
   public String getUserName() {  
       return userName;  
   }  
   public void setUserName(String userName) {  
       this.userName = userName;  
   }  
 
   @XmlAttribute  
   public String getEmailId() {  
       return emailId;  
   }  
   public void setEmailId(String emailId) {  
       this.emailId = emailId;  
   }  
}

再定义接口服务类:

package com.jimmy.mywebservice.controller;
import java.io.InputStream;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.jimmy.mywebservice.bean.User;
@Produces({ MediaType.APPLICATION_XML}) 
@Consumes({ MediaType.APPLICATION_XML}) 
public interface IRestStu {
@GET
@Path("/getUsers")
@Produces("application/xml")
public User getUsers();


@GET
@Path("/getUser/{id}")
@Produces("application/xml")
public User getUser(@PathParam("id") int id);


@POST
@Path("/createuser") 
@Consumes("application/xml")
public Response createUser();

@PUT  
   @Path("/updateuser/{id}")  
   @Consumes("application/xml") 
public Response updateUser(@PathParam("id") int id, InputStream is );
}

实现类:

public class IStuRestImpl implements IRestStu {

    public User getUsers() {  
    User userDetails = new User();  
        userDetails.setUserName("Krishna");  
        userDetails.setEmailId("krishna@gmail.com"); 
        System.out.println("test ");
        return userDetails;  
    }  
  
   
    public Response getUserHtml() {  
        //Test HTML view  
        return Response.ok().build();  
    }
@Override
public User getUser(int id) {
User userDetails = new User();  
        userDetails.setUserName("Krishna");  
        userDetails.setEmailId("krishna@gmail.com"); 
        System.out.println("test ");
        return userDetails;  
}
@Override
public Response createUser() {
// TODO Auto-generated method stub
return Response.ok().build();
}
@Override
public Response updateUser(int id, InputStream is) {
// TODO Auto-generated method stub
return Response.ok().build();
}  
}

以上 StuService 接口中提供了一系列的方法,在每个方法上都使用了 JAX-RS 提供的注解,主要包括以下三类:

  1. 请求方式注解,包括:@GET、@POST、@PUT、@DELETE
  2. 请求路径注解,包括:@Path ,其中包括一个路径参数
  3. 数据格式注解,包括:@Consumes(输入)、@Produces(输出),可使用 MediaType 常量
  4. 相关参数注解,包括:@PathParam(路径参数)、@FormParam(表单参数),此外还有 @QueryParam(请求参数)

针对getUser方法,简单解释一下:

该方法将被 PUT://updateuser/{id} 请求来调用,请求路径中的 id 参数将映射到 long id 参数上,请求体中的数据将自动转换为 JSON 格式并映射到 Map<String, Object> fieldMap 参数上,返回的 Product 类型的数据将自动转换为 JSON 格式并返回到客户端。

第三步:使用 CXF 发布 REST 服务

即配置rest-webservice.xml:

<?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:jaxrs="http://cxf.apache.org/jaxrs" 
         xmlns:soap="http://cxf.apache.org/bindings/soap"
           xmlns:context="http://www.springframework.org/schema/context" 
             xsi:schemaLocation=" http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
               http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context-3.0.xsd 
                 http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
                http://cxf.apache.org/jaxrs
                 http://cxf.apache.org/schemas/jaxrs.xsd">
  <context:property-placeholder/>
     <context:annotation-config/>
        <bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer"/>  
         <bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer"/>
<bean id="stuServiceImpl" class="com.jimmy.mywebservice.controller.IStuRestImpl"> 
 </bean> 
   <jaxrs:server id="stuRestService" address="/stuservices/v1.0">
        <jaxrs:serviceBeans>    
              <ref bean="stuServiceImpl"/>
        </jaxrs:serviceBeans> 
       <jaxrs:providers> 
       <bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider"/>
         </jaxrs:providers>      
</jaxrs:server>
</beans>

或者用程序发布也可。

第四步:查看服务发布成功否:

http://localhost:8080/webservice/stuservices/v1.0?_wadl&_type=xml

//可见,尽管都是xml,但和soap的wsdl还是结构上很大不同

<application xmlns="http://research.sun.com/wadl/2006/10" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<grammars>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" elementFormDefault="unqualified">
<xs:element name="user" type="user"/>
<xs:complexType name="user">
<xs:sequence/>
<xs:attribute name="emailId" type="xs:string"/>
<xs:attribute name="userName" type="xs:string"/>
</xs:complexType>
</xs:schema>
</grammars>
<resources base="http://localhost:8080/webservice/stuservices/v1.0">
<resource path="/stu">
<method name="POST">
<response>
<representation mediaType="application/xml"/>
</response>
</method>
<resource path="/getUser/{id}">
<param name="id" style="template" type="xs:int"/>
<method name="GET">
<request/>
<response>
<representation mediaType="application/xml"/>
</response>
</method>
</resource>
<resource path="/getUsers">
<method name="GET">
<response>
<representation mediaType="application/xml"/>
</response>
</method>
</resource>
<resource path="/{id}">
<param name="id" style="template" type="xs:int"/>
<method name="PUT">
<request>
<representation mediaType="application/xml"/>
</request>
<response>
<representation mediaType="application/xml"/>
</response>
</method>
</resource>
</resource>
</resources>
</application>



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值