Web Service初探
简介
简单地说WebService就是一种Web服务,他是一种跨编程语言和操作系统的远程调用技术。WebService的传输依赖于HTTP协议,通过SOAP协议使用XML格式进行数据传输。
WebService的三要素如下:
- SOAP (Simple Object Access Protocol): 简易对象访问协议,soap用来描述传递信息的格式
- WSDL (WebServices Description Language):Web服务描述语言,用来描述如何访问具体的接口,大多数情况下由软件自动生成
- UDDI (Universal Description Discovery and Integration):通用描述、发现及整合,用来管理、分发、查询webService
Web Service实例
下面直接给出一个WebService的具体实例来说明原生态的WebService开发
服务端开发
WebService接口和实现类代码编写
具体代码如下:
@WebService
public interface HelloService {
@WebMethod
String sayHello(String name);
}
@WebService // 实现类必须要添加@WebService注解
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
return "你好:" + name;
}
}
服务发布代码编写
以上我们定义了需要发布的接口,接下来就是将接口发布到注册中心使其成为WebService服务。具体代码如下:
public class WebServicePublisher {
public static void main(String[] args) {
// STEP1: 定义服务发布的地址
String address = "http://localhost:9999/WS/HelloService";
// STEP2: 发布WebService服务
Endpoint.publish(address, new HelloServiceImpl()); // 第一个参数表示发布到注册中心的地址 第二个参数表示当有客户端向该地址发送请求的时候,服务器端对应的处理类
// STEP3: 打印发布服务成功信息
System.out.println("HelloService发布成功!");
}
}
通过URL访问WSDL文件
服务发布成功之后,我们直接在浏览器输入:http://localhost:9999/WS/HelloService?wsdl即可获取注册中心的WSDL文件:
<definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://server.webservice.rampage.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://server.webservice.rampage.com/" name="HelloServiceImplService">
<types>
<xsd:schema>
<xsd:import namespace="http://server.webservice.rampage.com/" schemaLocation="http://localhost:9999/WS/HelloService?xsd=1"/>
</xsd:schema>
</types>
<message name="sayHello">
<part name="parameters" element="tns:sayHello"/>
</message>
<message name="sayHelloResponse">
<part name="parameters" element="tns:sayHelloResponse"/>
</message>
<portType name="HelloServiceImpl">
<operation name="sayHello">
<input message="tns:sayHello"/>
<output message="tns:sayHelloResponse"/>
</operation>
</portType>
<binding name="HelloServiceImplPortBinding" type="tns:HelloServiceImpl">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="sayHello">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="HelloServiceImplService">
<port name="HelloServiceImplPort" binding="tns:HelloServiceImplPortBinding">
<soap:address location="http://localhost:9999/WS/HelloService"/>
</port>
</service>
</definitions>
WSDL文档的相关说明如下:
- Types : 数据类型定义的容器,它使用某种类型系统(一般地使用XML Schema中的类型系统)。(入参和出参的数据类型)
- Message: 通信消息的数据结构的抽象类型化定义。使用Types所定义的类型来定义整个消息的数据结构(入参和出参)
- Operation: 对服务中所支持的操作的抽象描述,一般单个Operation描述了一个访问入口的请求/响应消息对(方法)
- PortType:对于某个访问入口点类型所支持的操作的抽象集合,这些操作可以由一个或多个服务访问点来支持(服务类)
- Binding: 特定服务访问点与具体服务类的绑定(不看内容,看关系)
- Port:定义为webservice单个服务访问点
- Service:相关服务访问点的集合
客户端开发
自动生成客户端代码
我们有两种方式可以生成客户端代码
1. 如果服务端已经启动,我们可以在CMD中使用wsimport命令来自动生成代码:
wsimport -s E:\workspacce\myWebServiceClient\src -keep http://localhost:9999/WS/HelloService?wsdl
其中-s参数指定的是生成的源码路径,这里我指定客户端代码路径(不需要指定到具体包路径,生成代码的时候会自动生成到与服务器端的同路径文件夹下)。最终生成的文件结构如下:
此时我们写的客户端测试代码为:
public static void main(String[] args) {
// STEP1: 实例化WebService工厂
HelloServiceImplService serviceFactory = new HelloServiceImplService();
// STEP2: 得到远程的Service实例
HelloServiceImpl serviceImpl = serviceFactory.getHelloServiceImplPort();
// STEP3: 远程调用WebService方法
System.out.println(serviceImpl.sayHello("KiDe"));
}
- 如果服务端没有启动,我们只有WSDL文件,那我们可以通过在eclipse中新建Web Service Client项目,并且选中WSDL文件,然后一路Next。最终生成的代码结构为:
我们写的客户端测试代码为:
public class WebServiceInvoker {
public static void main(String[] args) throws ServiceException, RemoteException {
/**
* Method1: 通过HelloServiceImplServiceLocator来获取远程接口
*/
/*// STEP1: 实例化WebService工厂
HelloServiceImplService serviceFactory = new HelloServiceImplServiceLocator();
// STEP2: 得到远程的Service实例
HelloServiceImpl serviceImpl = serviceFactory.getHelloServiceImplPort();
// STEP3: 远程调用WebService方法
System.out.println(serviceImpl.sayHello("KiDe"));*/
/**
* Method2: 通过代理类来获取远程接口
*/
// STEP1: 实例化WebService工厂
HelloServiceImplProxy serviceProxy = new HelloServiceImplProxy();
// STEP2: 得到远程的Service实例
HelloServiceImpl serviceImpl = serviceProxy.getHelloServiceImpl();
// STEP3: 远程调用WebService方法
System.out.println(serviceImpl.sayHello("KiDe"));
// System.out.println(serviceProxy.sayHello("KiDe")); // 也可以直接通过代理类调用服务
}
}
同理我们也可以通过指定远程接口实现类的方式自动生成服务端代码。其实通过eclipse创建客户端或者服务端的方式是使用了CXF框架。会发现此时WSDL生成的测试类调用远程WebService服务相当慢,并且在运行的时候会出现如下警告:
警告: Unable to find required classes (javax.activation.DataHandler and javax.mail.internet.MimeMultipart). Attachment support is disabled.
网上搜索发现时因为少了activation.jar和mail.jar,将这两个jar添加进入项目的build path之后发现告警消除,但是执行还是耗时很长。这说明CXF框架虽然简化了开发,但是执行效率大打折扣。
使用CXF来进行WebService开发
百科上关于CXF的解释如下:
Apache CXF是开源的,CXF是两个项目的结合:由IONA技术公司(现在是Progress的一部分)开发的Celtix和由Codehaus主持的团队开发的XFire,合并是由人们在Apache软件基金会共同完成的。CXF的名字来源于"Celtix"和"XFire"的首字母
官网上的说明如下:
Apache CXF™ is an open source services framework. CXF helps you build and develop services using frontend programming APIs, like JAX-WS and JAX-RS. These services can speak a variety of protocols such as SOAP, XML/HTTP, RESTful HTTP, or CORBA and work over a variety of transports such as HTTP, JMS or JBI.
下载Apache CXF
直接去官网http://cxf.apache.org/下载,这里我下载的版本为: 3.2.1。解压之后文件目录结构如下:
具体目录说明如下:
- licenses: 引用的第三方jar包的相关许可协议
- modules:包含了 CXF 框架根据不同特性分开进行编译的二进制包文件。发布基于 CXF 框架的 Web 项目时,可以选择使用该目录下的所有 .jar 文件,也可以选择 lib 目 录中的 cxf-2.0.2-incubator.jar 文件
- samples:包含了所有随 CXF 二进制包发布的示例,包含这些示例的源代码和相关 Web 应用配置文件,可以方便地用 Ant 来编译运行测试这些示例,来了解 CXF 的开发和使用的方法。可以通过 samples 目录和它各个子目录下的 README.txt 的文件来详细了解示例的编译与运行的步骤
- lib: 基于CXF框架开发可能需要用到的相关jar包
- bin:CXF框架提供的相关工具包
开发WebService服务器端
引入相关jar包
直接新建一个Java项目,然后将CXF的lib目录下的所有jar包添加到项目的build path。
编写服务接口并发布
直接上代码:
@WebService
@BindingType(value=javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)
public interface HelloService {
String sayHello(String name);
}
@WebService
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
return "你好:" + name;
}
}
public class ServicePublisher {
public static void main(String[] args) {
// STEP1: 创建Bean工厂
JaxWsServerFactoryBean factoryBean = new JaxWsServerFactoryBean();
// STEP2: 设置服务发布地址已经发布的接口
factoryBean.setAddress("http://localhost:8888/ws/HelloService");
factoryBean.setServiceClass(HelloService.class);
factoryBean.setServiceBean(new HelloServiceImpl());
// STEP3: 发布服务
factoryBean.create();
System.out.println("HelloService服务发布成功!");
}
}
需注意这里需用到JDK1.8
开发WebService客户端
使用CXF的工具生成客户端代码
在CXF工具的bin目录下执行下面命令:
wsdl2java –d . http://localhost:8888/ws/HelloService?wsdl
会在bin目录下生成对应客户端代码,代码与直接通过wsimport一致
编写客户端测试代码
与前面一致,这里不再说明
WebService调用流程分析
实现一个完整的WebService服务包括以下步骤:
◆ Web服务提供者设计实现Web服务,并将调试正确后的Web服务通过Web服务中介者发布,并在UDDI注册中心注册(发布)
◆ Web服务请求者向Web服务中介者请求特定的服务,中介者根据请求查询UDDI注册中心,为请求者寻找满足请求的服务(发现)
◆ Web服务中介者向Web服务请求者返回满足条件的Web服务描述信息,该描述信息用WSDL写成,各种支持Web服务的机器都能阅读(发现)
◆ 利用从Web服务中介者返回的描述信息生成相应的SOAP消息,发送给Web服务提供者,以实现Web服务的调用(绑定)
◆ Web服务提供者按SOAP消息执行相应的Web服务,并将服务结果返回给Web服务请求者(绑定)
在Web应用中使用WebService
-
在服务接口上添加@WebService注解
- 创建服务接口实现类
- 在web.xml中添加CXF的Servlet配置
<servlet> <servlet-name>cxf</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>cxf</servlet-name> <url-pattern>/ws/*</url-pattern> </servlet-mapping>
- 配置cxf-servlet.xml
<jaxws:server id="bye" address="/bye" serviceClass="com.rl.cxf.web.inter.ByeInter"> <jaxws:serviceBean> <bean class="com.rl.cxf.web.inter.ByeInterImpl"></bean> </jaxws:serviceBean> <jaxws:outInterceptors> <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean> </jaxws:outInterceptors> <jaxws:inInterceptors> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean> </jaxws:inInterceptors> </jaxws:server>
- 使用wsdl2java根据WSDL地址创建客户端代码
- 写客户端用例进行调用
其他
通过pom引入WebService相关jar包
一般来说如果web项目想集成CXF框架来进行WebService调用,至少需要引入CXF相关的jaxws和http协议的支持
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>3.2.1</version>
</dependency>
参考链接
http://blog.csdn.net/jiandanfeng2/article/details/53439748
http://blog.csdn.net/qq_14852397/article/details/52761425
http://blog.csdn.net/aqsunkai/article/details/51711087
http://blog.csdn.net/qq32933432/article/details/51394749
http://blog.csdn.net/qq_35712358/article/details/71244342
https://www.cnblogs.com/fengwenzhee/p/6915606.html
http://blog.csdn.net/yangwenxue_admin/article/details/51059125
与Spring框架集成请看后续更新的Spring官方文档解读之远程调用和WebService篇
黎明前最黑暗,成功前最绝望!