虽然在登录系统中使用了Web Service与服务端进行交互。但是在传递大量的数量时,Web Service显得有些笨拙。在本节将介绍移动电子相册中使用的另外一种与数据库交互的方法。直接发送HTTP GET或POST请求。这就要用到HttpGet、HttpPost以及HttpURLConnection这些类。
15.3.1 HttpGet类和HttpPost类
本节将介绍Android SDK集成的Apache HttpClient模块。要注意的是,这里的Apache HttpClient模块是HttpClient 4.0(org.apache.http.*),而不是Jakarta Commons HttpClient 3.x(org.apache.commons.httpclient.*)。
在HttpClient模块中用到了两个重要的类:HttpGet和HttpPost。这两个类分别用来提交HTTP GET和HTTP POST请求。为了测试本节的例子,需要先编写一个Servlet程序,用来接收HTTP GET和HTTP POST请求。读者也可以使用其他服务端的资源来测试本节的例子。
假设192.168.17.81是本机的IP,客户端可以通过如下的URL来访问服务端的资源:
http://192.168.17.81:8080/querybooks/QueryServlet?bookname=开发
在这里bookname是QueryServlet的请求参数,表示图书名,通过该参数来查询图书信息。
现在我们要通过HttpGet和HttpPost类向QueryServlet提交请求信息,并将返回结果显示在TextView组件中。
无论是使用HttpGet,还是使用HttpPost,都必须通过如下3步来访问HTTP资源。
1.创建HttpGet或HttpPost对象,将要请求的URL通过构造方法传入HttpGet或HttpPost对象。
2.使用DefaultHttpClient类的execute方法发送HTTP GET或HTTP POST请求,并返回HttpResponse对象。
3.通过HttpResponse接口的getEntity方法返回响应信息,并进行相应的处理。
如果使用HttpPost方法提交HTTP POST请求,还需要使用HttpPost类的setEntity方法设置请求参数。
本例使用了两个按钮来分别提交HTTP GET和HTTP POST请求,并从EditText组件中获得请求参数(bookname)值,最后将返回结果显示在TextView组件中。两个按钮共用一个onClick事件方法,代码如下:
public void onClick(View view)
{
// 读者需要将本例中的IP换成自己机器的IP
String url = "http://192.168.17.81:8080/querybooks/QueryServlet";
TextView tvQueryResult = (TextView) findViewById(R.id.tvQueryResult);
EditText etBookName = (EditText) findViewById(R.id.etBookName);
HttpResponse httpResponse = null;
try
{
switch (view.getId())
{
// 提交HTTP GET请求
case R.id.btnGetQuery:
// 向url添加请求参数
url += "?bookname=" + etBookName.getText().toString();
// 第1步:创建HttpGet对象
HttpGet httpGet = new HttpGet(url);
// 第2步:使用execute方法发送HTTP
GET请求,并返回HttpResponse对象
httpResponse = new DefaultHttpClient().execute(httpGet);
// 判断请求响应状态码,状态码为200表
示服务端成功响应了客户端的请求
if (httpResponse.getStatusLine().
getStatusCode() == 200)
{
// 第3步:使用getEntity方法获得返回结果
String result = EntityUtils.
toString(httpResponse.getEntity());
// 去掉返回结果中的"\r"字符,
否则会在结果字符串后面显示一个小方格
tvQueryResult.setText(result.replaceAll("\r", ""));
}
break;
// 提交HTTP POST请求
case R.id.btnPostQuery:
// 第1步:创建HttpPost对象
HttpPost httpPost = new HttpPost(url);
// 设置HTTP POST请求参数必须用NameValuePair对象
List<NameValuePair> params = new
ArrayList<NameValuePair>();
params.add(new BasicNameValuePair
("bookname", etBookName.getText(). toString()));
// 设置HTTP POST请求参数
httpPost.setEntity(new
UrlEncodedFormEntity(params, HTTP.UTF_8));
// 第2步:使用execute方法发送HTTP
POST请求,并返回HttpResponse对象
httpResponse = new DefaultHttpClient().
execute(httpPost);
if (httpResponse.getStatusLine().
getStatusCode() == 200)
{
// 第3步:使用getEntity方法获得返回结果
String result = EntityUtils.toString
(httpResponse.getEntity());
// 去掉返回结果中的"\r"字符,
否则会在结果字符串后面显示一个小方格
tvQueryResult.setText(result.replaceAll("\r", ""));
}
break;
}
}
catch (Exception e)
{
tvQueryResult.setText(e.getMessage());
}
HttpClient是一个很方便进行Http连接操作的工具包,用它可以设置代理和模拟浏览器下载网页,对于爬虫程序来说,是特别好的工具。
它提供的 HTTP 的访问主要是通过 GetMethod 类和 PostMethod 类来实现的,他们分别对应了 HTTP Get 请求与 Http Post 请求.
下面我分别给出两种访问方式的代码及注意事项:
get方式:
//生成 HttpClinet 对象
HttpClient client = new DefaultHttpClient();
//生成 GetMethod 对象
HttpGet httpGet = new HttpGet( psURL );
//设置请求头,这里很关键,细节在注意事项中描述
httpGet.setHeader("user-agent", "Mozilla/5.0 (Windows NT 5.1; rv:8.0.1) Gecko/20100101") ;
httpGet.setHeader("accept", "*/*") ;
httpGet.setHeader("accept-language", "zh-CN") ;
httpGet.setHeader("accept-encoding", "utf-8, deflate") ;
StringBuffer strBuf = new StringBuffer();
try {
//执行 HTTP GET 请求,获取响应
HttpResponse response = client.execute(httpGet);
//根据响应码判断是否正确获取响应
if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) {
//若正确获得响应则对内容进行处理
HttpEntity entity = response.getEntity();
if (entity != null) {
BufferedReader reader = new BufferedReader(
new InputStreamReader(entity.getContent(), "UTF-8"));
String line = null;
if (entity.getContentLength() > 0) {
strBuf = new StringBuffer((int) entity.getContentLength());
while ((line = reader.readLine()) != null) {
strBuf.append(line);
}
}
}
//释放连接
if (entity != null) {
EntityUtils.consume(entity);
}
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
post方式:
//存放参数
List<NameValuePair> nvps= new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("txtUserName", UAERNAME));
nvps.add(new BasicNameValuePair("txtPassword", PASSWORD));
nvps.add(new BasicNameValuePair("ImageButton1.x", "17"));
nvps.add(new BasicNameValuePair("ImageButton1.y", "10"));
nvps.add(new BasicNameValuePair("__VIEWSTATE", FLAG));
//生成 PostMethod 对象
HttpPost httpPostLogin = new HttpPost(URL)
//添加参数
httpPostLogin.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
//以下为执行请求,获取响应,并对响应进行处理,与get方式类似
httpResponseLogin = getHttpClientInstance().execute(httpPostLogin);
status=httpResponseLogin.getStatusLine().getStatusCode();
if (status == 302||status==HttpStatus.SC_OK) {
Header[] locationHeader = httpResponseLogin.getHeaders("location");
if (locationHeader != null) {
HttpEntity httpEntityLogin = httpResponseLogin.getEntity();
if (httpEntityLogin != null) {
EntityUtils.consume(httpEntityLogin);
}
}
}
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
以下为我在写爬虫程序的时候遇到的问题及解决方案,权作注意事项吧:
1、关于get方式设置请求头的问题,最令人头疼:
1)、上面实例中列出的四种请求头一般情况下已够用,无需添加。
2)、要特别注意accept-encoding的值,有两种:gzip, deflate 和utf-8, deflate。
gzip是经过压缩的大量数据的,一般不常用;
utf-8符合一般使用规律,具体可以两种都尝试一下,或者干脆不加该请求头。
2、无论哪种方式,接受后一定要使用
EntityUtils.consume(entity);释放连接