简介: 使用 Apache HttpClient 库访问 JAX-RS web 服务。Jersey 是 JAX-RS 的参考实现,它简化了 Java™ 环境下的 RESTful Web 服务的开发。Android 是一款流行的智能手机,本文将展示如何为 Android 创建一个 JAX-RS 客户端。您将创建一个访问 JAX-RS Web 服务的 Apache HttpClient 库客户端。
转自:http://www.ibm.com/developerworks/cn/xml/x-android-jax-rs/
REST 软件架构基于具象资源传输。RESTful Web 服务提供了一些优势:简单、轻量级、快速。RESTful Web 服务公开了一组由 URI 标识的资源。资源将根据 HTTP 方法 GET、POST、PUT 和 DELETE 作出响应。资源可通过各种形式访问,如 HTML、普通文本、XML、PDF、JPEG 或 JSON。Java API for RESTful Web 服务 (JAX-RS) 在 JSR 311 中定义。Jersey 是 JAX-RS 的参考实现,简化了 Java 中 RESTful Web 服务的开发。
在本文中,使用 Apache HttpClient 库为流行的智能手机平台 Android 创建一个 JAX-RS 客户端。您可以 下载 本文使用的样例代码。
在为 JAX-RS Web 服务创建客户端之前,需要对环境进行设置。参见 参考资料 中的链接。
Jersey 是使用 JDK 6.0 构建的,因此还需要安装 JDK 6.0。
CLASSPATH
中。 C:\Jersey\jersey-bundle-1.4.jar;C:\Jersey\jersey-archive-1.4\lib\asm-3.1.jar; C:\Jersey\jersey-archive-1.4\lib\jsr311-api-1.1.1.jar |
创建一个 Eclipse 项目
在本节中,您将创建一个 Web 项目并将 JAX-RS facet 添加到该项目中。使用以下步骤创建 Eclipse 项目。
AndroidJAX-RS
,选择默认的 Content Directory,并单击 Finish。 将创建一个 Dynamic Web Project 并添加到 Project Explorer。右键单击项目节点并选择 Properties。
将添加一个用户库。单击 Add JARs 以将 Jersey JARs 添加到用户库。如图 4所示,添加以下 Jersey JAR:
com.sun.jersey.spi.container.servlet.ServletContainer
,如图 5所示。单击 OK。 目标运行时通过 JAX-RS project facet 进行配置。单击 Properties 对话框中的 OK。
JAX-RS User 库被添加到项目中,JAX-RS servlet 和 servlet 映射在 web.xml 中进行了配置。需要为 com.sun.jersey.config.property.resourceConfigClass
和com.sun.jersey.config.property.packages
init 参数添加 init-param
元素。清单 2 显示了此web.xml
。
清单 2. web.xml
<?xml version="1.0" encoding="UTF-8"?> <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> |
创建和运行资源类
下一步是使用一个 root 资源类创建一个 RESTful Web 服务资源。root 资源类是带有 @PATH
注释的 POJO。它包含至少一个带注释的方法,该注释为@PATH
、@GET
、@PUT
、@POST
或 @DELETE
。
AndroidJAX-RS/src
jaxrs
HelloWorldResource
单击 Finish。
使用 @PATH
注释标注 Java 类。清单 3中的代码指定了 URI 路径,Java 类在该路径中应该托管为 /helloworld
。
清单 3.使用 @Path 注释资源类
@Path("/helloworld") public class HelloWorldResource { .... } |
要添加资源方法以生成三个不同的 MIME 类型,添加 getClichedMessage()
、getXMLMessage()
和getHTMLMessage()
方法。使用 @GET
注释每一个方法,这表示方法应当处理 HTTP GET 请求。指定String
作为每个方法的返回类型。使用 @PRODUCES
注释每一个方法,并为每个方法指定一个不同的 MIME 类型。
现在,需要用 MIME 类型 text/plain
、text/xml
和 text/html
输出 “Hello JAX-RS” 方法。getXMLMessage
方法用@Produces
("text/xml"
)进行了注释,生成一条 XML 消息。对于使用 @GET
注释了的方法,仅取消其中一个方法的注释。如果没有指定其他不同的路径组件,@GET
请求将被路由到用@GET
注释的方法。如果有多个方法匹配某个请求 URI,将使用 JAX-RS 选择算法来选择资源方法。例如,可以指定带有 @GET
注释的多个方法,做法是对带有 @GET
注释的方法使用不同的 path
id。清单 4展示了 root 资源类。
清单 4.HelloWorldResource.java
package jaxrs; import javax.ws.rs.GET; import javax.ws.rs.Produces; import javax.ws.rs.Path; import javax.ws.rs.core.MediaType; // The Java class will be hosted at the URI path //"/helloworld" @Path("/helloworld") public class HelloWorldResource { // The Java method will process HTTP GET requests @GET // The Java method will produce content identified by the MIME Media // type "text/plain" @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> "; // } } |
运行资源类以生成不同的输出类型。注释掉不执行测试的方法,对于每一次测试,保持一个方法未注释。首先,将 text/xml
MIME 类型作为输出进行测试。启动应用程序/Web 服务器(如果尚未启动的话)。右键单击资源类并选择Run As > Run on Server,如图 8所示。
图 8.运行资源类
在服务器上,按照 web.xml 的指定,init 参数 com.sun.jersey.config.property.resourceConfigClass
作为com.sun.jersey.api.core.PackagesResourceConfig
启动,而 init 参数 com.sun.jersey.config.property.packages
作为jaxrs
启动。找到 root 资源类 jaxrs.HelloWorldResource
。启动 Jersey 应用程序 v1.4,AndroidJAX-RS 模块部署到服务器上。
创建 Android 客户端项目
在本节中,您将创建一个 Android 项目,在其中将为 Android 创建 JAX-RS 客户端。
AndroidJAXRSClient
AndroidJAXRSClient
和包名 android.jaxrs
AndroidJAXRSClient
。 一项活动代表一个用户交互,而扩展 Activity 类的类为 UI 创建了一个窗口。
8
Android 项目中的文件包括:
AndroidJAXRSClient
),该类扩展了 Activity
类 在 res/layout/main.xml 文件中,指定 Android UI 组件的布局。使用 android:orientation="vertical"
创建一个LinearLayout
。您将创建一个 UI,其中将以文本消息的形式显示来自 Web 服务的响应。添加 id 为 jaxrs
的TextView
元素,显示方法调用对其中一个 get
方法的 JAX-WS Web 服务响应。方法调用获得一条 Hello 消息作为响应,消息的格式为 XML、HTML 或文本。清单 5显示了 main.xml 文件:
清单 5.main.xml
<?xml version="1.0" encoding="utf-8"?> <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> |
要从 Android 设备访问 JAX-RS web 服务,在 AndroidManifest.xml 中启用 android.permission.INTERNET
权限,从而允许应用程序打开网络套接字。添加uses-permission
元素,如清单 6所示。
清单 6.设置 INTERNET 权限
<uses-permission android:name="android.permission.INTERNET"></uses-permission> |
使用 uses-sdk
元素指定最低 Android 版本。AndroidJAXRSClient
活动、intent-filter
和action
在 activity
元素和子元素中指定。清单 7显示了 AndroidManifest.xml 文件。
清单 7.AndroidManifest.xml
<?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> |
Android SDK 包含 Apache HttpClient 库。将清单 8中的类导入到 AndroidJAXRSClient
。
清单 8 Apache HttpClient 库
org.apache.http.HttpEntity; 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; |
AndroidJAXRSClient
类扩展了 Activity
类。在第一次调用 Activity 时用到了onCreate(Bundle savedInstanceState)
方法。使用 setContentView
方法和布局资源定义用户界面,如清单 9所示。
清单 9.定义 UI
setContentView(R.layout.main); |
清单 10展示了如何创建一个 Android 部件 TextView
对象,其中对 TextView
元素使用 findViewById
方法,id 为 main.xml 中定义的 jaxrs
。
清单 10.创建 Android 部件
TextView jaxrs = (TextView) findViewById(R.id.jaxrs); |
HttpClient
的默认实现是 DefaultHttpClient
。创建一个 DefaultHttpClient
对象,如清单 11所示。
清单 11. 创建一个 HttpClient
HttpClient httpclient = new DefaultHttpClient(); |
创建一个 HttpGet
对象,从服务器检索信息,如清单 12所示。为 URI 路径 /helloworld
上托管的资源指定 URL。为主机而不是本地主机指定 IP 地址。客户端运行在 Android 设备之上,Android 设备的本地主机并不是 JAX-RS Web 服务运行的主机(除非 JAX-RS Web 服务也托管在 Android 设备上,但是在本例中并不属于这种情况)。
清单 12.创建 HttpGet 对象
HttpGet request = new HttpGet("http://192.168.1.68:7001/AndroidJAX-RS/jaxrs/helloworld"); |
使用 Accept
头指定可接受的媒体类型。在 Accept
中只设置一种媒体类型,该类型与 JAX-RS Web 服务中生成的媒体类型对应。在首次运行时,将Accept
头设置为 text/xml
以输出 text/xml
响应,如清单 13所示。
清单 13. 设置 Accept 头
request.addHeader("Accept", "text/xml"); //request.addHeader("Accept", "text/html"); //request.addHeader("Accept", "text/plain"); |
测试每种响应类型的输出(普通文本、html 和 XML)。允许的响应类型应当匹配资源类中生成的 MIME 类型。资源类生成的 MIME 类型应当匹配一种可接受的 MIME 类型。如果生成的 MIME 类型和可接受的 MIME 类型不 匹配,那么将生成com.sun.jersey.api.client.UniformInterfaceException
。例如,将可接受的 MIME 类型设置为text/xml
,而将生成的 MIME 类型设置为 application/xml
。将生成 UniformInterfaceException
。如清单 14清单 14 所示,调用 HttpClient
的 execute()
方法,其中 HttpGet
方法作为参数,以检索HttpResponse
对象。
清单 14.获得 HttpResponse
HttpResponse response = httpclient.execute(request); |
使用 getEntity
方法从 HttpResponse
获取 HttpEntity
(清单 15)。
清单 15.获取 HttpEntity
HttpEntity entity = response.getEntity(); |
使用 getContent()
方法以 InputStream
的形式通过 HttpGet
获取内容(清单 16)。
清单 16.通过 HttpEntity 创建 InputStream
InputStream instream = entity.getContent(); |
为返回自 JAX-RS Web 服务的消息创建 StringBuilder
(清单 17)。
清单 17.创建 StringBuilder
StringBuilder sb = new StringBuilder(); |
从 InputStream
创建 BufferedReader
(清单 18)。
清单 18.创建一个 BufferedReader
BufferedReader r = new BufferedReader(new InputStreamReader(instream)); |
读取 BufferedReader
中的每一行并添加到 StringBuilder
(清单 19)。
清单 19.读取 BufferedReader
for (String line = r.readLine(); line != null; line = r.readLine()) { sb.append(line); } |
从 StringBuilder
获取 String
消息并结束 InputStream
(清单 20)。
清单 20.获取 StringBuilder 消息
String jaxrsmessage = sb.toString(); instream.close(); |
在 TextView
UI 组件上设置 String
消息(清单 21)。
清单 21.设置 StringBuilder 消息
jaxrs.setText(jaxrsmessage); |
清单 22展示了 AndroidJAXRSClient
类。
清单 22.AndroidJAXRSClient.java
package android.jaxrs; 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(); } } |
图 10展示了 Android 客户端应用程序的目录结构。(查看图 10 的 放大图)。
运行 Android 客户端
现在,我们准备运行 Android 客户端以调用 JAX-RS Web 服务和输出 XML 消息。右键单击 AndroidJAXRSClient 项目并选择Run As > Android Application,如图 11所示。
图 11.运行 Android JAX-RS 客户端
Android AVD 启动,JAX-RS 客户端应用程序安装在 Android 设备上,如图 12所示。
图 12.Android 上安装的 Android JAX-RS 客户端
AndroidJAXRSClient
活动启动,并且 JAX-RS Web 服务生成的 XML 消息被输出到 Android 设备,如图 13所示。
图 13.输出 XML 消息到 Android 设备
类似地,如果在资源类中,生成 text/html
媒体类型的方法是未注释的,那么输出为 HTML 消息,而 Accept
头被设置为接收相同的媒体类型。例如,在资源类中,取消清单 23中的方法的注释。
清单 23.在资源类中生成 HTML
@GET @Produces("text/html") public String getHTMLMessage() { return "<html> " + "<title>" + "Hello Android" + "</title>" + "<body><h1>" + "Hello Android" + "</body></h1>" + "</html> "; } |
在客户端类中,取消清单 24中 addHeader
调用的注释。
清单 24.将媒体类型设置为 Accept
request.addHeader("Accept", "text/html"); |
重新运行 AndroidJAXRSClient
应用程序以获取 HTML 响应,如图 14所示。
图 14.到 Android 设备的 HTML 输出
要获得文本响应,对清单 25中资源类中的方法取消注释。
清单 25.在资源类中生成文本媒体类型
@GET @Produces("text/plain") public String getClichedMessage() { return "Hello Android"; } |
在客户端类中,取消清单 26中的以下 Accept
头媒体类型设置的注释。
清单 26.设置 Accept 头
request.addHeader("Accept", "text/plain"); |
重新运行 AndroidJAXRSClient
应用程序以获取文本消息输出,如图 15所示。
图 15.输出文本消息到 Android 设备
结束语
在本文中,您了解了如何创建一个 JAX-RS Web 服务并从 Android 客户端调用该 Web 服务。您向 Android 设备发送了 XML、HTML 和文本输出。