微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

客户端和服务端通讯的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. false;  
  15. }  
  16.     //  下载图像  
  17. byte[] downloadByteImage()  
  18. byte[] buffer = new byte[8192];  
  19. try  
  20.         FileInputStream fis = new FileInputStream("e:\\my.jpg");  
  21.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  22. int count = 0;  
  23.         while ((count = fis.read(buffer)) >= 0)  
  24.         {  
  25.             baos.write(buffer, 0, count);  
  26.         }  
  27.   
  28.         buffer = baos.toByteArray();  
  29.         fis.close();  
  30. return buffer;  
  31. }  

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

图1  WSDL

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

图2  下载和显示图像


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

package service;  
  • import java.io.Serializable;  
  • class Student implements Serializable  
  • {  
  • public String id;  
  • public String name;  
  • }  

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

    import java.io.ByteArrayInputStream;  
  • import java.io.ObjectInputStream;  
  •   
  • class SchoolService  
  • void setStudent(String base64)  
  •         {  
  •             new sun.misc.BASE64Decoder().decodeBuffer(base64);  
  •             ByteArrayInputStream bais = new ByteArrayInputStream(buffer);  
  •             ObjectInputStream ois = new ObjectInputStream(bais);  
  •             Student student = (Student) ois.readobject();  
  •             System.out.println("id:" + student.id);  
  •             System.out.println("name:" + student.name);  
  •         }  
  •     }  
  • 在上面的代码中的base64参数表示base64编码格式 的序列化对象。在setStudent方法中通过解码将其还原成Student对象,然后输出id和name属性值。

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

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

    void onClick_SetStudent(View view)  

  •             Student student = new Student();  
  •             student.id = "4321";  
  •             student.name = "超人";  
  •             ByteArrayOutputStream baos =              ObjectOutputStream oos = new ObjectOutputStream(baos);  
  •             oos.writeObject(student);  
  • byte[] buffer = baos.toByteArray();  
  •             oos.close();  
  •             baos.close();  
  •             String base64 = new String(Base64.encodeBase64(buffer));  
  •             String serviceUrl = "http://192.168.17.82:8080/axis2/services/SchoolService?wsdl";  
  •             String methodName = "setStudent";  
  •             SoapObject request = new SoapObject("http://service", methodName);  
  •             request.addProperty("base64", base64);  
  •             SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(  
  •                     SoapEnvelope.VER11);  
  •             envelope.bodyOut = request;  
  •             HttpTransportSE ht = new HttpTransportSE(serviceUrl);  
  •             ht.call(null, envelope);  
  •             envelope.getResponse();  
  • catch (Exception e)  
  •             Log.d("setStudent_exception", String.valueOf(e));  
  •         }  
  •     }  
  • 在上面的代码中,首先创建了Student对象(要注意,这时在服务端和客户端都需要有一个Student类),并设置了Student对象的属性值。然后会使用下面的代码将Student对象编码成Base64格式。

    ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  • ObjectOutputStream oos = new ObjectOutputStream(baos);  
  • oos.writeObject(student);  
  • byte[] buffer = baos.toByteArray();  
  • oos.close();  
  • baos.close();  
  • 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请求,代码如下:

     

    package net.blogjava.mobile;  
  • import java.io.IOException;  
  • import java.io.PrintWriter;  
  • import javax.servlet.servletexception;  
  • import javax.servlet.http.HttpServlet;  
  • import javax.servlet.http.HttpServletRequest;  
  • import javax.servlet.http.HttpServletResponse;  
  • /** 
  •  * Servlet implementation class QueryServlet 
  •  */  
  • class QueryServlet extends HttpServlet  
  • private static final long serialVersionUID = 1L;  
  •     @Override  
  • protected void service(HttpServletRequest request,  
  •             HttpServletResponse response) throws servletexception, IOException  
  •         response.setContentType("text/html;charset=utf-8");   
  •         String queryStr = "";  
  • if ("post".equals(request.getmethod().toLowerCase()))  
  •             queryStr = "POST请求;查询字符串:" + new String(request.getParameter("bookname").getBytes(  
  •                     "iso-8859-1"), "utf-8");  
  • else if ("get".equals(request.getmethod().toLowerCase()))  
  •             queryStr = "GET请求;查询字符串:" + request.getParameter("bookname");  
  •         String s =queryStr  
  •                 + "[Java Web开发速学宝典;Java开发指南思想(第4版);Java EE开发宝典;C#开发宝典]";  
  •         PrintWriter out = response.getWriter();  
  •         out.println(s);  
  • 在运行本例之前,需要先在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事件方法代码如下:

    void onClick(View view)  
  • //  读者需要将本例中的IP换成自己机器的IP  
  •     String url = "http://192.168.17.82:8080/querybooks/QueryServlet";  
  •     TextView tvQueryResult = (TextView) findViewById(R.id.tvQueryResult);  
  •     EditText etBookName = (EditText) findViewById(R.id.etBookName);  
  •     HttpResponse httpResponse = null;  
  •     {  
  • 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);  
  •         tvQueryResult.setText(e.getMessage());  
  •     }  

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

    图6  Get请求查询结果

    图7  Post请求查询结果


    总结


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

    相关文章

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

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


    作者介绍


    李宁,东北大学计算机专业硕士,拥有超过10年的软件开发经验。曾任国内某知名企业项目经理;目前担任eoeandroid和ophonesdn版主;中国移动开发者社区OPhone专家;51CTO客作专家;CSDN博客专家。曾领导并参与开发了多个大中型项目。目前主要从事Android及其相关产品的研发。从2005年进入写作领域以来,为《程序员》、《电脑编程技巧与维护》、《电脑报》、IT168、天极网等平面媒体和网络媒体撰写了一百多篇原创技术和评论文章。并在个人blog(http://nokiaguy.blogjava.net)上发表了大量的原创技术文章。2007年获《电脑编程技巧与维护》优秀作者。2009年获得OPhone征文大赛二等奖。个人著作:《Android/OPhone开发完全讲义》、《人人都玩开心网:Ext JS+Android+SSH整合开发Web与移动SNS》、《Java Web开发速学宝典》。
     

    (声明:本网的新闻及文章版权均属OPhone SDN网站所有,如需转载请与我们编辑团队联系。任何媒体、网站或个人未经本网书面协议授权,不得进行任何形式的转载。已经取得本网协议授权的媒体、网站,在转载使用时请注明稿件来源。)

  • 版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

    相关推荐