用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>
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>
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;
}
}
你能贴个Link嘛?
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!)
我用了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>
另外,对于一个WS的初学者,很满怀信心的写一个小程序,却遇到不知如果解决的错误,是很沮丧的。希望大虾鼎力相助。谢谢
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);
}
}
懂了吧!?!
虽然你回答很详细,但我还是有若干不明白的地方:
1(Server Side)。我是调用别人的Web Service (http://swanandmokashi.com/HomePage/WebServices/StockQuotes.asmx),所以我不知道怎么Deploy的,而且照理说我也不需要知道Deploy的细节,这才是WS的优点之一吧2。如果不使用存根类可以嘛?如果我只要得到返回的XML文本,然后自己用JDOM解析,应该也是可以的吧,因为我用 tcpMon已经截获到了返回的结果。可是在AXIS里面该如何才可以得到返回的原始XML文本那?
帮帮忙了,谢谢
第一步,还是用Axis提供的WSDL2JAVA方法生成Client端的存根,对于上面的例子,就是说你在Client端必须有stocks.util.StockQuote的可序列化存根类。
第二步,调用的时候,这样写:
call.setReturnType(qRet);
StockQuote[] sq=(StockQuote[]) call.invoke(new Object[] { "amd" });这里的StockQuote不再是你最初的那个StockQuote,而是由Wsdl2java工具产生的那个StockQuote。你再试试吧!或者等pstone2002(一只特立独行的猪)给你一个可用的例子。
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