从“国网网省四线一库”标准到Web Service Client在Spring Boot中的实现(一)

前言

国网四线一库

国网四线一库·百度百科

四线一库简述

“四线一库”是指单相智能电能表自动化检定流水线、三相智能电能表自动化检定流水线、低压电流互感器自动化检测流水线、用电采集终端自动化检测流水线、智能化仓储库房。

01

简单的来说所谓“四线一库”的标准,是由南瑞集团负责研发的一个为实现国网电能表检定自动化的标准,该标准包含了电能表检定流水线、电流互感器检定流水线、用电采集终端检定流水线、智能化仓储库房等四条生产线和一个数据中心。

但由于各个流水线的检定设备和检定软件都是由不同的厂家提供,所以为了实现各个流水线之间的数据交互,南瑞提供了一个数据库,该数据库负责各个流水线之间的数据交换。

四线一库的数据交换

02

上图是省级计量中心调度层次

03

上图是电表检定台与主数据中心的交互流程

大致过程就是,主站在编辑好检定任务和检定方案后,选择需要出库检定的设备,生成一个条形码,该条形码仅包含了检定任务编号,这时,所有有关数据都会保存到对应的数据库的表中,
在检定台端,拿到条码后,扫描条码,根据条码中的任务编号,从数据库中通过联表查询,获取到该任务的所有信息,然后根据这些信息,生成对应检定台所需的检定参数及数据,在完成检定之后,最后将检定数据转换为主站数据库结构,上传到数据库中。

在这个过程中,重要的事件节点需要通知主站,比如获取检定数据,开始检定,检定完成等,这些事件节点都需要通过Web Service的方式通知主站。

吐槽一下这个标准

首先不谈让第三方直接操作数据库,所导致的数据安全,数据同步以及数据一致性的问题,单纯的从技术角度来看,这个标准的设计就是依托答辩。

webservices的设计,本就是是为了解决不同平台,不同语言之间的数据交换问题,但是这个标准,却仅仅将其用作了事件通知上,这样子我有理由怀疑南瑞的设计者,只是为了有一个高大上的名词,而将其加入到了这个标准中。

或者是为了减轻自己的工作量,将数据的工作交给了第三方,但是这样子的话,就会导致第三方的工作量增加。

这样导致第三方会不断地重复造数据操作层的“轮子”,而且这个轮子还是一个不安全的“轮子”。

其次WebServices在当下已经不是一个有活力,或者说有优势的技术了,并且有逐步被淘汰和取代的迹象

很明显一些主流的框架已经不推荐WebServices,比如Spring Boot,Spring Cloud等,这些框架都是基于Restful的架构。

Web Service资料

Web Service简介·知乎

Web Service 简述

Web Service也叫XML Web Service, WebService是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求,轻量级的独立的通讯技术。是通过SOAP在Web上提供的软件服务,使用WSDL文件进行说明,并通过UDDI进行注册。WebService是一种跨编程语言和跨操作系统平台的远程调用技术。

还可以从多个角度来理解WebService,从表面看,WebService就是一个应用程序向外界暴露出一个能通过Web进行调用的API,也就是说能用编程的方法通过Web来调用这个应用程序。我们把调用这个WebService的应用程序叫做客户端,而把提供这个WebService的应用程序叫做服务端。从深层次看,WebService是建立可互操作的分布式应用程序的新平台,是一个平台,是一套标准。它定义了应用程序如何在Web上实现互操作性,你可以用任何你喜欢的语言,在任何你喜欢的平台上写Web service ,只要我们可以通过Web service标准对这些服务进行查询和访问。

WebService三要素

SOAP、WSDL、UDDI(UniversalDescriptionDiscovery andIntegration)三者构成了WebService的三要素。下面详细阐述这三大技术:

SOAP

WebService通过HTTP协议发送请求和接收结果时,发送的请求内容和结果内容都采用XML格式封装,并增加了一些特定的HTTP消息头,以说明HTTP消息的内容格式,这些特定的HTTP消息头和XML内容格式就是SOAP协议。SOAP提供了标准的RPC(远程调用技术)方法来调用Web Service。

SOAP协议组成:

SOAP协议 = HTTP协议 + XML数据格式

SOAP协议定义了SOAP消息的格式,SOAP协议是基于HTTP协议的,SOAP也是基于XML的,XML是SOAP的数据编码方式。

WSDL

好比我们去商店买东西,首先要知道商店里有什么东西可买,然后再来购买,商家的做法就是张贴广告海报。 WebService也一样,WebService客户端要调用一个WebService服务,首先要有知道这个服务的地址在哪,以及这个服务里有什么方法可以调用,所以,WebService务器端首先要通过一个WSDL文件来说明自己家里有啥服务可以对外调用,服务是什么(服务中有哪些方法,方法接受的参数是什么,返回值是什么),服务的网络地址用哪个url地址表示,服务通过什么方式来调用。

WSDL(Web Services Description Language)就是这样一个基于XML的语言,用于描述Web Service及其函数、参数和返回值。它是WebService客户端和服务器端都能理解的标准格式。因为是基于XML的,所以WSDL既是机器可阅读的,又是人可阅读的,这将是一个很大的好处。一些最新的开发工具既能根据你的Web service生成WSDL文档,又能导入WSDL文档,生成调用相应WebService的代理类代码。

UDDI

uddi是一个跨产业,跨平台的开放性架构,可以帮助 Web 服务提供商在互联网上发布 Web 服务的信息。UDDI 是一种目录服务,企业可以通过 UDDI 来注册和搜索 Web 服务。简单来说,UDDI 就是一个目录,只不过在这个目录中存放的是一些关于 Web 服务的信息而已。

WebService 的优势

  • 跨平台调用
  • 跨语言调用
  • 远程调用

初探WebService

我在接触网络编程的时候,就听说过WebService,但是一直没有机会去接触,这次正好有机会,就好好学习一下。

由于我入门的时候正是RESTful风格的兴起,所以我对WebService的印象就是一个过时的技术,当时毫不犹豫地选择了RESTful。

这不巧了吗,国企就喜欢用过时的技术。

简单的WebService调用

首先我找到了一个用来测试的的webService,地址是:http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl

我这里使用了我最熟悉的编程语言Java来进行测试。

使用Apache的CXF框架来进行WebService的调用。

首先使用CXF的wsdl2java命令来生成客户端代码。

1
wsdl2java -encoding utf-8 -p '包名' -d '代码生成目录' http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl   

生成的代码如下:

04

然后就可以使用这些代码来进行WebService的调用了。

1
2
3
4
5
6
7
8
9
//查询手机归属地
public class Test {
public static void main(String[] args) {
MobileCodeWS mobileCodeWS = new MobileCodeWS();
MobileCodeWSSoap mobileCodeWSSoap = mobileCodeWS.getMobileCodeWSSoap();
String mobileCodeInfo = mobileCodeWSSoap.getMobileCodeInfo("13993226784", null);
System.out.println(mobileCodeInfo);
}
}

运行结果如下:

05

简单的抓包分析

我们使用Wireshark来抓包,看看WebService的请求和响应的数据包是什么样的。

06

我通过Java代码调用了WebService,然后通过Wireshark抓包,可以看到,首先可以清楚地看到它发送了两条HTTP请求,第一条是GET请求,第二条是POST请求。

07

我们先来看第一条GET请求,这条请求是用来获取WSDL文件的,WSDL文件是用来描述WebService的,我们可以看到,它的请求地址是:http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl

08

GET请求的响应如上图所示,我们可以看到,它的响应内容是一个XML文件,这个XML文件就是WSDL文件,它描述了这个WebService的一些信息,比如它的命名空间,它的方法,它的参数,它的返回值等等。和我们在浏览器中访问的WSDL文件是一样的。

再来看第二条POST请求

09

我们可以看到,它的请求地址是:http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx

可以先看请求头,我们可以看到,它的请求头中有一个SOAPAction,它的值是:http://WebXml.com.cn/getMobileCodeInfo,

这个值就是我们在Java代码中调用的方法名。还有一个比较重要的请求头是Content-Type,它的值是:text/xml;charset=UTF-8,这个值说明了它的请求体是一个XML文件。

它的请求体是一个XML文件,这个XML文件就是SOAP协议,它描述了这个WebService的一些信息,比如它的命名空间,它的方法,它的参数,它的返回值等等。里面就含咱们的手机号。

10

上图是它的响应,响应体中也是一个XML文件,它描述了这个WebService的一些信息,比如它的命名空间,它的方法,它的参数,它的返回值等等。里面就含咱们的手机号归属地。

简单猜想

我们可以看到,我们在通过CXF框架生成的客户端代码中,调用了一个getMobileCodeInfo方法,这个方法的参数是一个String类型的手机号,返回值是一个String类型的手机号归属地。

我们在调用这个方法的时候,它会先发送一个GET请求,获取WSDL文件,然后再发送一个POST请求,请求体是一个XML文件,这个XML文件就是SOAP协议,它描述了这个WebService的一些信息,比如它的命名空间,它的方法,它的参数,它的返回值等等。里面就含咱们的手机号。

通过这个我们可以得出,第一步其实对我们获取结果是多余的,也就是说我们可以跳过第一步的获取WSDL文件,直接发送POST请求,实现结果的获取。

当然这一切建立在WebService的服务端是不变的情况下,如果服务端的WSDL文件发生了变化,那么我们就需要重新获取WSDL文件,然后再发送POST请求。

但对于我们来说我们的代码本来就是通过WSDL文件生成的,如果WSDL文件发生了变化,我们肯定需要重新生成客户端代码。

验证猜想

由于浏览器发送POST请求比较麻烦,所以我们使用Postman来发送POST请求。

11

我们可以看到,我们发送了一个POST请求,请求体是一个XML文件,这个XML文件就是SOAP协议,里面就含咱们的手机号。

响应体也是一个XML文件,里面就含咱们的手机号归属地。

12

需要注意这几个请求头需要设置,这个是和服务端的实现限制有关的,如果不设置,可能会导致请求失败。

简单总结

首先CXF帮我实现的客户端代码就是实现了请求体的封装,响应体的解析,我们只需要调用它的方法就可以了。

然后通过Web Service的调用过程,用http协议做了响应的请求。

这无疑提高了我们的开发效率,我们不需要关心底层的实现,只需要关心我们的业务逻辑就可以了。

但通过这番分析,我们也可以看到,Web Service的调用过程是比较简单的。

我们完全可以通过jdk提供的网络编程来实现,而且可以只做相应的POST请求。

虽然这么说,但秉着不重复造轮子的原则,我们搞清楚了它的原理,但还是使用CXF框架来实现WebService的调用。