【IT168技术】REST的软件架目前已经开始在互联网中逐渐应用起来了。REST的优势在于:非常简单,轻量并且诉苦快。RESTful的web service通过URL的方式对外提供资源服务。而资源的服务充分利用了HTTP协议中的GET,POST,PUT和DELETE去实现,而且可以用各类格式去访问这些资源,比如HTML,普通文本,XML,PDF,JPEG或者JSON。目前在RESTful的JAVA API的最新标准(JAX-RS)是JSR 311。Jersey则是JAX-RS标准的一个参考实现,并且简化了使用JAVA 去开发RESTful。
本文将介绍如何使用Apache的开源HttpClient库,结合Android客户端去创建访问一个JAX-RS RESTful标准的Web服务。可以在本文最后下载相关的代码。本文的适合阅读的读者对象为对Android及RESTful有初步理解的开发者。
设置开发环境
1 安装Eclipse
2 下载并安装Android for Eclipse的插件ADT。
3 安装Android SDK 2.2或以上的开发包并安装好。
4 到Jersey主页(http://jersey.java.net/)下载Jersey相关包,本文用到的版本为
jersey-archive-1.4.zip,下载后,其中会包含jersey 的jar包,并且下载jersey-bundle-1.4.jar。注意的是,使用Jersey的话要使用JDK 1.6,所以请下载并安装好JDK 1.6。
5 注意把如下的三个包放到工程的lib目录下:
jersey-bundle-1.4.jar、asm-3.1.jar、jsr311-api-1.1.1.jar。
创建Eclipse工程
在本节中,将学习如何使用Eclipse搭建JAX-RS的RESTful Webservice。请按如下步骤执行:
1) 在eclipse中,选择File菜单->New,在打开的菜单中选择新建立一个
Dynamic Web Project,再点Next下一步
2)指定应用的名字,比如AndroidJAX-RS,
▲
3 点Next后,在如下图中,选定希望要用的运行时容器,比如TOMCAT
▲
4 点NEXT后,再在tomcat的配置窗口中,配置相关的JDK和TOMCAT参数,最后点FINISH。
5 这样就增加了一个动态web工程。鼠标右键点工程的属性,在打开的页面中,如下图,选择Project Facets,再选择JAX-RS (REST Web Services) 1.1项,再点选Further configuration required,如下图:
▲
6 在配置选项中,选择自定义用户类库,创建一个新的自定义用户类库,点Add Jar,增加如下的三个jersey 包: jersey-bundle-1.4.jar、asm-3.1.jar、jsr311-api-1.1.1.jar。
如下图:
▲
7 在JAX-RS Capabilities窗口中,指定JAX-RS servlet class name为:
com.sun.jersey.spi.container.servlet.ServletContainer,并点OK,如下图:
▲
最后在项目的Facets窗口中,点apply 应用,如下图,完成整个设置:
▲
8) 同时,要设置web.xml,配置JAX-RS 的servlet参数,如下代码:
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/
xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/
ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<servlet>
<description>JAX-RS Tools Generated - Do not modify</description>
<servlet-name>JAX-RS Servlet</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
<param-value>com.sun.jersey.api.core.PackagesResourceConfig</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>jaxrs</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JAX-RS Servlet</servlet-name>
<url-pattern>/jaxrs/*</url-pattern>
</servlet-mapping>
</web-app>
这里配置了两个初始化参数,分别为:
com.sun.jersey.config.property.resourceConfigClass 和
com.sun.jersey.config.property.packages
编写RESTful代码
接下来,我们开始编写RESTful代码。步骤如下:
在File>New>Other中,选择新建一个JAVA 类文件,点finish,如下图设置:
▲
接下来,我们使用注解为程序增加RESTful的功能。JAX-RS中的一个特点是可以使用JAVA中的各种注解简便地为程序增加RESTful的功能。下面是其代码:
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
@Path("/helloworld")
public class HelloWorldResource {
@GET
@Produces("text/plain")
public String getClichedMessage() {
// Return some cliched textual content
return "Hello Android";
}
// @GET
// @Produces("text/xml")
// public String getXMLMessage() {
// return "<?xml version=\"1.0\"?>" + "<hello> Hello Android" + "</hello>";
// }
// @GET
//@Produces("text/html")
//public String getHTMLMessage() {
//return "<html> " + "<title>" + "Hello Android" + "</title>"
// + "<body><h1>" + "Hello Android" + "</body></h1>" +
"</html> ";
// }
}
首先,在这里加了注解@Path,名称为helloworld,表示凡是以/helloworld形式URL访问的请求,都会交由HelloWorldResource类来处理。为了能让程序对不同类型的MIME 类型都能处理,因此增加getClichedMessage(), getXMLMessage(), 和getHTMLMessage()方法,并且在每个方法中要添加@GET注解,以表明该方法能接受HTTP的get请求。同时通过使用@PRODUCES注解,以表示该方法产生的返回结果将以何种MIME类型返回给用户,比如
@Produces("text/xml"),则表明该方法返回的结果以XML形式返回给用户。
可以看到,上面的代码中,分别针对text/plain,text/xml,text/html三种不同的MIME类型编写了不同的方法,读者可以分别注释掉其中的一些以观察运行效果。
创建Android客户端
接下来,我们开始创建Android的客户端,通过Apache的HTTP CLIENT访问RESTful服务。步骤如下:
1) 在Eclipse中,选择新建立一个Android Project,方法是在File->New菜单中,选择Android Project,点NEXT进入下一步。
2) 在Android Project的相关设置中,按如下图进行设置:
▲
可以看到,我们选用的是Android 2.2的SDK,应用的名称为AndroidJAXRSClient,创建的Activity名为AndroidJAXRSClient。接下来,首先创建main.xml,代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="@+id/jaxrs"
android:layout_width="fill_parent" android:layout_height="wrap_content"
/>
</LinearLayout>
可以看到,在这个布局文件中,只是简单放置了一个textview 文本显示控件,这个控
件是用来显示服务端返回的JAX-RS的RESTful的结果。
为了能获得服务端返回的结果,需要Android使用网络访问权限功能,因此必须在配置文件AndroidManifest.xml中进行设置,添加如下这句话:
并指定应用程序启动的Activity,整个完成的配置文件如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.jaxrs" android:versionCode="1" android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".AndroidJAXRSClient" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
</manifest>
接下来,我们可以使用Apache HttpClient的开源HTTP访问类库,去访问服务端的JAX-RS服务了。要注意的是,Android的SDK中已经内置了Apache HttpClient的相关类库了,可以直接引入,即:
org.apache.http.HttpResponse;
org.apache.http.client.ClientProtocolException;
org.apache.http.client.HttpClient;
org.apache.http.client.methods.HttpGet;
org.apache.http.impl.client.DefaultHttpClient;
下面直接给出客户端Android访问服务端JAX-RS服务的代码,再逐一解析:
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
public class AndroidJAXRSClient extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView jaxrs = (TextView) findViewById(R.id.jaxrs);
try {
HttpClient httpclient = new DefaultHttpClient();
HttpGet request = new HttpGet(
"http://192.168.1.68:7001/AndroidJAX-RS/jaxrs/helloworld");
//request.addHeader("Accept", "text/html");
// request.addHeader("Accept", "text/xml");
request.addHeader("Accept", "text/plain");
HttpResponse response = httpclient.execute(request);
HttpEntity entity = response.getEntity();
InputStream instream = entity.getContent();
String jaxrsmessage = read(instream);
jaxrs.setText(jaxrsmessage);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static String read(InputStream instream) {
StringBuilder sb = null;
try {
sb = new StringBuilder();
BufferedReader r = new BufferedReader(new InputStreamReader(
instream));
for (String line = r.readLine(); line != null; line = r.readLine()) {
sb.append(line);
}
instream.close();
} catch (IOException e) {
}
return sb.toString();
}
}
在oncreate()方法中,首先通过
HttpClient httpclient = new DefaultHttpClient();
建立了httpclient类的的一个实例,然后创建一个http get的请求,如下:
HttpGet request = new HttpGet("http://192.168.1.68:7001/AndroidJAX-RS/jaxrs/helloworld");
在请求的URL中,指定了服务端JAX-RS的URL,注意一定要加上/helloworld,不要漏掉。然后再指定发送到服务端JAX-RS的HTTP的HEADER的类型,即:
request.addHeader("Accept", "text/xml");
//request.addHeader("Accept", "text/html");
//request.addHeader("Accept", "text/plain");
可以分别指定三种不同的header,然后通过httpclient的execute方法,执行向服务端发送请求,并获得返回的内容的实例response,如下:
HttpResponse response = httpclient.execute(request);
Response是HttpResonse的实例,代表服务端返回的内容,而为了更好地得到返回的内容,调用response.getEntity()得到HttpEntity实例,如下:
HttpEntity entity = response.getEntity();
再通过entity的getContent方法获得返回结果的一个字节输入流,即:
InputStream instream = entity.getContent();
接下来,在read的静态方法中,读入这个instream,注意将其解析构造成一个StringBuffer,最后再转换为字符串,并通过Android的jaxrs.setText(jaxrsmessage)显示出来。
最后,运行Android应用程序,在手机模拟器中可以得到如下结果:
▲
可以看到,Android的客户端通过访问JAX-RS的RESTful web service,得到了返回的XML字符串。同样,如果将以下的代码分别注释,再运行,可以分别看到text/plain,text/html为资源类型返回的不同结果:
request.addHeader("Accept", "text/plain");
request.addHeader("Accept", "text/html");
当然,在服务端的HelloWorldResource中,也要分别将之前注释掉的getHTMLMessage()方法和getClichedMessage()方法启用。它们的运行结果分别如下两图:
小结
本文介绍了如何通过Apache的开源HttpClient去访问一个符合JAX-RS标准的RESTful服务,其中jersey是目前JAX-RS RESTful标准的一个不错的开源实现。而由于RESTful的简单,开发快捷,运行速度快,因此很适合象Android等移动设备进行访问,给用户会有很好的运行体验。读者可以通过本文的例子,加以扩展,可以通过RESTful搭建不少web服务,然后通过Android客户端去访问。