一、概念定义
Web Service是一个平台独立的,低耦合的,自包含的、基于可编程的web应用程序,可使用开放的XML标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的互操作的应用程序。
简单对象访问协议(Simple Object Access Protocol,SOAP)是一种基于 XML 的协议,可以和现存的许多因特网协议和格式结合使用,包括HTTP,SMTP,MIME,基于“通用”传输协议是 SOAP的一个优点。它还支持从消息系统到远程过程调用RPC等大量的应用程序。SOAP提供了一系列的标准,如WSRM(WS-Reliable Messaging)确保可靠性与安全性,确保异步处理与调用;WS-Security、WS-Transactions和WS-Coordination等标准提供了上下文信息与对话状态管理。
REST(Representational State Transfer)一种轻量级的Web Service架构,可以完全通过HTTP协议实现。其实现和操作比SOAP和XML-RPC更为简洁,还可以利用缓存Cache来提高响应速度,性能、效率和易用性上都优于SOAP协议。 RESTful 简化了 web service 的设计,它不再需要 wsdl ,也不再需要 soap 协议,而是通过最简单的 http 协议传输数据 ( 包括 xml 或 json) 。既简化了设计,也减少了网络传输量(因为只传输代表数据的 xml 或 json ,没有额外的 xml 包装)。REST架构对资源的操作包括获取、创建、修改和删除资源的操作正好对应HTTP协议提供的GET、POST、PUT和DELETE方法(Verb)。
Restful与SOAP的区别
安全性:SOAP会好于REST
效率和易用性(REST更胜一筹)
成熟度(总的来说SOAP在成熟度上优于REST)
二、框架对比
参考文档:https://blog.youkuaiyun.com/xybelieve1990/article/details/50955230
1、JWS是Java语言对WebService服务的一种实现,用来开发和发布服务。而从服务本身的角度来看JWS服务是没有语言界限的。但是Java语言为Java开发者提供便捷发布和调用WebService服务的一种途径,java6才开始支持。
2、Axis2是Apache下的一个重量级WebService框架,准确说它是一个Web Services / SOAP / WSDL 的引擎,是WebService框架的集大成者,它不但能制作和发布WebService,而且可以生成Java和其他语言版WebService客户端和服务端代码。这是它的优势所在。但是,这也不可避免的导致了Axis2的复杂性,使用过的开发者都知道,它所依赖的包数量和大小都是很惊人的,打包部署发布都比较麻烦,不能很好的与现有应用整合为一体。但是如果你要开发Java之外别的语言客户端,Axis2提供的丰富工具将是你不二的选择。
3、CXF是Apache旗下一个重磅的SOA简易框架,它实现了ESB(企业服务总线)。CXF来自于XFire项目,经过改造后形成的,就像目前的Struts2来自WebWork一样。可以看出XFire的命运会和WebWork的命运一样,最终会淡出人们的视线。CXF不但是一个优秀的Web Services / SOAP / WSDL 引擎,也是一个不错的ESB总线,为SOA的实施提供了一种选择方案,当然他不是最好的,它仅仅实现了SOA架构的一部分。
三、服务端实现
1、JWS实现
WebService.java
import javax.jws.WebMethod;
@javax.jws.WebService
public interface WebService {
@WebMethod
String setService(String request);
}
WebServiceImpl.java
package webservices;
import javax.jws.WebParam;
import webservices.WebService;
import webservices.Treasury;
@javax.jws.WebService
public class WebServiceImpl implements WebService {
@Override
public String setService(@WebParam(name="request")String request){
Treasury treasury = new Treasury();
String result = treasury.setService(request);
return result;
}
}
WebServicePublish.java
package webservices;
import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.xml.ws.Endpoint;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import webservices.serviceImpl.WebServiceImpl;
import webservices.util.IpUtil;
public class WebServicePublish {
private static Logger log = Logger.getLogger(WebServicePublish.class);
public static void main(String[] args) {
try {
String ipAddress = InetAddress.getLocalHost().getHostAddress();
if (IpUtil.isIPv6Address(ipAddress)) {
ipAddress = "["+ipAddress+"]";
}
String address = "http://"+ipAddress+":8080/webservices";
Endpoint.publish(address , new WebServiceImpl());
log.info("webService publish success ^_^ url:"+address);
} catch (UnknownHostException e) {
log.error("get local host ipaddress error:"+e);
}
}
}
注意:JWS有很多的注解适配,可参考:https://www.jianshu.com/p/d9a59a99f097
如在WebServiceImpl配置
@javax.jws.WebService( targetNamespace="http://webservice",
name="webservicesPortType",
serviceName="webservices",
portName="webservicesHttpSoap12"
)
@javax.jws.soap.SOAPBinding(style=Style.DOCUMENT,parameterStyle=ParameterStyle.WRAPPED)
@BindingType(value =SOAPBinding.SOAP12HTTP_BINDING)
2、Axis2实现
参考:https://blog.youkuaiyun.com/qq877507054/article/details/61922139
3、CXF实现
参考:https://www.cnblogs.com/yg_zhang/p/5928951.html
四、客户端实现
1、wsimport生成客户端
JDK提供了一个wsimport.exe的命令,主要是用于将WebService生成客户端代码,然后好调用WebService。
wsimport是根据JDK1.6.0_21及以上的生成本地代码的,它只能解析服务器端的SOAP协议为1.1,不能解析SOAP1.2的协议。如果解析SOAP1.2 将会解析不完全。
用法:前提是已经将JDK配置为了path环境变量 C:\Documents and Settings\Administrator>wsimport -s D:\test -p webservice http://localhost:30823/server/webservices?wsdl
参数解释:
-s 后面指定生成源码文件的路径,
-p 自定义类包 http://localhost:8080/server/webservices?wsdl 是wsdl的路径。
-d 后面指定生成class文件的路径
2、Axis2生成客户端
1、 下载axis包(http://axis.apache.org/axis2/java/core/download.html),比如当前版本为axis2-1.7.9,解压至本地。
2、 打开cmd,进入axis2-1.7.9\bin目录下,执行命令:
wsdl2java -uri http://www.webxml.com.cn/WebServices/TrainTimeWebService.asmx?wsdl -p cn.com.webxml -o train
如:wsdl2java -uri http://localhost:30823/server/webservices?wsdl -o D:\\test
wsdl2java -uri D:\\test\\webservices.xml -o D:\\test
参数解释:
-uri表示参数指定了wsdl文件的路径,可以是本地路径,也可以是网络路径
-p参数指定了生成的Java类的包名
-o参数指定了生成的一系列文件保存的根目录
3、在执行完上面的命令后,就会发现在当前目录下多了个src目录拷贝整个文件夹放置工程目录下,并将axis2-1.7.9\lib下的lib包引入到工程中。
4、编写客户端调用代码,参照内容如下:
package webservice;
import java.rmi.RemoteException;
import org.apache.axis2.AxisFault;
import webservices.WebServiceImplServiceStub.SetServiceE;
import webservices.WebServiceImplServiceStub.SetServiceResponseE;
public class Client {
public static void main(String[] args){
WebServiceImplServiceStub stub = null;
try {
stub = new WebServiceImplServiceStub();
SetServiceE setServiceE = new SetServiceE();
WebServiceImplServiceStub.SetService setService = new WebServiceImplServiceStub.SetService();
String request= "<?xml version=\"1.0\" encoding=\"UTF-8\"?><request number=\"ID-0601-170922-0029\" time=\"2019-02-22 09:15:34\" ></request>";
setService.setRequest(request);
setServiceE.setSetService(setService);
SetServiceResponseE setServiceResponseE = stub.setService(setServiceE);
System.out.println(setServiceResponseE.getSetServiceResponse().get_return());
} catch (AxisFault e) {
e.printStackTrace();
}catch (RemoteException e) {
e.printStackTrace();
}
}
}
3、CFX生成客户端
1、 下载cxf包(http://cxf.apache.org/download.html),比如当前版本为apache-cxf-3.3.0,解压至本地。
2、 打开cmd,进入apache-cxf-3.3.0\bin目录下,执行命令:
wsdl2java -d D:\\src -client http://api.xxx.cn/****/service/registerService?wsdl
如:wsdl2java -d D:\\test -client http://localhost:30823/server/webservices?wsdl
参数解释:
-p 指定其wsdl的命名空间,也就是要生成代码的包名:
-d 指定要产生代码所在目录
-client 生成客户端测试web service的代码
-server 生成服务器启动web service的代码
-impl 生成web service的实现代码
-ant 生成build.xml文件
-all 生成所有开始端点代码:types,service proxy,,service interface, server mainline, client mainline, implementation object, and an Ant build.xml file.
3、在执行完上面的命令后,就会发现在当前目录下多了个src目录拷贝整个文件夹放置工程目录下。
4、在WebServiceImpl_WebServiceImplPort_Client文件中,修改入参调用即可,如:
java.lang.String _setService_request = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><request number=\"ID-0601-170922-0029\" time=\"2019-02-22 09:15:34\"></request>";
五、其他说明
1、客户端主要依赖wsdl生成代码,若更换了服务端方式很可能会导致生成的WSDL也不一样,那么客户端需要重新适配。有个项目就是因为觉得axis2太厚重不利于整合,改用了JWS方式实现,但又希望客户对端不做同步修改,折腾了很久也没对接上。
2、Soap协议有1.1和1.2区分,通过soapUI发送,格式头部信息是不同。
soapenv为1.1
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://webservice">
<soapenv:Header/>
<soapenv:Body>
<ser:setService>
<!--Optional:-->
<request><![CDATA[<?xml version="1.0" encoding="UTF-8"?><request number="ID-0601-170922-0029" time="2019-02-22 09:15:34"></request>]]></request>
</ser:setService>
</soapenv:Body>
</soapenv:Envelope>
soap则为1.2
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:web="http://webservice">
<soap:Header/>
<soap:Body>
<web:setService>
<!--Optional:-->
<request><![CDATA[<?xml version="1.0" encoding="UTF-8"?><request number="ID-0601-170922-0029" time="2017-09-22 09:15:34" ></request>]]></request>
</web:setService>
</soap:Body>
</soap:Envelope>
3、WSDL格式字段说明