logo
 
 
|
|
|
|
|
|
|
|
 
 
您的位置:首页 - 专业知识
WebServices和Xfire技术总结
[2011-03-18]
WebServices和Xfire技术总结

WebServices概述

WebService是一种分布式环境.可以通过接口和代理远程访问对象,并可在这些对象上进行操作,并且它的设计理念相当好--“双跨”--跨平台、跨语言。

学习WebService,就不能不知道两个概念SOAP、WSDL。

SOAP概述:

SOAP意思是简单对象访问协议(Simple Object Access Protocol)。的确如它的名字一样,SOAP是很简单的。它是一个基于XML的协议,允许程序组件和应用程序彼此使用一种标准的Internet协议--HTTP来通讯。SOAP是一种独立的平台,它不依赖程序语言,它是简单的,弹性的,很容易扩展的。目前,应用程序能够彼此使用一种基于DCOM和CORBA技术的远程过程调用(RPC)来进行相互通讯,但HTTP不被设计为这个目的。RPC在Internet上应用是非常困难的,它们会出现许多兼容性和安全性的问题,因为防火墙和代理服务器通常都会阻断(block)这些类型的流量。应用程序之间最好的通讯方式是通过HTTP协议,因为HTTP是支持所有Internet浏览器和服务器的。基于这个目的,SOAP协议被创建出来。

  那么,它们是如何运作的呢?比如,一个应用程序(A)需要和另一个应用程序(B)在SOAP的帮助下进行彼此通讯。它们将使用下面的框架图来完成这个过程:
 
这个SOAP信封(SOAP envelope)是一个包含以下内容的XML文档:
 
具体的,一个SOAP信封在一个HTTP数据包之上,我理解它最终会被HTTP协议打包,它是这个样子:
被发送到SOAP Service的SOAP Envelope

<?xml version=1.0 encoding=UTF-8?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/
soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/
XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Body>
<ns1:sayHi xmlns:ns1="urn:HelloWorld_SOAPService"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/
soap/encoding/">
<ourName xsi:type="xsd:string">Superman</ourName>
</ns1:sayHi>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>:

  从SOAP Service接收的SOAP Envelope

<?xml version=1.0 encoding=UTF-8?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/
soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/
XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Body>
<ns1:sayHiResponse xmlns:ns1="urn:HelloWorld_SOAPService"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.
org/soap/encoding/">
<return xsi:type="xsd:string">Hello my friend, Superman!
Glad to see you!</return>
</ns1:sayHiResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

要理解SOAP Envelope中的所有标签的含义,需要花一点时间阅读 http://www.w3.org/2001/06/soap-envelope 命名空间规范。
其实在后面的学习中,因为Java提供了各种XML的API(JDOM),再搭配上XFire这个SOAP架构,所以一般只需要知道SOAP的工作原理就够了,基本上不会涉及到自己去写一个SOAP信封。

WSDL概述

你会怎样向别人介绍你的Web service有什么功能,以及每个函数调用时的参数呢?你可能会自己写一套文档,你甚至可能会口头上告诉需要使用你的Web service的人。这些非正式的方法至少都有一个严重的问题:当程序员坐到电脑前,想要使用你的Web service的时候,他们的工具(如Visual Studio)无法给他们提供任何帮助,因为这些工具根本就不了解你的Web service。解决方法是:用机器能阅读的方式提供一个正式的描述文档。Web service描述语言(WSDL)就是这样一个基于XML的语言,用于描述Web service及其函数、参数和返回值。因为是基于XML的,所以WSDL既是机器可阅读的,又是人可阅读的,这将是一个很大的好处。一些最新的开发工具既能根据你的Web service生成WSDL文档,又能导入WSDL文档,生成调用相应Web service的代码。

XFire

XFire是一个开源的SOAP框架,用它可以快速开发WS。
它在Eclipse下的配置也是相当简单,甚至你可能都不需要做什么配置。
在Eclipse下新建一个Web Service Project工程,这个工程与传统的Web Project工程不同的不过是通过向导添加XFire以及services.xml。
 
然后我们next,这时的界面是传统Web Project工程的界面,需要输入工程名什么的,填好,next
 
这个界面设置你的XFire参数,这些参数会被写进Web.xml中,next
 
我的MyEclipse集成了XFire1.1,当然还可以通过User Libraries加载你的XFire包。
这时就配置好了,这里要说明的是,services.xml文件会自动加载到类路径下,具体路径是\Apache Software Foundation\Tomcat 5.5\webapps\SimpleWSExam\WEB-INF\classes\META-INF\xfire
web.xml:
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemalocation="http://java.sun.com/xml/ns/j2ee   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"></web-app> <servlet></servlet> 
 
开发一个简单的WS

首先先来写WS服务器端,通过XFire你无须任何其它的操作,只需要为已经实现的POJOs设计相应的窄接口就OK了,当然我们也可以反过来,先设计接口,再实现它,为了让例子最简单,例子采用后者
服务器端某接口:
HelloWorldService.java
/**
 * HelloWorldService 中声明需要发布成 Web 服务的所有 Java 方法 HelloWorldService 作为Web服务接口
 */
public interface HelloWorldService {
 /**
  * sayHello 方法声明了 Web 服务对外暴露的接口
  *
  * @return 返回给客户端的字符串
  */
 public String sayHello(String name);
 }
接口实现:
HelloWorldServiceImpl.java
/**
 * HelloWorldServiceImpl 中为 Web 服务接口中声明的所有 Java 方法提供具体实现 HelloWorldServiceImpl
 * 作为 Web 服务的实现类
 */
public class HelloWorldServiceImpl implements HelloWorldService {
 /*
  * sayHello 方法为 HelloWorldService 服务接口定义的 sayHello 方法提供具体实现
  *
  * @see org.vivianj.XFire.pojo.HelloWorldService#sayHelloToXFire()
  */
 public String sayHello(String name) {
  return "Hello World!"+name;
 }
}
然后我们配置它,XFire让我们只需要在services.xml中配置即可
services.xml
<beans xmlns="&amp;lt;a href=" _fcksavedurl=""" config=" _fcksavedurl=" xfire.codehaus.org=""></beans> 
关于services.xml各元素信息,请参阅官方文档http://xfire.codehaus.org/services.xml+Reference。
现在我们的Web服务已经配置好了,我们可以在地址栏中输入http://localhost:8080/SimpleWSExam/services,可以看到
 
单击wsdl连接,可以看到关于这个WS的WSDL。在XFire下配置WS就是这么简单!
现在我们来写客户端,
HelloWorldClient.java
public class HelloWorldClient {
 public static void main(String args[]){
  String serviceURL = "http://localhost:8080/SimpleWSExam/services/HelloWorldService";
        Service serviceModel = new ObjectServiceFactory().create(HelloWorldService.class,null,"http://localhost:8080/SimpleWSExam/services/HelloWorldService);
       
        XFireProxyFactory serviceFactory = new XFireProxyFactory();
        try {
   HelloWorldService hello=(HelloWorldService)serviceFactory.create(serviceModel, serviceURL);
        System.out.println(hello.sayHello("Jackal Wood"));
   } catch (MalformedURLException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 
 }
}
一个众人皆知的道理是,WS是只读的,也就是说,WS不能有setxxx()。
如果取的值是List或者是Map,则需要在与源文件相同的目录下创建名为xxxx.aegis.xml的文件,其中xxxx是服务的类名,比如我们在接口中添加public List getList();并实现之,如果客户端想调用这个函数,需要写HelloWorldService.aegis.xml:
      <mapping></mapping><method name="getList">
<return-type componenttype="java.lang.String"></return-type></method>
并且注意路径,
 
 Aegis 是 XFire 的缺省的绑定方式,可以将 XML 映射成 POJO。,在官方例子中,aegis文件中对类的描述基本是全部的,不像我这里只是写上必须的描述。关于aegis,请见其它更详细的资料。当然XFire不仅仅可以绑定aegis,它还支持JAXB2、XMLBeans、Castor、Jibx。

身份验证

XFire提供了四种身份验证的方式,分别是http验证,JSR181,Handler验证,WS-Security。
这里我们只谈Handler验证。
SOAP的原理告诉我们一个WS交互的流程是客户端发送请求->服务器接收请求->服务器发送数据->客户端接收数据,handler可以让我们在这四个操作中之前进行编码,所以,我们的验证进行在客户端发送请求和服务器接收请求的时候,因此,我们要写两个handler,然后把它们装配上就可以了。
服务器接收请求:
AuthentificationHandler.java:
package org.vivianj.xfire.handlers;
import org.codehaus.xfire.MessageContext;
import org.codehaus.xfire.handler.AbstractHandler;
import org.jdom.Element;
import org.jdom.Namespace;
public class AuthentificationHandler extends AbstractHandler {
 public void invoke(MessageContext cfx) throws Exception {
  // TODO Auto-generated method stub
 
      if(cfx.getInMessage().getHeader() == null)
      {
       throw new org.codehaus.xfire.fault.XFireFault("请求必须包含验证信息",org.codehaus.xfire.fault.XFireFault.SENDER);
      }
      Element token=cfx.getInMessage().getHeader().getChild("AuthenticationToken");
      if (token == null)
      {
          throw new org.codehaus.xfire.fault.XFireFault("请求必须包含身份验证信息",
            org.codehaus.xfire.fault.XFireFault.SENDER);
      }
      String username = token.getChild("Username").getValue();
      String password = token.getChild("Password").getValue();
      try
      {
          //进行身份验证
         if(username.equals("jackal") && password.equals("talent"))
          //这语句不显示
          System.out.println("身份验证通过");
         else throw new Exception();
                  // 身份验证通过
         // cfx.setProperty(User_KEY, user);
      }
      catch (Exception e)
      {
          throw new   org.codehaus.xfire.fault.XFireFault("非法的用户名和密码",   org.codehaus.xfire.fault.XFireFault.SENDER);
      }
  }
}
客户端发送请求:
ClientAuthenticationHandler.java
package org.vivianj.xfire.handlers;
import org.codehaus.xfire.MessageContext;
import org.codehaus.xfire.handler.AbstractHandler;
import org.jdom.Element;
import org.jdom.Namespace;

public class ClientAuthenticationHandler extends AbstractHandler {
        private String username = null;
        private String password = null;
        public ClientAuthenticationHandler() {
        }
        public ClientAuthenticationHandler(String username,String password) {
            this.username = username;
            this.password = password;
        }
        public void setUsername(String username) {
            this.username = username;
        }
        public void setPassword(String password) {
            this.password = password;
        }
        public void invoke(MessageContext context) throws Exception {
             Element el = new Element("header");
            context.getOutMessage().setHeader(el);
           
            Element auth = new Element("AuthenticationToken");
            Element username_el = new Element("Username");
            username_el.addContent(username);
            Element password_el = new Element("Password");
            password_el.addContent(password);
            auth.addContent(username_el);
            auth.addContent(password_el);
            el.addContent(auth);
        }
    }

可以看到,客户端在发送数据前做的事情是:往SOAP信封里加入了一个头信息,并在这个头信息中包含了AuthenticationToken属性,它又包含了Username以及Password两个属性,而用户名和密码的值通过形参穿过来。这里面用到了JDOM,JDOM是一个针对JAVA的轻量级的文档对象模型。
服务器接受到SOAP信封后先找到这个验证信息,然后验证它。
装配:
客户端装配:
只需要在客户端程序HelloWorldClient.java中加入
 Client client = Client.getInstance(hello);
 client.addOutHandler(new ClientAuthenticationHandler("jackal","talent"));
服务器端装配:
需要在services.xml中开始写入,重写后的文件
services.xml:
 
<beans xmlns="&amp;lt;a href=" config=" _fcksavedurl=" xfire.codehaus.org=""></beans>
<beans xmlns="http://xfire.codehaus.org/config/1.0"></beans>

上一篇:关于界面测试经验总结
下一篇:软件质量管理
   
IT行业的高速发展,技术最重要 IT行业的高速发展,技术最重要
热烈祝贺我校吴鼎同学成功就业与江苏华招网信息技术有限公司 热烈祝贺我校吴鼎同学成功就业与江苏华招网信息技术有限公司
北大青鸟 好技术才有好工作 北大青鸟 好技术才有好工作
企业需要技术型人才 企业需要技术型人才
北大青鸟:IT行业人才需求旺、技术职位独领风骚 北大青鸟:IT行业人才需求旺、技术职位独领风骚
 

在线报名

  • 姓       名:*
  • 高考成绩:*
  • 电       话:*
  • 地       址:*
 
课程咨询
 

 
中博教育客服在线
 
©南京北大青鸟 隐私政策
学费咨询
学历咨询
专业咨询
订座试听
就业咨询
课程咨询
测试认证
软件认证