技术开发 频道

Apache HttpClient Android客户端编程

  【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,

创建Eclipse工程

  3 点Next后,在如下图中,选定希望要用的运行时容器,比如TOMCAT

创建Eclipse工程

  4 点NEXT后,再在tomcat的配置窗口中,配置相关的JDK和TOMCAT参数,最后点FINISH。

  5 这样就增加了一个动态web工程。鼠标右键点工程的属性,在打开的页面中,如下图,选择Project Facets,再选择JAX-RS (REST Web Services) 1.1项,再点选Further configuration required,如下图:

创建Eclipse工程

  6 在配置选项中,选择自定义用户类库,创建一个新的自定义用户类库,点Add Jar,增加如下的三个jersey 包: jersey-bundle-1.4.jar、asm-3.1.jar、jsr311-api-1.1.1.jar。

  如下图:

创建Eclipse工程

  7 在JAX-RS Capabilities窗口中,指定JAX-RS servlet class name为:

  com.sun.jersey.spi.container.servlet.ServletContainer,并点OK,如下图:

创建Eclipse工程

  最后在项目的Facets窗口中,点apply 应用,如下图,完成整个设置:

创建Eclipse工程

  8) 同时,要设置web.xml,配置JAX-RS 的servlet参数,如下代码:

    <?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>

  这里配置了两个初始化参数,分别为:

  com.sun.jersey.config.property.resourceConfigClass 和

  com.sun.jersey.config.property.packages

  编写RESTful代码

  接下来,我们开始编写RESTful代码。步骤如下:

  在File>New>Other中,选择新建一个JAVA 类文件,点finish,如下图设置:

编写RESTful代码

  接下来,我们使用注解为程序增加RESTful的功能。JAX-RS中的一个特点是可以使用JAVA中的各种注解简便地为程序增加RESTful的功能。下面是其代码:

package jaxrs;
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客户端

  可以看到,我们选用的是Android 2.2的SDK,应用的名称为AndroidJAXRSClient,创建的Activity名为AndroidJAXRSClient。接下来,首先创建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>

  可以看到,在这个布局文件中,只是简单放置了一个textview 文本显示控件,这个控

  件是用来显示服务端返回的JAX-RS的RESTful的结果。

  为了能获得服务端返回的结果,需要Android使用网络访问权限功能,因此必须在配置文件AndroidManifest.xml中进行设置,添加如下这句话:

<uses-permission  android:name="android.permission.INTERNET"></uses-permission>
    并指定应用程序启动的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.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;

  下面直接给出客户端Android访问服务端JAX-RS服务的代码,再逐一解析:

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();

     }

}

  在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客户端

  可以看到,Android的客户端通过访问JAX-RS的RESTful web service,得到了返回的XML字符串。同样,如果将以下的代码分别注释,再运行,可以分别看到text/plain,text/html为资源类型返回的不同结果:

  request.addHeader("Accept", "text/plain");

  request.addHeader("Accept", "text/html");

  当然,在服务端的HelloWorldResource中,也要分别将之前注释掉的getHTMLMessage()方法和getClichedMessage()方法启用。它们的运行结果分别如下两图:

创建Android客户端

创建Android客户端

  小结

  本文介绍了如何通过Apache的开源HttpClient去访问一个符合JAX-RS标准的RESTful服务,其中jersey是目前JAX-RS RESTful标准的一个不错的开源实现。而由于RESTful的简单,开发快捷,运行速度快,因此很适合象Android等移动设备进行访问,给用户会有很好的运行体验。读者可以通过本文的例子,加以扩展,可以通过RESTful搭建不少web服务,然后通过Android客户端去访问。

0