引言
有没有一种办法可以实现跨应用程序进行通信和跨平台进行通信呢? 换句话说,就是有什么办法可以实现我的应用程序 A 可以和应用程序 B 进行通信呢? 或者说是,我用 Java 写的应用程序和用 . Net 开发的应用程序之间进行通信呢? 很多时候,上面提到的这些,我们是必须要使用的,比如,一个跨应用程序吧。
举一个日常生活的例子吧,我们平常都会使用QQ上面的天气预报功能 吧,那么这个功能是怎么实现的呢?
WebService简介
如果简单的说的话,WebServices就是一组函数库,但是又有不同点,平常我们的函数库都是写在本地上的,而WebService是位于远程机器上(当然也可以是本地机器中)。那么正经一点的说法就是:WebService服务是一种部署在 Web 上的对象或者是应用程序组件,是一种跨编程语言和跨操作系统平台的远程调用技术。
WebService的特点
(1),WebServices 是自包含的。
(2),WebServices 是自我描述的。
(3),WebServices 是跨平台和跨语言的。
(4),WebServices 是基于开放和标准的。
(5),WebServices 是可以组合的。
(6),WebServices 是松散耦合的。
WebService体系结构
Web 服务中介者:
也称为服务代理,用来注册已经发布的 Web服务提供者,并对其进行分类,同时提供搜索服务, 简单来说的话,Web 服务中介者的作用就是把一个 Web 服务请求者和合适的 Web 服务提供者联系在一起,充当一个管理者的角色,一般是通过 UDDI来实现。
Web 服务请求者:
也就是 Web 服务功能的使用者,它通过服务注册中心也 就是 Web 服务中介者查找到所需要的服务,再利用 SOAP 消息向 Web 服务提供者发送请求以获得服务。
Web 服务提供者:
可以发布 Web 服务,并且对使用自身服务的请求 进行响应,Web 服务的拥有者,它会等待其他的 服务或者是应用程序访问自己。
WebServices三种基本元素
SOAP : SOAP 呢,其指导理念是“唯一一个没有发明任何新技术的技术”,是一种用于访问 Web 服务的协议。因为SOAP 基于XML 和 HTTP ,其通过XML 来实现消息描述,然后再通过 HTTP 实现消息传输。
WSDL : WSDL 即Web Services Description Language也就是 Web 服务描述语言。 是基于 XML的用于描述 Web 服务以及如何访问 Web 服务的语言。 WSDL 描述了 Web服务的三个基本属性: (1)服务所提供的操作 (2)如何访问服务 (3)服务位于何处(通过 URL 来确定就 OK 了)
UDDI : UDDI 即 Universal Description,Discovery and Integration,也就是通用的描述,发现以及整合。UDDI 呢是一种目录服务,企业可以通过 UDDI 来注册和搜索 Web 服务。简单来时候话,UDDI 就是一个目录,只不过在这个目录中存放的是一些关于 Web 服务的信息而已。
Apache CXF 简介
Apache CXF = Celtix + XFire,开始叫 Apache CeltiXfire,后来更名为 Apache CXF 了。 CXF 继承了 Celtix 和 XFire 两大开源项目的精华,提供了对 JAX-WS 全面的支持,并且提供 了多种 Binding 、DataBinding、Transport 以及各种 Format 的支持,并且可以根据实际项 目的需要,采用代码优先(Code First)或者 WSDL 优先(WSDL First)来轻松地实现 Web Services 的发布和使用。
Apache CXF特点 : 灵活部署 轻量级容器,可在 Tomcat 或基于 Spring 的容器中部署 Services。 支持多种编程语言 全面支持 JAX-WS 2.0 客户端/服务器编程模型。
CXF使用的相关jar包
我们基于web项目进行的 WebService接口开发,所以 需要导入spring和spring web的相关jar包。 由于cxf-rt-transports-http- jetty.jar依赖jetty的相关jar 包,所以在这里引入。
WebService两大风格
报文格式:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <STUDENT> <NAME>SAM-SHO</NAME> <StudentPhones> <StudentPhone> <num>13612345678</num> <type>移动</type> </StudentPhone> <StudentPhone> <num>13798765432</num> <type>联通</type> </StudentPhone> </StudentPhones> <StudentAddress> <homeAddress>苏州高新区</homeAddress> <workAddress>苏州园区</workAddress> </StudentAddress> </STUDENT>
报文格式:
1 <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> 2 <soap:Header> 3 </soap:Header> 4 <soap:Body> 5 <ns2:sayHi xmlns:ns2="http://service.cxf.com/"> 6 <text>hjp</text> 7 <address>shanghai</address> 8 </ns2:sayHi> 9 </soap:Body> 10 </soap:Envelope>
构建模块:
• 必需的 Envelope 元素,可把此 XML 文档标识为一条 SOAP 消息
• 可选的 Header 元素,包含头部信息
• 必需的 Body 元素,包含所有的调用和响应信息
• 可选的 Fault 元素,提供有关在处理此消息所发生错误的信息
实例:
1).工程右键—New—Interface,添加代码:
说明: @WebService:标记表示该接口是一个WebService服务。
@WebMethod:标记表示WebService中的方法。
@WebParam(name="paramName")表示方法中的参数,name属性限制了参数的名称,若没有指定该属性,参数将会被重命名。
1 package com.cxf.service; 2 3 import javax.jws.WebParam; 4 import javax.jws.WebService; 5 6 @WebService 7 public interface HelloWorld { 8 9 public String sayhi(@WebParam(name="text")String text); 10 11 }
编写WebService的实现层
1 package com.cxf.service; 2 3 import javax.jws.WebService; 4 5 @WebService(endpointInterface="com.cxf.service.HelloWorld" , serviceName="HelloService") 6 public class HelloWorldImpl implements HelloWorld{ 7 8 @Override 9 public String sayhi(String text) { 10 11 return "say hello,"+text; 12 } 13 14 }
说明: @WebService(endpointInterface=”对应的WebService接口”,serviceName=”WebService的名字,自己定义”)。
编写发布WebService的类
1 package com.cxf.service; 2 3 import javax.xml.ws.Endpoint; 4 5 public class WebserviceApp { 6 7 public static void main(String[] args) { 8 System.out.println("start service"); 9 HelloWorldImpl hwi = new HelloWorldImpl(); 10 String address = "http://localhost:8080/helloworld"; 11 Endpoint.publish(address, hwi); 12 System.out.println("end service"); 13 14 } 15 16 }
说明: 使用Endpoint.publish(url,WebService)方法,该方法需要两个参数,一个是服务的发布地址,即最后你在浏览器上访问你发布的WebServcie时用的Url,另一个参数就是你要发布的WebService的实现类。右键——Run as——Java Application,服务发布成功后,访问http://localhost:8080/helloworld?wsdl进行测试,看到如下图效果即为成功。(必须带上?wsdl,不然是不被识别的,它代表的是对这个WebService的相关描述)
查看是否成功发布
编写客户端调用
1 public class HelloWorldClient { 2 3 public static void main(String[] args) { 4 /*System.out.println("+++++++++start webservice"); 5 ApplicationContext factory = new ClassPathXmlApplicationContext("/applicationContext.xml"); 6 HelloWorld client = (HelloWorld)factory.getBean("client"); 7 String result =client.sayHi("hello spring"); 8 System.out.println(result);*/ 9 10 //不与spring结合的发布方式 11 JaxWsProxyFactoryBean factory2 = new JaxWsProxyFactoryBean(); 12 factory2.getInInterceptors().add(new LoggingInInterceptor()); 13 factory2.getOutInterceptors().add(new LoggingOutInterceptor()); 14 factory2.setServiceClass(HelloWorld.class); 15 factory2.setAddress("http://localhost:8080/helloworld"); 16 HelloWorld client2 = (HelloWorld) factory2.create(); 17 String reply = client2.sayHi("hello world!"); 18 System.out.println(reply); 19 } 20 }
用JaxWsProxyFactoryBean方法创建一个客户端厂;factory2.getInInterceptors().add() 和factory2.getOutInterceptors().add()方法,是为了打印控制台日志的。重点是factory2.setServiceClass(HelloWorld.class),表明你的WebService接口是哪一个,然后factory2.setAddress()表明你的服务地址是什么,最后进行客户端client的生成,调用相应的方法
查看调用结果
WebService与Spring的结合
有的WebService服务需要我们根据需求去自主发布,但是有些公用的服务,我们可以在启动Tomact启动时就同时发布上去,在Tomact启动完成后,我们马上就可以进行使用,那么为了实现这个想法,我们就需要用到WebService与Spring的结合。
1).定义服务接口: 同上;
2).编译服务实现层: 同上;
3).在web.xml中增加监听
1 <servlet> 2 <servlet-name>CXFServlet</servlet-name> 3 <servlet-class> 4 org.apache.cxf.transport.servlet.CXFServlet 5 </servlet-class> 6 <load-on-startup>1</load-on-startup> 7 </servlet> 8 <!-- 对cxf服务进行监听,所有的/webservice/*请求都会被拦截,类似于Spring mvc的拦截器 --> 9 <servlet-mapping> 10 <servlet-name>CXFServlet</servlet-name> 11 <url-pattern>/webservice/*</url-pattern> 12 </servlet-mapping>
配置文件的引入
配置application文件
新建名为applicationContext.xml的配置文件。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:jaxws="http://cxf.apache.org/jaxws" 5 xmlns:jaxrs="http://cxf.apache.org/jaxrs" 6 xsi:schemaLocation=" 7 http://www.springframework.org/schema/beans 8 http://www.springframework.org/schema/beans/spring-beans.xsd 9 http://cxf.apache.org/jaxws 10 http://cxf.apache.org/schemas/jaxws.xsd 11 http://cxf.apache.org/jaxrs 12 http://cxf.apache.org/schemas/jaxrs.xsd"> 13 <import resource="classpath:META-INF/cxf/cxf.xml"/> 14 15 <jaxws:endpoint 16 id="helloWorld" 17 implementor="com.cxf.service.HelloWorldImpl" 18 address="/helloWorld" /> 19 20 <!-- 为了实现spring的客户端调用接口配置 --> 21 <bean id="client" 22 class="com.cxf.client.HelloWorldClient" 23 factory-bean="clientFactory" 24 factory-method="create"/> 25 <bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean"> 26 <property name="serviceClass" value="com.cxf.service.HelloWorld"/> 27 <property name="address" value="http://localhost:8080/CXFDemo/webservice/helloWorld"/> 28 </bean> 29 </beans>
启动Tomact,查看结果
访问的url为localhost:8080(根据实际情况自行修改)/项目名/webservice(web.xml中的配置)/address(application文件中的发布地址)?wsdl。
客户端更改