客户端和服务端通讯的N种方式(三)

对于byte字节数组来说,Axis2会自动将其序列化,然后使用Base64编码格式进行传输,因此,在服务端可以直接使用byte[]作为参数类型或返回值的类型。在下面的内容我们将会看到如何使用byte[]来重新改写服务端的程序。

服务端直接使用byte[]

在上一篇文章中,服务端使用了String类型的参数和返回值。这虽然也可以完成我们的任务,但Axis2会自动处理byte[]类型,因此,我们可以直接将String变成byte[]。例如,上传和下载图像的代码如下:

 

  1. //  上传图像  
  2. public boolean updateByteImage(byte[] buffer)  
  3. {  
  4.     try  
  5.     {              
  6.         FileOutputStream fos = new FileOutputStream("d:\\my.jpg");  
  7.         fos.write(buffer);  
  8.         fos.close();  
  9.         return true;  
  10.     }  
  11.     catch (Exception e)  
  12.     {  
  13.         // TODO: handle exception  
  14.     }  
  15.     return false;  
  16. }  
  17.     //  下载图像  
  18. public byte[] downloadByteImage()  
  19. {  
  20.     byte[] buffer = new byte[8192];  
  21.     try  
  22.     {  
  23.         FileInputStream fis = new FileInputStream("e:\\my.jpg");  
  24.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  25.         int count = 0;  
  26.         while ((count = fis.read(buffer)) >= 0)  
  27.         {  
  28.             baos.write(buffer, 0, count);  
  29.         }  
  30.   
  31.         buffer = baos.toByteArray();  
  32.   
  33.         fis.close();  
  34.     }  
  35.     catch (Exception e)  
  36.     {  
  37.         // TODO: handle exception  
  38.     }  
  39.     return buffer;  
  40. }  

在上面的代码中将参数和返回值的类型变成了byte[]。重新部署这个WebService,会得到如图1所示的WSDL。

图1  WSDL

在图1中的黑圈里的类型是xs:base64Binary,说明Axis2可以将byte[]转换成Base64格式的字符串。
对于客户端来说,代码并不需要做任何修改,完全感觉不到服务端使用的是String还是byte[]。将String类型改成byte[]类型后,效果和上一篇文章中的例子完全相同,下载图像的效果如图2所示。

图2  下载和显示图像


通过Base64编码传递对象(服务端实现)
在第一篇文章中直接将一个Product对象传到了客户端。除了这种方法外,还可以将对象序列化,并对其Base64编码后进行传递。例如,在本例中有一个Student类,代码如下:

  1. package service;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. public class Student implements Serializable  
  6. {  
  7.     public String id;  
  8.     public String name;  
  9. }  


要想序列化对象,类必须实现java.io.Serializable接口。下面的代码是提供服务的SchoolService类。
 

  1. package service;  
  2.   
  3. import java.io.ByteArrayInputStream;  
  4. import java.io.ObjectInputStream;  
  5.   
  6. public class SchoolService  
  7. {  
  8.   
  9.     public void setStudent(String base64)  
  10.     {  
  11.         try  
  12.         {  
  13.             byte[] buffer = new sun.misc.BASE64Decoder().decodeBuffer(base64);  
  14.             ByteArrayInputStream bais = new ByteArrayInputStream(buffer);  
  15.             ObjectInputStream ois = new ObjectInputStream(bais);  
  16.   
  17.             Student student = (Student) ois.readObject();  
  18.             System.out.println("id:" + student.id);  
  19.             System.out.println("name:" + student.name);  
  20.         }  
  21.         catch (Exception e)  
  22.         {  
  23.   
  24.         }  
  25.     }  
  26. }  

在上面的代码中的base64参数表示base64编码格式 的序列化对象。在setStudent方法中通过解码将其还原成Student对象,然后输出id和name属性值。

通过Base64编码传递对象(客户端实现)
 

下面是客户端调用服务端的setStudent方法的代码。

 

  1. public void onClick_SetStudent(View view)  
  2.     {  
  3.         try  
  4.         {  
  5.             Student student = new Student();  
  6.             student.id = "4321";  
  7.             student.name = "超人";  
  8.             ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  9.             ObjectOutputStream oos = new ObjectOutputStream(baos);  
  10.             oos.writeObject(student);  
  11.             byte[] buffer = baos.toByteArray();  
  12.             oos.close();  
  13.             baos.close();  
  14.             String base64 = new String(Base64.encodeBase64(buffer));  
  15.   
  16.             String serviceUrl = "http://192.168.17.82:8080/axis2/services/SchoolService?wsdl";  
  17.             String methodName = "setStudent";  
  18.             SoapObject request = new SoapObject("http://service", methodName);  
  19.   
  20.             request.addProperty("base64", base64);  
  21.             SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(  
  22.                     SoapEnvelope.VER11);  
  23.             envelope.bodyOut = request;  
  24.             HttpTransportSE ht = new HttpTransportSE(serviceUrl);  
  25.             ht.call(null, envelope);  
  26.   
  27.             envelope.getResponse();  
  28.   
  29.         }  
  30.         catch (Exception e)  
  31.         {  
  32.             Log.d("setStudent_exception", String.valueOf(e));  
  33.         }  
  34.     }  

在上面的代码中,首先创建了Student对象(要注意,这时在服务端和客户端都需要有一个Student类),并设置了Student对象的属性值。然后会使用下面的代码将Student对象编码成Base64格式。

  1. ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  2. ObjectOutputStream oos = new ObjectOutputStream(baos);  
  3. oos.writeObject(student);  
  4. byte[] buffer = baos.toByteArray();  
  5. oos.close();  
  6. baos.close();  
  7. String base64 = new String(Base64.encodeBase64(buffer));  

接下来的实现过程就是调用WebService,并传递Base64格式的参数。运行程序后,单击屏幕上方的按钮,就会在服务端的控制台输出id和name属性值,如图3所示。

图3  在服务端输出Student对象的属性值
 


脱离WebService,使用更自由的HTTP访问网络


在前面几篇文章中, 一直在使用WebService来与服务端进行交互,然而,使用WebService虽然可以很容易地传递数据,但也会受到很多限制,例如,由于WebService使用了XML格式传输数据,因此,在传递二进数据时必须将数据进行编码才能进行传递。这样将会使数据量明显增大,而且还会面临不同的WebService引擎不兼容的问题。因此,在接下来的内容会介绍一种更灵活的数据传输方式:HTTP。虽然WebService也是通过HTTP进行传输的,但对用户却是透明的。而通过HTTP可以直接来控制传输的过程。

HTTP是Internet中广泛使用的协议。几乎所有的语言和SDK都会不同程度地支持HTTP,当然, OPhone SDK也不例外。在OPhone SDK中可以采用多种方式使用HTTP,例如,HttpURLConnection、HttpGet、HttpPost等。


提交HTTP GET和HTTP POST请求


在这里首先要介绍一下OPhone 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请求,代码如下:

 

  1. package net.blogjava.mobile;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.PrintWriter;  
  5. import javax.servlet.ServletException;  
  6. import javax.servlet.http.HttpServlet;  
  7. import javax.servlet.http.HttpServletRequest;  
  8. import javax.servlet.http.HttpServletResponse;  
  9.   
  10. /** 
  11.  * Servlet implementation class QueryServlet 
  12.  */  
  13. public class QueryServlet extends HttpServlet  
  14. {  
  15.     private static final long serialVersionUID = 1L;  
  16.   
  17.     @Override  
  18.     protected void service(HttpServletRequest request,  
  19.             HttpServletResponse response) throws ServletException, IOException  
  20.     {  
  21.         response.setContentType("text/html;charset=utf-8");   
  22.         String queryStr = "";  
  23.         if ("post".equals(request.getMethod().toLowerCase()))  
  24.             queryStr = "POST请求;查询字符串:" + new String(request.getParameter("bookname").getBytes(  
  25.                     "iso-8859-1"), "utf-8");  
  26.         else if ("get".equals(request.getMethod().toLowerCase()))  
  27.             queryStr = "GET请求;查询字符串:" + request.getParameter("bookname");  
  28.   
  29.         String s =queryStr  
  30.                 + "[Java Web开发速学宝典;Java开发指南思想(第4版);Java EE开发宝典;C#开发宝典]";  
  31.         PrintWriter out = response.getWriter();  
  32.         out.println(s);  
  33.     }  
  34. }  

在运行本例之前,需要先在PC上安装Tomcat,并将querybooks工程直接复制到<Tomcat安装目录>\webapps目录即可。然后启动Tomcat。在浏览器地址栏中输入如下的URL:

http://localhost:8080/querybooks/query.jsp

如果出现如图4所示的页面,说明querybooks已经安装成功。

图4  querybooks的测试页面


在querybooks工程中有一个QueryServlet类,访问这个类的URL如下:

http://192.168.17.82:8080/querybooks/QueryServlet?bookname=开发

其中“192.168.17.82”是PC的IP地址,bookname是QueryServlet的请求参数,表示图书名,通过该参数来查询图书信息。在图4所示的页面中的文本框内输入“开发”,然后单击【查询】按钮,页面会以HTTP POST方式向QueryServlet提交请求信息,如果成功提交,将显示如图5所示的内容。

图5  返回的响应信息

现在我们要通过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事件方法,代码如下:

  1. public void onClick(View view)  
  2. {  
  3.     //  读者需要将本例中的IP换成自己机器的IP  
  4.     String url = "http://192.168.17.82:8080/querybooks/QueryServlet";  
  5.     TextView tvQueryResult = (TextView) findViewById(R.id.tvQueryResult);  
  6.     EditText etBookName = (EditText) findViewById(R.id.etBookName);  
  7.     HttpResponse httpResponse = null;  
  8.     try  
  9.     {  
  10.         switch (view.getId())  
  11.         {  
  12.             //  提交HTTP GET请求  
  13.             case R.id.btnGetQuery:  
  14.                 //  向url添加请求参数  
  15.                 url += "?bookname=" + etBookName.getText().toString();  
  16.                 //  第1步:创建HttpGet对象  
  17.                 HttpGet httpGet = new HttpGet(url);  
  18.                 //  第2步:使用execute方法发送HTTP GET请求,并返回HttpResponse对象  
  19.                 httpResponse = new DefaultHttpClient().execute(httpGet);  
  20.                 //  判断请求响应状态码,状态码为200表示服务端成功响应了客户端的请求  
  21.                 if (httpResponse.getStatusLine().getStatusCode() == 200)  
  22.                 {  
  23.                     //  第3步:使用getEntity方法获得返回结果  
  24.                     String result = EntityUtils.toString(httpResponse.getEntity());  
  25.                     //  去掉返回结果中的“\r”字符,否则会在结果字符串后面显示一个小方格  
  26.                     tvQueryResult.setText(result.replaceAll("\r"""));  
  27.                 }  
  28.                 break;  
  29.             //  提交HTTP POST请求  
  30.             case R.id.btnPostQuery:  
  31.                 //  第1步:创建HttpPost对象  
  32.                 HttpPost httpPost = new HttpPost(url);  
  33.                 //  设置HTTP POST请求参数必须用NameValuePair对象  
  34.                 List<NameValuePair> params = new ArrayList<NameValuePair>();  
  35.                 params.add(new BasicNameValuePair("bookname", etBookName  
  36.                         .getText().toString()));  
  37.                 //  设置HTTP POST请求参数  
  38.                 httpPost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));  
  39.                 //  第2步:使用execute方法发送HTTP POST请求,并返回HttpResponse对象  
  40.                 httpResponse = new DefaultHttpClient().execute(httpPost);  
  41.                 if (httpResponse.getStatusLine().getStatusCode() == 200)  
  42.                 {  
  43.                     //  第3步:使用getEntity方法获得返回结果  
  44.                     String result = EntityUtils.toString(httpResponse.getEntity());  
  45.                     //  去掉返回结果中的“\r”字符,否则会在结果字符串后面显示一个小方格  
  46.                     tvQueryResult.setText(result.replaceAll("\r"""));  
  47.                 }  
  48.                 break;  
  49.         }  
  50.     }  
  51.     catch (Exception e)  
  52.     {  
  53.         tvQueryResult.setText(e.getMessage());  
  54.     }  
  55. }  


运行本例,在文本编辑框中输入“开发”,并单击【GET查询】和【POST查询】按钮,会在屏幕下方法显示如图6和图7所示的信息。

图6  Get请求查询结果

图7  Post请求查询结果


总结


本文主要介绍了如何通过Base64编码来传递可序列化的对象。通过对二进制进行编码,我们可以传递任何形式的数据。虽然WebService可以满足大多数要求。但如果想更灵活地传输数据,直接使用HTTP就显得非常必要。在下一篇文章中将着重介绍HTTP传输数据的各种方法。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值