欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Web Service 运行原理详细介绍

程序员文章站 2024-03-31 20:57:04
     利用清明小假期,温习了一遍web service的相关内容,对其工作原理进行了简要总结。以供有需求的朋友和自己日后参考。文...

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

      web服务中,我们应该首先了解相关的术语含义:wsdl、uddi....相关术语方面的介绍在此不再赘述,重点放在原理上。
在web服务中,存在三个角色:服务提供者、服务请求者和服务中介,三者之间的关系如图1-1所示

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

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

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

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

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

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

   Web Service 运行原理详细介绍

图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服务

/** 
* 通过soap1.1协议调用web服务 
* 
* text/xml 这是基于soap1.1协议 
* 
* @param wsdl wsdl路径 
* @param method方法名 
* @param namespace命名空间 
* @param headerparameters 头参数 
* @param bodyparameters  体参数 
* @param isbodyparametersns 体参数是否有命名空间 
* @return string 
* @throws exception 
*/ 
public static string invokebysoap11(string wsdl, string method, 
string namespace, map<string, string> headerparameters, 
map<string, string> bodyparameters, boolean isbodyparametersns) 
throws exception { 
stringbuffer soapofresult = null; 
 
// 去除 ?wsdl,获取方法列表 
int length = wsdl.length(); 
wsdl = wsdl.substring(0, length - 5); 
//以字符串为参数创建url实例 
url url = new url(wsdl); 
//创建连接 
httpurlconnection conn = (httpurlconnection) url.openconnection(); 
//设置请求方式 
conn.setrequestmethod("post"); 
//如果打算使用 url连接进行输入,则将 doinput 标志设置为 true 
conn.setdoinput(true); 
//如果打算使用 url连接进行输出,则将 doinput 标志设置为 true 
conn.setdooutput(true); 
//主要是设置httpurlconnection请求头里面的属性(k-v) 
conn.setrequestproperty("content-type", "text/xml;charset=utf-8"); 
//获取输入流(相对于客户端来说,使用的是outputstream) 
outputstream out = conn.getoutputstream(); 
// 获取soap1.1版本消息 
stringbuilder sb = new stringbuilder(); 
sb.append("<soap:envelope xmlns:xsi=\"http://www.w3.org/2001/xmlschema-instance\"  
xmlns:xsd=\"http://www.w3.org/2001/xmlschema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" "); 
sb.append("xmlns:ns0=\"" + namespace + "\""); 
sb.append(">"); 
//拼装消息头 
if (headerparameters != null) { 
sb.append("<soap:header>"); 
for (entry<string, string> headerparameter : headerparameters 
.entryset()) { 
sb.append("<ns0:"); 
sb.append(headerparameter.getkey()); 
sb.append(">"); 
sb.append(headerparameter.getvalue()); 
sb.append("</ns0:"); 
sb.append(headerparameter.getkey()); 
sb.append(">"); 
} 
sb.append("</soap:header>"); 
} 
//拼装消息体 
sb.append("<soap:body><ns0:"); 
sb.append(method); 
sb.append(">"); 
// 输入参数 
if (bodyparameters != null) { 
for (entry<string, string> inputparameter : bodyparameters 
.entryset()) { 
if (isbodyparametersns) { 
sb.append("<ns0:"); 
sb.append(inputparameter.getkey()); 
sb.append(">"); 
sb.append(inputparameter.getvalue()); 
sb.append("</ns0:"); 
sb.append(inputparameter.getkey()); 
sb.append(">"); 
} else { 
sb.append("<"); 
sb.append(inputparameter.getkey()); 
sb.append(">"); 
sb.append(inputparameter.getvalue()); 
sb.append("</"); 
sb.append(inputparameter.getkey()); 
sb.append(">"); 
} 
} 
} 
sb.append("</ns0:"); 
sb.append(method); 
sb.append("></soap:body></soap:envelope>"); 
//测试用 
system.out.println(sb.tostring()); 
//写入soap消息(相对于客户端来说,使用的是out.write()) 
out.write(sb.tostring().getbytes()); 
//获取服务器端的相应 
int code = conn.getresponsecode(); 
if (code == 200) { 
inputstream is = conn.getinputstream(); 
byte[] b = new byte[1024]; 
int len = 0; 
soapofresult = new stringbuffer(); 
//从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。以整数形式返回实际读取的字节数 
//如果因为流位于文件末尾而没有可用的字节,则返回值 -1; 
while ((len = is.read(b)) != -1) { 
//converts the byte array to a string using the named charset.  
string s = new string(b, 0, len, "utf-8"); 
soapofresult.append(s); 
} 
} 
conn.disconnect(); 
return soapofresult == null ? null : soapofresult.tostring(); 
} 

    注:在客户端发送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数据后会进行相应的解析操作。如下:

// 将soap协议进行解析(dom解析只能用于解析xml文档类型,而soap消息就是采用xml数据格式) 
document doc = xmlutil.string2doc(result); 
element ele = (element) doc.getelementsbytagname("return").item(0); 
方法中使用到的string2doc()方法体如下: 
public static document string2doc(string str) { 
//将xml文档解析成dom树 
documentbuilderfactory factory = documentbuilderfactory.newinstance(); 
document document = null; 
documentbuilder build; 
if (str == null || str.equals("")) { 
return null; 
} 
try { 
inputstream bais = new bytearrayinputstream(str.getbytes("utf-8")); 
build = factory.newdocumentbuilder(); 
//parse the content of the given inputstream as an xml document and return a new dom document object.  
document = build.parse(bais); 
} catch (exception e) { 
e.printstacktrace(); 
} 
return document; 
} 

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

    以上是web服务的基本工作原理。

    感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!