loading...
WebService基础概念(一)
Published in:2022-01-31 | category: WebService
Words: 3.6k | Reading time: 14min | reading:

WebService技术讲解

WebService

WebService简介

Web Service技术, 能使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件, 就可相互交换数据或集成。依据Web Service规范实施的应用之间, 无论它们所使用的语言、 平台或内部协议是什么, 都可以相互交换数据。

简单的说,WebService就是一种跨编程语言和跨操作系统平台的远程调用技术。所谓跨编程语言和跨操作平台,就是说服务端程序采用java编写,客户端程序则可以采用其他编程语言编写,反之亦然。跨操作系统平台则是指服务端程序和客户端程序可以在不同的操作系统上运行。 远程调用,就是一台计算机的应用可以调用其他计算机上的应用。例如:支付宝,支付宝并没有银行卡等数据,它只是去调用银行提供的接口来获得数据。还有天气预报等,也是气象局把自己的系统服务以webservice服务的形式暴露出来,让第三方网站和程序可以调用这些服务功能。

WebService原理

XML,SOAP和WSDL就是构成WebService平台的三大技术 。

WebService采用Http协议来在客户端和服务端之间传输数据。WebService使用XML来封装数据,XML主要的优点在于它是跨平台的。

WebService通过HTTP协议发送请求和接收结果时,发送的请求内容和结果内容都采用XML格式封装,并增加了一些特定的HTTP消息头,以说明HTTP消息的内容格式,这些特定的HTTP消息头和XML内容格式就是SOAP协议规定的。

WebService服务器端首先要通过一个WSDL文件来说明自己有什么服务可以对外调用。简单的说,WSDL就像是一个说明书,用于描述WebService及其方法、参数和返回值。 WSDL文件保存在Web服务器上,通过一个url地址就可以访问到它。客户端要调用一个WebService服务之前,要知道该服务的WSDL文件的地址。WebService服务提供商可以通过两种方式来暴露它的WSDL文件地址:1.注册到UDDI服务器,以便被人查找;2.直接告诉给客户端调用者。

WebService交互的过程就是,WebService遵循SOAP协议通过XML封装数据,然后由Http协议来传输数据。

Java WebService规范

Java 中共有三种WebService 规范,分别是JAXM&SAAJ、JAX-WS(JAX-RPC)、JAX-RS。

(1)JAX-WS:

JAX-WS(Java API For XML-WebService)。早期的基于SOAP 的JAVA 的Web 服务规范JAX-RPC(java API For XML-Remote Procedure Call)目前已经被JAX-WS 规范取代,JAX-WS 是JAX-RPC 的演进版本,但JAX-WS 并不完全向后兼容JAX-RPC,二者最大的区别就是RPC/encoded 样式的WSDL,JAX-WS 已经不提供这种支持。JAX-RPC 的API 从JAVA EE5 开始已经移除,如果你使用J2EE1.4,其API 位于javax.xml.rpc.包。JAX-WS(JSR 224)规范的API 位于javax.xml.ws.包,其中大部分都是注解,提供API 操作Web 服务(通常在客户端使用的较多,由于客户端可以借助SDK 生成,因此这个包中的API 我们较少会直接使用)。

(2)JAXM&SAAJ:

JAXM(JAVA API For XML Message)主要定义了包含了发送和接收消息所需的API,相当于Web 服务的服务器端,其API 位于javax.messaging.*包,它是Java EE 的可选包,因此你需要单独下载。

SAAJ(SOAP With Attachment API For Java,JSR 67)是与JAXM 搭配使用的API,为构建SOAP 包和解析SOAP 包提供了重要的支持,支持附件传输,它在服务器端、客户端都需要使用。这里还要提到的是SAAJ 规范,其API 位于javax.xml.soap.*包。

JAXM&SAAJ 与JAX-WS 都是基于SOAP 的Web 服务,相比之下JAXM&SAAJ 暴漏了SOAP更多的底层细节,编码比较麻烦,而JAX-WS 更加抽象,隐藏了更多的细节,更加面向对象,实现起来你基本上不需要关心SOAP 的任何细节。那么如果你想控制SOAP 消息的更多细节,可以使用JAXM&SAAJ。

(3)JAX-RS:

JAX-RS 是JAVA 针对REST(Representation State Transfer)风格制定的一套Web 服务规范,由于推出的较晚,该规范(JSR 311,目前JAX-RS 的版本为1.0)并未随JDK1.6 一起发行。

WebService入门案例

服务端实现

我们来实现一个编写天气系统的案例,客户端发送城市名称,服务端回应相应的天气。

1
2
3
4
5
6
7
8
/**
* 编写SEI,SEI在webService中称为portType,在java中就是普通接口
* @author yangkai
*/
public interface WeatherInterface {

String queryWeather(String cityName);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 编写SEI实现类,此类作为webService提供服务类
* // @WebSerivce表示该类是一个服务类,需要发布其中的public方法
* @author yangkai
*/
@WebService
public class WeatherInterfaceImpl implements WeatherInterface {


@Override
public String queryWeather(String cityName) {
System.out.println("获取城市名: " + cityName);
String weather = "多云转晴";
return weather;
}
}
1
2
3
4
5
6
7
8
9
10
11
/**
* 发布服务,Endpoint类发布服务,publish方法,两个参数: 1. 服务地址 2. 服务实现类
* @author yangkai
*/
public class WeatherServer {

public static void main(String[] args) {

Endpoint.publish("http://127.0.0.1:33245/weather", new WeatherInterfaceImpl());
}
}

测试服务是否发布成功,通过阅读wsdl,确定客户端调用的接口、方法、参数和返回值存在,证明服务发布成功。

// 我们在浏览器输入 http://127.0.0.1:33245/weather?wsdl 来获取wsdl文件进行阅读

// wsdl,是以XML文件形式来描述WebService的“说明书”,有了说明书,我们才可以知道如何使用或是调用这个服务。

// 现在我们还不知道怎么阅读,后面我们会详解,只要能获取到,就你那个确定WebService服务发布成功.

image-20211130092017826

客户端的实现

1
2
3
4
5
6
7
8
9
10
// 客户端调用服务有很多种方法,我们先用工具生成客户端代码,后面会详解
// wsimport是jdk自带的webservice客户端工具,可以根据wsdl文档生成客户端调用代码(Java代码)。当然,无论服务器端的WebService是用什么语言写的,都可以生成调用webservice的客户端代码

1.创建一个客户端空项目,cmd命令行进入此项目的src目录
使用以下命令生成客户端代码

wsimport -s . http://127.0.0.1:12345/weather?wsdl

-s是指编译出源代码文件,后面的.(点)指將代码放到当前目录下.
最后面的http….是指获取wsdl说明书的地址
1
2
3
4
5
6
7
8
9
10
11
12
public class WeatherClient {

public static void main(String[] args) {
// 创建服务视图,视图是从wdsl文件的service标签的name属性获取的
WeatherInterfaceImplService weatherInterfaceImplService = new WeatherInterfaceImplService();
// 获取服务实现类,实现类从wsdl文件的portType的name属性获取
WeatherInterfaceImpl port = weatherInterfaceImplService.getPort(WeatherInterfaceImpl.class);
// 获取查询方法,从portType的operation获取
String s = port.queryWeather("上海");
System.out.println(s);
}
}

至此,我们的客户单就可以获取远程服务端的数据,接下来我们来详解一下各个部分。

WSDL

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

文档结构

image-20211130093109312

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

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

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

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

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

阅读方式

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

  1. 先看Service标签,看相应的port的binding信息,然后通过值查找上面的binding标签。
  2. 通过binding标签可以获得具体协议等信息,然后查看binding的type属性
  3. 通过binding的type属性,查找对应的portType,可以获得可操作的方法和参数、返回值等。
  4. 通过portType下的operation标签的message属性,可以向上查找Message获取具体的参数信息

SOAP

SOAP即简单的对象访问协议,他是使用http发送的XML格式的数据,它可以跨平台,跨防火墙,SOAP不是webservice的专有协议。

SOAP=http + xml

SOAP结构

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

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

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

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

UDDI

UDDI是一种目录服务,企业可以使用它对Web services 进行注册和搜索。如果我们要使用一种服务,但是不知道地址(wsdl等),我们就可以在UDDI中查找,大部分情况下我们都是知道服务地址的。

Webservice的客户端调用方式

生成客户端调用方式

wsimport是jdk自带的webservice客户端工具,可以根据wsdl文档生成客户端调用代码(java代码).
wsimport.exe位于JAVA_HOME\bin目录下
常用参数为:
-d<目录> - 将生成.class文件。默认参数。
-s<目录> - 将生成.java文件。
-p<生成的新包名> -将生成的类,放于指定的包下

公网服务地址(里面提供了许多免费调用的服务)

http://www.webxml.com.cn/zh_cn/index.aspx

第一步:wsimport生成客户端代码

wsimport -p cn.cad.mobile -s . http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl

会出现一些警告,是因为服务端提供的一些方法是SOAP1.2标准的,这个工具没有实现SOAP1.2标准的生成方式。

第二步:查看wsdl文件,获取我们需要的信息

image-20211130155714674

第三步 根据获取到的服务名等信息来创建我们的客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

public class MobileClient {
public static void main(String[] args) {
// 创建服务视图
MobileCodeWS mobileCodeWS = new MobileCodeWS();
// 获取服务实现类
MobileCodeWSSoap port = mobileCodeWS.getPort(MobileCodeWSSoap.class);
ArrayOfString databaseInfo = port.getDatabaseInfo();
System.out.println(databaseInfo.toString());

// 调用查询方法
String mobileCodeInfo = port.getMobileCodeInfo("xxxxxxxxxxx", null);
System.out.println(mobileCodeInfo);
}
}

第四步 获取到信息

image-20211130155909088

service编程调用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* service变成调用方式
* 该种方式可以自定义命名空间,服务视图名等元素,方便以后维护,是一种标准的开发方式
*/
public class MobileClient2 {

public static void main(String[] args) throws MalformedURLException {
// 创建WSDL文件的URL
URL wsdDocumentLocation = new URL("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl");

// 创建服务名称
// namespaceURI - 命名空间地址
// localPart 服务视图名
QName serviceName = new QName("http://WebXml.com.cn/", "getMobileCodeInfo");
Service service = Service.create(wsdDocumentLocation, serviceName);

// 获取服务实现类
MobileCodeWSSoap mobileCodeWSSoap = service.getPort(MobileCodeWSSoap.class);

// 调用方法
String mobileCodeInfo = mobileCodeWSSoap.getMobileCodeInfo("13825012138", null);
System.out.println(mobileCodeInfo);
}
}

HttpURLConnection调用方式

这种方式是由自己编写客户端,不再由工具生成,比较麻烦

开发步骤:

第一步:创建服务地址

第二步:打开一个通向服务地址的连接

第三步:设置参数

第四步:组织SOAP数据,发送请求

第五步:接收服务端响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/**
* 这种方式是自己编写客户端,不再由工具生成,比较麻烦
* 开发步骤:
* 1. 创建服务地址
* 2. 打开一个通向服务地址的连接
* 3. 设置参数
* 4. 组织SOAP数据,发送请求
* 5. 接收服务端响应
*/
public class MoblieClient3 {
public static void main(String[] args) throws IOException {
// 第一步:创建服务地址,不是WSDL地址
URL url = new URL("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx");
// 第二步:打开一个通向服务地址的连接
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
// 第三步: 设置参数
// 3.1 发送方式设置: POST必须大写
httpURLConnection.setRequestMethod("POST");
// 3.2 设置数据格式 content-type
httpURLConnection.setRequestProperty("content-type", "text/xml;charset=UTF-8");
// 3.3 设置输入输出,因为默认新创建的connection没有读写权限
httpURLConnection.setDoInput(true);
httpURLConnection.setDoOutput(true);

// 第四步:组织SOAP数据,发送请求
String xml = getXML("xxxxxxxxxx");
OutputStream outputStream = httpURLConnection.getOutputStream();
outputStream.write(xml.getBytes());

// 第五步:接收服务端响应,打印
int responseCode = httpURLConnection.getResponseCode();
if (200 == responseCode) {
// 表示服务端响应成功
InputStream is = httpURLConnection.getInputStream();
// 将字节流转换为字符流
InputStreamReader isr = new InputStreamReader(is, "utf-8");
// 使用缓冲区
BufferedReader bufferedReader = new BufferedReader(isr);
StringBuilder stringBuilder = new StringBuilder();
String temp = null;

while(null != (temp = bufferedReader.readLine())) {
stringBuilder.append(temp);
}

System.out.println(stringBuilder.toString());

is.close();
isr.close();
bufferedReader.close();
}
}

//组织数据,将数据拼接一下
public static String getXML(String phoneNum){
String soapXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+"<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/\">"
+"<soap:Body>"
+"<getMobileCodeInfo xmlns=\"http://WebXml.com.cn/\">"
+"<mobileCode>"+phoneNum+"</mobileCode>"
+"<userID></userID>"
+"</getMobileCodeInfo>"
+"</soap:Body>"
+"</soap:Envelope>";
return soapXML;
}

}

image-20211130160303738

使用注解修改WSDL内容

作用: 通过注解,可以更加形象的描述Web服务。对自动生成的wsdl文档进行修改。为使用者提供一个更加清晰的wsdl文档

WebService的注解都位于javax.jws包下:

@WebService- 定义服务,在类上边

​ targetNamespace: 指定命名空间

​ name: portType的名称

​ portName: port的名称

​ serviceName: 服务名称

​ endpointInterface: SEI接口地址,如果一个服务类实现了多个接口,只需要发布一个接口的方法,可以通过此注解指定要发布服务的接口

@WebMethod - 定义方法,在公开方法上边

​ operationName: 方法名

​ exclude: 设置为true表示此方法不是webservice方法,反之则表示WebService方法,默认是false

@WebResult - 定义返回值,在方法返回值前边

​ name: 返回结果值的名称

@WebParam - 定义参数,在方法参数前边

​ name: 指定参数名称

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@WebService(
targetNamespace = "http://service.cad.com",
portName = "WeatherSOAPPort",
serviceName = "WeatherWSS",
name = "WeatherSOAP"
)
public class WeatherInterfaceImpl implements WeatherInterface {

@WebMethod(
operationName = "getWeather",
exclude = false
)
@Override
public @WebResult(name = "result")String queryWeather(@WebParam(name = "城市名") String cityName) {
System.out.println("获取城市名: " + cityName);
String weather = "多云转晴";
return weather;
}
}
Prev:
WebService基础概念(二)
Next:
Rocket基本概念
catalog
catalog