Spring整合CXF,发布RSETful 风格WebService

文章链接:http://zhangfan822.iteye.com/blog/1617299
这篇文章是承接之前CXF整合Spring的这个项目示例的延伸,所以有很大一部分都是一样的。关于发布CXF WebServer和Spring整合CXF这里就不再多加赘述了。如果你对Spring整合CXF WebService不了解,具体你可以参看这两篇文章:
http://www.cnblogs.com/hoojo/archive/2011/03/30/1999563.html
http://www.cnblogs.com/hoojo/archive/2012/07/13/2590593.html
如果你不了解restful风格的WebService,你可以参考:
http://www.oracle.com/technetwork/articles/javase/index-137171.html
SpringMVC对RESTful的支持:
http://www.cnblogs.com/hoojo/archive/2011/06/10/2077422.html
使用 Jersey框架,搭建RESTful WebService(这个也比较简单)
http://www.ibm.com/developerworks/cn/web/wa-aj-tomcat/
官方文档:http://jersey.java.net/nonav/documentation/latest/user-guide.html#d4e8
其中,比较常用的RESTful框架就有Jersey、Spring REST、CXF RESTful,这些都可以很好的整合Spring框架,发布也相当的简单。且简单、易用、易上手,文档也比较丰富。
开发环境:
System:Windows
JavaEE Server:tomcat6
JavaSDK: jdk6+
IDE:eclipse、MyEclipse 6.6

开发依赖库:
JDK6、 JavaEE5、CXF-2.3.3、Spring 3.0.4

下面我们就接着http://www.cnblogs.com/hoojo/archive/2011/03/30/1999563.html这篇文章,开始我们CXF RESTful WebService的旅程,enjoy~!^_*

准备工作

首先,你需要添加相关的jar包

Spring整合CXF,发布RSETful 风格WebService

其中,jsr331-api-1.1.1.jar是必须的,利用CXF发布REST服务得用到它,在cxf的lib库中可以找到这个jar。

下载地址:http://www.apache.org/dyn/closer.cgi?path=/cxf/2.3.11/apache-cxf-2.3.11.zip

其它的jar包都是非必须的!

package com.hoo.entity;  
   
import java.util.Map;  
import javax.xml.bind.annotation.XmlRootElement;  
   
/** 
 * <b>function:</b> MapBean 封装Map集合元素 
 * @author hoojo 
 * @createDate 2012-7-20 下午01:22:31 
 * @file MapBean.java 
 * @package com.hoo.entity 
 * @project CXFWebService 
 * @blog http://blog.csdn.net/IBM_hoojo 
 * @email [email protected] 
 * @version 1.0 
 */  
@XmlRootElement  
public class MapBean {  
    private Map<String, User> map;  
      
    //@XmlElement(type = User.class)  
    public Map<String, User> getMap() {  
        return map;  
    }  
    public void setMap(Map<String, User> map) {  
        this.map = map;  
    }  
}  
   
  
package com.hoo.entity;  
   
import java.util.HashMap;  
import java.util.List;  
import javax.xml.bind.annotation.XmlRootElement;  
   
/** 
 * <b>function:</b> Users Entity 
 * @author hoojo 
 * @createDate 2011-3-18 上午09:27:31 
 * @file Users.java 
 * @package com.hoo.entity 
 * @project CXFWebService 
 * @blog http://blog.csdn.net/IBM_hoojo 
 * @email [email protected] 
 * @version 1.0 
 */  
@XmlRootElement(name = "UserInfos")  
public class Users {  
    private List<User> users;  
      
    private User[] userArr;  
      
    private HashMap<String, User> maps;  
      
      
   // getter/setter  
}  
package com.hoo.entity;  
   
import java.io.Serializable;  
import javax.xml.bind.annotation.XmlRootElement;  
   
/** 
 * <b>function:</b>User Entity 
 * @author hoojo 
 * @createDate Dec 16, 2010 10:20:02 PM 
 * @file User.java 
 * @package com.hoo.entity 
 * @project AxisWebService 
 * @blog http://blog.csdn.net/IBM_hoojo 
 * @email [email protected] 
 * @version 1.0 
 */  
@XmlRootElement(name = "UserInfo")  
public class User implements Serializable {  
    private static final long serialVersionUID = 677484458789332877L;  
    private int id;  
    private String name;  
    private String email;  
    private String address;  
      
    //getter/setter  
      
    @Override  
    public String toString() {  
        return this.id + "#" + this.name + "#" + this.email + "#" + this.address;  
    }  
}   
 

一、定义你的WebService的接口RESTSample.java,代码如下

package com.hoo.service;  
   
import java.io.IOException;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
import javax.ws.rs.Consumes;  
import javax.ws.rs.DELETE;  
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.Context;  
import javax.ws.rs.core.MediaType;  
   
import com.hoo.entity.MapBean;  
import com.hoo.entity.User;  
import com.hoo.entity.Users;  
   
   
/* 
     注释(Annotation):在 javax.ws.rs.* 中定义,是 JAX-RS (JSR 311) 规范的一部分。  
    @Path:定义资源基 URI。由上下文根和主机名组成,资源标识符类似于 http://localhost:8080/RESTful/rest/hello。  
    @GET:这意味着以下方法可以响应 HTTP GET 方法。  
    @Produces:以纯文本方式定义响应内容 MIME 类型。 
     
    @Context: 使用该注释注入上下文对象,比如 Request、Response、UriInfo、ServletContext 等。  
    @Path("{contact}"):这是 @Path 注释,与根路径 “/contacts” 结合形成子资源的 URI。  
    @PathParam("contact"):该注释将参数注入方法参数的路径,在本例中就是联系人 id。其他可用的注释有 @FormParam、@QueryParam 等。  
    @Produces:响应支持多个 MIME 类型。在本例和上一个示例中,APPLICATION/XML 将是默认的 MIME 类型。 
 */  
/** 
 * <b>function:</b> CXF RESTful风格WebService 
 * @author hoojo 
 * @createDate 2012-7-20 下午01:23:04 
 * @file RESTSampleSource.java 
 * @package com.hoo.service 
 * @project CXFWebService 
 * @blog http://blog.csdn.net/IBM_hoojo 
 * @email [email protected] 
 * @version 1.0 
 */  
@Path(value = "/sample")  
public interface RESTSample {  
      
    @GET  
    @Produces(MediaType.TEXT_PLAIN)  
    public String doGet();  
      
    @GET  
    @Produces(MediaType.TEXT_PLAIN)  
    @Path("/request/{param}")  
    public String doRequest(@PathParam("param") String param,   
            @Context HttpServletRequest servletRequest, @Context HttpServletResponse servletResponse);  
      
    @GET  
    @Path("/bean/{id}")  
    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })  
    public User getBean(@PathParam("id") int id);  
      
    @GET  
    @Path("/list")  
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })  
    public Users getList();  
      
    @GET  
    @Path("/map")  
    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })  
    public MapBean getMap();  
      
    /* 
        @Consumes:声明该方法使用 HTML FORM。  
        @FormParam:注入该方法的 HTML 属性确定的表单输入。  
        @Response.created(uri).build(): 构建新的 URI 用于新创建的联系人(/contacts/{id})并设置响应代码(201/created)。 
        您可以使用 http://localhost:8080/Jersey/rest/contacts/<id> 访问新联系人 
     */  
    @POST  
    @Path("/postData")  
    public User postData(User user) throws IOException;  
      
    @PUT  
    @Path("/putData/{id}")  
    @Consumes(MediaType.APPLICATION_XML)  
    public User putData(@PathParam("id") int id, User user);  
      
    @DELETE  
    @Path("/removeData/{id}")  
    public void deleteData(@PathParam("id") int id);  
}  

二、RESTSample接口的实现,这里我们只是简单的实现下,并不是涉及实际的具体业务

package com.hoo.service;  
   
import java.io.IOException;  
import java.util.ArrayList;  
import java.util.HashMap;  
import java.util.List;  
import java.util.Map;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
import javax.ws.rs.DELETE;  
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.Context;  
import javax.ws.rs.core.MediaType;  
import javax.ws.rs.core.Request;  
import javax.ws.rs.core.UriInfo;  
import com.hoo.entity.MapBean;  
import com.hoo.entity.User;  
import com.hoo.entity.Users;  
   
   
/* 
     注释(Annotation):在 javax.ws.rs.* 中定义,是 JAX-RS (JSR 311) 规范的一部分。  
    @Path:定义资源基 URI。由上下文根和主机名组成,资源标识符类似于 http://localhost:8080/RESTful/rest/hello。  
    @GET:这意味着以下方法可以响应 HTTP GET 方法。  
    @Produces:以纯文本方式定义响应内容 MIME 类型。 
     
    @Context: 使用该注释注入上下文对象,比如 Request、Response、UriInfo、ServletContext 等。  
    @Path("{contact}"):这是 @Path 注释,与根路径 “/contacts” 结合形成子资源的 URI。  
    @PathParam("contact"):该注释将参数注入方法参数的路径,在本例中就是联系人 id。其他可用的注释有 @FormParam、@QueryParam 等。  
    @Produces:响应支持多个 MIME 类型。在本例和上一个示例中,APPLICATION/XML 将是默认的 MIME 类型。 
 */  
/** 
 * <b>function:</b> CXF RESTful风格WebService 
 * @author hoojo 
 * @createDate 2012-7-20 下午01:23:04 
 * @file RESTSampleSource.java 
 * @package com.hoo.service 
 * @project CXFWebService 
 * @blog http://blog.csdn.net/IBM_hoojo 
 * @email [email protected] 
 * @version 1.0 
 */  
@Path(value = "/sample")  
public class RESTSampleSource implements RESTSample {  
      
    @Context  
    private UriInfo uriInfo;  
      
    @Context  
    private Request request;  
   
      
    @GET  
    @Produces(MediaType.TEXT_PLAIN)  
    public String doGet() {  
        return "this is get rest request";  
    }  
      
    @GET  
    @Produces(MediaType.TEXT_PLAIN)  
    @Path("/request/{param}")  
    public String doRequest(@PathParam("param") String param,   
            @Context HttpServletRequest servletRequest, @Context HttpServletResponse servletResponse) {  
        System.out.println(servletRequest);  
        System.out.println(servletResponse);  
        System.out.println(servletRequest.getParameter("param"));  
        System.out.println(servletRequest.getContentType());  
        System.out.println(servletResponse.getCharacterEncoding());  
        System.out.println(servletResponse.getContentType());  
        return "success";  
    }  
      
    @GET  
    @Path("/bean/{id}")  
    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })  
    public User getBean(@PathParam("id") int id) {  
        System.out.println("####getBean#####");  
        System.out.println("id:" + id);  
        System.out.println("Method:" + request.getMethod());  
        System.out.println("uri:" + uriInfo.getPath());  
        System.out.println(uriInfo.getPathParameters());  
          
        User user = new User();  
        user.setId(id);  
        user.setName("JojO");  
        return user;  
    }  
      
    @GET  
    @Path("/list")  
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })  
    public Users getList() {  
        System.out.println("####getList#####");  
        System.out.println("Method:" + request.getMethod());  
        System.out.println("uri:" + uriInfo.getPath());  
        System.out.println(uriInfo.getPathParameters());  
          
        List<User> list = new ArrayList<User>();  
        User user = null;  
        for (int i = 0; i < 4;i ++) {  
            user = new User();  
            user.setId(i);  
            user.setName("JojO-" + i);  
            list.add(user);  
        }  
        Users users = new Users();  
        users.setUsers(list);  
        return users;  
    }  
      
    @GET  
    @Path("/map")  
    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })  
    public MapBean getMap() {  
        System.out.println("####getMap#####");  
        System.out.println("Method:" + request.getMethod());  
        System.out.println("uri:" + uriInfo.getPath());  
        System.out.println(uriInfo.getPathParameters());  
          
        Map<String, User> map = new HashMap<String, User>();  
        User user = null;  
        for (int i = 0; i < 4;i ++) {  
            user = new User();  
            user.setId(i);  
            user.setName("JojO-" + i);  
            map.put("key-" + i, user);  
        }  
        MapBean bean = new MapBean();  
        bean.setMap(map);  
        return bean;  
    }      
      
    /* 
        @Consumes:声明该方法使用 HTML FORM。  
        @FormParam:注入该方法的 HTML 属性确定的表单输入。  
        @Response.created(uri).build(): 构建新的 URI 用于新创建的联系人(/contacts/{id})并设置响应代码(201/created)。 
        您可以使用 http://localhost:8080/Jersey/rest/contacts/<id> 访问新联系人 
     */  
    @POST  
    @Path("/postData")  
    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })  
    public User postData(User user) throws IOException {  
        System.out.println(user);  
        user.setName("jojo##12321321");  
        return user;  
    }   
      
    @PUT  
    @Path("/putData/{id}")  
    @Produces({ MediaType.APPLICATION_XML })  
    public User putData(@PathParam("id") int id, User user) {  
        System.out.println("#####putData#####");  
        System.out.println(user);  
        user.setId(id);  
        user.setAddress("hoojo#gz");  
        user.setEmail("[email protected]");  
        user.setName("hoojo");  
        System.out.println(user);  
        return user;  
    }  
      
    @DELETE  
    @Path("/removeData/{id}")  
    public void deleteData(@PathParam("id") int id) {  
        System.out.println("#######deleteData#######" + id);  
    }  
}  

三、配置我们的WebService,修改applicationContext-server.xml。这里主要是添加jaxrs标签的支持,修改头部文件如下:

@GET  
@Path("/bean/{id}")  
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })  
public User getBean(@PathParam("id") int id)  

结果如下

Spring整合CXF,发布RSETful 风格WebService

一篇xml文档内容。

四、编写客户端代码,调用RESTful WebService

package com.hoo.client;  
   
import java.io.IOException;  
import javax.ws.rs.core.MediaType;  
import org.apache.cxf.jaxrs.client.WebClient;  
import org.junit.After;  
import org.junit.Before;  
import org.junit.Test;  
import org.springframework.context.ApplicationContext;  
import org.springframework.context.support.ClassPathXmlApplicationContext;  
import com.hoo.entity.MapBean;  
import com.hoo.entity.User;  
import com.hoo.entity.Users;  
import com.hoo.service.RESTSample;  
   
/** 
 * <b>function:</b> RESTful风格WebService 
 * @author hoojo 
 * @createDate 2012-7-20 下午03:31:03 
 * @file RSETServiceClient.java 
 * @package com.hoo.client 
 * @project CXFWebService 
 * @blog http://blog.csdn.net/IBM_hoojo 
 * @email [email protected] 
 * @version 1.0 
 */  
public class RSETServiceClient {  
   
    private static WebClient client;  
      
    @Before  
    public void init() {  
        // 手动创建webClient对象,注意这里的地址是发布的那个/rest地址  
        //String url = "http://localhost:8000/CXFWebService/rest/";  
        //client = WebClient.create(url);  
   
        // 从Spring Ioc容器中拿webClient对象  
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-client.xml");  
        client = ctx.getBean("webClient", WebClient.class);  
    }  
      
    @After  
    public void destory(){  
    }  
      
    @Test  
    public void testGet() {  
        System.out.println(client.path("sample").accept(MediaType.TEXT_PLAIN).get(String.class));  
    }  
      
    @Test  
    public void testRequest() {  
        System.out.println(client.path("sample/request/234234").accept(MediaType.TEXT_PLAIN).get(String.class));  
    }  
      
    @Test  
    public void testBean() {  
        User user = client.path("sample/bean/{id}", 25).accept(MediaType.APPLICATION_XML).get(User.class);  
        System.out.println(user);  
    }  
      
    @Test  
    public void testList() {  
        System.out.println(client.path("sample/list").accept(MediaType.APPLICATION_XML).get(Users.class).getUsers());  
    }  
      
    @Test  
    public void testMap() {  
        System.out.println(client.path("sample/map").accept(MediaType.APPLICATION_XML).get(MapBean.class).getMap());  
    }  
      
    @Test  
    public void testDeleteData() {  
        client.path("sample/removeData/23").delete();  
    }  
      
    @Test  
    public void testPostData() {  
        User user = new User();  
        user.setId(21432134);  
        user.setAddress("hoojo#gz");  
        user.setEmail("[email protected]");  
        user.setName("hoojo");  
        System.out.println(client.path("sample/postData").accept(MediaType.APPLICATION_XML).post(user, User.class));  
    }  
      
    @Test  
    public void testPutData() {  
        User user = new User();  
        user.setId(21432134);  
        System.out.println(client.path("sample/putData/1").accept(MediaType.APPLICATION_XML).put(user).getEntity());  
    }  
}  

如果你喜欢用Spring的方式,还需要在applicationContext-client.xml中增加如下配置

//RESTSample sample = JAXRSClientFactory.create("http://localhost:8000/CXFWebService/rest", RESTSample.class);  
   
// 从Spring Ioc容器中拿webClient对象  
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-client.xml");  
RESTSample sample = ctx.getBean("restSampleBean", RESTSample.class);  
   
System.out.println(sample);  
   
System.out.println(sample.doGet());  
//System.out.println(sample.doRequest("haha", null, null));  
System.out.println(sample.getBean(22));  
System.out.println(sample.getList());  
System.out.println(sample.getMap().getMap());  
User user = new User();  
user.setId(21432134);  
user.setAddress("hoojo#gz");  
user.setEmail("[email protected]");  
user.setName("hoojo");  
System.out.println(sample.postData(user));  
System.out.println(sample.putData(111, user));  
sample.deleteData(2);  

这种方式相对比WebClient要简单,直接使用接口中的方法即可。同样如果你要整合到Spring可以在applicationContext-client.xml中增加配置如下:

Xml代码  Spring整合CXF,发布RSETful 风格WebService
  1. <bean id="restSampleBean" class="org.apache.cxf.jaxrs.client.JAXRSClientFactory" factory-method="create">  
  2.     <constructor-arg type="java.lang.String" value="http://localhost:8000/CXFWebService/rest/" />  
  3.     <constructor-arg type="java.lang.Class" value="com.hoo.service.RESTSample" />  
  4. </bean>  

执行以上方法可以看到控制台打印结果如下:

 写道
client console
org.apache.cxf.jaxrs.client.ClientProxyImpl@1cf7491
this is get rest request
22#JojO#null#null
com.hoo.entity.Users@16eb6bc
{key-0=0#JojO-0#null#null, key-1=1#JojO-1#null#null, key-2=2#JojO-2#null#null, key-3=3#JojO-3#null#null}
21432134#jojo##12321321#[email protected]#hoojo#gz
111#hoojo#[email protected]#hoojo#gz

server console
####getBean#####
id:22
Method:GET
uri:sample/bean/22
{id=[22]}
####getList#####
Method:GET
uri:sample/list
{}
####getMap#####
Method:GET
uri:sample/map
{}
21432134#hoojo#[email protected]#hoojo#gz
#####putData#####
21432134#hoojo#[email protected]#hoojo#gz
111#hoojo#[email protected]#hoojo#gz
#######deleteData#######2

就这样,整合restful WebService成功。