Web Service进阶(一)运行原理

举报
SHQ5785 发表于 2020/12/30 01:13:06 2020/12/30
【摘要】       利用清明小假期,温习了一遍Web Service的相关内容,对其工作原理进行了简要总结。以供有需求的朋友和自己日后参考。文章若有不当之处,敬请朋友们提出宝贵建议,以求共勉。       Web服务中,我们应该首先了解相关的术语含义:WSDL、UDDI....相关术语方面的介绍在此不再赘述,重点放在原理上。 在Web服务中,存在三个角色:服务提供者、服务请求者和...

      利用清明小假期,温习了一遍Web Service的相关内容,对其工作原理进行了简要总结。以供有需求的朋友和自己日后参考。文章若有不当之处,敬请朋友们提出宝贵建议,以求共勉。

      Web服务中,我们应该首先了解相关的术语含义:WSDL、UDDI....相关术语方面的介绍在此不再赘述,重点放在原理上。

在Web服务中,存在三个角色:服务提供者、服务请求者和服务中介,三者之间的关系如图1-1所示:(摘录自:http://www.cnblogs.com/Jessy/p/3528341.html)。

    实现一个完整的Web服务包括以下步骤:

   ◆ Web服务提供者设计实现Web服务,并将调试正确后的Web服务通过Web服务中介者发布,并在UDDI注册中心注册; (发布)

   ◆ Web服务请求者向Web服务中介者请求特定的服务,中介者根据请求查询UDDI注册中心,为请求者寻找满足请求的服务; (发现)

   ◆ Web服务中介者向Web服务请求者返回满足条件的Web服务描述信息,该描述信息用WSDL写成,各种支持Web服务的机器都能阅读;(发现)

   ◆ 利用从Web服务中介者返回的描述信息(WSDL)生成相应的SOAP消息,发送给Web服务提供者,以实现Web服务的调用;(绑定)

   ◆ Web服务提供者按SOAP消息执行相应的Web服务,并将服务结果返回给Web服务请求者。(绑定)

  

图1-1 Web service的体系结构

注:WSDL的作用就是一个Web服务说明书。服务请求者根据此WSDL生成相应的SOAP消息,服务提供者在收到SOAP请求消息后,

进行服务的绑定。

以下代码是在web.xml中的servlet配置

<!-- 在向servlet或JSP页面制定初始化参数或定制URL时,必须首先命名servlet或JSP页面。Servlet元素就是用来完成此项任务的。 -->
<servlet>
<servlet-name>UserService</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
<!-- 标记容器是否在启动的时候就加载这个servlet(实例化并调用其init()方法;正数的值越小,该servlet的优先级越高,应用启动时就越先加载 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 服务器一般为servlet提供一个缺省的URL:http://host/webAppPrefix/servlet/ServletName。

但是,常常会更改这个URL,以便servlet可以访问初始化参数或更容易地处理相对URL。在更改缺省URL时,使用servlet-mapping元素。 -->
<servlet-mapping>
<servlet-name>UserService</servlet-name>
<!-- 描述了相对于Web应用的根目录的URL。url-pattern元素的值必须以斜杠(/)起始。 -->
<url-pattern>/user</url-pattern>
</servlet-mapping>

红色代码部分很重要,会在Web容器启动的时候加载相应的servlet。绿色部分为该服务的外部接口。以此找到相应的jax-ws.xml文件(如下所示)

<endpoint name="UserPort" implementation="cn.ujn.service.UserService"
url-pattern="/user">
</endpoint>

进而绑定到相关的相应的实现类cn.ujn.service.UserService中。客户端发送的SOAP请求消息消息体body中包含有客户端所请求的方法名和参数信息。

以下为客户端封装的soap消息体(以Json方式与服务端进行数据传输)(SOAP Rerquest Envelope):

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:q0="http://ujn.cn/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

 

-    <soapenv:Body>
-    <q0:login>
         <arg0>{"username":"shq","password":"shq"}</arg0>
  </q0:login>
  </soapenv:Body>
  </soapenv:Envelope>

以下为SOAP1.1协议调用Web服务

 


  
  1. /**
  2. * 通过SOAP1.1协议调用Web服务
  3. *
  4. * text/xml 这是基于soap1.1协议
  5. *
  6. * @param wsdl WSDL路径
  7. * @param method方法名
  8. * @param namespace命名空间
  9. * @param headerParameters 头参数
  10. * @param bodyParameters 体参数
  11. * @param isBodyParametersNS 体参数是否有命名空间
  12. * @return String
  13. * @throws Exception
  14. */
  15. public static String invokeBySoap11(String wsdl, String method,
  16. String namespace, Map<String, String> headerParameters,
  17. Map<String, String> bodyParameters, boolean isBodyParametersNS)
  18. throws Exception {
  19. StringBuffer soapOfResult = null;
  20. // 去除 ?wsdl,获取方法列表
  21. int length = wsdl.length();
  22. wsdl = wsdl.substring(0, length - 5);
  23. //以字符串为参数创建URL实例
  24. URL url = new URL(wsdl);
  25. //创建连接
  26. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  27. //设置请求方式
  28. conn.setRequestMethod("POST");
  29. //如果打算使用 URL连接进行输入,则将 DoInput 标志设置为 true
  30. conn.setDoInput(true);
  31. //如果打算使用 URL连接进行输出,则将 DoInput 标志设置为 true
  32. conn.setDoOutput(true);
  33. //主要是设置HttpURLConnection请求头里面的属性(K-V)
  34. conn.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
  35. //获取输入流(相对于客户端来说,使用的是OutputStream)
  36. OutputStream out = conn.getOutputStream();
  37. // 获取soap1.1版本消息
  38. StringBuilder sb = new StringBuilder();
  39. sb.append("<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
  40. xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" ");
  41. sb.append("xmlns:ns0=\"" + namespace + "\"");
  42. sb.append(">");
  43. //拼装消息头
  44. if (headerParameters != null) {
  45. sb.append("<soap:Header>");
  46. for (Entry<String, String> headerParameter : headerParameters
  47. .entrySet()) {
  48. sb.append("<ns0:");
  49. sb.append(headerParameter.getKey());
  50. sb.append(">");
  51. sb.append(headerParameter.getValue());
  52. sb.append("</ns0:");
  53. sb.append(headerParameter.getKey());
  54. sb.append(">");
  55. }
  56. sb.append("</soap:Header>");
  57. }
  58. //拼装消息体
  59. sb.append("<soap:Body><ns0:");
  60. sb.append(method);
  61. sb.append(">");
  62. // 输入参数
  63. if (bodyParameters != null) {
  64. for (Entry<String, String> inputParameter : bodyParameters
  65. .entrySet()) {
  66. if (isBodyParametersNS) {
  67. sb.append("<ns0:");
  68. sb.append(inputParameter.getKey());
  69. sb.append(">");
  70. sb.append(inputParameter.getValue());
  71. sb.append("</ns0:");
  72. sb.append(inputParameter.getKey());
  73. sb.append(">");
  74. } else {
  75. sb.append("<");
  76. sb.append(inputParameter.getKey());
  77. sb.append(">");
  78. sb.append(inputParameter.getValue());
  79. sb.append("</");
  80. sb.append(inputParameter.getKey());
  81. sb.append(">");
  82. }
  83. }
  84. }
  85. sb.append("</ns0:");
  86. sb.append(method);
  87. sb.append("></soap:Body></soap:Envelope>");
  88. //测试用
  89. System.out.println(sb.toString());
  90. //写入SOAP消息(相对于客户端来说,使用的是out.write())
  91. out.write(sb.toString().getBytes());
  92. //获取服务器端的相应
  93. int code = conn.getResponseCode();
  94. if (code == 200) {
  95. InputStream is = conn.getInputStream();
  96. byte[] b = new byte[1024];
  97. int len = 0;
  98. soapOfResult = new StringBuffer();
  99. //从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。以整数形式返回实际读取的字节数
  100. //如果因为流位于文件末尾而没有可用的字节,则返回值 -1;
  101. while ((len = is.read(b)) != -1) {
  102. //Converts the byte array to a string using the named charset.
  103. String s = new String(b, 0, len, "UTF-8");
  104. soapOfResult.append(s);
  105. }
  106. }
  107. conn.disconnect();
  108. return soapOfResult == null ? null : soapOfResult.toString();
  109. }

 

注:在客户端发送SOAP请求消息后便处于阻塞状态。直至服务端返回状态码。

以下为服务端进行响应(SOAP Response Envelope):

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">

 

-<S:Body>
-<ns2:loginResponse xmlns:ns2=" http://ujn.cn/">
  <return>1</return>
</ns2:loginResponse>
  </S:Body>
</S:Envelope>

    客户端接收到服务端发来的Json数据后会进行相应的解析操作。如下:

 


  
  1. // 将Soap协议进行解析(DOM解析只能用于解析XML文档类型,而SOAP消息就是采用XML数据格式)
  2. Document doc = XmlUtil.string2Doc(result);
  3. Element ele = (Element) doc.getElementsByTagName("return").item(0);
  4. 方法中使用到的string2Doc()方法体如下:
  5. public static Document string2Doc(String str) {
  6. //将XML文档解析成DOM树
  7. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  8. Document document = null;
  9. DocumentBuilder build;
  10. if (str == null || str.equals("")) {
  11. return null;
  12. }
  13. try {
  14. InputStream bais = new ByteArrayInputStream(str.getBytes("UTF-8"));
  15. build = factory.newDocumentBuilder();
  16. //Parse the content of the given InputStream as an XML document and return a new DOM Document object.
  17. document = build.parse(bais);
  18. } catch (Exception e) {
  19. e.printStackTrace();
  20. }
  21. return document;
  22. }

 

    根据返回结果,客户端再进行相应的处理。

    以上是web服务的基本工作原理。在此感谢实验室徐师兄的技术支持。

文章来源: shq5785.blog.csdn.net,作者:No Silver Bullet,版权归原作者所有,如需转载,请联系作者。

原文链接:shq5785.blog.csdn.net/article/details/44916035

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。