Web Service技术的SOAP实现

7 篇文章 0 订阅

写在前面的话:本文章由刘源师兄分享,非我原创。此处仅作学习记录之用。

0 SOA

  • SOA

    SOA(Service-Oriented Architecture,面向服务架构):SOA的提出是在企业计算领域,就是要将紧耦合的系统,划分为面向业务的,粗粒度,松耦合,无状态的服务。服务发布出来供其他服务调用,一组互相依赖的服务就构成了SOA架构下的系统。

    SOA来源于早期的基于组件的分布式计算方式,在OMG和IONA的推动下,成为一个大家所广泛认可的规范。

    SOA的优势在于它的高可复用性、灵活性,以及更好的扩展性和可用性。

    SOA架构:
    SOA架构

  • 服务

    一种可重复的业务活动的逻辑上的描述,是一种自包含的、可组合的“黑盒子”。

  • SOA与Web Service

    SOA是一种思想,它是一个架构理念,Web Service是实现它的技术方法。

1 简介

1.1 提出

许多企业或组织使用多个系统进行业务管理,这些系统可能运行在不同的操作系统或使用不同的编程语言开发。为了使得系统间可以通信,实现信息共享,迫切需要一种跨语言跨平台的应用或设备间通信技术。

引子:物联网——智能家居——远程控制——Web Service

1.2 定义

W3C定义

Web Service是一种软件系统,旨在通过网络支持可互操作的机器间的交互。它有一个以机器可处理的格式(具体是WSDL)描述的界面。 其他系统使用SOAP消息按照其描述中指定的方式与Web Service进行交互,一般通过将包含序列化XML的HTTP与其他 Web相关标准一起使用进行传输。

A Web service is a software system designed to support interoperable machine-to-machine interaction over a network. It has an interface described in a machine-processable format (specifically WSDL). Other systems interact with the Web service in a manner prescribed by its description using SOAP messages, typically conveyed using HTTP with an XML serialization in conjunction with other Web-related standards.

— W3C

维基百科定义

Web Service是一台电子设备向另一台电子设备提供的服务,使得彼此间可以通过万维网通信。在Web Service中,Web技术(例如,最初设计用于人机对话的HTTP)被用于机器到机器的通信,更具体地说,用于传送诸如XML和JSON的机器可读文件格式。

A web service is a service offered by an electronic device to another electronic device, communicating with each other via the World Wide Web. In a web service, the Web technology such as HTTP—originally designed for human-to-machine communication—is utilized for machine-to-machine communication, more specifically for transferring machine-readable file formats such as XML and JSON.

— Wikiwand

通俗的说,Web Service是一种实现SOA的技术,通过标准的Web协议提供服务,目的是保证不同平台的应用程序可以互操作。

1.3 特点

完整的封装性:服务请求者只能看到服务中的方法列表,方法的实现对请求者是透明的。

松耦合:服务提供者崩溃,不会导致服务请求者崩溃。每个服务都是自包含且逻辑独立的。

使用标准协议规范:XML、HTTP。

高度可互操作性:跨平台(操作系统)、跨语言(编程语言)。

高度可集成能力:可集成多个Web Service满足业务需求。

动态性:可自动发现服务并进行调用。

1.4 主要实现方式

  • XML-RPC

  • SOAP

    XML-RPC的修改版,比XML-RPC更强大。成熟度高。若无特别指明,Web Service一般指用SOAP实现的Web Service。

  • REST

    效率性能好,但安全性比SOAP差。

1.5 架构

[Web Service架构

Web services architecture: the service provider sends a WSDL file to UDDI. The service requester contacts UDDI to find out who is the provider for the data it needs, and then it contacts the service provider using the SOAP protocol. The service provider validates the service request and sends structured data in an XML file, using the SOAP protocol. This XML file would be validated again by the service requester using an XSD file.

1.6 组成元素

1.6.1 WSDL
  • 定义

    WSDL(Web Services Description Language,网络服务描述语言) ,WDSL文件是一个XML文档,用来描述某个 Web service。它可规定服务的位置,以及此服务提供的操作(或方法)。

  • 语法

元素定义
\web service 使用的数据类型
\web service 使用的消息
\web service 执行的操作
\web service 使用的通信协议

- 基本结构实例
WSDL

  • 详细结构实例

    以getTestData方法为例:

    binding元素描述了getTestData方法及其输入输出消息getDataRequest、getTestDataResponse;

    message元素描述getDataRequest、getTestDataResponse对应的类型getTestData、getTestDataResponse;

    types元素描述getTestData、getTestDataResponse对应的数据类型string、ArrayOfTestData的详细信息。

这里写图片描述

1.6.2 SOAP
  • 定义

    SOAP(Simple Object Access Protocol,简单对象访问协议)是一种基于XML的独立于平台和语言的的简单灵活的轻量级通信协议,用于在分散或分布式的环境中通过HTTP交换信息。

    备注:除HTTP外,还可使用FTP、SMTP等其他协议。

  • 语法

    • 构建结构

    一条 SOAP 消息就是一个普通的 XML 文档,包含下列元素:

    1. 必需的 Envelope 元素,可把此 XML 文档标识为一条 SOAP 消息
    2. 可选的 Header 元素,包含头部信息
    3. 必需的 Body 元素,包含所有的调用和响应信息
    4. 可选的 Fault 元素,提供有关在处理此消息所发生错误的信息

    所有以上的元素均被声明于针对 SOAP 封装的默认命名空间中:http://www.w3.org/2001/12/soap-envelope
    以及针对 SOAP 编码和数据类型的默认命名空间:http://www.w3.org/2001/12/soap-encoding

    • 语法规则

    一些重要的语法规则:

    1. SOAP 消息必须用 XML 来编码
    2. SOAP 消息必须使用 SOAP Envelope 命名空间
    3. SOAP 消息必须使用 SOAP Encoding 命名空间
    4. SOAP 消息不能包含 DTD 引用
    5. SOAP 消息不能包含 XML 处理指令

      • 消息基本结构实例
    <?xml version="1.0"?>
    <soap:Envelope
    xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
    soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
    
    <soap:Header>
      ...
      ...
    </soap:Header>
    
    <soap:Body>
      ...
      ...
      <soap:Fault>
        ...
        ...
      </soap:Fault>
    </soap:Body>
    
    </soap:Envelope>
  • 请求与应答示例实例

    遵守 SOAP 编码规则的 HTTP 请求/响应。SOAP=HTTP+XML,即采用 HTTP 作为底层通信协议,XML 作为数据传送的格式,允许服务提供者和服务消费者经过防火墙在因特网上进行通信交互。

    SOAP 请求

    POST /InStock HTTP/1.1
    Host: www.example.org
    Content-Type: application/soap+xml; charset=utf-8
    Content-Length: nnn
    
    <?xml version="1.0"?>
    <soap:Envelope
    xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
    soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
    
    <soap:Body xmlns:m="http://www.example.org/stock">
      <m:GetStockPrice>
        <m:StockName>IBM</m:StockName>
      </m:GetStockPrice>
    </soap:Body>
    
    </soap:Envelope>

    SOAP 响应

    HTTP/1.1 200 OK
    Content-Type: application/soap+xml; charset=utf-8
    Content-Length: nnn
    
    <?xml version="1.0"?>
    <soap:Envelope
    xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
    soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
    
    <soap:Body xmlns:m="http://www.example.org/stock">
      <m:GetStockPriceResponse>
        <m:Price>34.5</m:Price>
      </m:GetStockPriceResponse>
    </soap:Body>
    
    </soap:Envelope>
1.6.3 UDDI
  • 定义

    UDDI (Universal Description, Discovery and Integration,通用描述、发现与集成)提供一种由 WSDL 描述的目录服务,企业可以使用它对 Web Service 进行注册和搜索。

2 发布

2.1 Java平台

2.1.1 JAX-WS

JAX-WS(Java API for XML Web Services)作为Java EE的组成部分,是Java语言中一个用来创建Web Service的API,尤其是SOAP形式的Web Service。

  • 服务端——定义接口

    package com.ouc.iot.demo.service;
    
    import javax.jws.WebMethod;
    import javax.jws.WebParam;
    import javax.jws.WebResult;
    import javax.jws.WebService;
    import javax.jws.soap.SOAPBinding;
    
    /**
    * web Service JAX-WS方式实现demo
    * @author IoT
    */
    @WebService
    @SOAPBinding(style = SOAPBinding.Style.RPC)
    public interface SayHiService {
    
    /**
     * @param name 问候人
     * @return 包含name的问候语
     */
    @WebMethod
        @WebResult(name="message")
    public String sayHiDefault(@WebParam(name = "name") String name);
    }

  • 服务端——实现接口

    package com.ouc.iot.demo.service.impl;
    
    import javax.jws.WebService;
    
    import com.ouc.iot.demo.service.SayHiService;
    
    @WebService(endpointInterface = "com.ouc.iot.demo.service.SayHiService")
    public class SayHiSerimpl implements SayHiService{
        @Override
    public String sayHiDefault(String name){
        String str = "hi, " + name + "!";
        System.out.println(str);
        return str;
    }
    }

  • 服务端——发布接口

    package com.ouc.iot.demo.main;
    
    import javax.xml.ws.Endpoint;
    
    import com.ouc.iot.demo.service.impl.SayHiSerimpl;
    
    /**
    * 发布Web Service
    * @author IoT
    */
    public class Main {
    
    public static void main(String[] args) {
        Endpoint.publish("http://localhost:8080/webservice_jws/webservice", new SayHiSerimpl());
    }
    
    }

    浏览器查看WSDL

1
2
3
4

  • 客户端——调用接口

    生成客户端代码

    wsimport(Java自带工具)、Axis2 WSDL2java、CXF WSDL2java三种方式,下面以wsimport为例:

    wsimport http://localhost:8080/webservice_jws/webservice?wsdl -p com.ouc.iot.demo.service -s e:/ws
    
    #wsimport url路径 -p 自定义包名 -s 文件生成目录  
    
    package com.ouc.iot.demo;
    
    import java.net.MalformedURLException;
    import java.net.URL;
    
    import javax.xml.namespace.QName;
    import javax.xml.ws.Service;
    
    import com.ouc.iot.demo.service.SayHiService;
    
    /**
    * 测试JWS实现
    * 
    * @author IoT
    *
    */
    public class TestWB {
    
    public static void main(String[] args) {
        try {
            // 创建访问WSDL服务地址的URL
            URL url = new URL("http://localhost:8080/webservice_jws/webservice?wsdl");
            // 通过QName指明服务的和具体信息,在definitions元素获取
            QName sname = new QName("http://impl.service.demo.iot.ouc.com/", "SayHiSerimplService");
            // 创建服务
            Service service = Service.create(url, sname);
            // 实现接口
            SayHiService sayHiService = service.getPort(SayHiService.class);
            System.out.println(sayHiService.sayHiDefault("java"));
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }
    
    }
2.1.2 Axis2

Apache Axis2 是一个Web Service的核心引擎。作为Apache Axis的继任者,它对Apache Axis进行了重新设计和编写,并有Java和C两种实现版本。重量级的框架,功能强大。

Apache Axis2/Java官网:http://axis.apache.org/axis2/java/core/

Apache Axis2/C官网:http://axis.apache.org/axis2/c/core/

以下介绍“axis2插件导出.aar包,通过axis2+tomcat方式发布服务”方式

  • 將Axis2安装到Tomcat中

    Step1:下载axis2-war包,解压得到axis2.war。

    Step2:将axis2.war复制到tomcat\webapps下。

    Step3:进入tomcat\bin,通过tomcat7w.exe启动Tomcat。

    Step4:访问http://localhost:8080/axis2/,出现如下界面:

a

  • 安装axis2-eclipse插件

    Step1:下载axis2-eclipse-service-plugin.zip。

    Step2:将上述压缩包中,plugins文件夹中的jar包复制到eclipse\dropins下。

    Step3:重启Eclipse。

  • 服务端——定义接口

package com.ouc.iot.demo.service;

public interface SayHiService {
    /**
     * @param name 问候人
     * @return 包含name的问候语
     */
    public String sayHiDefault(String name);
}
  • 服务端——实现接口
package com.ouc.iot.demo.service.impl;

import com.ouc.iot.demo.service.SayHiService;

public class SayHiSerimpl implements SayHiService{
    @Override
    public String sayHiDefault(String name){
        String str = "hi, " + name + "!";
        System.out.println("Axis2:" + str);
        return str;
    }
}
  • 服务端——发布接口

    借助axis2插件,导出.aar包

    Step1:Eclipse-file-other-Axis2 Service Archiver。

    Step2:输入项目名\target\classes,勾选“Include .class files only”。

    Step3:Skip WSDL。

    Step4:若无额外包,直接跳过。

    Step5:勾选“Generate the service xml automatically”。

    Step6:输入接口名和完整的接口实现类名,选择要发布的方法。

    Step7:输入.arr包的名称与保存位置。

    Step8:启动Tomcat,访问http://localhost:8080/axis2/,点击Services,如下图:

b

c

  • 测试方法

d

  • 客户端——调用接口

    生成客户端代码

    下载axis2–bin.zip,解压后在bin目录下运行:

    wsdl2java -uri http://localhost:8080/axis2/services/SayHiSerimpl?wsdl -p com.ouc.iot.demo.service -o stub
    
    # -s 
    

    客户端代码生成:https://axis.apache.org/axis2/java/core/docs/

    package com.ouc.iot.demo;
    
    import com.ouc.iot.demo.service.SayHiSerimplStub;
    
    public class TestWB {
    
    public static void main(String[] args) {
        try {
            String url = "http://localhost:8080/axis2/services/SayHiSerimpl";
            SayHiSerimplStub stub = new SayHiSerimplStub(url);
            SayHiSerimplStub.SayHiDefault request = new SayHiSerimplStub.SayHiDefault();
            request.setName("axis2");
            SayHiSerimplStub.SayHiDefaultResponse response = stub.sayHiDefault(request);
            System.out.println(response.get_return());
        } catch (org.apache.axis2.AxisFault e) {
            e.printStackTrace();
        } catch (java.rmi.RemoteException e) {
            e.printStackTrace();
        }
    }
    }
    <dependency>
    <groupId>org.apache.axis2</groupId>
    <artifactId>axis2</artifactId>
    <version>1.7.6</version>
    <type>pom</type>
    </dependency>
    <dependency>
    <groupId>org.apache.axis2</groupId>
    <artifactId>org.apache.axis2.osgi</artifactId>
    <version>1.7.6</version>
    </dependency>

e

2.1.3 CXF

Apache CXF 是一个开源的Web Service框架,是Celtix项目和XFire项目结合的产物。 CXF使用前端编程APIs,比如JAX-WS and JAX-RS来构建和开发服务。

官网:http://cxf.apache.org/

客户端代码生成:http://cxf.apache.org/docs/wsdl-to-java.html

wsdl2java -p com.ouc.iot.demo.service -d src http://localhost:8090/webservice_jws/webservice?wsdl
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-frontend-jaxws</artifactId>
    <version>3.1.14</version>
</dependency>
<dependency>
     <groupId>org.apache.cxf</groupId>       
     <artifactId>cxf-rt-transports-http</artifactId>
     <version>3.1.14</version>
</dependency>)
package com.ouc.iot.demo;

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

import com.ouc.iot.demo.service.SayHiService;

public class TestWB {

    public static void main(String[] args) {
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setServiceClass(SayHiService.class);
        factory.setAddress("http://localhost:8090/webservice_jws/webservice");
        SayHiService sayHiService = factory.create(SayHiService.class);
        String welcome = sayHiService.sayHiDefault("CXF");
        System.out.println(welcome);
    }

}

g

2.2 .NET平台

2.3 Python平台

Spyne:http://spyne.io

3 多服务发布与自定义类的使用

使用Axis2发布,在项目根目录下建立META-INF文件夹,在其下编写services.xml,如下:

<?xml version="1.0" encoding="UTF-8"?>
<serviceGroup>
    <service name="SayHiService">
        <description>SayHiService</description>
        <parameter name="ServiceClass">com.ouc.iot.demo.service.impl.SayHiSerimpl</parameter>
        <operation name="sayHiDefault"><messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out" class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/></operation> -->
    </service>
    <service name="GetLocationInfoService">
        <description>GetLocationInfoService</description>
        <parameter name="ServiceClass">com.ouc.iot.demo.service.impl.GetLocationInfoSerImpl</parameter>
        <operation name="getLocationbyIP"><messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out" class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/></operation>
        <operation name="getLocationbyLngLat"><messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out" class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/></operation>
    </service>
</serviceGroup>

在导出.aar包时,选择services.xml,而非自动生成。注意:不允许中文字符存在。

服务端项目结构:
w

  • 客户端调用

    package com.ouc.iot.demo;
    
    import com.ouc.iot.demo.service.GetLocationInfoServiceStub;
    import com.ouc.iot.demo.service.SayHiServiceStub;
    
    public class TestWB {
    
    public static void main(String[] args) {
        try {
            String url = "http://localhost:8080/axis2/services/SayHiService";
            SayHiServiceStub stub = new SayHiServiceStub(url);
            SayHiServiceStub.SayHiDefault request = new SayHiServiceStub.SayHiDefault();
            request.setName("Axis2");
            SayHiServiceStub.SayHiDefaultResponse response = stub.sayHiDefault(request);
            System.out.println(response.get_return());
        } catch (org.apache.axis2.AxisFault e) {
            e.printStackTrace();
        } catch (java.rmi.RemoteException e) {
            e.printStackTrace();
        }
    
        try {
            String url = "http://localhost:8080/axis2/services/GetLocationInfoService";
            GetLocationInfoServiceStub stub = new GetLocationInfoServiceStub(url);
            GetLocationInfoServiceStub.GetLocationbyIP ip_request = new GetLocationInfoServiceStub.GetLocationbyIP();
            ip_request.setIp("127.0.0.1");
            GetLocationInfoServiceStub.GetLocationbyIPResponse ip_response = stub.getLocationbyIP(ip_request);
            System.out.println(ip_response.get_return());
        } catch (org.apache.axis2.AxisFault e) {
            e.printStackTrace();
        } catch (java.rmi.RemoteException e) {
            e.printStackTrace();
        }
        //复杂数据交互
        try {
            String url = "http://localhost:8080/axis2/services/GetLocationInfoService";
            GetLocationInfoServiceStub stub = new GetLocationInfoServiceStub(url);
            GetLocationInfoServiceStub.GetLocationbyLngLat lnglat_request = new GetLocationInfoServiceStub.GetLocationbyLngLat();
            //形参赋值
            GetLocationInfoServiceStub.LngandLatDTO lngandLatDTO = new GetLocationInfoServiceStub.LngandLatDTO();
            lngandLatDTO.setLongitude("E120度33分00秒");
            lngandLatDTO.setLatitude("N36度07分00秒");
            lnglat_request.setLngandLatDTO(lngandLatDTO);
            //请求
            GetLocationInfoServiceStub.GetLocationbyLngLatResponse lnglat_response = stub.getLocationbyLngLat(lnglat_request);
            //输出
            System.out.println(lnglat_response.get_return().getCode());
            System.out.println(lnglat_response.get_return().getCountry() + ", " + 
                    lnglat_response.get_return().getProvince() + ", " + 
                    lnglat_response.get_return().getCity());
        } catch (org.apache.axis2.AxisFault e) {
            e.printStackTrace();
        } catch (java.rmi.RemoteException e) {
            e.printStackTrace();
        }
    }
    }

4 管理

登录Axis2的控制台,默认用户名是’admin’,默认密码是’axis2’。可在AXIS2_HOME/conf/axis2.xml文件中修改,如下:

<parameter name="userName">admin</parameter>
<parameter name="password">axis2</parameter>

登录后,界面如下:

y3

4.1 热部署与热更新

热部署:部署新的.aar包。

热更新:更新已存在的(即同名的).arr包。若热更新关闭,虽然也会替换同名.aar,但必须要Tomcat重启才可以生效。

热部署默认启用,热更新默认禁用,可在axis2.xml中修改配置启用热更新:

<parameter name="hotdeployment">true</parameter>
<parameter name="hotupdate">true</parameter>

点击左侧Tools—Upload Service进行服务的热部署和热更新:

t8

4.2 服务的禁用与启用

注意:以下三项操作均是临时性的,当web服务器重启后,所有修改失效。

禁用服务:将服务的Service Status变为’Inactive’。

点击左侧Services—Deactive Service,界面如下:

55

启用服务:将服务的Service Status变为’Active’。

点击左侧Services—Active Service,界面如下:

56

编辑参数:编辑Service Parameters与Operation Parameters。

点击左侧Services—Edit Parameters

57

4.3 移除服务

将服务从列表中移除,移除后不可还原。但重启Tomcat,移除失效。

操作如下:

59

5 TO-DO

  • [ ] 安全性
    • [ ] WS-Security
  • [ ] 与Web应用集成的发布方式
    • [ ] JAX-WS基于Web容器发布Web Service
    • [ ] CXF基于Web容器发布Web Service
  • [ ] 客户端调用
    • [ ] JAX-WS、Axis2、CXF间服务的相互调用
    • [ ] 异步调用
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值