第一部分 什么是REST服务
Representational State Transfer,中文名:表征状态转移,简称:REST。它是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。
需要注意的是,REST是设计风格而不是标准。REST通常基于使用HTTP,URI,和XML以及HTML这些现有的广泛流行的协议和标准。
· 资源是由URI来指定。
· 对资源的操作包括获取、创建、修改和删除资源,这些操作正好对应HTTP协议提供的GET、POST、PUT和DELETE方法。
· 通过操作资源的表现形式来操作资源。
· 资源的表现形式则是XML或者HTML,取决于读者是机器还是人,是消费web服务的客户软件还是web浏览器。当然也可以是任何其他的格式。
REST的要求
· 客户端和服务器结构
· 连接协议具有无状态性
· 能够利用Cache机制增进性能
· 层次化的系统
· 随需代码 - Javascript (可选)
以上知识点来源于维基百科(http://zh.wikipedia.org/zh-cn/REST)
REST多层调用架构(来源于网络)
上图将传统MVC与Rest服务进行了对别。蓝色部分就是我们今天要讲的Rest服务,红色部分就是传统的MVC结构。
通过上面的比较总结出一下几点供大家参考
1.相对于传统,页面----->Struts-------->Spring------------->数据持久,这样一条龙式的开发模式;Rest显得更加分离,从逻辑上分为了:客服端和服务端,客服端主要关心数据的解析,展示,而服务器端只关注逻辑代码的编写以及接口的定义,从传统的一个人包打天下升级为各司其职,明确的分工,使程序的开发效率大幅提升
2.由于在REST设计时,就已将所有的构建都看成资源,通过统一的URI进行标示,使用传统的http协议进行传输,所以Rest天生就有客服端无关性,即同样的接口,既可以通过Flex进行消费也可以通过Ajax消费,甚至可以通过java后台直接消费,这样优良的特性,带来了客服端丰富多样的展示方式
3.由于Rest面向服务编程,打破了传统开发模式下,一个项目一个后台服务的模式,使一个Rest可以为多个系统服务,同时一个系统也能同时消费多个服务,消费与服务的打断,带来了无限可能的重组,大大提供了代码的可复用性以及系统的可扩展性
4.方便的封装模式,从传统开发模式过渡到Rest架构,程序员只需修改调用后台的方式,特别是wink与spring的集成只需几个常用的标记与接口方法书写,就能将传统业务代码华丽变身为REST服务
第二部分 Apache Wink 结合Spring 开发Rest服务
1. 需要的主要依赖包
本项目使用maven管理,以下是需要的依赖包引用
<dependency>
<groupId>com.hdsx</groupId>
<artifactId>dao</artifactId>
<version>2.0.1</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.1.0.RELEASE</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.1.0.RELEASE</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>3.1.0.RELEASE</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.12</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.5.4</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.wink</groupId>
<artifactId>wink-server</artifactId>
<version>1.1.3-incubating</version>
</dependency>
<dependency>
<groupId>org.apache.wink</groupId>
<artifactId>wink-spring-support</artifactId>
<version>1.1.3-incubating</version>
<exclusions>
<exclusion>
<artifactId>spring</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
其中dao是对mybatis的简单封装,简化了持久化操作,在下一篇博文里再讨论这个封装,你可以直接使用mybatis进行替换。
2. Web.xml配置文件
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:META-INF/server/wink-core-context.xml
classpath:applicationContext.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
配置spring监听,需要注意的是对 classpath:META-INF/server/wink-core-context.xml的配置,其位于wink-spring-support中,是wink与spring集成的核心配置文件
<servlet>
<servlet-name>restService</servlet-name>
<servlet-class>
org.apache.wink.server.internal.servlet.RestServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>restService</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
配置wink的servlet,完对rest服务的调用转发
3. 编写业务逻辑代码
@Service
public class TestServerImpl implements TestServer {
public string sayHello(String name)
{
return "hello:"+name;
}
}
业务代码和以前一样,不需要特别的处理
4. 编写rest接口
@Path("/test")
@Service
public class TestRestServer{
@Resource(name="testServerImpl")
private TestServer testServer;
@GET
@Path("/hello")
@Produces(MediaType.APPLICATION_JSON)
public String sayHello(@QueryParam("name") String name)
{
return testServer.sayHello(name);
}
}
该类中有很多rest标注,如果你不懂请参考,(http://www.ibm.com/developerworks/cn/web/wa-apachewink1)
该类用来将javabean暴露成rest接口,同时它也是受管于Spring,同样可以通过简单的@Resource注入对应的资源,是不是很简单。
5. Spring 配置文件
<bean class= "org.apache.wink.spring.Registrar" >
<property name="classes" >
<set value-type= "java.lang.Class" >
<value>
org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider
</value>
</set>
</property>
<property name="instances" >
<set>
<ref bean="testRestServer" />
</set>
</property>
</bean>
Registrar类主要完成对Provider和Resource的注册工作
有两种属性:
Classes:指定类,格式;包+类名
Instances:对spring管理对象的引用
通过上述几步我们就完成了Spring和apache wink的简单集成
第三部分 Ajax调用Rest服务
1. 客服端javascript
为了方便页面调用,对jquery的ajax调用进行了简单封装
function restClient()
{
/**
* 使用get方式调用服务
* @param url 资源地址
* @param data 参数
* @param dataType 返回值类型
* @param contentType 访问类型或参数类型
* @param cache 是否缓存
* @param async 是否异步加载
* @param success 成功时回调函数
* @param error 失败时回调函数
*/
this.get=function get(url,data,dataType,contentType,cache,async,success,error)
{
ajax("GET",url,data,dataType,contentType,cache,async,success,error);
};
/**
* 使用post方式调用服务
* @param url 资源地址
* @param data 参数
* @param dataType 返回值类型
* @param contentType 访问类型或参数类型
* @param cache 是否缓存
* @param async 是否异步加载
* @param success 成功时回调函数
* @param error 失败时回调函数
*/
this.post=function post(url,data,dataType,contentType,cache,async,success,error)
{
ajax("POST",url,data,dataType,contentType,cache,async,success,error);
};
/**
* 使用put方式调用服务
* @param url 资源地址
* @param data 参数
* @param dataType 返回值类型
* @param contentType 访问类型或参数类型
* @param cache 是否缓存
* @param async 是否异步加载
* @param success 成功时回调函数
* @param error 失败时回调函数
*/
this.put=function put(url,data,dataType,contentType,cache,async,success,error)
{
ajax("PUT",url,data,dataType,contentType,cache,async,success,error);
};
/**
* 使用delete方式调用服务
* @param url 资源地址
* @param data 参数
* @param dataType 返回值类型
* @param contentType 访问类型或参数类型
* @param cache 是否缓存
* @param async 是否异步加载
* @param success 成功时回调函数
* @param error 失败时回调函数
*/
this.del=function del(url,data,dataType,contentType,cache,async,success,error)
{
ajax("DELETE",url,data,dataType,contentType,cache,async,success,error);
};
/**
* 将form表单转化为json数组
* @param formid form表单id
* @returns json数组
*/
this.form2Json=function form2Json(formid) {
var formObj = $("#"+formid);
var JsonObj = "'{";
var a = formObj.serializeArray();
var index = 0;
$.each(a, function() {
index++;
JsonObj += "\"" + this.name + "\":\"" + this.value + "\"";
if(a.length != 1 && a.length != index) {
JsonObj += ",";
}
});
JsonObj += "}'";
return eval(JsonObj);
};
/**
* jquery ajax方法
* @param type 调用类型
* @param url 资源地址
* @param data 参数
* @param dataType 返回值类型
* @param contentType 访问类型或参数类型
* @param cache 是否缓存
* @param async 是否异步加载
* @param success 成功时回调函数
* @param error 失败时回调函数
*/
function ajax(type,url,data,dataType,contentType,cache,async,success,error)
{
$.ajax(
{
type: type,
data: data,
dataType:dataType,
contentType:contentType,
url:url,
success: success,
error: error,
async:async,
cache:cache
});
}
}
2. 调用代码
function sayHello()
{
var rc=new restClient();
Var parameter={};
Parameter.name="xxx";
rc.post("http://xx.x.x.x:xx/xxxx/rest/test/hello",parameter,"json",'application/json',false,false,success,error);
}
function success(data, textStatus)
{
Alert(data);
}
function error()
{
alert("调用失败");
};
自此spring与wink集成与调用就完成了,但是需要注意的是,如果在调用中出行调用失败时,请查看一下是否是:你的服务与你的调用页面不在一个域里,如果出现跨域问题,可以通过apache代理解决
最后祝你工作愉快
注:apache wink 地址:http://incubator.apache.org/wink/
例子下载地址:http://download.youkuaiyun.com/detail/kehongyong/4167213