WebServices介绍简单使用

同进程查找JDNI服务
比如说我们通过JNDI来查找Tomcat中配置的DataSource,代码如下
Context context = new InitialContext();
DataSource ds = (DataSource)context.lookup("java:/comp/env/jdbc/oracleds");
将这两行代码放到JSP页面中,在new InitialContext()之后,就能在JNDI服务上查到DataSource
这是因为JSP和JNDI服务是在同一个进程里的。但如果不是同一个进程,则不能new InitialContext()
这就好像是两间屋子里面的资源无法共享一样,除非穿墙,否则是无法拿到对面屋子里的资源的
所以在main()方法中是无法有效的执行这两行代码的
因为在运行main()方法时,它会在一个进程中启动JVM来解析class,而Tomcat那里又是另外一个进程
所以在这两个进程之间,只是通过简单的new InitialContext()是找不到JNDI服务的,事实上这个过程就是在远程调用
其实所谓的远程,并不是说跨机器、跨网络就是远程,只要是两个进程之间的调用,就算是远程调用了
也就是说只要是不在同一个JVM里面(更准确的来说是不在同一个地址空间内)的调用,它就是远程调用
也就是说如果我们在同一个机器上,启动两个进程,然后进行互相调用,那么这个过程就已经是远程调用了



分布式通信的基本原理
主要是使用客户端上的Stub(存根)和远程对象上的Skeleton(骨架)作为中介,来实现分布式通信的
在客户端会有一个叫做Stub(存根)的东西,其实现采用的是非常典型的代理模式,是远程对象在客户端的代理
Stub会封装所交互的数据的访问细节(如何压缩、压包、编码等),然后通过相应的协议与Skeleton(骨架)交换数据
对于Java领域的分布式通信技术,较常见的有EJB技术、CORBA技术、WebService技术等等
如果是EJB技术,那么Stub就会采用RMI-IIOP协议来传送数据给Skeleton
如果是CORBA技术,那么Stub就会采用IIOP协议来传送数据给Skeleton
如果是WebServices技术,那么Stub就会通过SOAP(搜魄)协议来传送数据给Skeleton
也就是说Stub会按照特定协议将信息传送给Skeletion
而Skeleton会将Stub传送过来的数据解析成特定的语言对象并发送给远程对象,即服务端
比如说服务端是采用Java开发的,那么Skeleton就会将接收到的数据解析成Java对象,再传送给服务端
同理若服务端是采用C#开发的,那么Skeleton就会将接收到的数据解析成C#对象,再传送给服务端
接着服务端就会返回信息给客户端,于是Skeleton就会将所要返回的信息进行压缩编码并通过相应的协议传送给Stub
接着Stub就会将Skeleton传送过来的信息解开,再传送给客户端,所以客户端就获得了相应的服务端的返回信息了
这里的客户端对象和远程对象是位于不同的JVM中的,或者说是不同的系统平台中,此即分布式通信
它主要就是靠Stub和Skeleton来通讯,说白了,分布式通信也就是Stub和Skeleton之间的通信



分布式通信的举例
假设有两个服务器,本地的服务器采用的是Java开发的远程的是一个采用C#开发的天气预报的服务器,二者可以通过以下几种方式通信
1、如果二者不采用某些技术来通信的话,也是可以的
     比如远程服务器开放数据库表,然后本地服务器使用JDBC访问这个开放的数据库表,也能够实现分布式通信
     只不过开放数据库表的做法,不太好。会暴露表结构、安全性也不是特别好、并且也是不标准的
     另外有些数据,并不是单纯的一张表就能体现出来的,可能要通过一定的算法计算出来结果的
2、如果二者采用WebServices通信的话,那么就是使用SOAP协议来交互数据,该数据就是采用HTTP协议传送XML文件
     但此时双方进行通信的过程中,由于采用的是SOAP协议,所以双方交换的数据是大文本(通常是XML文件)文件
     这时就有一个问题:假设需要请求10000条数据,那么所交换的这个大文本文件的体积,将会是非常大的,传送的过程就会很耗时
     有一个解决办法是:可以让Java通过它的ZIP  API压缩该XML文件,然后上传到FTPServer上,服务端再下载这个压缩后的XML文件
     接着服务端再解压缩这个XML文件,然后读取,再进行相应的处理,这也是解决SOAP协议传递大文本文件的速度特别慢的办法之一
3、可以令远程服务器把天气预报的数据,定时的上报到某一个FTPServer,然后客户端的Java程序也定时的到FTPServer上取数据
4、第三种方式的缺点是不实时。我们也可以让客户端发送消息给远程的服务端,服务端会侦听,然后再发送消息返回给客户端
5、二者采用纯粹的IIOP(属于CORBA技术架构)协议来通信
6、如果远程服务器是采用EJB开发的,那么二者可以通过RMI-IIOP协议通信。而RMI-IIOP协议采用的是二进制传输,效率会更快
     由于EJB也应用了CORBA的IIOP协议,所以在异构系统整合的时候,CORBA的互通性会比较好
     步骤大致是服务器端先把EJB注射到JNDI树上,然后客户端的Java程序lookup这个JNDI树上对应的名字,这样EJB就传过来了
     也就是说此时Stub就动态的传到客户端的Java程序中了,然后客户端就调用Stub,接下来就是Stub和Skeleton打交道了
     另外EJB只能使用Java来写,但是可以使用CORBA技术来调用EJB



EJB的前生
在EJB1.X的时候,对于分布式通信的服务的支持还很差
比如写一个EJB的话,则至少要写三个类,然后编译,编译成Stub和Skeleton,这时大约会编译出来5、6个类
后来有所改善,最先改的就是JBOSS。开发JBOSS的EJB容器的这个人,在Java技术上是非常厉害的一个人,传说中的大牛吧
引入了JDK的动态代理来完成Stub的自动生成,所以EJB的开发就简单了一些,只写三个类就可以了,存根会在运行时生成
也就是在把EJB注射到JNDI上之后,我们就可以在另一个JVM里面lookup这个JNDI的名字,这样便得到了EJB
然后它就会序列化的把EJB传送到客户端它传的就是Stub,而它在JVM内存里面是看不见的
当我们在客户端调用相应方法的时候,其实在内存里面调用的就是Stub,然后Stub再与远端打交道



WebServices——解决异构系统之间的通信
从标准上来说,整个技术架构是WebServices(带s的), 有时会看到很多人写成WebService(不带s的),其实这是不标准的
WebService指的是单独一个服务,而WebServices指的是它的技术架构
目前WebServices技术使用的稍多些,因为它走的是HTTP协议,它可以穿越防火墙,它天生就能穿越80端口
但是WebServices的缺点就是:慢!!因为WebServices是基于HTTP协议传送大文本,实际传送的是XML文件
IIOP(属于CORBA技术架构)协议传送的就是二进制,所以它的效率要比WebServices快很多
所以在一些行业里,也大量的使用了CORBA技术,比如说电信网
而CORBA的缺点就是:编程模型复杂,它是属于重量级的



SOAP——简单对象访问协议
假设我们在本地通过Java写一个main()方法与远程的一个可以是用任何语言写的取得天气预报的服务打交道
如果打交道的过程中采用的是WebServices技术的话,那么它传送给远程的就是XML文件,使用的是SOAP协议
SOAP即简单对象访问协议其实质就是HTTP+XML,也就是说它是通过HTTP协议来传送XML文件
也就是说SOAP是基于XML的简易协议,可以使应用程序在HTTP之上进行信息交换
或者更简单地说SOAP是用于访问网络服务的协议,而一条SOAP消息就是一个普通的XML文档
使用SOAP协议通信的过程中,远程对象会将所要返回的信息形成一个XML文件传给Stub
然后客户端就会把XML文件转换成Java对象,而当客户端在调用远程服务时
客户端就会把Java对象转换成XML文件作为参数传给Skeleton,而Skeleton就负责把XML文件转换成远程服务的相应语言的对象
比如说服务端是采用Java开发的,那么Skeleton就会将接收到的数据解析成Java对象,再传送给服务端
同理若服务端是采用C#开发的,那么Skeleton就会将接收到的数据解析成C#对象,再传送给服务端
所以,WebServices能够实现异构语言的通信,可以用来整合异构系统
同理,如果不是异构系统的话,也就没有必要使用WebServices技术
比如说客户端和远程对象都是采用Java开发的,那么就没有必要使用WebServices了
因为二者都是采用Java开发的,它们之间可以直接以二进制来传输数据,访问效率会快的很多
而WebServices其实就是基于XML的数据交换,即WebServices所传送的是大文本,效率自然就慢了
除非我们的系统是采用多语言开发的,那么就可以考虑使用WebServices技术
或者说我们的系统想做的通用一些,则可以采用并开放WebServices的一些方法
其实SOAP就是用来最终完成Web服务的调用的而WSDL则用于描述如何使用SOAP来调用Web服务



WSDL——WebServices描述语言
仍以上面为例,即客户端采用Java开发,服务端是采用C#开发的天气预报的服务
作为客户端,它知道在服务端提供了一个能够获取天气预报的服务,并且客户端也可以调用该服务
但作为服务端,应该对这些服务进行描述,以告诉客户端都有哪些服务可供调用
而这个服务是不能用C#语言来描述的,因为采用Java开发的客户端是无法识别的
所以服务端就需要使用一套语言来描述它所提供的服务,这套语言就是WSDL
其实WSDL就是一个XML文件,也就是说WebServices定义了一套标准,里面都是XML格式
使用这套标准来描述服务端对外提供的服务,比如C#的方法名、参数名、返回值等信息
假设服务端的天气预报功能还没有使用C#来实现,并且客户端也没有使用Java来实现
这时突然要求定义一套标准来描述一下即将准备实现的服务端的天气预报的功能
并且客户端可以任意调用这个天气预报功能,此时就可以写一套WSDL来描述方法名、参数、返回值等信息
当服务端的C#得到该WSDL时,就可以通过WSDL生成C#代码,然后它就可以把取得天气预报功能的逻辑补充上
而客户端的Java在得到这个WSDL之后,同样可以生成Java代码,然后把相应的约定的接口实现补充上
在使用WSDL生成相应语言的代码的过程中,就需要用到一些引擎来实现
比如在WebServices中就有:Axis、CXF、XFire等框架,它们就可以根据WSDL解析成Java代码
所以WSDL是一种中立的语言
CORBA架构中也有类似于WSDL的一种东西,叫做IDL它的语法类似于C++语言,但IDL不是C++



UDDI——发现和整合服务
类似于JNDI。客户端去寻找服务端所能提供的服务时,可以找UDDI索要,而UDDI就会把WSDL传送给客户端
实际上,该过程一般不通过UDDI,而是直接把WSDL拷贝过来就可以了,可以通过Email或硬盘直接拷贝
当客户端得到WSDL之后,就可以通过SOAP协议与远程的服务端进行通信了


服务端示例:

关于XFire的集合映射:这里使用了JDK5.0提供的 新特性中的泛型机制 ,所以不需要<InterfaceName>.aegis.xml文件
                              如果您使用的是JDK4,那么就需要配置<InterfaceName>.aegis.xml文件,相关资料请找Google老师
交待一下我的开发环境:MyEclipse6.5 、Tomcat-6.0.10、JDK1.5.0_08、XFire-1.2.6
如果对WebServics还不是很了解,请参阅我之前写过的一篇文章——What is WebServices
MyEclipse6.5自身便提供了对XFire的支持,所以我们可以直接创建一个Web Service Project
创建步骤——略。网上有很多,希望勤快的您能够自行查阅
下面展示的是WebServices服务端的全部代码 。代码已亲测,全部通过
其中包含了使用XFire处理简单对象的传递、对象的传递、List的传递

 

首先是web.xml文件

[xhtml] view plain copy

    <?xml version="1.0" encoding="UTF-8"?>  
    <web-app xmlns="http://java.sun.com/xml/ns/javaee"  
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5"  
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">  
        <servlet>  
            <servlet-name>XFireServlet</servlet-name>  
            <servlet-class>org.codehaus.xfire.transport.http.XFireConfigurableServlet</servlet-class>  
        </servlet>  
        <servlet-mapping>  
            <servlet-name>XFireServlet</servlet-name>  
            <url-pattern>/services/*</url-pattern>  
        </servlet-mapping>  
    </web-app>  
    <!-- XFireServlet拦截了所有关于/services/*的请求,即只在这个URI下开放WebService服务 -->  
    <!-- 所以对外系统开放的SebService的URL基本上都是【http://127.0.0.1:端口/项目/services/服务名】的形式 -->  
    <!-- 当我们将该WebService项目部署到Tomcat上之后,打开浏览器,然后输入http://127.0.0.1:8080/XFire_demo/services/XFireServer?wsdl -->  
    <!-- 其中XFireServer是services.xml中<service>标签的<name>元素所定义的内容,而问号后面的wsdl参数表示查看该Web服务的WSDL(Web服务描述语言)文件 -->  

然后是services.xml文件

[xhtml] view plain copy

    <?xml version="1.0" encoding="UTF-8"?>  
    <!-- 该文件用于将我们写的一般的Java类暴露成WebService -->  
    <!-- This file should be placed in your classpath at "META-INF/xfire/services.xml" -->  
    <!-- 这是XFire官网上说的,即services.xml文件需要保存在classpath下面的/META-INF/xfire/目录中 -->  
    <!-- 但MyEclipse却在项目中建立了一个WebService文件夹来保存services.xml文件 -->  
    <!-- 其实MyEclipse已帮我们映射好了位置,它会自动将该文件存放在WEB-INF/classes/META-INF/xfire/目录下 -->  
    <beans xmlns="http://xfire.codehaus.org/config/1.0">  
        <!-- service标签和它所包含的XML内容为发布成Web服务的POJO提供完整的描述 -->  
        <!-- ★★注意★★在使用XFire与Spring2.0集成时,正常情况下,控制台会报告异常 -->  
        <!-- ★★注意★★此时把xmlns="http://xfire.codehaus.org/config/1.0"写到<service>标签里面,即可 -->  
        <!-- ★★注意★★<beans><service xmlns="http://xfire.codehaus.org/config/1.0">...<servcie><beans> -->  
        <service>  
            <!-- Web服务被发布时所采用的唯一名称,即我们的WebServices服务对外提供的名字 -->  
            <!-- 该名字可以是任何的合法名字,它将会被客户端程序和其它需要调用我们的服务的组件用到 -->  
            <!-- 并且,服务准备好(比如发布到Tomcat上)以后,可以在浏览器中使用该名字来查看WSDL -->  
            <!-- The name element is required -->  
            <name>XFireServer</name>  
              
            <!-- Web服务发布时所使用的命名空间 -->  
            <!-- The namespace element is optional -->  
            <namespace>http://www.jadyer.com/XFireDemo</namespace>  
              
            <!-- 指定所要提供WebServices服务的Java类的名字,包括包名和类名 -->  
            <!-- 这里我们指定的是HelloService接口 -->  
            <!-- 如果我们的Java类没有实现任何接口,那么这里就可以直接指定Java类的名字 -->  
            <!-- The serviceClass element is required -->  
            <serviceClass>com.jadyer.server.HelloService</serviceClass>  
              
            <!-- 指定当WebServices服务被调用时,服务端用来处理请求的接口的Java实现类,包括包名和类名 -->  
            <!-- 这是一个可选元素,如果<serviceClass>指定的是一个接口,那么就必须在这里指定相应的实现类 -->  
            <!-- The implementationClass element is optional -->  
            <implementationClass>com.jadyer.server.HelloServiceImpl</implementationClass>  
        </service>  
    </beans>  

接着是暴露成Web服务的接口类

[java] view plain copy

    package com.jadyer.server;  
    import java.util.List;  
    import com.jadyer.model.Person;  
    import com.jadyer.model.User;  
    /** 
     * 暴露成web服务的接口类 
     */  
    public interface HelloService {  
        public String sayHello(String name); //简单对象的传递  
        public Person getPerson(User u); //对象的传递  
        public List<Person> getPersonList(Integer age, String name); //List的传递  
    }  

然后是暴露成Web服务的接口的实现类

[java] view plain copy

    package com.jadyer.server;  
    import java.util.ArrayList;  
    import java.util.List;  
    import com.jadyer.model.Person;  
    import com.jadyer.model.User;  
    /** 
     * 暴露成web服务的接口的实现类 
     * @see 该类必须显式或隐式的提供一个public的无参的【即默认的】构造函数 
     * @see 否则XFire将无法初始化该类 
     */  
    public class HelloServiceImpl implements HelloService {  
          
        //Default constructor  
        public HelloServiceImpl(){}  
        public String sayHello(String name) {  
            if(null==name){  
                return "Hello,World";  
            }else{  
                return "Hello," + name;  
            }  
        }  
        public Person getPerson(User u) {  
            Person p = new Person();  
            p.setAge(24);  
            p.setName(u.getName());  
            return p;  
        }  
        public List<Person> getPersonList(Integer age, String name) {  
            Person p = new Person();  
            p.setAge(age);  
            p.setName(name);  
            List<Person> list = new ArrayList<Person>();  
            list.add(p);  
            return list;  
        }  
    }  

最后再把两个POJO类补充上

[java] view plain copy

    package com.jadyer.model;  
    public class User {  
        private String name;  
        /*-- getter和setter略 --*/  
    }  
    /** 
     * 两个POJO类 
     */  
    package com.jadyer.model;  
    public class Person {  
        private Integer age;  
        private String name;  
        /*-- getter和setter略 --*/  
    }  

客户端:

关于XFire的集合映射:这里使用了JDK5.0提供的 新特性中的泛型机制 ,所以不需要<InterfaceName>.aegis.xml文件
                              如果您使用的是JDK4,那么就需要配置<InterfaceName>.aegis.xml文件,相关资料请找Google老师
交待一下我的开发环境:MyEclipse6.5 、Tomcat-6.0.10、JDK1.5.0_08、XFire-1.2.6
如果对WebServics还不是很了解,请参阅我之前写过的一篇文章——What is WebServices
MyEclipse6.5自身便提供了对XFire的支持,所以我们可以直接创建一个Web Service Project
创建步骤——略。网上有很多,希望勤快的您能够自行查阅
下面展示的是WebServices服务端的全部代码 。代码已亲测,全部通过
其中包含了使用XFire处理简单对象的传递、对象的传递、List的传递

 

首先是web.xml文件

[xhtml] view plain copy

    <?xml version="1.0" encoding="UTF-8"?>  
    <web-app xmlns="http://java.sun.com/xml/ns/javaee"  
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5"  
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">  
        <servlet>  
            <servlet-name>XFireServlet</servlet-name>  
            <servlet-class>org.codehaus.xfire.transport.http.XFireConfigurableServlet</servlet-class>  
        </servlet>  
        <servlet-mapping>  
            <servlet-name>XFireServlet</servlet-name>  
            <url-pattern>/services/*</url-pattern>  
        </servlet-mapping>  
    </web-app>  
    <!-- XFireServlet拦截了所有关于/services/*的请求,即只在这个URI下开放WebService服务 -->  
    <!-- 所以对外系统开放的SebService的URL基本上都是【http://127.0.0.1:端口/项目/services/服务名】的形式 -->  
    <!-- 当我们将该WebService项目部署到Tomcat上之后,打开浏览器,然后输入http://127.0.0.1:8080/XFire_demo/services/XFireServer?wsdl -->  
    <!-- 其中XFireServer是services.xml中<service>标签的<name>元素所定义的内容,而问号后面的wsdl参数表示查看该Web服务的WSDL(Web服务描述语言)文件 -->  

然后是services.xml文件

[xhtml] view plain copy

    <?xml version="1.0" encoding="UTF-8"?>  
    <!-- 该文件用于将我们写的一般的Java类暴露成WebService -->  
    <!-- This file should be placed in your classpath at "META-INF/xfire/services.xml" -->  
    <!-- 这是XFire官网上说的,即services.xml文件需要保存在classpath下面的/META-INF/xfire/目录中 -->  
    <!-- 但MyEclipse却在项目中建立了一个WebService文件夹来保存services.xml文件 -->  
    <!-- 其实MyEclipse已帮我们映射好了位置,它会自动将该文件存放在WEB-INF/classes/META-INF/xfire/目录下 -->  
    <beans xmlns="http://xfire.codehaus.org/config/1.0">  
        <!-- service标签和它所包含的XML内容为发布成Web服务的POJO提供完整的描述 -->  
        <!-- ★★注意★★在使用XFire与Spring2.0集成时,正常情况下,控制台会报告异常 -->  
        <!-- ★★注意★★此时把xmlns="http://xfire.codehaus.org/config/1.0"写到<service>标签里面,即可 -->  
        <!-- ★★注意★★<beans><service xmlns="http://xfire.codehaus.org/config/1.0">...<servcie><beans> -->  
        <service>  
            <!-- Web服务被发布时所采用的唯一名称,即我们的WebServices服务对外提供的名字 -->  
            <!-- 该名字可以是任何的合法名字,它将会被客户端程序和其它需要调用我们的服务的组件用到 -->  
            <!-- 并且,服务准备好(比如发布到Tomcat上)以后,可以在浏览器中使用该名字来查看WSDL -->  
            <!-- The name element is required -->  
            <name>XFireServer</name>  
              
            <!-- Web服务发布时所使用的命名空间 -->  
            <!-- The namespace element is optional -->  
            <namespace>http://www.jadyer.com/XFireDemo</namespace>  
              
            <!-- 指定所要提供WebServices服务的Java类的名字,包括包名和类名 -->  
            <!-- 这里我们指定的是HelloService接口 -->  
            <!-- 如果我们的Java类没有实现任何接口,那么这里就可以直接指定Java类的名字 -->  
            <!-- The serviceClass element is required -->  
            <serviceClass>com.jadyer.server.HelloService</serviceClass>  
              
            <!-- 指定当WebServices服务被调用时,服务端用来处理请求的接口的Java实现类,包括包名和类名 -->  
            <!-- 这是一个可选元素,如果<serviceClass>指定的是一个接口,那么就必须在这里指定相应的实现类 -->  
            <!-- The implementationClass element is optional -->  
            <implementationClass>com.jadyer.server.HelloServiceImpl</implementationClass>  
        </service>  
    </beans>  

接着是暴露成Web服务的接口类

[java] view plain copy

    package com.jadyer.server;  
    import java.util.List;  
    import com.jadyer.model.Person;  
    import com.jadyer.model.User;  
    /** 
     * 暴露成web服务的接口类 
     */  
    public interface HelloService {  
        public String sayHello(String name); //简单对象的传递  
        public Person getPerson(User u); //对象的传递  
        public List<Person> getPersonList(Integer age, String name); //List的传递  
    }  

然后是暴露成Web服务的接口的实现类

[java] view plain copy

    package com.jadyer.server;  
    import java.util.ArrayList;  
    import java.util.List;  
    import com.jadyer.model.Person;  
    import com.jadyer.model.User;  
    /** 
     * 暴露成web服务的接口的实现类 
     * @see 该类必须显式或隐式的提供一个public的无参的【即默认的】构造函数 
     * @see 否则XFire将无法初始化该类 
     */  
    public class HelloServiceImpl implements HelloService {  
          
        //Default constructor  
        public HelloServiceImpl(){}  
        public String sayHello(String name) {  
            if(null==name){  
                return "Hello,World";  
            }else{  
                return "Hello," + name;  
            }  
        }  
        public Person getPerson(User u) {  
            Person p = new Person();  
            p.setAge(24);  
            p.setName(u.getName());  
            return p;  
        }  
        public List<Person> getPersonList(Integer age, String name) {  
            Person p = new Person();  
            p.setAge(age);  
            p.setName(name);  
            List<Person> list = new ArrayList<Person>();  
            list.add(p);  
            return list;  
        }  
    }  

最后再把两个POJO类补充上

[java] view plain copy

    package com.jadyer.model;  
    public class User {  
        private String name;  
        /*-- getter和setter略 --*/  
    }  
    /** 
     * 两个POJO类 
     */  
    package com.jadyer.model;  
    public class Person {  
        private Integer age;  
        private String name;  
        /*-- getter和setter略 --*/  
    }  

 


WebService SOAP、Restful和HTTP(post/get)请求区别

web service(SOAP)

Webservice的一个最基本的目的就是提供在各个不同平台的不同应用系统的协同工作能力。
Web service 就是一个应用程序,它向外界暴露出一个能够通过Web进行调用的API。
SOAP是一种简单基于xml的轻量协议,用户web上交换结构化信息和类型信息。
soap请求是HTTP POST的一个专用版本,遵循一种特殊的xml消息格式Content-type设置为: text/xml任何数据都可以xml化。
本文将通过一个简单的示例讲解和演示Android平台的Web Service开发。

Ksoap2-android简介

  在Android平台调用Web Service需要依赖于第三方类库ksoap2,它是一个SOAP Web service客户端开发包,主要用于资源受限制的Java环境如Applets或J2ME应用程序(CLDC/ CDC/MIDP)。认真读完对ksoap2的介绍你会发现并没有提及它应用于Android平台开发,没错,在Android平台中我们并不会直接使用ksoap2,而是使用ksoap2 android。KSoap2 Android 是Android平台上一个高效、轻量级的SOAP开发包,等同于Android平台上的KSoap2的移植版本。

  需要引入ksoap2-android-assembly-2.5.2-jar-with-dependencies.jar
//WebService的命名空间
  static final String namespace = "http://impl.service.suncreate.com";
  //服务器发布的url
  static final String url = http://10.100.3.41/axis2/services/UploadService;
  final String methodName = "upload"; // 函数名
  final int sessionID = "111111";  //sessionID
  //创建HttpTransportSE对象,通过HttpTransportSE类的构造方法可以指定WebService的url
  HttpTransportSE transport = new HttpTransportSE(url);
  transport.debug = true;
  //指定WebService的命名空间和函数名
  SoapObject soapObject = new SoapObject(namespace, methodName);
  //设置调用方法参数的值
  soapObject.addProperty("sessionID", sessionID); //sessionID
  soapObject.addProperty("data", cds); //cds是需要传递的对象
  SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER10);
  envelope.bodyOut = transport;
  envelope.setOutputSoapObject(soapObject);
  //使用call方法调用WebService方法
  transport.call(null, envelope);
  SoapObject sb = (SoapObject) envelope.bodyIn;
  String xmlMessage = sb.toString(); // 获取从服务器端返回的XML字符串

Restful

REST(Representational State Transfer)一种轻量级的Web Service架构,可以完全通过HTTP协议实现。其实现和操作比SOAP和XML-RPC更为简洁,还可以利用缓存Cache来提高响应速度,性能、效率和易用性上都优于SOAP协议。
REST架构对资源的操作包括获取、创建、修改和删除资源的操作正好对应HTTP协议提供的GET、POST、PUT和DELETE方法(Verb)

Restful与SOAP的区别

安全性:SOAP会好于restful
效率和易用性(REST更胜一筹)
成熟度(总的来说SOAP在成熟度上优于REST)

HTTP-GET 和 HTTP-POST
HTTP-GET和HTTP-POST是标准协议,他们使用HTTP(超文本传输协议)谓词(谓词是指条件表达式的求值返回真或假的过程。)对参数进行编码并将参数作为名称/值对传递,还使用关联的请求语义。每个协议都包含一系列HTTP请求标头,HTTP请求标头及其他一些信息定义客户端向服务器请求哪些内容,哪个服务器用一系列HTTP响应标头和所请求的数据进行响应。

HTTP-GET 使用 MIME 类型 application/x-www-form-urlencoded(将追加到处理请求的服务器的 URL 中)以 URL 编码文本的形式传递其参数。 URL 编码是一种字符编码形式,可确保传递的参数中包含一致性文本,例如将空格编码为 %20,其它符号转换为%XX,其中XX为该符号以16进制表示的ASCII(或ISO Latin-1)值。 追加的参数也称为查询字符串。

与 HTTP-GET 类似,HTTP-POST 参数也是 URL 编码的。 但是,名称/值对是在实际的 HTTP 请求消息内部传递的,而不是作为 URL 的一部分进行传递。
我们日常网站、系统都是使用这种形式进行访问我们的应用程序。

package cn.roco.manage.service;

import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

public class NewsService {

    public static final int POST = 1;
    public static final int GET = 2;
    public static final int HttpClientPost = 3;

    /**
     * 保存数据
     * 
     * @param title
     *            标题
     * @param length
     *            时长
     * @param flag
     *            true则使用POST请求 false使用GET请求
     * @return 是否保存成功
     * @throws Exception
     */
    public static boolean save(String path, String title, String timelength,
            int flag) throws Exception {
        Map<String, String> params = new HashMap<String, String>();
        params.put("title", title);
        params.put("timelength", timelength);
        switch (flag) {
        case POST:
            return sendPOSTRequest(path, params, "UTF-8");
        case GET:
            return sendGETRequest(path, params, "UTF-8");
        case HttpClientPost:
            return sendHttpClientPOSTRequest(path, params, "UTF-8");
        }
        return false;
    }

    /**
     * 通过HttpClient框架发送POST请求
     * HttpClient该框架已经集成在android开发包中
     * 个人认为此框架封装了很多的工具类,性能比不上自己手写的下面两个方法
     * 但是该方法可以提高程序员的开发速度,降低开发难度
     * @param path
     *            请求路径
     * @param params
     *            请求参数
     * @param encoding
     *            编码
     * @return 请求是否成功
     * @throws Exception
     */
    private static boolean sendHttpClientPOSTRequest(String path,
            Map<String, String> params, String encoding) throws Exception {
        List<NameValuePair> pairs = new ArrayList<NameValuePair>();// 存放请求参数
        if (params != null && !params.isEmpty()) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                //BasicNameValuePair实现了NameValuePair接口
                pairs.add(new BasicNameValuePair(entry.getKey(), entry
                        .getValue()));
            }
        }
        UrlEncodedFormEntity entity = new UrlEncodedFormEntity(pairs, encoding);    //pairs:请求参数   encoding:编码方式
        HttpPost httpPost = new HttpPost(path); //path:请求路径
        httpPost.setEntity(entity); 

        DefaultHttpClient client = new DefaultHttpClient(); //相当于浏览器
        HttpResponse response = client.execute(httpPost);  //相当于执行POST请求
        //取得状态行中的状态码
        if (response.getStatusLine().getStatusCode() == 200) {
            return true;
        }
        return false;
    }

    /**
     * 发送POST请求
     * 
     * @param path
     *            请求路径
     * @param params
     *            请求参数
     * @param encoding
     *            编码
     * @return 请求是否成功
     * @throws Exception
     */
    private static boolean sendPOSTRequest(String path,
            Map<String, String> params, String encoding) throws Exception {
        StringBuilder data = new StringBuilder();
        if (params != null && !params.isEmpty()) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                data.append(entry.getKey()).append("=");
                data.append(URLEncoder.encode(entry.getValue(), encoding));// 编码
                data.append('&');
            }
            data.deleteCharAt(data.length() - 1);
        }
        byte[] entity = data.toString().getBytes(); // 得到实体数据
        HttpURLConnection connection = (HttpURLConnection) new URL(path)
                .openConnection();
        connection.setConnectTimeout(5000);
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Content-Type",
                "application/x-www-form-urlencoded");
        connection.setRequestProperty("Content-Length",
                String.valueOf(entity.length));

        connection.setDoOutput(true);// 允许对外输出数据
        OutputStream outputStream = connection.getOutputStream();
        outputStream.write(entity);

        if (connection.getResponseCode() == 200) {
            return true;
        }
        return false;
    }

    /**
     * 发送GET请求
     * 
     * @param path
     *            请求路径
     * @param params
     *            请求参数
     * @param encoding
     *            编码
     * @return 请求是否成功
     * @throws Exception
     */
    private static boolean sendGETRequest(String path,
            Map<String, String> params, String encoding) throws Exception {
        StringBuilder url = new StringBuilder(path);
        url.append("?");
        for (Map.Entry<String, String> entry : params.entrySet()) {
            url.append(entry.getKey()).append("=");
            url.append(URLEncoder.encode(entry.getValue(), encoding));// 编码
            url.append('&');
        }
        url.deleteCharAt(url.length() - 1);
        HttpURLConnection connection = (HttpURLConnection) new URL(
                url.toString()).openConnection();
        connection.setConnectTimeout(5000);
        connection.setRequestMethod("GET");
        if (connection.getResponseCode() == 200) {
            return true;
        }
        return false;
    }
}

SOAP与HTTP的区别

大多数对外接口会实现web service方法而不是http方法。
web service相对http (post/get)的好处

1.接口中实现的方法和要求参数一目了然

2.不用担心大小写问题

3.不用担心中文urlencode问题

4.代码中不用多次声明认证(账号,密码)参数

5.传递参数可以为数组,对象等…

6.web service相对http(post/get)由于要进行xml解析,速度可能会有所降低。

7.web service 完全可以可以被http(post/get)替代,而且现在的开放平台都是用的HTTP(post/get)实现的

另外一个例子:

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;

/**调用第三方的webservice服务 ,获取电话号码信息
 * 
 */
public class MobileCodeService {
    //1. http-get方式访问webservice
    public void get(String mobileCode ,String userID ) throws Exception{
        URL url=new URL("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx/getMobileCodeInfo?mobileCode="+mobileCode+
                "&userID="+userID);
        HttpURLConnection conn=(HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(5000);
        conn.setRequestMethod("GET");
        if(conn.getResponseCode()==HttpURLConnection.HTTP_OK){ //结果码=200
            InputStream is=conn.getInputStream();
            //内存流 ,  
            ByteArrayOutputStream boas=new ByteArrayOutputStream();
            byte[] buffer=new byte[1024];
            int len=-1;
            while((len=is.read(buffer))!=-1){
                boas.write(buffer, 0, len);
            }
            System.out.println("GET请求获取的数据:"+boas.toString());    
            boas.close();
            is.close();
        }
    }
    
    //2.Post请求 :通过Http-Client 框架来模拟实现 Http请求
    public void post(String mobileCode ,String userID) throws Exception{
        /**HttpClient访问网络的实现步骤:
         *  1. 准备一个请求客户端:浏览器 
         *  2. 准备请求方式: GET 、POST
         *  3. 设置要传递的参数
         *  4.执行请求
         *  5. 获取结果
         */
        HttpClient client=new HttpClient();
        PostMethod postMethod=new PostMethod("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx/getMobileCodeInfo");
        //3.设置请求参数
        postMethod.setParameter("mobileCode", mobileCode);
        postMethod.setParameter("userID", userID);
        //4.执行请求 ,结果码
        int code=client.executeMethod(postMethod);
        //5. 获取结果
        String result=postMethod.getResponseBodyAsString();
        System.out.println("Post请求的结果:"+result);
    }
    //2.Post请求 :通过Http-Client 框架来模拟实现 Http请求
    public void soap() throws Exception{

        HttpClient client=new HttpClient();
        PostMethod postMethod=new PostMethod("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx");
        //3.设置请求参数
          postMethod.setRequestBody(new FileInputStream("D:/soap.xml")); 
          //修改请求的头部
          postMethod.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
        //4.执行请求 ,结果码
        int code=client.executeMethod(postMethod);
        System.out.println("结果码:"+code);
        //5. 获取结果
        String result=postMethod.getResponseBodyAsString();
        System.out.println("Post请求的结果:"+result);
    }

    public static void main(String[] args) throws Exception{
        MobileCodeService ws=new MobileCodeService();
        ws.get("15958083603", "");
        ws.post("15958012349", "");
        ws.soap();

    }

}

转自:https://blog.csdn.net/jadyer/article/details/6065037

https://blog.csdn.net/l469121903/article/details/50054083

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值