用TcpMon得到的Response如下:
HTTP/1.1 200 OKServer: Microsoft-IIS/5.0Date: Thu, 03 Apr 2003 16:10:15 GMTCache-Control: private, max-age=0Content-Type: text/xml; charset=utf-8Content-Length: 728<?xml version="1.0" encoding="utf-8"?>
   <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <soap:Body>
         <GetStockQuotesResponse xmlns="http://swanandmokashi.com/">
            <GetStockQuotesResult>
               <Quote>
                  <CompanyName>ADV MICRO DEVICE</CompanyName>
                  <StockTicker>AMD</StockTicker>
                  <StockQuote>7.28</StockQuote>
                  <LastUpdated>10:51am</LastUpdated>
                  <Change>+0.28</Change>
                  <OpenPrice>7.19</OpenPrice>
                  <DayHighPrice>7.38</DayHighPrice>
                  <DayLowPrice>7.15</DayLowPrice>
                  <Volume>4256800</Volume>
                  <MarketCap>2.517B</MarketCap>
                  <YearRange>3.10 - 15.30</YearRange>
               </Quote>
            </GetStockQuotesResult>
         </GetStockQuotesResponse>
      </soap:Body>
   </soap:Envelope>

解决方案 »

  1.   

    StockQuote定义如下
    public class StockQuote {
      private String companyName;
      private String stockTicker;
      private String stockQuote;
      private String lastUpdated;
      private String change;
      private String openPrice;
      private String dayHighPrice;
      private String dayLowPrice;
      private String volume;
      private String etCap;
      private String yearRange;
      public String getCompanyName() {
        return companyName;
      }
      public void setCompanyName(String companyName) {
        this.companyName = companyName;
      }
      public String getStockTicker() {
        return stockTicker;
      }
      public void setStockTicker(String stockTicker) {
        this.stockTicker = stockTicker;
      }
      public String getStockQuote() {
        return stockQuote;
      }
      public void setStockQuote(String stockQuote) {
        this.stockQuote = stockQuote;
      }
      public String getLastUpdated() {
        return lastUpdated;
      }
      public void setLastUpdated(String lastUpdated) {
        this.lastUpdated = lastUpdated;
      }
      public String getChange() {
        return change;
      }
      public void setChange(String change) {
        this.change = change;
      }
      public String getOpenPrice() {
        return openPrice;
      }
      public void setOpenPrice(String openPrice) {
        this.openPrice = openPrice;
      }
      public String getDayHighPrice() {
        return dayHighPrice;
      }
      public void setDayHighPrice(String dayHighPrice) {
        this.dayHighPrice = dayHighPrice;
      }
      public String getDayLowPrice() {
        return dayLowPrice;
      }
      public void setDayLowPrice(String dayLowPrice) {
        this.dayLowPrice = dayLowPrice;
      }
      public String getVolume() {
        return volume;
      }
      public void setVolume(String volume) {
        this.volume = volume;
      }
      public String getMarketCap() {
        return etCap;
      }
      public void setMarketCap(String etCap) {
        this.etCap = etCap;
      }
      public String getYearRange() {
        return yearRange;
      }
      public void setYearRange(String yearRange) {
        this.yearRange = yearRange;
      }
    }
      

  2.   

    我觉得最好用Map来处理对象数组。
      

  3.   

    Norwaywoods, 你是说不用数组,而用MAP嘛?
      

  4.   

    是的!Axis内置支持map.其实,有很多问题说不清楚的。最好!去看看axis自带例子。
      

  5.   

    Axis的文档我只看到一个简单的例子阿
    你能贴个Link嘛?
      

  6.   

    What Axis can not send via SOAP
    Arbitrary Objects without Pre-Registration
    You cannot send arbitrary Java objects over the wire and expect them to be understood at the far end. With RMI you can send and receive Serializable Java objects, but that is because you are running Java at both ends. Axis will only send objects for which there is a registered Axis serializer. This document shows below how to use the BeanSerializer to serialize any class that follows the JavaBean pattern of accessor and mutator. To serve up objects you must either register your classes with this BeanSerializer, or there must be serialization support built in to Axis. 
    Remote References
    This is neither part of the SOAP specification, or the JAX-RPC specification. You cannot return some object reference and expect the caller to be able to use it as an endpoint for SOAP calls or as a parameter in other calls. Instead you must use some other reference mechanism, such as storing them in a HashMap with numeric or string keys that can be passed over the wire. 
    Encoding Your Beans - the BeanSerializer
    Axis includes the ability to serialize/deserialize, without writing any code, arbitrary Java classes which follow the standard JavaBean pattern of get/set accessors. All you need to do is tell Axis which Java classes map to which XML Schema types. Configuring a bean mapping looks like this: 
    <beanMapping qname="ns:local" xmlns:ns="someNamespace"
                 languageSpecificType="java:my.java.thingy"/>
    The <beanMapping> tag maps a Java class (presumably a bean) to an XML QName. You'll note that it has two important attributes, qname and languageSpecificType. So in this case, we'd be mapping the "my.java.thingy" class to the XML QName [someNamespace]:[local]. 
    Let's take a look at how this works in practice. Go look at samples/userguide/example5/BeanService.java. The key thing to notice is that the argument to the service method is an Order object. Since Order is not a basic type which Axis understands by default, trying to run this service without a type mapping will result in a fault (if you want to try this for yourself, you can use the bad-deploy.wsdd file in the example5 directory). But if we put a beanMapping into our deployment, all will be well. Here's how to run this example (from the example5 directory): % java org.apache.axis.client.AdminClient -llocal:///AdminService deploy.wsdd
    <Admin>Done processing</Admin>% java samples.userguide.example5.Client -llocal://
    Hi, Glen Daniels!You seem to have ordered the following:1 of item : mp3jukebox
    4 of item : 1600mahBatteryIf this had been a real order processing system, we'd probably have charged you about now.
    %
    When Beans Are Not Enough - Custom Serialization
    Just as JWS deployment is sometimes not flexible enough to meet all needs, the default bean serialization model isn't robust enough to handle every case either. At times there will be non-bean Java classes (especially in the case of pre-existing assets) which you need to map to/from XML, and there also may be some custom XML schema types which you want to map into Java in particular ways. Axis gives you the ability to write custom serializers/deserializers, and some tools to help make your life easier when you do so. 
    TBD - this section will be expanded in a future version! For now look at the DataSer/DataDeser classes (in samples/encoding). Also look at the BeanSerializer, BeanDeserializer, ArraySerializer, ArrayDeserializer and other classes in the org.apache.axis.encoding.ser package. Deploying custom mappings - the <typeMapping> tag
    Now that you've built your serializers and deserializers, you need to tell Axis which types they should be used for. You do this with a typeMapping tag in WSDD, which looks like this: 
    <typeMapping qname="ns:local" xmlns:ns="someNamespace"
                 languageSpecificType="java:my.java.thingy"
                 serializer="my.java.Serializer"
                 deserializer="my.java.DeserializerFactory"
                 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
    This looks a lot like the <beanMapping> tag we saw earlier, but there are three extra attributes. One, serializer, is the Java class name of the Serializer factory which gets the serializer to be used to marshal an object of the specified Java class (i.e. my.java.thingy) into XML. Two, deserializer, is the class name of a Deserializer factory that gets the deserializer to be used to unmarshall XML into the correct Java class. Finally, the encodingStyle, which is SOAP encoding. (The <beanMapping> tag is really just shorthand for a <typeMapping> tag with serializer="org.apache.axis.encoding.ser.BeanSerializerFactory", deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory", and encodingStyle="http://schemas.xmlsoap.org/soap/encoding/", but clearly it can save a lot of typing!) 
      

  7.   

    谢谢 Norwaywoods 和skyyoung(路人甲)
    我用了HashMap来作为返回类型,程序运行没有任何Run Time错误,但得到得HashMap得Size却是0程序如下:
    QName qRet = new QName("http://swanandmokashi.com/","GetStockQuotesResponse");call.registerTypeMapping(HashMap.class,qRet,new MapSerializerFactory(HashMap.class,qRet),new MapDeserializerFactory(HashMap.class,qRet));call.setReturnType(qRet);HashMap hm=(HashMap)call.invoke(new Object[] { "amd" });
                  
    System.out.println(hm.size());请问我得程序哪里有问题?以下是返回的XML消息<?xml version="1.0" encoding="utf-8"?>
       <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
          <soap:Body>
             <GetStockQuotesResponse xmlns="http://swanandmokashi.com/">
                <GetStockQuotesResult>
                   <Quote>
                      <CompanyName>ADV MICRO DEVICE</CompanyName>
                      <StockTicker>AMD</StockTicker>
                      <StockQuote>7.28</StockQuote>
                      <LastUpdated>10:51am</LastUpdated>
                      <Change>+0.28</Change>
                      <OpenPrice>7.19</OpenPrice>
                      <DayHighPrice>7.38</DayHighPrice>
                      <DayLowPrice>7.15</DayLowPrice>
                      <Volume>4256800</Volume>
                      <MarketCap>2.517B</MarketCap>
                      <YearRange>3.10 - 15.30</YearRange>
                   </Quote>
                </GetStockQuotesResult>
             </GetStockQuotesResponse>
          </soap:Body>
       </soap:Envelope>
      

  8.   

    我想,Deserialization应该就是针对那段返回的XML文本的。
    另外,对于一个WS的初学者,很满怀信心的写一个小程序,却遇到不知如果解决的错误,是很沮丧的。希望大虾鼎力相助。谢谢
      

  9.   

    搂主不用说的那么惨吧!其实,大家都很忙,而且也没有义务回答没一个问题。所以你的心态,应该摆正,自立更生。下面是这个问题:
    1.Server side:注册你的HashMap中要包含的类型(这里只有复杂类型需要注册,简单类型可以忽略此步),如下例:
    <deployment xmlns="http://xml.apache.org/axis/wsdd/"
                xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
     <typeMapping qname="ns:stocks.util.StockQuote" xmlns:ns="http://norwaywoods.com"
                  languageSpecificType="java:stocks.util.StockQuote"
                  serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"
                  deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory"
                  encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
     <service name="StockQuoteService" provider="java:RPC">
      <parameter name="className" value="stocks.soapservices.StockQuoteService"/>
      <parameter name="allowedMethods" value="*"/>
      <parameter name="scope" value="Application"/>
     </service>
     <service name="NotificationService" provider="java:RPC">
      <parameter name="className" value="stocks.soapservices.NotificationService"/>
      <parameter name="allowedMethods" value="*"/>
      <parameter name="scope" value="Application"/>
     </service>
    </deployment>2.Client Side:
    你必须用Axis提供的WSDL2JAVA方法生成Client端的存根,对于上面的例子,就是说你在Client端必须有stocks.util.StockQuote的可序列化存根类。当然,如果你够强,也可以自己写存根类,呵呵!3.Just Call it:
    利用Axis帮你生成的Client存根调用该Service.这里怕你不懂,节选一段代码:
    if (super.cachedEndpoint == null) {
                throw new org.apache.axis.NoEndPointException();
            }
            org.apache.axis.client.Call _call = createCall();
            _call.setOperation(_operations[2]);
            _call.setUseSOAPAction(true);
            _call.setSOAPActionURI("");
            _call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOAP11_CONSTANTS);
            _call.setOperationName(new javax.xml.namespace.QName("http://localhost:8080/axis/services/StockQuoteService", "getAllQuotes"));        setRequestHeaders(_call);
            setAttachments(_call);
            java.lang.Object _resp = _call.invoke(new java.lang.Object[] {});        if (_resp instanceof java.rmi.RemoteException) {
                throw (java.rmi.RemoteException)_resp;
            }
            else {
                getResponseHeaders(_call);
                extractAttachments(_call);
                try {
                    return (java.util.HashMap) _resp;
                } catch (java.lang.Exception _exception) {
                    return (java.util.HashMap) org.apache.axis.utils.JavaUtils.convert(_resp, java.util.HashMap.class);
                }
            }
    懂了吧!?!
      

  10.   

    把你WSDL发布一下告诉我,我看看能不能帮你搞定。
      

  11.   

    谢谢 Norwaywoods的详细回复。呵呵,我没有说那么惨,这是好多天没有进展,身边也没有同学WS的人可以请教,故有此感受。
    虽然你回答很详细,但我还是有若干不明白的地方:
    1(Server Side)。我是调用别人的Web Service (http://swanandmokashi.com/HomePage/WebServices/StockQuotes.asmx),所以我不知道怎么Deploy的,而且照理说我也不需要知道Deploy的细节,这才是WS的优点之一吧2。如果不使用存根类可以嘛?如果我只要得到返回的XML文本,然后自己用JDOM解析,应该也是可以的吧,因为我用 tcpMon已经截获到了返回的结果。可是在AXIS里面该如何才可以得到返回的原始XML文本那?
      

  12.   

    pstone2002(一只特立独行的猪),WSDL在http://swanandmokashi.com/HomePage/WebServices/StockQuotes.asmx?WSDL
    帮帮忙了,谢谢
      

  13.   

    我上面说的只是告诉大家怎样用Axis传一个Hashtable.这在Axis的官方maillist上可是个非常火的问题呀!如果你需要call别人的webservice,那就不需要服务端的设置了。
    第一步,还是用Axis提供的WSDL2JAVA方法生成Client端的存根,对于上面的例子,就是说你在Client端必须有stocks.util.StockQuote的可序列化存根类。
    第二步,调用的时候,这样写:
                call.setReturnType(qRet);
     StockQuote[] sq=(StockQuote[]) call.invoke(new Object[] { "amd" });这里的StockQuote不再是你最初的那个StockQuote,而是由Wsdl2java工具产生的那个StockQuote。你再试试吧!或者等pstone2002(一只特立独行的猪)给你一个可用的例子。
      

  14.   

    (小弟插句嘴)请问各位高手,如果我向从server端返回一个并非axis spc上定义的标准对象,但是却是java的对象,比如org.jdom.Element,应该怎么办呢,具体在程序中应该如何指定returnType等等呢?烦劳回答
      

  15.   

    哈哈,已经帮你搞定了,你按下面的步骤去做,如果还不明白,我把源码打包发给你。
    1,保存上面那个WSDL文件,叫StockQuotes.wsdl
    2,wsdl2java -v -o output StockQuotes.wsdl //详细请参见wsdl2java命令选项
    3,你会发现多生成了两个JAVABEAN,一个叫ArrayOfQuote,另一个叫Quote,呵呵,这里如果你不用wsdl2java自动生成代码,而是自己根据WSDL写的话,那就有的麻烦了。写一个客户端叫StockQuotesClient.java如下:
    package com.swanandmokashi;public class StockQuotesClient {  public static void main(String[] args) {
        try{
         StockQuotesLocator StockQuotesLocator = new StockQuotesLocator();
         System.out.println("the Web Service:"+StockQuotesLocator.getStockQuotesSoapAddress());
         StockQuotesSoap StockQuotesSoap = StockQuotesLocator.getStockQuotesSoap();
         ArrayOfQuote arrayQueote = StockQuotesSoap.getStockQuotes("amd");
         Quote[] quoteArray = arrayQueote.getQuote();
         System.out.println("quoteArray's length:"+quoteArray.length);
         Quote quote = quoteArray[0];
         System.out.println("CompanyName:"+quote.getCompanyName());
         System.out.println("StockTicker:"+quote.getStockTicker());
         System.out.println("StockQuote:"+quote.getStockQuote());
         System.out.println("LastUpdated:"+quote.getLastUpdated());
         System.out.println("Change:"+quote.getChange());
         System.out.println("OpenPrice:"+quote.getOpenPrice());
         System.out.println("DayHighPrice:"+quote.getDayHighPrice());
         System.out.println("DayLowPrice:"+quote.getDayLowPrice());
         System.out.println("Volume:"+quote.getVolume());
         System.out.println("MarketCap:"+quote.getMarketCap());
         System.out.println("YearRange:"+quote.getYearRange());   
        }catch(Exception e){
         System.out.println(e);
        }
      }}
    运行后返回如下:
    --------------------------------------------------------------------
    D:\myproject\xml\output>java com/swanandmokashi/StockQuotesClient
    the Web Service:http://swanandmokashi.com/HomePage/WebServices/StockQuotes.asmx
    quoteArray's length:1
    CompanyName:ADV MICRO DEVICE
    StockTicker:AMD
    StockQuote:7.60
    LastUpdated:4:03pm
    Change:+0.20
    OpenPrice:7.40
    DayHighPrice:7.71
    DayLowPrice:7.33
    Volume:10342300
    MarketCap:2.627B
    YearRange:3.10 - 15.30