WebService
1、概念
1.1 WebService
Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求,轻量级的独立的通讯技术。是:通过SOAP在Web上提供的软件服务,使用WSDL文件进行说明,并通过UDDI进行注册。 说白了 WebService 是一种跨编程语言、跨操作系统平台的远程调用技术。
连接不同系统之间的一个桥梁/纽带,可以实现不同编程语言,不同系统之间的交互。
本质就是XML流的解析
1.1.1 远程调用技术
远程调用是指一台设备上的程序A可以调用另一台设备上的方法B。比如:银联提供给商场的pos刷卡系统,商场的pos机转账调用的转账方法的代码其实是跑在银行服务器上的。再比如,amazon,天气预报系统,淘宝网,校内网,百度等把自己的系统服务以WebService服务的形式暴露出来,让第三方网站和程序可以调用这些服务功能,这样扩展了自己系统的市场占有率。
1.1.2 跨操作系统平台
-
从表面上看
-
WebService是指一个应用程序向外界暴露了一个能通过Web调用的API接口,我们把调用这个WebService的应用程序称作客户端,把提供这个WebService的应用程序称作服务端。
-
-
从深层上看
-
WebService是建立可互操作的分布式应用程序的新平台,是一个平台,是一套标准。它定义了应用程序如何通过Web实现互操作性,通过WebService标准对服务进行查询和访问。
-
1.2 WebService(SAOP)与HTTP接口的区别
1.2.1 什么是SAOP
SAOP请求是HTTP POST 的一个专用版本,遵循一种特殊的xml消息格式Content-type 设置为:text/xml 任何数据都可以xml化,也都能JSON化
1.2.2 WebService 作用
大多数对外接口会实现webService方法而不是http方法,如果不会,那就没有办法对接
1.2.3 WebService 相对http(post/get)好处
- 接口中实现的方法和要求参数一目了然
- 不用担心大小写问题
- 不用担心中文urlencode问题
- 代码中不用多次声明认证(账号,密码)参数
- 传递参数可为数组,对象等
1.2.4 WebService 相对http的速度
相对http较慢,因为要对xml进行解析
1.2.5 WebService 可以被http(post/get)代替么?
可以,开放平台都是使用http实现的
1.2.6 总结
- HTTP Service 通过post和get 得到你想要的东西
- WebService就是使用soap协议得到你想要的东西,相比httpService能处理些更加复杂的数据类型
- http协议传输的都是字符串了,WebService则是包装成了更复杂的对象
1.3 XML与JSON的区别
1.3.1 XML
- XML 指可扩展标记语言(EXtensible Markup Language)
- XML 是一种可扩展标记语言,HTML就是基于XML演变而来的
- XML 的设计宗旨是传输数据,而非显示数据
- XML 标签没有被预定义。需要自行定义标签
- XML 被设计为具有自我描述性
- XML 是W3C的推荐标准
1.3.2 JSON
- JSON (JavaScript Object Notation) 是一种格式,一种轻量级的数据交换格式。
- 易于人阅读和编写,同时也易于机器解析和生成。
- JSON采用完全独立于语言的文本格式,但是也使用C语言家族的习惯(包括C,C++,C#,Java,JavaScript,Perl,Python)
- 这些特性使其成为理想的数据交换语言
1.3.3 比较
XML 能做的 JSON都能做。
JSON 比XML 格式更简单,使用更方便,更加流行,占用带宽更小,传输速度更快,能直接为服务器端代码使用
JSON 对数据的描述性比XML较差
JSON只提供整体解析方案,而这种方法只在解析较少的数据时才能起到良好的效果;
XML提供了对大规模数据的逐步解析方案,这种方案很适合于对大量数据的处理。(DOM 和 SAX)
1.4 WSDL
- WSDL 网络服务描述语言, 是一种基于XML用来描述WebService 以及如何访问WebService的语言
- WSDL 文档包含一系列描述某个WebService的定义
1.4.1 WSDL 结构
WSDL 利用几个主要的元素来描述某个WebService的
元素 | 作用 |
---|---|
< portType > | WebService执行的操作,即可调用的方法 |
< message > | WebService 使用的消息 |
< types > | WebService 使用的数据类型 |
< binding > | WebService 使用的通信协议 |
除此之外,WSDL还可以包含其他的元素,比如extension、service元素
<definitions>
<types>
数据类型定义
</types>
<message>
消息定义
</message>
<portType>
操作,可调用的方法
</portType>
<binding>
通信协议
</binding>
</definitions>
完整的WSDL
XML里面的标签都是自己定义的,通过命名空间来进行限制
其中 标签里面的 xmlns:标签名=“URL” 这个是命名空间,给标签一个唯一的标识符,里面的URL 不解析,只是用来标识而已。
一般都是使用 < 命名空间:元素 > 这种前缀命名的方式来使用,这样在使用两个XML时,同名的元素不会发生命名冲突。
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
jaxb:version="2.0"
xmlns:ns0="http://hsc.itf.nc/TM"
targetNamespace="http://hsc.itf.nc/TM">
<jaxws:bindings>
<jaxws:package name="nc.itf.hsc"/>
</jaxws:bindings>
<wsdl:types>
<xsd:schema xmlns:ns="http://hsc.itf.nc/TM"
attributeFormDefault="unqualified"
elementFormDefault="unqualified"
targetNamespace="http://hsc.itf.nc/TM" jaxb:version="2.0">
<xsd:annotation>
<xsd:appinfo>
<jaxb:schemaBindings>
<jaxb:package name="nc.itf.hsc"/>
</jaxb:schemaBindings>
</xsd:appinfo>
</xsd:annotation>
<xsd:element name="MY">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="string" minOccurs="0" nillable="true" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="MYResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="return" minOccurs="0" nillable="true" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
<wsdl:message name="MYRequest">
<wsdl:part name="parameters" element="ns0:MY"/>
</wsdl:message>
<wsdl:message name="MYResponse">
<wsdl:part name="parameters" element="ns0:MYResponse"/>
</wsdl:message>
<wsdl:portType name="TMPortType">
<wsdl:operation name="MY">
<wsdl:input message="ns0:MYRequest" wsaw:Action="urn:MY"/>
<wsdl:output message="ns0:MYResponse" wsaw:Action="urn:MYResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="TMSOAP11Binding" type="ns0:TMPortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<wsdl:operation name="MY">
<soap:operation soapAction="urn:MY" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="TM">
<wsdl:port name="TMSOAP11port_http" binding="ns0:TMSOAP11Binding">
<soap:address location="http://localhost/uapws/service/TM"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
1.4.2 解读
一般而言,只需要关注三个地方就可以
-
< XXX:definitions targetNamespace=“URL” >
在NC中,这个URL 一般指向 接口
在用cxf+spring编写webservice的时候,targetNamespace要指向服务类的接口所在的包名而不是实现类的包名,否则,在客户端将不能识别可用的服务。
这是个命名空间,子节点中也有targtNamespace
-
< xx:types >< xx:element name=“方法名”> < /xx:types >
在这个元素里面可以知道 可掉用方法的名称,入参参数名与参数类型。参数名称按照WSDL中的参数名进行请求而不是接口中的参数名
<xsd:element name="MY"> <xsd:complexType> <xsd:sequence> <xsd:element name="string" minOccurs="0" nillable="true" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element>
-
< xxx:service >< xx:address localhost=“URL” />< /xxx:service >
这里的URL是接口的请求地址
1.4.3 httpURLConnection方式调用
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
public class Test {
public static void main(String[] args) throws IOException {
//第一步:创建服务地址,这里的请求地址就是上面第三个标签里面的请求地址
URL url = new URL("请求地址?wsdl");
//第二步:打开一个通向服务地址的连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//第三步:设置参数
//3.1发送方式设置:POST必须大写
connection.setRequestMethod("POST");
//3.2设置数据格式:content-type
connection.setRequestProperty("content-type", "text/xml;charset=utf-8");
//3.3设置输入输出,因为默认新创建的connection没有读写权限,
connection.setDoInput(true);
connection.setDoOutput(true);
//第四步:组织SOAP数据,发送请求
String soapXML = getXML("参数值");
//将信息以流的方式发送出去
OutputStream os = connection.getOutputStream();
os.write(soapXML.getBytes());
//第五步:接收服务端响应,打印
int responseCode = connection.getResponseCode();
if(200 == responseCode){//表示服务端响应成功
//获取当前连接请求返回的数据流
InputStream is = connection.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
String temp = null;
while(null != (temp = br.readLine())){
sb.append(temp);
}
/**
* 打印结果
*/
System.out.println(sb.toString());
is.close();
isr.close();
br.close();
}
os.close();
}
public static String getXML(String phone){
String soapXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2003/XMLSchema-instance\" "
+"xmlns:web=\"http://WebXml.com.cn/\" "
+"xmlns:xsd=\"http://www.w3.org/2003/XMLSchema\" "
+"xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
+"<soap:Body>"
+"<web:方法名>"
+"<xxx:参数名>"
+phone//xml的格式,在前面加<![CDATA[xml]]>
+"</xxx:参数名>"
+"</web:方法名>"
+"</soap:Body>"
+"</soap:Envelope>";
return soapXML;
}
}
2、使用
目前在用JDK1.5 开发NC,所以内容上显示偏向这个方面
2.1 发布
2.1.1 NC发布WeService 接口
2.1.1.1 写好接口于实现类代码
接口中方法的返回值,最好不要使用jar包中的类型,不然,在发布接口的时候不会生成WSDL文件,报null。建议用String作为返回值,
2.1.1.2 发布
找到要发布的接口,右击
填写接口名称
配置实现类
配置授权
操作成功
2.1.1.3 测试
启动后访问 http://localhost/uapws/service,能够看到自己发布的接口
点击访问自己这个接口 显示WSDL就说明发布成功了
2.1.2 Spring 发布接口
这个以后写,先放着
2.2 调用
2.2.1 AXIS 调用
能够支持JDK1.5 jar包地址:https://pan.baidu.com/s/1rvg8M-YGAJ-bULPBPE7CIA 提取码:ylsp
2.2.1.1 NC 调用方法
一般直接的请求NC接口会直接返回wsdl文件的页面,并不会请求到方法
将上面全部解压,然后将lib文件夹下面的jar包全部导入进去,一个也不要少,不然会报错。
- 生成对应类
运行下面类,生成可调用接口的对应类。
import org.apache.axis.wsdl.WSDL2Java;
public class Axis {
public static void main(String[] args) throws Exception {
String wsdl = "http://localhost/uapws/service/nc.intf.hsc.WebXXX?wsdl";
WSDL2Java.main(new String[] { "-o", "src","-p",生成位置, 请求地址 });
}
}
- 调用接口
import nc.ws.intf.WebXXX.stub.WebXXX;
import nc.ws.intf.WebXXX.stub.WebXXXLocator;
import nc.ws.intf.WebXXX.stub.WebXXXPortType;
public class Mains {
public static void main(String[] args) {
try {
WebXXX service = new WebXXXLocator();
WebXXXPortType port = (WebXXXPortType) service.getWebXXXSOAP11port_http();
System.out.println(port.WD("World").toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.2.2 SOAP调用 1.8可用
这个方式可以调用其他的WebService,但是不能调用NC发布的接口,下面代码中的地址是一个测试地址。
package com.duzq.ws;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
//1.5可用,但NC 有个锁,无法直接调用接口,需要加点其他的东西,这个要加的东西日后再学习
/**
* @ClassName Soap4
* @Description TODO
* @Author TR_XHT
* @Date 2021/4/20 16:01
* @Version 1.0
**/
public class Soap4 {
public static void main(String[] args) throws IOException {
//第一步:创建服务地址
URL url = new URL("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl");
//第二步:打开一个通向服务地址的连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//第三步:设置参数
//3.1发送方式设置:POST必须大写
connection.setRequestMethod("POST");
//3.2设置数据格式:content-type
connection.setRequestProperty("content-type", "text/xml;charset=utf-8");
//3.3设置输入输出,因为默认新创建的connection没有读写权限,
connection.setDoInput(true);
connection.setDoOutput(true);
//第四步:组织SOAP数据,发送请求
String soapXML = getXML("17321242779");
//将信息以流的方式发送出去
OutputStream os = connection.getOutputStream();
os.write(soapXML.getBytes());
//第五步:接收服务端响应,打印
int responseCode = connection.getResponseCode();
if (200 == responseCode) {//表示服务端响应成功
// 获取当前连接请求返回的数据流
InputStream is = connection.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
String temp = null;
while (null != (temp = br.readLine())) {
sb.append(temp);
}
/**
* 打印结果
*/
System.out.println(sb.toString());
is.close();
isr.close();
br.close();
}
os.close();
}
public static String getXML(String phone) {
String soapXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2003/XMLSchema-instance\" "
+ "xmlns:web=\"http://WebXml.com.cn/\" "
+ "xmlns:xsd=\"http://www.w3.org/2003/XMLSchema\" "
+ "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
+ "<soap:Body>"
+ "<web:getMobileCodeInfo>"
+ phone
+ "</web:getMobileCodeInfo>"
+ "</soap:Body>"
+ "</soap:Envelope>";
return soapXML;
}
}
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
2.2.3 CXF 调用
这个方法在JDK1.8适用,但在JDK1.5 中用不了,可以调用NC接口
//JDK1.8可以调用到,1.5不行....
import com.alibaba.fastjson.JSON;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
public class Test {
public static String callWebService(String wsdUrl, String operationName, String... params) {
Object[] objects = new Object[0];
try {
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient(wsdUrl);
//如果存在加密情况的话
//client.getOutInterceptors().add(new ClientLoginInterceptor(USER_NAME, PASS_WORD));
// invoke("方法名",参数1,参数2,参数3....);
objects = client.invoke(operationName, params);
} catch (Exception e) {
e.printStackTrace();
}
//log.info(wsdUrl + ",webservice服务返回信息{}", JSON.toJSONString(objects[0]));
System.out.println(JSON.toJSONString(objects[0]));
return JSON.toJSONString(objects[0]);
}
}
//调用上面方法
Test.callWebService("http://localhost/uapws/service/nc.intf.hsc.WebXXX?wsdl","WD","ccc");
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
<version>3.2.4</version>
<exclusions>
<exclusion>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
2.2.4 WSDL2JAVA
这个方法暂时没有用过,就先不写了