简介:
使用 Apache HttpClient 库访问 JAX-RS web 服务。Jersey
是 JAX-RS 的参考实现,它简化了 Java? 环境下的 RESTful Web 服务的开发。Android
是一款流行的智能手机,本文将展示如何为 Android 创建一个 JAX-RS 客户端。您将创建一个访问
JAX-RS Web 服务的 Apache HttpClient 库客户端。
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 客户端。您可以 下载 本文使用的样例代码。
常用缩略语
API:应用程序编程接口
HTML:超文本标记语言
HTTP:超文本传输协议
IDE:集成开发环境
JSON:JavaScript 对象符号
MIME:多用途网络邮件扩展
POJO:普通 Java 对象
REST:具象状态传输
SDK:软件开发工具包
UI:用户界面
URI:统一资源标识符
URL:统一资源定位符
XML:可扩展标记语言
设置环境
在为 JAX-RS Web 服务创建客户端之前,需要对环境进行设置。参见
参考资料 中的链接。
1.安装 Eclipse。
2.为 Eclipse 安装 Android Development Tools
(ADT) 插件,其中提供了一组供在 Eclipse 中开发 Android 应用程序的扩展。
3.为 Android 2.2 安装 SDK Platform。Android
SDK 为开发 Android 应用程序提供了工具。
4.创建一个 Android Virtual Device (AVD),这是
Eclipse 中的一个 Android 仿真器。
5.下载 Jersey 压缩文件 jersey-archive-1.4.zip,其中包含
Jersey JAR 和核心依赖文件。下载 Jersey 包 JAR jersey-bundle-1.4.jar。Jersey
是使用 JDK 6.0 构建的,因此还需要安装 JDK 6.0。
6.安装 Web 服务器,如 Tomcat,或应用程序服务器,如 WebSphere?,或
WebLogic 服务器。将清单 1 中的 Jersey JAR 文件添加到应用程序/Web 服务器的运行时
CLASSPATH 中。
清单 1. Jersey JAR 文件
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 项目。
选择 File > New,在 New 窗口中,选择 Web >
Dynamic Web Project。单击 Next。
指定项目名称(例如 AndroidJAX-RS)并单击 New Runtime,为您的
WebSphere、Tomcat 或 WebLogic 服务器配置一个新的目标运行时。图 1 展示了完成设置的
Dynamic Web Project 窗口。
图 1. 配置一个新的运行时
在 New Server Runtime Environment 窗口中,选择一个服务器,如
Tomcat 服务器、WebSphere 服务器或 WebLogic 服务器。单击 Next,如图 2
所示。
图 2. 选择一个应用程序或 Web 服务器
在 New IBM WebSphere v6.0 Runtime 窗口中,配置
JRE 和 IBM WebSphere Installation Directory。单击 Dynamic
Web Project 对话框中的 Next。为 Source 文件夹和 Output 文件夹选择默认的
Java 设置,并单击 Next。
将 Context root 指定为 AndroidJAX-RS,选择默认的
Content Directory,并单击 Finish。
将创建一个 Dynamic Web Project 并添加到 Project
Explorer。右键单击项目节点并选择 Properties。
选择 Project Facets,然后选择 JAX-RS (REST
Web Services) 1.1 项目 facet。单击 Further configuration
required,如图 3 所示。
图 3.配置 JAX-RS Project
Facet
在 JAX-RS Capabilities 窗口中,指定一个 Servlet
名称 (JAX-RS Servlet) 并配置一个 JAX-RS Implementation 库。选择
Type as User Library 并单击 Manage。
在 User Libraries 窗口中,单击 New。在 New User
Library 对话框中,指定 User library 名并单击 OK。
将添加一个用户库。单击 Add JARs 以将 Jersey JARs
添加到用户库。如图 4 所示,添加以下 Jersey JAR:
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
单击 OK。
图 4.添加 Jersey JAR 文件
在 JAX-RS Capabilities 窗口中,指定 JAX-RS
servlet 类名为com.sun.jersey.spi.container.servlet.ServletContainer,如图
5 所示。单击 OK。
图 5.指定 JAX-RS servlet
类
在 Project Facets 窗口中,单击 Apply,如图 6 所示,然后单击
OK。
图 6.应用 JAX-RS Project
Facet
目标运行时通过 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。
1.选择 File > New > Other。在 New
对话框中,选择 Java > Class,然后单击 Finish。
2.在 New Java Class 窗口中,如图 7 所示,指定:
1)一个 Source 文件夹:AndroidJAX-RS/src
2)包:jaxrs
3)类名:HelloWorldResource
单击 Finish。
图 7.创建资源类
使用 @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 客户端项目
1.在本节中,您将创建一个 Android 项目,在其中将为 Android
创建 JAX-RS 客户端。
2.在 Eclipse IDE 中,选择 File > New。在
New 对话框中,选择 Android > Android Project,然后单击 Next。
填充 New Android Project 窗口中的字段,如图 9 所示。
1)项目名:AndroidJAXRSClient
2)构建目标:Android Platform 2.2 API 8
3)属性:应用程序名 AndroidJAXRSClient 和包名 android.jaxrs
4)选择 Create Activity,并指定 Activity 类
AndroidJAXRSClient。
5)一项活动代表一个用户交互,而扩展 Activity 类的类为 UI
创建了一个窗口。
6)最低 SDK 版本:8
7)单击 Next
图 9.创建 JAX-RS 客户端类
Android 项目中的文件包括:
1.一个活动类 (AndroidJAXRSClient),该类扩展了 Activity
类
2.res/layout/main.xml 文件,指定 Android
应用程序的布局
3.AndroidManifest.xml 文件,包含应用程序配置信息,如包名、应用程序组件、流程、权限和
Android 系统的最低 API 级别。
在 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.xm
<?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 权限
<?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
的 放大图)。
图 10.Android 应用程序的目录结构
运行 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 和文本输出。
|