。
。
。
3. REST当前在JAVA中的实现
在JCP中(不会不知道JCP吧,所有的关于JAVA的规范都是由这个组织定义的 http://www.jcp.org/),已经有一个关于REST在JAVA中应用的规范JSR311,这个规范还没有正式发布,目前最新的版本是:Early Draft 1.0。虽然这个规范没有正式发布,但已经有一个参考实现了:Jersey。而且已经有一些IDE集成了REST Service的开发工具,例如:NetBeans 6.0等。
3.1 JSR311
这个规范主要定义了一系列Java API,这些API用来开发基于REST的WEB Services。在这里,只描述在使用过程中的一些关键部分,更详细的描述请参考JSR311的Specification 和 API Doc。
· Resource Class
在这个规范中,一个Resource对应一个Resource Class。这个Class必须具有以下的特征:
o URI Templates
一般情况下,一个Resource Class包含一个Annotation:@UriTemplate。例如:
@UriTemplate("widget/{id}") //指定Resource的相对URI
public class TestResource {
……
}
其中{id}是URI参数,根据HTTP Request的来确定,具体的值会注入(Inject)到相应的参数(实例参数或方法参数)当中。系统会根据HTTP Request所对应的URI来匹配URI Template,从而定位到某个Resource(规范中规定了匹配的顺序)。
o Resource Methods
Resource Methods就是在Resource Class中定义的用来处理HTTP Request的Method。每个HTTP Method都必须有一个Annotation: @HttpMethod,在这个Annotation中还可以指定处理的类型,例如:
@HttpMethod("GET")
public Widget getWidget(){
……
}
上面的例子指定getWidget()方法是用来处理HTTP GET的。当然,在Annotation @HttpMethod中也可以不显示的指定处理的类型,而是根据方法的名字来判断。例如:getWidget()方法,如果在@HttpMethod中没有指定具体处理类型,那么会缺省认为是HTTP GET类型,因为这个方法是以get开头的。又例如postWidget()方法,缺省情况下也会被指定成HTTP POST 类型。
另外,在HttpMethod中还可以使用一些特殊的参数,这些参数都会根据当前运行时的上下文环境注入进来,例如URI参数:
@UriTemplate("widget/{id}") //指定Resource的相对URI
public class TestResource {
@HttpMethod() //指定此方法为HttpMethod
public Widget getWidget(
//指定使用UriTemplate中的{id}作为参数
@UriParam("id") String id
){
……
}
}
其他可以使用的特殊参数包括:
@MatrixParam,@QueryParam,@UriParam
@HttpContext
@HeaderParam
另外,Resource Method还可以通过@ProduceMime和@ConsumeMime来指定返回或接受的数据类型,例如:
@HttpMethod() //指定此方法为HttpMethod
@ProduceMime("text/xml") //指定结果将以“text/xml”形式返回给客户端
public Widget getWidget(
//指定使用UriTemplate中的{id}作为参数
@UriParam("id") String id
){
……
}
o Sub Resource
Resource Class中的Method也可以使用@UriTemplate,如果这个Method同时使用了@HttpMethod,那么这个方法被称之为Sub Resource Method;否则,被称之为Sub Resource Locator。例如:
@UriTemplate("widgets")
public class WidgetList {
//Sub Resource Mothod
@HttpMethod
@UriTemplate("offers")
WidgetList getDiscounted() {
...
}
//Sub Resource Locator
@UriTemplate("{id}")
Widget findWidget(@UriParam("id") String id) {
return lookupWidget(id);
}
}
对于Sub Resource Method,系统会调用此Method来处理相应的HTTP Request;而对Sub Resource Location,系统会把相应的HTTP Request传递给这个Method所指定的Resource(也就是这个方法return的类型),并以此递归直到找到相应的处理方法。
· Others
JSR311规范其他的内容大部分都和Runtime的实现逻辑相关,例如如何匹配UriTemplate,缺省支持的MIME类型(和EntityProvider有关),等等,这里不再详述。
3.2 一个简单的应用实例
以下的实例是NetBeans6.0提供的Sample,具体内容大家可以参考NetBeans 6.0 的帮助文档:http://www.netbeans.org/kb/60/websvc/rest.html。
这个简单的实例就是直接通过数据库发布一个基于REST的Web Services。具体的流程如下:
· 建立NetBeans的REST开发环境
· 建立一个数据链接
· 通过数据库链接直接生成Server端的代码(右键菜单)
· 通过工具(右键菜单)发布Service到Server中,并通过IE测试。
下面,我们来简单分析一下Server端的代码:
总共包括三个package: services,entities和converters。其中,services包中定义了所有的Resource Class;entities包中的类是从数据库通过OR Mapping自动生成的,用来建立数据库和Java类之间的关系;converters包中的类是通过JAXB自动生成的,用来建立XML文档与Java类(entities中的类)之间的关系。
下面让我们看看客户端如何调用Server端的Services:
String url = //Web Services的URL
HttpClient httpClient = new HttpClient();
HttpMethod method = null;
method = new GetMethod(url);
String contentType = "application/xml";
method.setRequestHeader("Content-type", contentType + "; charset=utf8");
httpClient.executeMethod(method);
String response = method.getResponseBodyAsString();
4. References
[1]. R. Fielding. Architectural Styles and the Design of Network-based Software Architectures. See http://roy.gbiv.com/pubs/dissertation/top.htm
[2]. http://www.ibm.com/developerworks/cn/web/wa-ajaxarch/
[3]. http://www.xfront.com/REST-Web-Services.html
[4]. http://www.crummy.com/writing/RESTful-Web-Services/
[5]. http://www.jcp.org/en/jsr/detail?id=311
[6]. https://jersey.dev.java.net/