gnujaxp.jar与axis冲突问题

一个Web应用程序,在WTP里无法完成web services向导,手工配置axis后访问http://localhost:8080/myapp/servlet/AxisServlet 时提示如下错误:

org.apache.axis.InternalException: org.apache.axis.ConfigurationException: org.apache.axis.deployment.wsdd.WSDDException: Must include type attribute for Handler deployment!
org.apache.axis.deployment.wsdd.WSDDException: Must include type attribute for Handler deployment!
    at org.apache.axis.deployment.wsdd.WSDDHandler.<init>(WSDDHandler.java:50)
    at org.apache.axis.deployment.wsdd.WSDDDeployment.<init>(WSDDDeployment.java:176)
    at org.apache.axis.deployment.wsdd.WSDDDocument.setDocument(WSDDDocument.java:139)
    at org.apache.axis.deployment.wsdd.WSDDDocument.<init>(WSDDDocument.java:65)
    at org.apache.axis.configuration.FileProvider.configureEngine(FileProvider.java:179)
    at org.apache.axis.AxisEngine.init(AxisEngine.java:172)
    at org.apache.axis.AxisEngine.<init>(AxisEngine.java:156)
    at org.apache.axis.server.AxisServer.<init>(AxisServer.java:88)
    at org.apache.axis.server.DefaultAxisServerFactory.createServer(DefaultAxisServerFactory.java:109)
    at org.apache.axis.server.DefaultAxisServerFactory.getServer(DefaultAxisServerFactory.java:73)
    at org.apache.axis.server.AxisServer.getServer(AxisServer.java:73)
    at org.apache.axis.transport.http.AxisServletBase.getEngine(AxisServletBase.java:185)
    at org.apache.axis.transport.http.AxisServletBase.getOption(AxisServletBase.java:396)
    at org.apache.axis.transport.http.AxisServletBase.init(AxisServletBase.java:112)
    at org.apache.axis.transport.http.AxisServlet.init(AxisServlet.java:156)
    at javax.servlet.GenericServlet.init(GenericServlet.java:211)

经排除法发现只要删除WEB-INF/lib下的gnujaxp.jar即恢复正常。这个jar文件是因为应用程序使用到jfreechart带来的,按照jfree.org论坛里的说法,只有使用jre1.3.1版本jfreechart才真正需要此文件,所以删掉它问题解决,WTP里web services向导恢复正常。

BTW, 除了axis,这个gnujaxp.jar好像还和spring、ibatis等环境有冲突,见这个google查询结果

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2007/08/17/859449.html

WSRP调用中的若干问题和解决

1、在soapui里调用远程getMarkup()方法,http头里无法包含cookie信息

解决方法:用soapui把soap消息发送至tcpmon,然后在tcpmon里修改http消息(添加cookie段),再重新发送。

2、安装wtp后eclipse里不出现相应功能

解决方法:安装JEM-SDK,它是wtp的先决条件。其他先决条件还有EMF SDK和GEF SDK。

3、从WSRP的WSDL生成Java代码后,访问getMarkup()方法提示InvalidCookie

解决方法:先访问initCookie()方法,再访问getMarkup()。注意要调用Service#setMaintainSession(true)以保证程序对getMarkup()的调用会在http头里加入了cookie段。

4、Websphere Portal的WSRP的WSDL

解决方法:http://host:3333/wps/wsdl/wsrp_service.wsdl

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2007/04/11/709654.html

关于WSRP服务的异步调用

Portal可以将不同的Web应用聚合在同一页面,而Web Services for Remote Portlets (WSRP)规范允许Portal聚合远程Portal Server提供的Portlet,在这种关系下,远程Portal被称为Producer,本地Portal被称为Consumer,最终用户只访问Consumer,并不需要了解Producer的存在。WSRP和普通Web Services比起来更容易使用,因为界面部分已经由Producer提供了,我们只要在Consumer里做一些设置而不是编写JSP代码。

听起来不错,但为此我们也许要付出些代价,其中我想最突出的是性能问题。因为Consumer在向最终用户返回聚合后的页面前,必须等待所有Portlet包括远程Portlet返回结果,这样,只要有一个Portlet响应时间较长,整个页面就变得很慢。在使用WSRP时,用户到Consumer一般是远程访问,而Consumer到Producer也是远程的,这必然带来额外的时间开销。

一个可能的解决方法是在Consumer里异步显示每个Portlet(或仅异步显示那些远程Portlet),AJAX技术听起来是一个不错的选择,lao_lee的这篇文章里曾提到他们有过类似的想法:

05年时我们曾经的一个idea是,把每一个portlet封装为一个web service服务点, (WSRP已经可以作到这一点), 然后改进聚合器,让聚合器首先把页面的框架和js返回,然后每一个portlet通过AJAX请求异步拿到自己的内容. 这里涉及到一个关键问题是URL改写.

我想除了URL改写以外还有些问题必须处理。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2006/12/27/605510.html

Encoded vs Literal, RPC vs Document

我一直没有分清题目里所写的概念,看过JAX-RPC规范后还是模糊,原因主要是对XML本身就没有特别深入的理解。不过现在感觉好象明白了一些。

Encoded和Literal是两种Typing system,前者对应http://schemas.xmlsoap.org/soap/encoding/,后者利用XML Schema定义数据类型。

“Literal对应于types中的element只有一层,Encoded对应于types中element多层的。

用Literal描述的参数客户必须提供明确的参数名,用Encoded描述的参数客户可以用param1,param2,param3等代替。”

在Axis中,使用org.apache.axis.description.OperationDesc类指定自己要使用的方式,方法如下:

“oper.setStyle(org.apache.axis.enum.Style.DOCUMENT); oper.setUse(org.apache.axis.enum.Use.LITERAL);,这个是对于document方式的,如果是rpc方式应该设置为:oper.setStyle(org.apache.axis.enum.Style.RPC); oper.setUse(org.apache.axis.enum.Use.ENCODE);”,然后还要用call.setOperation(oper);把OperationDesc对象实例和Call对象联系起来。

----赵晓冬

关于RPC和Document的比较,这里有两篇不错的文章:Operation Style (Document/RPC) and Message format(literal/encoded)The Difference Between RPC and Document Style WSDL

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/12/06/73517.html

[WebServices]一个简单的WSDL文档(下)

虽然发布的服务很简单,Axis帮我们生成的WSDL文档看起来却是比较复杂的,之所以这样的主要原因是WSDL要考虑到兼容各种实现和具有可扩展性,这就像我们使用一些框架做开发会使代码总量增加,而好处是使逻辑更加清晰。这篇帖子的上半部分介绍了WSDL里常用到的名称空间,现在就来说说WSDL里各元素的含义。

一个WSDL文档里一般包含<types><message><portType><binding><service>这几个元素,其中<types>、<message>和<portType>可以看作抽象的接口定义,而<binding>和<service>是具体的实现,有些时候也把<binding>看作接口的一部分。你也许看过一些WSDL把这两部分分开写在两个xml文件里,并在其中一个文件里引入(import)另一个的情况,这也是为什么要区分接口和实现的原因之一。在现实世界里,接口部分很可能是由某个组织(例如某行业协会)制定好的,该组织的成员在发布自己的Web服务时都要引入它,从而达到统一标准的目的。

<types>标签

<types>标签用来定义Web服务里用到的,XML Schema定义的数据类型以外的自定义数据类型,对于我们自定义的类(Book),会对应到一个<complexType>,其中用<element>元素指定每个参数的类型。JAX-RPC规范中规定了Java语言的数据类型到XML Schema数据类型的映射,例如int - xsd:intjava.lang.String - xsd:string等等,还有数组的映射方式。

<message>标签

<message>标签定义Web服务里的消息,最常见的就是请求和响应消息。<message>中可以有<part>元素,它对应Java类中各个方法的参数或返回值,例如addBook()方法有一个Book类型的参数,则在WSDL中会有<part name="book" type="tns1:Book"/>的描述。

<portType>标签

<portType>标签表示一个服务的类型,就是接口的意思了。WSDL里有些概念很容易混淆,比如port和service的区别,我把service理解为有一个具体URL的服务,而port代表某一地址,portType是service的抽象,不知道对不对。我们看一个WSDL文档,一般就该先找<portType>元素,看看这个WSDL代表的Web服务里都有哪些方法,它们的参数和返回值是什么。这些方法是在<portType>里用<operation>元素表示的,<operation>可以有<input>和<output>子元素,表示方法的输入和输出。注意,方法可以是只有输入或只有输出的。

<binding>标签

<binding>标签将portType与具体的传输协议绑定。现在,绝大多数都是与SOAP绑定的,对每一个方法的输入和输出,都要指定SOAP的表示方法。JAX-RPC规范规定,SOAP绑定可以有rpc和document两种类型,分别表示远程过程调用和基于消息的方式。use属性可以是encoded或literal,对于前者要支持rpc的方式,对于后者要支持rpc和document的方式,它们使得SOAP消息的格式有所区别,但我还没有仔细研究,你可以参考一下JAX-RPC 1.1版本的6.3-6.4节。

又想起另外一个问题,SOAP和HTTP的关系是怎样的,绑定到SOAP就等于绑定到HTTP了吗,应该不是,那么在哪里指定Web服务绑定的应用层协议(HTTP、SMTP等等)呢?(Update: 由transport属性指定应用层协议)

<service>标签

最后,<service>标签通过<port>子元素把服务联系到一个具体的URL,更确切点,应该是把一个已绑定的portType联系到某个URL,这样就知道该把SOAP消息发给哪个服务器了。

我觉得之所以应该花比较多的时间理解WSDL,因为WSDL在整个Web服务中扮演了十分核心的角色,它是对Web服务的一个比较完整的语法上的描述,同时,它还与XML、SOAP以及UDDI都有着非常密切的联系,因此对于我们更好的认识Web服务体系结构是很重要的。虽然现在的Web服务开发工具都能自动进行Java - WSDL的转换,但理解WSDL对于Web服务的不论是设计、开发还是修改调试都是必要的。

参考资料

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/10/16/53112.html

[WebServices]一个简单的WSDL文档(上)

现在,简单解释一下《使用Axis发布简单的Web服务》中发布的Web服务所对应WSDL文档的内容和结构。请注意,同样的Java类在不同的Web服务开发包中得到的WSDL文档不一定完全相同,这里还是以使用Axis的情况作为例子。

虽然比较长,但为了方便起见还是把完整的WSDL贴在下面,然后进行说明。由于我对Web服务的认识还很不够,所以几乎可以肯定会存在一些误解,仅作参考。

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://localhost:8080/bookstore/services/BookSvc" 
  xmlns="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:apachesoap="http://xml.apache.org/xml-soap" 
  xmlns:impl="http://localhost:8080/bookstore/services/BookSvc" 
  xmlns:intf="http://localhost:8080/bookstore/services/BookSvc" 
  xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
  xmlns:tns1="http://model.bookstore.com" 
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <wsdl:types>
    <schema targetNamespace="http://model.bookstore.com" xmlns="http://www.w3.org/2001/XMLSchema">
      <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
      <complexType name="Book">
        <sequence>
          <element name="ISDN" nillable="true" type="xsd:string"/>
          <element name="name" nillable="true" type="xsd:string"/>
          <element name="page" type="xsd:int"/>
        </sequence>
      </complexType>
    </Schema>
  </wsdl:types>
  <wsdl:message name="addBookResponse">
  </wsdl:message>
  <wsdl:message name="addBookRequest">
    <wsdl:part name="book" type="tns1:Book"/>
  </wsdl:message>
  <wsdl:portType name="BookSvc">
    <wsdl:operation name="addBook" parameterOrder="book">
      <wsdl:input message="intf:addBookRequest" name="addBookRequest"/>
      <wsdl:output message="intf:addBookResponse" name="addBookResponse"/>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="BookSvcSoapBinding" type="intf:BookSvc">
    <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="addBook">
      <wsdlsoap:operation soapAction=""/>
      <wsdl:input name="addBookRequest">
        <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://bookstore.com" use="encoded"/>
      </wsdl:input>
      <wsdl:output name="addBookResponse">
        <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8080/bookstore/services/BookSvc" use="encoded"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="BookSvcService">
    <wsdl:port binding="intf:BookSvcSoapBinding" name="BookSvc">
      <wsdlsoap:address location="http://localhost:8080/bookstore/services/BookSvc"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

每个WSDL的根元素都是<definitions>,一般都在这里定义文档中的各种名称空间。对于上面的WSDL,定义了不少名称空间,现在来说说它们的作用。

我们都知道,WSDL应该是格式正确的XML文档。进一步,还应该把它看作一个Schema,因此,<definitions>元素中可以定义targetNamespace属性,表示在这个元素下的所有元素都属于这个目标名称空间。

xmlns表示缺省的名称空间,请注意在上面的文档中,这个缺省名称空间的值和xmlns:wsdl的值是相同的(都是http://schemas.xmlsoap.org/wsdl/)。因此,在这个WSDL中的很多<wsdl:XXX>元素,例如<wsdl:types>、<wsdl:portType>等等,实际上省略掉前面的“wsdl:”效果也是一样的。

名称空间xmlns:apachesoap在文档中并没有使用到,这个应该是Axis为某些情况预留的名称空间,或者是为了兼容以前的版本使用,因为Axis的前身是Apache Soap项目。

名称空间xmlns:intf和xmlns:impl分别代表接口(interface)和实现(implement),可以看出它们的值也是相同的,并且和<definitions>的targetNamespace一致。这是为了在文档中引用已定义的属于该目标名称空间的元素使用的,例如“<wsdl:binding name="BookSvcSoapBinding" type="intf:BookSvc">”,其中的BookSvc一定是在前面某个元素中定义的,并且属于<definitions>中指定的目标名称空间。Axis把intf和impl分开是有道理的,因为在很多情况下,一个WSDL会引用另外一个WSDL,后者可能只定义了数据类型、消息和端口类型这些抽象元素,而前者中定义绑定和服务端口等和实现有关的内容。这里先不做讨论。

名称空间xmlns:soapenc在这个文档里也没有用到,所以先不解释了。

名称空间xmlns:tns1,在很多WSDL里这个名字都叫tns的,没有后面的数字1,不知道Axis为什么起这样的名字。不过没有关系,名称空间的名字本来就没有实际的意义,只是一个代号而已。tns是This NameSpace的缩写,用来对当前WSDL进行引用。由于一个WSDL映射一个包(package),所以Axis为我们生成的WSDL里,tns1的值(http://model.bookstore.com)包含java包(com.bookstore.model)的信息就是顺理成章的了。请注意,tns1的值和<wsdl:types>里的<schema>元素的targetNamespace值是相同的。

名称空间xmlns:wsdlsoap是在与soap绑定时使用的,例如<wsdlsoap:binding>、<wsdlsoap:operation>等元素会用到。

名称空间xmlns:xsd是对XML Schema中各种数据类型的引用,例如string、boolean等等。想知道XML Schema中一共都定义了哪些数据类型,只要查看该名称空间的值(http://www.w3.org/2000/10/XMLSchema)即可。

没想到只是名称空间就写了这么多,而WSDL的结构还有不少内容,所以还是分为两部分吧,下一篇说说这个WSDL中的各个元素的作用。

参考资料

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/10/13/51614.html

[WebServices]使用Axis发布简单的Web服务(补充)

这篇帖子是对《使用Axis发布简单的Web服务》的补充。

可以看出,在Axis里书写deploy.wsdd并利用org.apache.axis.client.AdminClient发布,其主要工作就是把标签中的内容添加在server-config.wsdd里,所以一般直接编辑server-config.wsdd文件会更方便一些。不过当你还没有server-config.wsdd文件时,使用deploy.wsdd的方法会更方便些,因为AdminClient会帮你生成一些额外的xml元素(等等),而这些元素是必要的。

服务发布以后,就可以在IE浏览器里看到它的WSDL,一般是服务的URL后面加一个“?wsdl”,例如添加图书的WSDL可以通过http://localhost:8080/bookstore/services/BookSvc?wsdl看到。至于Java类是以何种规则映射到WSDL的,请参考JAX-RPC规范;WSDL本身的说明见这里;为了搞清生成的WSDL中各种URL格式的名称空间,最好对XML Schema有所了解,我觉得这篇文章还不错。

我们还可以通过IE浏览器直接调用服务,方法是在服务URL后加“method=xxx”,其中xxx是要调用的方法名称。例如可以通过http://localhost:8080/bookstore/services/BookSvc?method=addBook调用添加图书方法,按照我们的服务类,在Tomcat的控制台上应该可以看到打出了“Book has been added.”的字样。

因为添加图书方法的参数是一个自定义类型,所以在IE里调用时不能指定参数值(或者是可以以其他格式指定,但我还不知道);如果参数是简单类型,就可以指定了。例如我们可以为BookSvc增加一个echo()方法,参数是一个java.lang.String类型的值,如下所示,然后重新编译并启动Tomcat(server-config.wsdd文件不必更改)。

public void echo(String str){
    System.out.println("Hello "+str);
}

在IE里输入http://localhost:8080/bookstore/services/BookSvc?method=echo&str=Mike,就会看到Tomcat的控制台里打出了“Hello Mike”。如果有多个参数,只要把这些参数都列在URL里即可。

相关链接

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/10/10/50530.html

[WebServices]使用Axis发布简单的Web服务

使用Axis,要发布一个Web服务非常简单,简直不能再简单了,尽管看起来过程和相关代码有些长。我这个帖子里用到了这些软件:Axis 1.1、Eclipse 2.1和Eclipse的Tomcat插件2.2(Sysdeo Tomcat plugin)。发布的方法如下:

我要发布的服务是一个图书商店,公布的方法有添加图书addBook、列表图书listBooks、删除图书deleteBook等等,为简单起见这里就只发布一个添加图书方法,因为其他方法的发布是类似的。

1、首先在Eclipse里新建一个名为bookstore的Tomcat工程,注意要安装了前面说的Tomcat插件才有这个选项的。如果没有安装可以建立一个java工程,然后手动建立必要的目录结构(WEB-INF等),并在Tomcat的server.xml里手动增加与项目对应的<context>项。

2、接下来建立图书类(com.bookstore.model.Book),图书有名称、ISDN号和页数三个属性,这是一个Bean类,代码如下

package com.bookstore.model;

public class Book {
    private String name;
    private String ISDN;
    private int page;

    public String getISDN() {
        return ISDN;
    }

    public String getName() {
        return name;
    }

    public int getPage() {
        return page;
    }

    public void setISDN(String string) {
        ISDN = string;
    }

    public void setName(String string) {
        name = string;
    }

    public void setPage(int i) {
        page = i;
    }
}

3、接下来建立用来提供服务的类(com.bookstore.BookSvc),这个类就是实际的功能类了,它里面只有一个public的addBook()方法,而它的参数只有一个就是要添加的图书。代码如下:

package com.bookstore;

import com.bookstore.model.Book;

public class BookSvc {

    public void addBook(Book book){
        //here you save a book into database
        System.out.println("Book has been added.");
    }
}

4、现在,把下载来的Axis解压缩到一个文件夹,这里假设你解到C:\axis-1_1。把C\:axis-1_1\webapps\axis\WEB-INF\lib目录下的所有.jar文件复制到你的这个web应用程序的WEB-INF\lib下,再把C:\axis-1_1\webapps\axis\WEB-INF目录下的web.xml复制到你的web应用程序的WEB-INF下。这个步骤相当于在你的web应用程序中配置了Axis。

5、为了让Axis知道你要发布哪些服务,你得在WEB-INF下建立一个名为server-config.wsdd的文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
 <globalConfiguration>
  <parameter name="adminPassword" value="admin"/>
  <parameter name="attachments.Directory" value="C:\eclipse\workspace\bookstore\WEB-INF\attachments"/>
  <parameter name="attachments.implementation" value="org.apache.axis.attachments.AttachmentsImpl"/>
  <parameter name="sendXsiTypes" value="true"/>
  <parameter name="sendMultiRefs" value="true"/>
  <parameter name="sendXMLDeclaration" value="true"/>
  <parameter name="axis.sendMinimizedElements" value="true"/>
  <requestFlow>
   <handler type="java:org.apache.axis.handlers.JWSHandler">
    <parameter name="scope" value="session"/>
   </handler>
   <handler type="java:org.apache.axis.handlers.JWSHandler">
    <parameter name="scope" value="request"/>
    <parameter name="extension" value=".jwr"/>
   </handler>
  </requestFlow>
 </globalConfiguration>
 <handler name="LocalResponder" type="java:org.apache.axis.transport.local.LocalResponder"/>
 <handler name="Authenticate" type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/>
 <handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/>
 <service name="Version" provider="java:RPC">
  <parameter name="allowedMethods" value="getVersion"/>
  <parameter name="className" value="org.apache.axis.Version"/>
 </service>
 <service name="BookSvc" provider="java:RPC">
  <parameter name="allowedMethods" value="*"/>
  <parameter name="className" value="com.bookstore.BookSvc"/>
 </service>
 <service name="AdminService" provider="java:MSG">
  <parameter name="allowedMethods" value="AdminService"/>
  <parameter name="enableRemoteAdmin" value="false"/>
  <parameter name="className" value="org.apache.axis.utils.Admin"/>
  <namespace>http://xml.apache.org/axis/wsdd/</namespace>
 </service>
 <transport name="local">
  <responseFlow>
   <handler type="LocalResponder"/>
  </responseFlow>
 </transport>
 <transport name="http">
  <requestFlow>
   <handler type="URLMapper"/>
   <handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/>
  </requestFlow>
 </transport>
</deployment>

这个文件里发布了三个服务:Version、AdminService和我们的BookSvc。还有一个方法可以生成这个文件,好象Axis推荐使用这种生成的方法,就是在同样目录下写一个deploy.wsdd文件(如果不想看可以直接跳到下一步),内容如下:

<deployment xmlns="http://xml.apache.org/axis/wsdd/"
            xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
 <service name="BookSvc" provider="java:RPC">
  <parameter name="className" value="com.bookstore.BookSvc"/>
  <parameter name="allowedMethods" value="*"/>
 </service>
</deployment>

也就是说deploy.wsdd里只包含关于我们的服务的描述,确认Tomcat已经启动,然后在同一目录下用下面这个命令生成server-config.wsdd文件:

java org.apache.axis.client.AdminClient -lhttp://localhost:8080/bookstore/services/AdminService deploy.wsdd

其中bookstore是我这个web应用程序的虚拟路径。

6、重新启动Tomcat,访问路径http://localhost:8080/bookstore/services,就可以看到现在发布了三个Web服务,如下图。点击每个服务后的wsdl链接可以看到对应的WSDL描述。

file

相关链接

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/10/09/50216.html

Web服务系列(三) XML技术

file

对于XML这个名字,我们已经再熟悉不过了。它可以说是既简单又复杂,因为XML本身具有简单明确的规则,但随着越来越多基于XML技术的新应用的出现,它又演化出各种复杂的语言。希望这篇帖子能为你解决以下问题:XML是什么、我们为什么需要它以及怎样使用它。

XML,全称是可扩展标记语言(eXtensible Markup Language),它是一种标记语言。标记语言的特点是具有三个要素:标记、元素和属性。先看一段简单的XML例子,如下所示:

<?xml version="1.0"?>
<team>
  <member leader="true">
    <name>张浩</name>
    <age>25</age>
  </member>
  <member leader="false">
    <name>孙亮</name>
    <age>25</age>
  </member>
</team>

可以看出XML文档具有树状的结构,应该说这种结构是很适合描述数据的,所以会有不少人把XML作为持久化数据的方式。上面的XML文档中,用尖括号括起来的是标记,例如<team><member>等等,带斜线/的是结束标记,不带的是开始标记,如果是空标记可以写作<team />的形式;开始标记和结束标记与它们之间的内容合称元素;属性是一个名称-值对,例如leader="true"表示leader是member元素的属性。

从XML的格式很容易想到HTML,HTML也是一种标记语言,还有WML、XHTML等等都是标记语言,XML与它们的不同之处在于:XML是创造这些标记语言的元语言。如果拿面向对象语言来类比的话,那就是HTML、WML、XHTML等等都继承了XML,是XML的子类。因此,凡是XML具备的特性,它们也都具备。例如,一个文档只能有一个根元素,标记可以嵌套但不能交叉,属性必须用双引号括起来,开始标记和结束标记必须配套等等。如果一个XML文档不遵守这些规则,则称它是无效的。另外,还可以通过DTD或Schema对XML格式增加额外的约束,例如可以要求<team>元素下至少有一个<member>元素,<age>元素为可选的等等,如果XML文档是有效的同时还满足这些额外要求,则称这个文档是格式良好的。

DTD和Schema是验证XML是否格式良好的两种方式。DTD出现得比较早,它不是XML格式的;Schema则是XML格式的,并且功能更强,支持正则表达式。在XML文档头部可以引用这些文件,处理该XML文档时就会对它进行验证,如果验证失败则不会做进一步处理。为节约篇幅,DTD和Schema的格式这里就不细说了。一般来说,如果在程序中需要定义自己的XML格式,最好先定义DTD或Schema,我们平常使用的大部分XML文档如web.xml、struts-config.xml都有自己的DTD或Schema用来保证格式。

还要说一下名称空间的问题。名称空间是标记的前缀,XML文档在实际应用中可能会被合并,这个前缀保证了合并后的文档中不会出现冲突的标记。为了保证这个唯一性,名称空间一般使用URL的格式,例如:

<myNS:team xmlns:myNS="http://www.mysite.com">
    ...
</myNS:team>

其中myNS是我们随便起的名字,后面的xmlns:myNS属性指定了这个名字代表的名称空间,应该注意真正有意义的是team这个名字。一个完整的标记应该是名称空间:标记名这样的形式,带有名称空间的XML文档读起来会有点乱,所以要认清哪些是重要的,哪些是暂时可以忽略的。

作为一种描述数据的方式,只要发挥想象力,XML可以有无限多种用途,你订阅过RSS吗,那也是其中之一。在Web服务中,我们用XML在服务提供者和使用者之间传递请求和响应数据(SOAP是其中一种格式)、用XML描述服务(例如WSDL),还用XML将服务组装成完整的流程(比如使用BPEL4WS),这些格式规范将在后面的帖子中一一介绍。对了,是XML的可扩展性成就了它们。

要在程序中使用XML,也许是从XML格式的配置文件中读取信息,或是向其他系统提供XML格式的数据,或者其他方式,最直接的方法是使用XML解释器,目前比较常见的DOM、SAX、JDOM和JAXP,其中JAXP作为Java扩展是一个统一的接口,前三者是它的实现方式。关于这些解释器的比较,有很多文章可以参考,这里就不赘述了,我用过DOM和JDOM,比较喜欢后者,因为代码量会小一些。

虽然直接使用XML解释器处理XML格式信息并在服务提供者和使用者间传递也是Web服务,但那样太麻烦了,我们将不得不处理各种琐碎问题(例如数据类型映射),同时产生大量代码。因此,有必要使用专门处理Web服务中各种专用XML格式的解释器,Apache Axis(前身是Apache SOAP)就是其中一种,它可以解释SOAP信息,比起直接用前面所说的XML解释器方便很多。

关于XML还有太多内容,例如XSL用来表现XML、XSLT用来在不同格式XML间转换,XPATH用来在XML文档中找到合适的元素,等等。怎么样,帖子开头提到的问题解决了吗?如果没有也没关系,IBM开发人员网站上有一个XML专区,在那里你一定会大开眼界,如果你是新手,先看看这个教程,可比我写得好多了,呵呵...下一贴开始讲SOAP。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/08/06/30885.html

Web服务系列(二) Web服务的结构

我发现写日志可以帮助自己整理思路,有些技术在一段时间不用后,如果以日志的形式写出来,对于巩固记忆是十分有效的。比如这个Web服务系列,为了尽量避免错误,我会重新查阅资料,在这个过程中又能学到新的知识。不过,Web服务涉及的面太广了,而且新技术出现那么快,即使全部时间都用来研究它也不可能面面俱到,就像一本很厚很厚的书,经常翻翻反而会有意想不到的收获。

上一篇帖子里已经说过Web服务是做什么用的了,在这一篇里要说说Web服务的结构,也就是Web服务的协议栈。协议是各角色间用来沟通的基础,之所以称为栈,是由于这些协议是一层层垒起来的,下面一层是上面一层的基础。就像OSI的七层网络协议的关系。

现在要向你介绍一些概念了,它们是:XML、SOAP、WSDL、UDDI和BPEL4WS。对于XML相信大家都不会陌生,它是可扩展标记语言(eXtensible Markup Language)的缩写,是Web服务各种协议的基础;SOAP是简单对象访问协议(Simple Object Access Protocal)的缩写,它主要用于在服务提供者和使用者之间传送各种请求和应答数据;WSDL代表Web服务定义语言(Web Services Description Language),服务提供者使用这种语言发布自己的Web服务,供潜在的服务使用者使用;UDDI的意思是统一描述发现和集成(Universal Description, Discovery and Integration),UDDI项目由UDDI社区维护,服务提供者可以将自己的服务注册到UDDI服务器中,服务使用者可以在服务器中浏览和查询所需服务;BPEL4WS的意思是用于Web服务的业务流程执行语言(Business Process Execution Language for Web Services),它可以将多个Web服务组装成完整的业务流程,体现了Web服务的真正强大之处(组装)。

只这么简单一说,你可能对其中有些概念并不明白,不过没有关系,在以后的帖子里会对每个概念展开来说明。还要说明一点,列出的这些概念是实际构造和使用Web服务时使用最为广泛的技术,但Web服务并不一定必须使用这些,除XML外,其他技术都有替代品,只是并不那么流行而已。下面我们就来看看Web服务的协议栈是个什么样子的吧,如图所示。

file
图1 Web服务协议栈

最底层是服务传输层,在图中可以看到Web服务可以使用多种(OSI应用层)网络协议进行消息传递,HTTP是使用最为广泛的,因为HTTP的请求应答模式十分符合RPC类型调用,SMTP主要用于异步方式的调用,例如订阅信息等等。

服务消息层的协议定义了消息的格式,在这一层里几乎全部是以SOAP为协议的,至少我还没见过使用其他协议的例子。SOAP的基础是XML,也就是说,SOAP消息一定都是XML格式的。

服务描述层的协议用于对如何使用这个Web服务进行描述,描述信息一般包括使用到的数据类型、消息格式、方法名称和参数(在WSDL里的称呼有所不同)等等。WSDL也是以XML为基础的。

服务发布和发现层协议是供注册中心这个角色使用的,UDDI是目前使用最广泛的注册中心,图中其他几种方式也有应用。

服务组装层用于组装Web服务成为新的服务,这些被组装起来的服务一般体现了一定的业务流程。其好处是各服务间耦合很小,改变起来十分容易。在这一层里,目前有不少协议正在竞争,BPEL4WS可以说具有一定的优势吧。

待开发的协议与我们比较小,暂时不说了。图中右边三个纵向协议贯穿整个Web服务生命周期,它们是服务管理、服务质量和服务安全。因为将来很多的Web服务是要收费才可以使用的,和钱挂钩的东西就必须能够管理、保证质量和安全才行。一直以来,它们都是Web服务研究的难点(因为涉及到太多方面的利益),目前在功能方面Web服务已经做好了准备,如果能够攻破这些非功能性的难题,我想Web服务距离大规模应用就不远了。

图1是比较常见的一种协议栈图,实际上由于Web服务的使用方式多种多样,协议栈图也未必相同。例如w3.org上的是这样,它把XML也技术表现在图上,体现了其在Web服务中的基础地位。

总结一下Web服务的关键技术:XML、SOAP、WSDL、UDDI和BPEL4WS。

如果觉得这一篇有点抽象,那很正常,因为出现了新的概念。另外,我自己对Web服务的理解也是来源与书本,项目经验不足,缺少对这个行业的宏观认识,所以在写出来的时候都要斟酌一二,拿不准的尽量不写。没关系,下面几篇讲的是具体技术,可以醒醒了:)

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/08/05/30402.html