服务器主动向android手机端推送消息---------Web Service技术解析

Web Service不是框架,更甚至不是一种技术,而是一种跨平台、跨语言的规范。是为了解决不同语言所编写的应用之间如何相互调的需求场景,集中解决:远程调用、跨平台调用和跨语言调用。

Web Service在实际中的用途;1、Linux上的java应用,去调用Windows平台上的C应用。2、不同公司的业务整合,业务整合就要带来不同公司的系统整合,不同公司的系统可能存在平台不同、语言不同的问题。

W3C组织对WebService的定义如下,它是一个软件系统,为了支持跨网络的机器间相互操作交互而设计。WebService服务通常被定义为一组模块化的API,它们可以通过网络进行调用,来执行远程系统的请求服务。以 HTTP 协议为基础,通过XML进行客户端和服务器端通信的框架/组件。  

有两个关键点:

1. 服务端提供的功能 通过 xml 描述

2. 第一步中的描述的功能 嵌入到HTTP协议中,使得能通过HTTP协议进行通信(所谓的 SOAP )。


采用这两个技术的目的主要是:

1. 跨平台 支持 HTTP 协议的主机和服务器 都能够建立通信联系 并且大部分的主机和服务器 (99.999% 以上 将支持 HTTP 协议。一般而言,不同目标主机之间的通信,需要通过防火墙,打开某个端口 , HTTP 协议的优势在于,防火墙一般不会封掉 80 端口 这样就可以方便,安全的通信。


2. 跨语言 任何语言都支持 XML 文本解析 这个的目的是为了实现不同语言之间的通信 通信的内容,是被xml 限制的,因此这样进行通信,能跨越语言障碍,即, Java 开发的服务端,客户端可以用 访问 可以用javaVB 等访问 反之亦然。

当然, 架构比我们上面说到的图要更为复杂,上面只是说明了一来一回的通信 实际情况还需要考虑以下问题 ,参照图例说明:

1. 服务器端 (Provider) 提供统一的标准化服务。 就像开办一个公司 即 Server Provider), 工商行政管理局,注册一下公司地址和性质。 目的是 别人要用公司的服务,从工商管理局就知道你的地址。这样统一的做法,是方便所有的公司以及所有需要公司提供服务的客户。 并且这些信息是最大限度的公开。


2. 客户端 (Requester) 到注册中心 (Registry) 拿到公司的基本信息之后 去找到这个公司 然后使用该公司提供的服务。


注意上面图中的基本步骤的标号 现解释如下

1. Provider节点提供好服务后 首先注册到节点Registry

和 3. Requester节点到Regitry节点查信息找到需要的Provider及其提供的 Service

4. Requester 使用 Provider 提供的服务

其细节部分的流程图如下图所示:


1. Client有需要,想调用一个服务,但不知道哪里去调用 但知道 UDDI Registry 上可以查到。

2. 果然 UDDI 记录了某个一个叫做 Web Server A 的服务器能提供这样的服务。

3. 于是 Client 去 Web Server A, 询问确切的调用方法。

4. Web Server A 看到 Client 提出的确切方法查询之后, 立即返回给它一个 WSDL 描述的 xml 文档这里记录他能提供的各类方法接口 .

5. Client了解到这些之后,将这些 xml 的接口方法,封装成为 HTTP 请求 发给 Web Server A. 这些封装方式采用的是标准的SOAP方式 实质是满足 HTTP 协议的一些 SOAP 的报文消息。

6. Web Server A 回应的也是HTTP协议的SOAP。这样双方的请求--响应完全畅通。

上面我们看到的是应用原理图,进一步深入,Webservice协议架构图如下图所示:


上面我们详细介绍了发现Service(UDDI), Service提供的接口描述(WSDL), 调用Service(SOAP), 以及传输(HTTP)的的整个过程。这个技术的核心是SOAP

SOAP+HTTP 协议已经足够成熟,不用我们自己通过xml生成带有SOAP变迁的HTML脚本,有很多工具可以帮住我们实现。事实上,开发起来还是相当简便的。 应用开发可分为如下两种情况:

情况 A:已知存在 Web Service, 客户端的开发可以通过以下步骤 

1. 通过UDDI,查找到Client程序需要的Web Service的位置

2 . 通过 WebService 找到 WSDL 接口描述文件

3 . 通过工具,将步骤 得到的 WSDL 文件,生成一个 Client Stub, 这个实质上是代码 也就是打了一个桩。把这个stub的代码归并到 Client 程序中

4.  每次Client需要调用WebService的时候,直接调用步骤4生成的Stub接口,就实现了对 Server 端的调用。

情况B:Server 端的开发,同样无需做解析SOAP这样的事,框架会帮我们做好。大致步骤如下 :

1 . 实现 WebServer 需要提供的所有功能

2 . 利用WSDL文件(或者IDL)生成Server Stub, 这些代码将负责接收从外界获得的请求,并将其转发给 Web Server Service Implementation(实现代码)。当 Service Implementation 的代码处理完,产生结果之后,又会把结果交给 Server Stub, 然后Server Stub可以产生一个SOAP 的响应 . Server Stub + Server Implementation 合在一起 称为 Web Service Container, 个就是让发送到 WebService 的 HTTP 请求,直接送到 Server Stub 上面的。


Web Service整体处理过程是:对于服务器端就是将已经实现了的应用接口暴露出来供他人调用。对于客户端来说就是根据WSDL文件来产生对应的客户端代码,这样我们客户端就可以根据生成的代码来调用服务器端所暴露出来的接口程序了。

上面说的都是理论,肯定会有点晕。下面通过几个简单的例子我们就会清楚了解Web Service了。

在开发Web Service时有很多工具,我用的是CFX。

Apache CXF = Celtix + XFireApache CXF 的前身是叫Apache CeltiXfire,现在已经正式更名为Apache CXF 了,以下简称CXFCXF继承了 Celtix 和 XFire 两大开源项目的精华,提供了对 JAX-WS全面的支持,并且提供了多种 Binding Data BindingTransport 以及 Format的支持,并且可以根据实际项目的需要,采用 Code First 或者 WSDL First 来轻松地实现 Web Services 的发布和使用。我用的版本是apache-cxf-2.4.0。

下载完成后,将其解压到任意文件夹,我解压到了D:\。解压后进入bin目录会看到*.bat批处理文件,我们以后开发过程中就要用到这些文件。为了方便使用将bin目录添加到系统环境变量Path中。例如我的就是将D:\apache-cxf-2.4.0\bin添加到系统环境变量Path的尾端。

添加好后,我们就开始做第一个例子:

每个Web Service组件需要2个部分,接口和实现类。首先开发Web Service服务器端,分为3个步骤

1、开发一个Web Service业务接口,该接口要用@WebService修饰,代码如下:


package org.fkjava.cxf.ws;

import javax.jws.WebService;

/*Web Service业务接口,该接口要用@WebService修饰,注意@WebService的位置*/
@WebService
public interface HelloWorld {
	
	public String sayHi(String name);

}

2、开发一个Web Service实现类,实现类也需要用@WebService修饰,代码如下:


package org.fkjava.cxf.ws.impl;

import java.util.Date;

import javax.jws.WebService;

import org.fkjava.cxf.ws.HelloWorld;

/*endpointInterface为接口名,注意是完整的接口名(包括完整的包名和类名,serviceName为服务名可以随便取,这里也是注意@WebService的位置*/
@WebService(endpointInterface="org.fkjava.cxf.ws.HelloWorld"
		,serviceName="HelloWorldWs")
public class HelloWorldWs implements HelloWorld {


	public String sayHi(String name) {
		return name + ",您好" + "现在时间是:" + new Date();
	}

}

3、发布Web Service,发布Web Service是通过在main函数中处理的,代码如下:

package main;

import javax.xml.ws.Endpoint;

import org.fkjava.cxf.ws.HelloWorld;
import org.fkjava.cxf.ws.impl.HelloWorldWs;

public class ServerMain {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		HelloWorld hw = new HelloWorldWs();
		/*调用Endpoint的publish方法发布Web Service,第一个参数是绑定的服务地址,也就是本机的IP地址,
		注意IP地址后面还要跟一个服务名(随便取),这个名字在获得WSDL文件时要用*/
		Endpoint.publish("http://192.168.1.117/fkjava", hw);
		System.out.println("Web Service暴露成功");
	}

}


要发布Web Service还需要引入一些jar包,这些jar包可以在刚才解压的 apache-cxf-2.4.0\lib目录下找到,在我本机的绝对路径就是D:\apache-cxf-2.4.0\lib下可以找到这些jar包。

要在java Project中引入jar包可以右击工程-->Build Path-->Add Libraries-->User Library-->User Libraries

-->new->cfx2.4(这个是新建的报名,自己取)-->选中刚新建的cfx2.4-->Add External JARS-->选择要添加的jar包

(可多选)。

整个工程和引入的jar包如下所示:


运行这个工程,然后再浏览器重输入:http://192.168.1.117/fkjava?wsdl(http://192.168.1.117/fkjava

就是主函数中Endpoint.publish("http://192.168.1.117/fkjava", hw)语句的第一个参数)。回车可得WSDL描述文件:

WSDL(Web Service Definition Language)是Web Service描述语言,任何语言实现了Web Service ,都需要提供、

并暴露WSDL文档。我们的客户端就是根据WSDL文档来生成与服务器端对应的客户端代码的。

到此,服务器端开发完成,下面来看客户端。

1、调用CXF提供的wsdl2java工具,根究WSDL文档生成相应的java代码。

首先在eclipse中建一个空的java Project: WS_Client


然后使用cfx工具来生成客户端代码,操作如下:在cmd中进入刚才建立的空的工程WS_Client中的src目录,然后利用wsdl2java来生成客户端代码。



这里wsdl2java是apache-cxf-2.4.0\bin下的批处理文件,因为之前我们以将此目录配置到环境变量Path中,所以在此可以直接使用,红圈中wsdl2java 后面的地址就是产生前面WSDL文档的地址,当然这里也可以将之前产生的WSDL文档内容保存为文件,然后用wsdl2java + 此文件也可以产生客户端代码,但有了地址我们就不需要那么麻烦了。此时再看刚才建立的空工程WS_Client中已经有了cfx工具自动生成的代码(F5刷新下),这些代码就是服务器端所暴露的应用接口的代理,其中提供的方法与服务器端暴露出来的方法一一对应。


2、找到wsdl2java所生成的类中,一个继承了Service的类,该类的实例可当成工厂来用(就是上面的org.jkjava.cxf.impl.HelloWorldWs.java中的类,一般也是*.impl中的类)。下面给出部分代码:

@WebServiceClient(name = "HelloWorldWs", 
                  wsdlLocation = "http://192.168.1.117/fkjava?wsdl",
                  targetNamespace = "http://impl.ws.cxf.fkjava.org/") 
public class HelloWorldWs extends Service {

    public final static URL WSDL_LOCATION;

    public final static QName SERVICE = new QName("http://impl.ws.cxf.fkjava.org/", "HelloWorldWs");
    public final static QName HelloWorldWsPort = new QName("http://impl.ws.cxf.fkjava.org/", "HelloWorldWsPort");
    static {

从上可看到class HelloWorldWs extends Service。

3、在工程中添加包含main方法的类,调用Service子类的实例的getXXXPort(这里XXX通常都是继承了Service的类的类名)方法,返回远程Web Service的代理。代码如下:

package lee;

import org.fkjava.cxf.ws.HelloWorld;
import org.fkjava.cxf.ws.impl.HelloWorldWs;

public class ClientMain {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		HelloWorldWs factory = new HelloWorldWs();
		/*这里的HelloWorld是客户端的HelloWorld,拥有预付气短HelloWorld向同的方法,
		 此处返回的只是远程Web Service的代理*/
		HelloWorld hw = factory.getHelloWorldWsPort();
		//相当于调用远程服务器端HelloWorld中的sayHi()方法。
		System.out.println(hw.sayHi("孙悟空"));

	}

}

这时客户端工程目录为:

这时运行客户端工程就可以看到控制台输出:孙悟空,您好现在时间是:Wed Aug 21 01:07:23 CST 2013。调用服务器端的代码成功。

这里需要注意因为调用的是服务器端的服务,所以客户端要想运行成功,服务器端必须得是开着的。

第一个例子结束,下篇我们来看下第二个例子。


你可能感兴趣的:(项目总结)