聊聊日常开发中,如何对接WebService协议?

共 10449字,需浏览 21分钟

 ·

2021-09-17 21:21

嗨,大家好,今天想跟大家聊聊关于WebService这门技术,我在工作中,会经常对接一些第三方协议,很多都是WebService协议,那么接下来,我们就一起来深入了解一下这门技术吧,还是从基本概念及原理讲起,然后再讲实例运用。

我们围绕着WebService是什么,WebService原理,WebService怎么用呢?这三个方面来阐述。

希望你们能认真看完,对你工作中应该会有帮助的。记得点赞、关注哟。

WebService是什么

WebService是一种跨编程语言、跨操作系统平台的远程调用技术。

远程调用技术:远程调用是指一台设备上的程序A可以调用另一台设备上的方法B。比如,天气预报系统,淘宝网,校内网,百度等把自己的系统服务以WebService服务的形式暴露出来,让第三方网站和程序可以调用这些服务功能,这样扩展了自己系统的市场占有率。

跨编程语言:是指服务端、客户端程序的编程语言可以不同。

跨操作系统平台:是指服务端、客户端可在不同的操作系统上运行。

WebService 能解决:跨平台调用、跨语言调用、远程调用。

WebService原理

WebService遵循SOAP协议通过XML封装数据,然后由Http协议来传输数据。


WebService服务器端首先要通过一个WSDL文件来说明自己有什么服务可以对外调用。简单的说,WSDL就像是一个说明书,用于描述WebService及其方法、参数和返回值。WSDL文件保存在Web服务器上,通过一个url地址就可以访问到它。

客户端要调用一个WebService服务之前,要知道该服务的WSDL文件的地址。

WebService服务提供商可以通过两种方式来暴露它的WSDL文件地址:1、注册到UDDI服务器,以便被人查找;2、直接告诉给客户端调用者。

SOAP协议

SOAP 是基于 XML 的简易协议,可使应用程序在 HTTP 之上进行信息交换。或者更简单地说:SOAP 是用于访问网络服务的协议。

SOAP 消息的基本结构

<?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 消息就是一个普通的 XML 文档,包含下列元素:

  • 必需的 Envelope 元素,可把此 XML 文档标识为一条 SOAP 消息

  • 可选的 Header 元素,包含头部信息

  • 必需的 Body 元素,包含所有的调用和响应信息

  • 可选的 Fault 元素,提供有关在处理此消息所发生错误的信息

WSDL

WSDL(Web Services Description Language), web服务描述语言,它是webservice服务端使用说明书,说明服务端接口、方法、参数和返回值,WSDL是随服务发布成功,自动生成,无需编写。

一个 WSDL 文档的主要结构是类似这样的

<definitions>

<types>
data type definitions........
</types>

<message>
definition of the data being communicated....
</message>

<portType>
set of operations......
</portType>

<binding>
protocol and data format specification....
</binding>

<service>
........
</service>

</definitions>
复制代码

WSDL文档应该从下往上阅读:

Service:相关端口的集合,包括其关联的接口、操作、消息等。

Binding:特定端口类型的具体协议和数据格式规范。

portType:服务端点,描述 web service可被执行的操作方法,以及相关的消息,通过binding指向portType。

message:定义一个操作(方法)的数据参数。

types:定义 web service 使用的全部数据类型。

UDDI

UDDI 的目的是为电子商务建立标准;UDDI是一套基于Web的、分布式的、为Web Service提供的、信息注册中心的实现标准规范,同时也包含一组使企业能将自身提供的Web Service注册,以使别的企业能够发现的访问协议的实现标准。

WebService协议的文档

当我们拿到一份WebService协议的文档时,一般情况文档里面都会提供相应的webservice地址,例如:http://ip:port?wsdl ,像这种地址我们直接可以在浏览器中打开,就是一个xml文档,里面包含了我们需要的所有信息,下面我们会讲的发布服务后的wsdl文档

自定义WebService服务

Apache CXF 是一个开源的 Services 框架,CXF 帮助您来构建和开发 Services 这些 Services 可以支持多种协议,比如:SOAP、POST/HTTP、RESTful HTTP CXF 大大简化了 Service可以天然地和 Spring 进行无缝集成。

创建一个maven项目,引入依赖

<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.1.4</version>
</dependency>

<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.1.4</version>
</dependency>

<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-core</artifactId>
<version>3.1.4</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
复制代码

编写一个实体类Car

@Data
public class Car
{
private String brand;//品牌
private String plateNum;//车牌号
private double price;//价格单位:万
private String owner;//拥有者
}
复制代码

接口的代码编写

package com.cn.service;

import com.cn.domain.Car;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

@WebService
public interface CarService
{

/**
* 1.在类上添加@WebService注解,代表发布一个WebService服务。
* 2.给类添加上@WebService注解后,类中所有的非静态方法都将会对外公布。
* 3.如果希望某个方法不对外公开,可以在方法上添加@WebMethod(exclude=true),阻止对外公开。
* 4.如果一个类上,被添加了@WebService注解,则必须此类至少有一个可以公开的方法,否则将会启动失败。
* protected、private、final、static方法不能对外公开。
* 5.@targetNamespace 设置命名空间,默认包名,取反
*/


@WebMethod
public Car getCarInfo(@WebParam(name = "carBrand",
targetNamespace = "http://service.cn.com/")
String carBrand)
;

}
复制代码

接口的实现类

package com.cn.service;

import com.cn.domain.Car;

public class CarServiceImpl implements CarService
{
@Override
public Car getCarInfo(String carBrand)
{
Car car = new Car();
if (carBrand.equals("audi"))
{
car.setBrand("audi");
car.setOwner("Tom");
car.setPlateNum("皖A11011");
car.setPrice(50.00);
}
else if (carBrand.equals("bmw"))
{
car.setBrand("bmw");
car.setOwner("Jack");
car.setPlateNum("皖A8888M");
car.setPrice(60.00);
}
else
{
car.setBrand("其他");
car.setOwner("Rose");
car.setPlateNum("未知");
car.setPrice(00.00);
}
return car;
}
}
复制代码

服务发布

package com.cn;

import com.cn.service.CarServiceImpl;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;

public class AppTest
{
public static void main(String[] args)
{
//发布服务的工厂
JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
//设置服务的地址
factory.setAddress("http://127.0.0.1:9999");
//设置服务类
factory.setServiceBean(new CarServiceImpl());
//发布服务
factory.create();
System.out.println("发布服务成功,服务的wsdl地址是:http://127.0.0.1:9999?wsdl");
}

}
复制代码

发布成功后,可以在浏览器上输入网址:http://127.0.0.1:9999?wsdl

<wsdl:definitions name="CarServiceImplService" targetNamespace="http://service.cn.com/">

<wsdl:types>
<xs:schema elementFormDefault="unqualified" targetNamespace="http://service.cn.com/" version="1.0">
<xs:element name="getCarInfo" type="tns:getCarInfo"/>
<xs:element name="getCarInfoResponse" type="tns:getCarInfoResponse"/>
<xs:complexType name="getCarInfo">
<xs:sequence>
<xs:element minOccurs="0" name="carBrand" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="getCarInfoResponse">
<xs:sequence>
<xs:element minOccurs="0" name="return" type="tns:car"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="car">
<xs:sequence>
<xs:element minOccurs="0" name="brand" type="xs:string"/>
<xs:element minOccurs="0" name="owner" type="xs:string"/>
<xs:element minOccurs="0" name="plateNum" type="xs:string"/>
<xs:element name="price" type="xs:double"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
</wsdl:types>

<wsdl:message name="getCarInfoResponse">
<wsdl:part element="tns:getCarInfoResponse" name="parameters"> </wsdl:part>
</wsdl:message>
<wsdl:message name="getCarInfo">
<wsdl:part element="tns:getCarInfo" name="parameters"> </wsdl:part>
</wsdl:message>

<wsdl:portType name="CarService">
<wsdl:operation name="getCarInfo">
<wsdl:input message="tns:getCarInfo" name="getCarInfo"> </wsdl:input>
<wsdl:output message="tns:getCarInfoResponse" name="getCarInfoResponse"> </wsdl:output>
</wsdl:operation>
</wsdl:portType>

<wsdl:binding name="CarServiceImplServiceSoapBinding" type="tns:CarService">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getCarInfo">
<soap:operation soapAction="" style="document"/>
<wsdl:input name="getCarInfo">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getCarInfoResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>

<wsdl:service name="CarServiceImplService">
<wsdl:port binding="tns:CarServiceImplServiceSoapBinding" name="CarServiceImplPort">
<soap:address location="http://127.0.0.1:9999/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
复制代码

客户端调用

客户端的调用方式有很多种,这里我就不一一介绍了,我来说一下我平时工作中用的方式。

Soap客户端-SoapClient

在接口对接当中,WebService接口占有着很大份额,而我们为了使用这些接口,不得不引入类似Axis等库来实现接口请求。

客户端引入依赖

<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.3</version>
</dependency>
复制代码

现在有了Hutool,就可以在无任何依赖的情况下,实现简便的WebService请求。

根据上面的wsdl文档,我们知道了

  1. 方法名为:getCarInfo

  2. 参数只有一个,为:carBrand

  3. 定义了一个命名空间,URI为http://service.cn.com/

这样我们就能构建客户端请求

public class Test
{
public static void main(String[] args)
{
//设置webservice服务地址
SoapClient client = SoapClient.create("http://127.0.0.1:9999")
// 设置要请求的方法,传入对应的命名空间
.setMethod("getCarInfo", "http://service.cn.com/")
// 设置参数
.setParam("carBrand", "audi");
// 发送请求,参数true表示返回一个格式化后的XML内容
// 返回内容为XML字符串,可以配合XmlUtil解析这个响应
String result = client.send(true);
System.out.println(result);
System.out.println("----------------------------");
Document docResult = XmlUtil.readXML(result);
Object brand = XmlUtil.getByXPath("//return//brand", docResult, XPathConstants.STRING);
Object owner = XmlUtil.getByXPath("//return//owner", docResult, XPathConstants.STRING);
Object plateNum = XmlUtil.getByXPath("//return//plateNum", docResult, XPathConstants.STRING);
Object price = XmlUtil.getByXPath("//return//price", docResult, XPathConstants.STRING);
System.out.println("brand = " + brand);
System.out.println("owner = " + owner);
System.out.println("plateNum = " + plateNum);
System.out.println("price = " + price);
}
}
复制代码

返回的数据

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:getCarInfoResponse xmlns:ns2="http://service.cn.com/">
<return>
<brand>audi</brand>
<owner>Tom</owner>
<plateNum>皖A11011</plateNum>
<price>50.0</price>
</return>
</ns2:getCarInfoResponse>
</soap:Body>
</soap:Envelope>

----------------------------
brand = audi
owner = Tom
plateNum = 皖A11011
price = 50.0

Process finished with exit code 0
复制代码

SoapUI

链接:pan.baidu.com/s/1UIMv_E8x…提取码:b9rg

soapUI是一个开源测试工具,通过soap/http来检查、调用、实现Web Service的功能/负载/符合性测试。

用这个图形化工具也可以调用WebService服务,作为测试使用。

总结

关于WebService的知识就介绍这么多,其实在工作中,了解这些就够用了。了解WebService的原理最重要,还有很多的小知识点我这里就不一一赘述了,网上资料也很多,小伙伴们可以去查阅。我们一起加油~


作者:初念初恋
链接:https://juejin.cn/post/7008051173773180958
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。



浏览 63
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报