实现目标

http://localhost:9000/rs/roomservice 为入口, 
http://localhost:9000/rs/roomservice/room为房间列表, 
http://localhost:9000/rs/roomservice/room/001/ 为001号房间的信息, 
http://localhost:9000/rs/roomservice/room/001/person 为在001号房间主的人的列表

在Eclipse中新建一个Java Project

(可以不是WTP的Dynamic Web Project)参考文章:Apache CXF实现Web Service(1)中的介绍

再看pom.xml

<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.cnblog.richaaaard.cxfstudy</groupId>
<artifactId>cxf-test-standalone-rs-helloworld</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>cxf-test-standalone-rs-helloworld Maven Webapp</name>
<url>http://maven.apache.org</url> <properties>
<!-- <cxf.version>2.7.18</cxf.version> -->
<cxf.version>3.1.4</cxf.version>
</properties> <dependencies>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
</dependency>
<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-ws-security</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-ws-policy</artifactId>
<version>${cxf.version}</version>
</dependency>
<!-- <dependency> -->
<!-- <groupId>org.apache.cxf</groupId> -->
<!-- <artifactId>cxf-bundle-jaxrs</artifactId> -->
<!-- <version>${cxf.version}</version> -->
<!-- </dependency> -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
</dependencies> <build>
<finalName>cxfstudy</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**</include>
</includes>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<configuration>
<contextPath>/</contextPath>
<connectors>
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>9000</port>
</connector>
</connectors>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build> </project>

  与(1)中介绍的类同,JAXRSServerFactoryBean存在于cxf-rt-frontend-jaxrs中,而集合包cxf-bundle-jaxrs是不必要的

供资源使用的实体类Room和Person

package com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model;

import java.util.HashMap;
import java.util.Map; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name="Room")
public class Room {
public Room()
{
persons=new HashMap<String,Person>();
}
String id;
Map<String,Person> persons; public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Map<String, Person> getPersons() {
return persons;
}
public void setPersons(Map<String, Person> persons) {
this.persons = persons;
}
}

  注意不要漏掉@XmlRootElement

package com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="Person")
public class Person {
private String name;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
} }

  为了解决“No message body writer found for class”,即非简单对象无法序列化的问题,我们暂时先加两个Wrapper类作为Room的集合类和Person集合类,后面会专门介绍如何更优雅的解决这个问题。

Rooms.java

 package com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model;

 import java.util.Map;

 import javax.xml.bind.annotation.XmlRootElement;

 import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.dao.RoomDAO;

 @XmlRootElement(name="rooms")
public class Rooms {
Map<String,Room> rooms;
public Rooms()
{
rooms=RoomDAO.getMapOfRooms();
}
public Map<String, Room> getRooms() {
return rooms;
}
public void setRooms(Map<String, Room> rooms) {
this.rooms = rooms;
}
}

Persons.java

package com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model;

import java.util.Map;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="persons")
public class Persons {
Map<String,Person> persons;
public Persons()
{
persons=null;
}
public Persons(Room room)
{
persons=room.getPersons();
}
public Map<String, Person> getPersons() {
return persons;
}
public void setPersons(Map<String, Person> persons) {
this.persons = persons;
}
}

实体有了,需要数据,我们虚拟了一个DAO(原本DAO是数据访问层),这里我们直接将所需要测试的数据创建其中

 package com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.dao;

 import java.util.HashMap;
import java.util.Map; import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Person;
import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Room;
import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Rooms; public class RoomDAO {
private static Map<String, Room> rooms;
static {
rooms = new HashMap<String, Room>(); Person p1=new Person();
p1.setName("Boris");
p1.setSex("male"); Room r=new Room();
r.setId("001");
r.getPersons().put(p1.getName(), p1);
rooms.put("001", r);
} public static void addRoom(Room room) {
rooms.put(room.getId(), room);
} public static void deleteRoom(String id) {
if (rooms.containsKey(id)) {
rooms.remove(id);
} } public static void updateRoom(String id,Room room) {
rooms.remove(id);
rooms.put(room.getId(), room);
} public static Room getRoom(String id) {
if (rooms.containsKey(id)) {
return rooms.get(id);
} else {
return null;
}
}
/*operations to persons*/
public static void addPerson(String id_room,Person person) {
if(rooms.containsKey(id_room))
{
Room room=rooms.get(id_room);
room.getPersons().put(person.getName(), person);
}
} public static Rooms getRooms()
{
return new Rooms();
} public static void deletePerson(String id_room,String name)
{
if(rooms.containsKey(id_room))
{
Room room=rooms.get(id_room);
room.getPersons().remove(name);
}
} public static Map<String, Room> getMapOfRooms()
{
return rooms;
}
}

到这里,我们基本已经完成准备工作

那么如何写一个RESTful Web Service呢?

package com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.service;

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 com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.dao.RoomDAO;
import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Person;
import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Persons;
import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Room;
import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Rooms; @Path("/roomservice")
@Produces("application/xml")
public class RoomService { @GET
@Path("/room/{id}")
@Consumes("application/xml")
public Room getRoom(@PathParam("id")String id )
{
System.out.println("get room by id= "+id);
Room room=RoomDAO.getRoom(id);
return room;
}
@GET
@Path("/room")
@Consumes("application/xml")
public Rooms getAllRoom()
{
System.out.println("get all room");
Rooms rooms=RoomDAO.getRooms();
return rooms;
} @POST
@Path("/room")
@Consumes("application/xml")
public void addRoom(Room room)
{
System.out.println("add room which id is:"+room.getId());
RoomDAO.addRoom(room);
}
@PUT
@Path("/room/{id}")
@Consumes("application/xml")
public void updateRoom(@PathParam("id")String id,Room room)
{
System.out.println("update room which original id is:"+room.getId());
RoomDAO.updateRoom(id,room);
}
@DELETE
@Path("/room/{id}")
@Consumes("application/xml")
public void deleteRoom(@PathParam("id")String id)
{
System.out.println("remove room by id= "+id);
RoomDAO.deleteRoom(id);
}
@POST
@Path("/room/{id}")
@Consumes("application/xml")
public void addPerson(@PathParam("id") String id,Person person)
{
System.out.println("add person who's name is:"+person.getName());
RoomDAO.addPerson(id, person);
} @GET
@Path("/room/{id}/person")
@Consumes("application/xml")
public Persons getAllPersonOfRoom(@PathParam("id") String id)
{
// System.out.println("get room by id= "+id);
// Room room=RoomDAO.getRoom(id);
// return room.getPersons();
// TODO No message body writer HashMap
System.out.println("get room by id= "+id);
Room room=RoomDAO.getRoom(id);
return new Persons(room);
} @DELETE
@Path("/room/{id}/{name}")
@Consumes("application/xml")
public void deletePerson(@PathParam("id")String id,@PathParam("name")String name)
{
System.out.println("remove person who's name is: "+name);
RoomDAO.deletePerson(id, name);
}
}

注意在类头上的Annotation @Path和@Produces

@Path("/roomservice")——指这个服务的根路径,用于区分其他服务

@Produces("application/xml")——指这个服务生产xml的响应

最后我们还需一个服务

我们使用与(1)类似的方法,用JAXRSServerFactoryBean来启动一个服务

package com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.server;

import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;

import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Person;
import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Persons;
import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Room;
import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Rooms;
import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.service.RoomService; public class Server { public static void main(String[] args) {
RoomService service = new RoomService(); // Service instance
JAXRSServerFactoryBean restServer = new JAXRSServerFactoryBean();
restServer.setResourceClasses(Room.class, Person.class, Rooms.class, Persons.class);
restServer.setServiceBean(service);
restServer.setAddress("http://localhost:9000/rs");
restServer.create();
}
}

运行服务Run As... -> Java Application

124 [main] WARN org.apache.cxf.jaxrs.utils.ResourceUtils - No resource methods have been found for resource class com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Room
124 [main] WARN org.apache.cxf.jaxrs.utils.ResourceUtils - No resource methods have been found for resource class com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Person
125 [main] WARN org.apache.cxf.jaxrs.utils.ResourceUtils - No resource methods have been found for resource class com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Rooms
125 [main] WARN org.apache.cxf.jaxrs.utils.ResourceUtils - No resource methods have been found for resource class com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Persons
222 [main] INFO org.apache.cxf.endpoint.ServerImpl - Setting the server's publish address to be http://localhost:9000/rs
284 [main] INFO org.eclipse.jetty.util.log - Logging initialized @500ms
318 [main] INFO org.eclipse.jetty.server.Server - jetty-9.2.11.v20150529
330 [main] WARN org.eclipse.jetty.server.handler.AbstractHandler - No Server set for org.apache.cxf.transport.http_jetty.JettyHTTPServerEngine$1@49e202ad
357 [main] INFO org.eclipse.jetty.server.ServerConnector - Started ServerConnector@7364985f{HTTP/1.1}{localhost:9000}
357 [main] INFO org.eclipse.jetty.server.Server - Started @582ms
362 [main] WARN org.eclipse.jetty.server.handler.ContextHandler - Empty contextPath
369 [main] INFO org.eclipse.jetty.server.handler.ContextHandler - Started o.e.j.s.h.ContextHandler@351d0846{/,null,AVAILABLE}

  暂时忽略WARN里面的日志

然后我们通过浏览器测试

(测试方式有多种,原则上能对http Interceptor的工具都可以对web service进行测试,eclipse里有自带的工具,TcpTrace、SoapUI也都是比较好用的小工具)

*扩展,RESTful用json格式

我们将RoomService.java中所有的"application/xml"替换成"application.json",然后重启服务。

浏览器访问会出现一行错误提示

"

No message body writer has been found for class com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Rooms, ContentType: application/json

"

这是因为,CXF默认有xml的序列化provider,我们需要显性指定一个JsonProvider,这里我们先用一个业界比较流行的Jackson来支持。

先在pom中加入依赖

<dependency>
  <groupId>com.fasterxml.jackson.jaxrs</groupId>
  <artifactId>jackson-jaxrs-json-provider</artifactId>
  <version>2.6.3</version>
</dependency>

然后为我们的server实例指定一个JsonProvider: JacksonJsonProvider

package com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.server;

import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;

import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Person;
import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Persons;
import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Room;
import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Rooms;
import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.service.RoomService;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; public class Server { public static void main(String[] args) {
RoomService service = new RoomService(); // Service instance
JAXRSServerFactoryBean restServer = new JAXRSServerFactoryBean();
restServer.setResourceClasses(Room.class, Person.class, Rooms.class, Persons.class);
restServer.setServiceBean(service);
restServer.setAddress("http://localhost:9000/rs");
restServer.setProvider(new JacksonJsonProvider());
restServer.create();
}
}

返回浏览器,访问地址:http://localhost:9000/rs/roomservice/room 查看,这时我们看到json格式的数据正常返回了。

追问:如果我们用cxf自己的JSONProvider会怎样?

如果用cxf自己的JSONProvider,我们需要引入

cxf-rt-rs-extension-providers.jar

而这个jar在运行时还会依赖jettison里面的TypeConverter,所以我们需要引入

jettison.jar

<dependency>
<groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-rs-extension-providers</artifactId>
  <version>${cxf.version}</version>
</dependency> <dependency>
  <groupId>org.codehaus.jettison</groupId>
  <artifactId>jettison</artifactId>
  <version>1.3.7</version>
</dependency>

完事之后将Server里面的Provider换掉

package com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.server;

import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.provider.json.JSONProvider; import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Person;
import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Persons;
import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Room;
import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.model.Rooms;
import com.cnblog.richaaaard.cxftest.standalone.rs.helloworld.service.RoomService; public class Server { public static void main(String[] args) {
RoomService service = new RoomService(); // Service instance
JAXRSServerFactoryBean restServer = new JAXRSServerFactoryBean();
restServer.setResourceClasses(Room.class, Person.class, Rooms.class, Persons.class);
restServer.setServiceBean(service);
restServer.setAddress("http://localhost:9000/rs");
// restServer.setProvider(new JacksonJsonProvider());
restServer.setProvider(new JSONProvider<Object>());
restServer.create();
}
}

从浏览器访问,也同样得到了序列化的json:

不知道有没有人注意两个json string不太一样。这是因为不同库的实现方式不同,Jettison生成的字符串明显≥Jackson的实现。

那么问题来了

如何选择json的实现呢?在实际应用中,xml好还是json或是其他格式会更好呢?

  

 

参考:

http://www.cnblogs.com/ggjucheng/p/3352477.html

https://cwiki.apache.org/confluence/display/CXF20DOC/JAXRS+Services+Configuration

Apache CXF实现Web Service(2)——不借助重量级Web容器和Spring实现一个纯的JAX-RS(RESTful) web service的更多相关文章

  1. Apache CXF实现Web Service(1)——不借助重量级Web容器和Spring实现一个纯的JAX-WS web service

    废话少说,先在Eclipse中新建一个Java Project (可以不是WTP的Dynamic Web Project) 选择Java Project 再看pom.xml 我们使用cxf 3.1.4 ...

  2. Spring起步(一)Building a RESTful Web Service

    http://spring.io/guides/gs/rest-service/ 先放链接. 这个很小很小的一个功课,我却遇到了各种各样的奇葩错误,折腾了两天才弄好. 想要开始的话,需要一些准备工具 ...

  3. Apache CXF实现Web Service(3)——Tomcat容器和不借助Spring的普通Servlet实现JAX-RS(RESTful) web service

    起步 参照这一系列的另外一篇文章: Apache CXF实现Web Service(2)——不借助重量级Web容器和Spring实现一个纯的JAX-RS(RESTful) web service 首先 ...

  4. Apache CXF实现Web Service(5)—— GZIP使用

    Apache CXF实现Web Service(5)-- GZIP使用 参考来源: CXF WebService整合Spring Apache CXF实现Web Service(1)--不借助重量级W ...

  5. Apache CXF实现Web Service(4)——Tomcat容器和Spring实现JAX-RS(RESTful) web service

    准备 我们仍然使用 Apache CXF实现Web Service(2)——不借助重量级Web容器和Spring实现一个纯的JAX-RS(RESTful) web service 中的代码作为基础,并 ...

  6. Apache CXF实现WebService入门教程(附完整源码)

    Apache CXF实现WebService非常简单实用,只需要几步就可以实现一个简单的web service. 首先我们需要新建一个maven项目,在pom中添加依赖和jetty作为测试的web s ...

  7. Apache CXF 103 CXF Basics - partial

    本Spike记录中内容,如无特别指出,均引用[1]. 0 引言 0.1 基本的Web服务术语 XML 业界的结构化交换信息表示的事实上的标准. XML namespace是在XML文档中提供唯一的命名 ...

  8. Apache CXF 102 CXF with REST

    前言 续上篇Apache CXF 101,摘抄部分REST概念性知识,以运行实例考察CXF对REST的支持. 目录 1 REST简介 2 工具 3 运行实例 内容 本Spike记录中内容,如无特别指出 ...

  9. maven搭建webservice apache cxf实现

    用 web方式发布 webService 服务端.客户端 一.服务器端搭建 1.首先创建 一个web工程(增加Maven依赖) 2.增加Maven依赖包,如下: <project xmlns=& ...

随机推荐

  1. android属性

    一.布局 1.android:layout_gravity和android:gravity的区别 android:gravity 对齐方式,它是相对于控件本身对齐:android:layout_gra ...

  2. [terry笔记]ArchiveLog归档日志激增解决思路

    归档日志激增的危害是巨大的,最严重的结果就是数据库无法正常工作,导致整个系统无法正常工作,其次就算数据库可以正常工作,但激增的归档会对磁盘产生大量消耗,导致性能下降.       归档日志激增一般是因 ...

  3. 欢迎来到vmax-tam的博客

    欢迎来到vmax-tam的博客 我是一个新手程序员 以后会不断学习 把学到的东西记录下来 和大家一起分享的 谢谢大家指教

  4. ORACLE-用户常用数据字典的查询使用方法

    一.用户 查看当前用户的缺省表空间 SQL> select username,default_tablespace from user_users; USERNAME DEFAULT_TABLE ...

  5. dede 忘记密码在数据库中修改方法

    如何找回或修改dedecms后台管理员登录密码呢? 一个客户把密码忘了,找了很长一会没几个靠谱的回答,dede是使用md5加密,但是,它是显示32位md5加密码从第6位开始的20位 方法是直接修改其m ...

  6. App_Store - IOS应用审核的时隐私政策模板

    隐私政策  Poposoft尊重并保护所有使用服务用户的个人隐私权.为了给您提供更准确.更有个性化的服务,Poposoft会按照本隐私权政策的规定使用和披露您的个人信息.但Poposoft将以高度的勤 ...

  7. MVC4.0 使用Form认证,自定义登录页面路径Account/Login

    使用MVC4.0的时候,一般遇到会员登录.注册功能,我们都会使用Form认证,给需要身份验证的Action进行授权(需要登录后才能访问的Action添加[Authorize]属性标签),登录.注册的时 ...

  8. C#设计模式之装饰者模式(Decorator Pattern)

    1.概述 装饰者模式,英文名叫做Decorator Pattern.装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象. 2 ...

  9. Labview实现字符串加密

    Labview实现字符串加密 对字符串进行加密,规则是每个字母后移5 位 例如A 变为F,b 变为g,x 变为c,y 变为d- 实现效果 后端实现

  10. P1571: [Usaco2009 Open]滑雪课Ski

    DP. ; var t,s,n,i,j,m,l,a,c,d:longint; f,e:array[..,..maxn] of longint; q:array[..] of longint; g:ar ...