Web Service 运行原理详细介绍_java

     利用清明小假期,温习了一遍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服务请求者。(绑定)

  

图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服务的基本工作原理。

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

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索web
, service
, 运行原理
, 运行原理详解
运行原理解析
webservice运行原理、webservice详细、webservice原理流程图、webservice原理、webservice工作原理,以便于您获取更多的相关知识。

时间: 2024-07-28 21:41:17

Web Service 运行原理详细介绍_java的相关文章

Web Service单元测试工具实例介绍之SoapUI

原文  Web Service单元测试工具实例介绍之SoapUI SoapUI是当前比较简单实用的开源Web Service测试工具,提供桌面应用程序和IDE插件程序两种使用方式.能够快速构建项目和组织测试用例是该工具的一大特性,下面将通过实例介绍如果使用SoapUI进行Web Service单元测试. l        构建项目 SoapUI工具中的项目(Project)是由一个或多个Web Service组成的,这里我们以"中国电视节目预告 Web 服务: http://www.webxml

Docker 存储驱动详细介绍_java

Docker 存储驱动详细介绍 最近做项目,期间对Docker 存储驱动不会,于是在网上找资料,并解决了,这里就记录下. 目的 理解docker的存储方式 docker的image和container在host上的目录结构 docker image和container的内容与配置不同存储 Docker是一个开源的应用容器引擎,主要利用Linux内核namespace实现沙盒隔离,用Cgroup实现资源限制.Docker用于统一开发和部署的轻量级 Linux 容器,试图解决"依赖地狱"问

Android Service总结及详细介绍_Android

1.Service的种类 按运行地点分类: 类别 区别  优点 缺点   应用 本地服务(Local) 该服务依附在主进程上,  服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要IPC,也不需要AIDL.相应bindService会方便很多.  主进程被Kill后,服务便会终止.  非常常见的应用如:HTC的音乐播放服务,天天动听音乐播放服务. 远程服务(Remote) 该服务是独立的进程,  服务为独立的进程,对应进程名格式为所在包名

IISExpress 配置允许外部访问详细介绍_java

 IISExpress 配置允许外部访问详细介绍 1.找到IISExpress的配置文件,位于 <文档>/IISExpress/config文件夹下,打开applicationhost.config,找到如下代码: <site name="WebSite1" id="1" serverAutoStart="true"> <application path="/"> <virtualDi

JAVA和JAVAC 命令详细介绍_java

JAVA和JAVAC 命令 javac和java命令行中的-classpath选项 这是个很基础的问题,但是因为基本上都是用现有的IDE工具 来开发java程序,所以很少有人意识到这一点. javac -classpath,设定要搜索类的路径,可以是目录,jar文件,zip文件(里面都是class文件),会覆盖掉所有在CLASSPATH里面的设定. -sourcepath, 设定要搜索编译所需java 文件的路径,可以是目录,jar文件,zip文件(里面都是java文件). 所以一个完整的jav

Java类加载基本过程详细介绍_java

Java类加载基本过程详细介绍 基本过程: 根据类的全限定名称加载定义类的二进制字节流. 将字节流代表的静态存储结构转化为方法区的运行时数据结构 内存中生成一个代表这个类的java.lang.Class对象,作为方法去这个类的各种数据访问入口  数组类本身不通过类加载器创建,由java虚拟机直接创建,数组类的元素类型由类加载器加载. 数组类的元素类型:数组去掉所有维度后的类型,  文件格式验证: 0xCAFEBABY 魔数开头: 主次版本号当前虚拟机可处理: 常量类型: 索引执行类型: utf8

Java 高并发五:JDK并发包1详细介绍_java

在[高并发Java 二] 多线程基础中,我们已经初步提到了基本的线程同步操作.这次要提到的是在并发包中的同步控制工具. 1. 各种同步控制工具的使用 1.1 ReentrantLock ReentrantLock感觉上是synchronized的增强版,synchronized的特点是使用简单,一切交给JVM去处理,但是功能上是比较薄弱的.在JDK1.5之前,ReentrantLock的性能要好于synchronized,由于对JVM进行了优化,现在的JDK版本中,两者性能是不相上下的.如果是简

JAVA JNI函数的注册过程详细介绍_java

JAVA JNI函数的注册过程详细介绍 我们在java中调用Native code的时候,一般是通过JNI来实现的,我们只需要在java类中加载本地.so库文件,并声明native方法,然后在需要调用的地方调用即可,至于java中native方法的具体实现,全部交给了Native层.我们要在java中正确地调用到本地代码中对应函数的前提是什么呢?答案就是通过一定的机制建立java中native方法和本地代码中函数的一一对应关系,那么这种机制是什么呢?就是JNI函数的注册机制. JNI函数的注册有

java Spring 5 新特性函数式Web框架详细介绍_java

java Spring 5 新特性函数式Web框架 举例 我们先从示例应用程序的一些摘录开始.下面是暴露Person对象的响应信息库.很类似于传统的,非响应信息库,只不过它返回Flux<Person>而传统的返回List<Person>,以及返回Mono<Person>的地方返回Person.Mono<Void>用作完成标识:指出何时保存被完成. public interface PersonRepository { Mono<Person> g