加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

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

发布时间:2020-12-17 00:58:15 所属栏目:安全 来源:网络整理
导读:对于byte字节数组来说,Axis2会自动将其序列化,然后使用Base64编码格式进行传输,因此,在服务端可以直接使用byte[]作为参数类型或返回值的类型。在下面的内容我们将会看到如何使用byte[]来重新改写服务端的程序。 服务端直接使用byte[] 在上一篇文章中,服

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

服务端直接使用byte[]

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

?

view plain copy to clipboard print ?
  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网站所有,如需转载请与我们编辑团队联系。任何媒体、网站或个人未经本网书面协议授权,不得进行任何形式的转载。已经取得本网协议授权的媒体、网站,在转载使用时请注明稿件来源。)

  • (编辑:李大同)

    【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

      推荐文章
        热点阅读