diggbag

BlogJava 联系 聚合 管理
  0 Posts :: 13 Stories :: 6 Comments :: 0 Trackbacks

RESTful简要介绍

RESTful风格的WebService之所以当下如此流行,是由于其相对于SOAP风格的WebService更简洁、更轻量级,REST风格的WebService传输的是JSON或极其简洁的XML,因而其效率和性能都比较理想。

RESTful风格的WebService主张重用HTTP协议,面向资源编程(ROA)。扼要的说,RESTful风格WebService中,每一个URL即表示一个资源,比如http://www.example.com/employees/1 表示id1的员工。

1. 如果对此URL调用HTTP GET方法,则返回员工的XML形式;

2. 如果对此URL调用HTTP POST/PUT方法,则可以新增或者修改此员工;

3. 如果对此URL调用HTTP DELETE方法,则可以删除此员工;

因此,我们在设计一个RESTful风格的接口时,一定要拥有面向资源设计的考量!

此外,在实现接口的过程中,要遵循RESTful风格的几个特性,他们分别是:

1. 无状态性:HTTP本身即是无状态协议,因此RESTful天然的具备无状态性,具备优良的水平扩展能力!

2. 幂等性:GET/PUT/DELETE方法具备此特性,幂等性可概述为无论重复调用多少次,其结果都一致!POST例外,不过设计的时候也可以按照此特性设计!

3. 唯一性:即URL地址要唯一的表示一个资源!

关于事务、安全等更多的高级特性这里不阐述,有兴趣的可参考《Restful Web Service中文版》一书。

下面以开发一个普通接口和开发REST风格WebService接口为对比,指导大家快速入门。

开发一个普通的接口

2.1 定义DTO

public class Info implements Serializable {

private String id;

private String name;

private String description;

public String getId() {

return id;

}

public void setId(String id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getDescription() {

return description;

}

public void setDescription(String description) {

this.description = description;

}

}

2.2 定义接口

public interface SaleService extends Serializable {

public List<Info> getInfos();

public Info getInfo(String id);

public void saveOrUpdateInfo(Info info);

public void deleteInfo(String id);

}

2.3 实现类

接口的实现,就此省略。

开发RESTful风格WebService服务端

3.1 定义资源(定义DTO

@XmlRootElement(name = "Info")

public class Info implements Serializable {

private String id;

private String name;

private String description;

@XmlElement(name = "ID")

public String getId() {

return id;

}

public void setId(String id) {

this.id = id;

}

@XmlElement(name = "NAME")

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

@XmlElement(name = "DESCRIPTION")

public String getDescription() {

return description;

}

public void setDescription(String description) {

this.description = description;

}

}

解析:@XmlRootElement(name = "Info")之类的注释,是JAXB规范,用于XMLJava对象之间的互相转换。不熟悉JAXB规范的可以自行搜索相关资料。

Info对象对应的XML格式如下:

<Info>

<DESCRIPTION>des1</DESCRIPTION>

<ID>1</ID>

<NAME>name1</NAME>

</Info>

3.2 开发接口

@Produces({ MediaType.APPLICATION_XML })

public interface SaleService extends Serializable {

@GET

@Path("/infos")

public List<Info> getInfos();

@GET

@Path("/infos/{id}")

public Info getInfo(@PathParam("id") String id);

@POST

@Path("/infos")

@Consumes({ MediaType.APPLICATION_XML, MediaType.TEXT_XML,

MediaType.APPLICATION_JSON })

public void saveOrUpdateInfo(Info info);

@DELETE

@Path("/infos/{id}")

public void deleteInfo(@PathParam("id") String id);

}

解析:接口中的注释均为JSR311中的规范。

@Produces表示这个接口响应格式为XML


表示响应
http://www.example.com/.../infosGET请求,返回Info列表。


表示响应
http://www.example.com/.../infos/? 的GET请求,URL中的“?”作为参数代入方法中,最终返回对应的Info


表示响应http://www.example.com/.../infos 的POST请求,可以接受APPLICATION_XMLTEXT_XMLJSON格式,最终保存Info对象。


表示响应http://www.example.com/.../infos/? 的DELETE请求,URL中的“?”作为参数代入方法中,最终删除对应的Info

3.3 实现类

接口的实现,同上。

3.4 配置CXF(整合Springmaven

3.4.1 接口的Spring配置文件

定义接口的实现类

<bean id="saleService" class="com.csair.acp.service.impl.SaleServiceImpl" />

3.4.2 CXFSpring配置文件

<?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"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">

<import resource="classpath:META-INF/cxf/cxf.xml" />

<import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml" />

<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

<jaxrs:server id="saleRestService" address="/v1">

<jaxrs:serviceBeans>

<ref bean="saleService" />

</jaxrs:serviceBeans>

</jaxrs:server>

</beans>

解析:<ref bean="saleService" />对应接口的Spring定义,address="/v1"定义地址的前缀。比如: http://www.example.com/xxx/v1/infos/?

强烈建议加前缀!以此来提供不同版本的WebService访问!

3.4.3 修改web.xml

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>classpath*:spring/*.xml</param-value>

</context-param>

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</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>/*</url-pattern>

</servlet-mapping>

3.4.4 Maven配置

maven中使用cfx发布webservice需要添加如下依赖:

<dependency>

<groupId>org.apache.cxf</groupId>

<artifactId>cxf-bundle</artifactId>

<version>2.2.4</version>

</dependency>

<dependency>

<groupId>org.apache.cxf</groupId>

<artifactId>cxf-bundle-jaxrs</artifactId>

<version>2.2.4</version>

</dependency>

<dependency>

<groupId>org.apache.cxf</groupId>

<artifactId>cxf-rt-core</artifactId>

<version>2.2.4</version>

</dependency>

<dependency>

<groupId>org.apache.cxf</groupId>

<artifactId>cxf-rt-frontend-jaxrs</artifactId>

<version>2.2.4</version>

</dependency>

到此,配置完毕,可以启动部署到web容器中启动,在FireFox中访问http://localhost:8080/v1/infos ,看看是否有XML格式的输出。

开发RESTful风格WebService客户端(Java

4.1 定义客户端接口

public interface SaleClient extends Serializable {

public List<Info> getInfos();

public Info getInfo(String id);

public void saveOrUpdateInfo(Info info);

public void deleteInfo(String id);

}

4.2 定义实现类

客户端如果能引用服务端的jar包,那么开发将非常简单。

import com.csair.acp.resources.Info; //引用自服务端

import com.csair.acp.service.SaleService; //引用自服务端

public class SaleClientImpl implements SaleClient {

private static String BASE_ADDRESS = "http://localhost:8080/v1";

SaleService service;

public SaleClientImpl() {

initProxy();

}

private SaleService initProxy() {

service = JAXRSClientFactory.create(BASE_ADDRESS, SaleService.class);

WebClient.client(service).accept(MediaType.APPLICATION_XML);// 一定需要

return service;

}

@Override

public List<Info> getInfos() {

try {

return service.getInfos();

catch (WebApplicationException ex) {

ex.printStackTrace();

return null;

}

}

@Override

public Info getInfo(String id) {

try {

return service.getInfo(id);

catch (WebApplicationException ex) {

ex.printStackTrace();

return null;

}

}

@Override

public void saveOrUpdateInfo(Info info) {

try {

service.saveOrUpdateInfo(info);

catch (WebApplicationException ex) {

ex.printStackTrace();

}

}

@Override

public void deleteInfo(String id) {

try {

service.deleteInfo(id);

catch (WebApplicationException ex) {

ex.printStackTrace();

}

}

}

客户端的开发十分简便,如果用其他语言,那么需要自行使用对应的HTTP类库进行编码。

如果使用spring injecting proxies 方式进行配置,则使用如下配置:

<jaxrs:client id ="saleClient " address="http://localhost:8080/v1" serviceClass="com.csair.acp.service.SaleService">

</jaxrs:client>

具体配置参照:http://cxf.apache.org/docs/jax-rs-client-api.html

范例

本文对应的例子为maven构建:

rest-server为服务端,运行jetty:run即可

rest-client为客户端,运行rest-client/src/test/java/com/csair/acp/client/impl/SaleClientImplTest.java单元测试类即可

posted on 2011-10-24 17:27 哲同 阅读(7962) 评论(0)  编辑  收藏 所属分类: java相关

只有注册用户登录后才能发表评论。


网站导航: