要調用的Web服務是求兩個整數和,并返回結果。
服務的WSDL文件內容如下:
<?xml version="1.0" encoding="utf-8" ?>
<wsdl:definitions
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="http://tempuri.org/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
targetNamespace="http://tempuri.org/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<s:schema elementFormDefault="qualified"
targetNamespace="http://tempuri.org/">
<s:element name="AddTwoIntegers">
<s:complexType>
<s:sequence>
<s:elementminOccurs="1" maxOccurs="1" name="IntegerOne" type="s:int" />
<s:elementminOccurs="1" maxOccurs="1" name="IntegerTwo" type="s:int" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="AddTwoIntegersResponse">
<s:complexType>
<s:sequence>
<s:elementminOccurs="1" maxOccurs="1" name="AddTwoIntegersResult" type="s:int" />
</s:sequence>
</s:complexType>
</s:element>
</s:schema>
</wsdl:types>
<wsdl:message name="AddTwoIntegersSoapIn">
<wsdl:part name="parameters" element="tns:AddTwoIntegers" />
</wsdl:message>
<wsdl:message name="AddTwoIntegersSoapOut">
<wsdl:part name="parameters" element="tns:AddTwoIntegersResponse" />
</wsdl:message>
<wsdl:portType name="SimpleServiceSoap">
<wsdl:operation name="AddTwoIntegers">
<wsdl:input message="tns:AddTwoIntegersSoapIn" />
<wsdl:output message="tns:AddTwoIntegersSoapOut" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="SimpleServiceSoap" type="tns:SimpleServiceSoap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
<wsdl:operation name="AddTwoIntegers">
<soap:operation soapAction="http://tempuri.org/AddTwoIntegers" style="document" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="SimpleService">
<documentation xmlns="http://schemas.xmlsoap.org/wsdl/" />
<wsdl:port name="SimpleServiceSoap" binding="tns:SimpleServiceSoap">
<soap:address location="http://localhost/Develop.NET/Home.Develop.WebServices/SimpleService.asmx"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
javaScript代碼中利用了MS的HTTP代理對象XMLHTTP,在Mozilla's Web brower中相應的組件是XMLHttpRequest,他們都提供了類似的方法來完成soap請求。下面的代碼用的是IE中的XMLHTTP對象。代碼假定調用過程中沒有Fault。
function fncAddTwoIntegers(a, b)
{
var oXmlHttp = new ActiveXObject("MSXML2.XMLHTTP");
oXmlHttp.open("POST", "http://localhost/Develop.NET/Home.Develop.WebServices/SimpleService.asmx'", false);
oXmlHttp.setRequestHeader("Content-Type", "text/xml");
oXmlHttp.setRequestHeader("SOAPAction", "http://tempuri.org/AddTwoIntegers");
oXmlHttp.send("
<soap:Envelopexmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>
<soap:Body>
<AddTwoIntegersxmlns='http://tempuri.org/'>
<IntegerOne>" + a + "</IntegerOne>
<IntegerTwo>" + b + "</IntegerTwo>
</AddTwoIntegers>
</soap:Body>
</soap:Envelope>");
return oXmlHttp.responseXML.selectSingleNode("http://AddTwoIntegersResult").text;
}
原文英文出自:
http://builder.com.com/5100-6371_14-5887775.html?tag=nl.e601
Document方式是Web service缺省調用模式,和literal相組合,給我們調用Web service提供了極大的便利,省去了RPC調用方式的復雜類型序列化的問題,所以,Doucment調用方式在BPEL領域應用非常廣泛,下面介紹基于Axis利用Document方式來調用一個Web service.
1. Web service準備:
Web service你可以任意實現一個,我是利用Oracle BPEL,通過建立一個BPEL流程,然后把它發布為Web service(具體創建過程省略),這里重要的是Web service的WSDL文件,這是我們調用的門戶。
下面是我的Web service的WSDL文件內容:
<definitions
name="HelloWorld"
targetNamespace="http://xmlns.oracle.com/HelloWorld"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:client="http://xmlns.oracle.com/HelloWorld"
>
<types>
<schema attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://xmlns.oracle.com/HelloWorld"
xmlns="http://www.w3.org/2001/XMLSchema">
<element name="HelloWorldProcessRequest">
<complexType>
<sequence>
<element name="input" type="string"/>
</sequence>
</complexType>
</element>
<element name="HelloWorldProcessResponse">
<complexType>
<sequence>
<element name="result" type="string"/>
</sequence>
</complexType>
</element>
</schema>
</types>
<message name="HelloWorldRequestMessage">
<part name="payload" element="client:HelloWorldProcessRequest"/>
</message>
<message name="HelloWorldResponseMessage">
<part name="payload" element="client:HelloWorldProcessResponse"/>
</message>
<portType name="HelloWorld">
<operation name="process">
<input message="client:HelloWorldRequestMessage"/>
<output message="client:HelloWorldResponseMessage"/>
</operation>
</portType>
<binding name="HelloWorldBinding" type="client:HelloWorld">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="process">
<soap:operation style="document" soapAction="process"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="HelloWorld">
<port name="HelloWorldPort" binding="client:HelloWorldBinding">
<soap:address location="http://robin:9700/orabpel/default/HelloWorld/1.0"/>
</port>
</service>
<plnk:partnerLinkType name="HelloWorld">
<plnk:role name="HelloWorldProvider">
<plnk:portType name="client:HelloWorld"/>
</plnk:role>
</plnk:partnerLinkType>
</definitions>
2. 編寫調用類,代碼如下:
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import java.util.Vector;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.rpc.ServiceException;
import org.apache.axis.client.Call;
import org.apache.axis.constants.Style;
import org.apache.axis.message.SOAPBodyElement;
import org.apache.xml.serialize.DOMSerializerImpl;
import org.apache.xml.serialize.OutputFormat;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class BPELServiceTest {
//service的命名空間
static final String ns = "http://xmlns.oracle.com/HelloWorld";
public static void main(String args[]){
Call call = null;
try {
call = createCall();
Vector rtn = (Vector) call.invoke(createRequest());
parse(rtn);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FactoryConfigurationError e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
* 創建Call對象,對設置相關屬性,注意:其中的屬性應該是通過分析WSDL文件由程序動態獲得來賦值,
* 這里全部簡化為靜態賦值
*/
static Call createCall() throws MalformedURLException, ServiceException{
org.apache.axis.client.Service s = new org.apache.axis.client.Service();
Call call = (Call) s.createCall();
call.setTargetEndpointAddress(new URL("http://robin:9700/orabpel/default/HelloWorld/1.0"));
call.setSOAPActionURI("process");
call.setOperationName("process");
call.setProperty(Call.OPERATION_STYLE_PROPERTY, Style.DOCUMENT.getName());
call.setPortName(new QName(ns, "HelloWorldPort"));
call.setPortTypeName(new QName(ns, "HelloWorld"));
return call;
}
/*
*創建請求參數,實際上就是構建DOM片斷,根據Web service對輸入參數的要求來構建,要多復雜,都可以實現,
*這就是Docuemnt的好處,省去了復雜對象的序列化。
*/
static Object[] createRequest() throws ParserConfigurationException, FactoryConfigurationError{
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = db.newDocument();
Element root = doc.createElementNS(ns, "HelloWorldProcessRequest");
Element input = doc.createElementNS(ns, "input");
input.appendChild(doc.createTextNode("robin"));
root.appendChild(input);
doc.appendChild(root);
return new Object[]{new SOAPBodyElement(root)};
}
// 對返回結果進行解析,并打印。
static void parse(Vector v) throws Exception{
Document doc = ((SOAPBodyElement) v.get(0)).getAsDocument();
Element root = doc.getDocumentElement();
OutputFormat of = new OutputFormat();
of.setIndent(4);
System.out.println(new DOMSerializerImpl().writeToString(root));
}
}
上述代碼運行輸出結果為:
<?xml version="1.0"?>
<HelloWorldProcessResponse xmlns="http://xmlns.oracle.com/HelloWorld">
<result xmlns="http://xmlns.oracle.com/HelloWorld">robin</result>
</HelloWorldProcessResponse>
上面的代碼很簡單,需要說明的是:采用Document調用,實際上invoke方法的參數是一個元素類型為SOAPBodyElement的對象數組,而返回結果是一個元素類型的SOAPBodyElement的Vector對象。
這一小節介紹如何編寫一個自定義的注解類型,以及如何應用JDK5.0 java.lang.annotation包中提供的4種注解:
@Documented,@Retention,@Target,@Inherited
1. 編寫自定義@Todo注解經常我們在寫程序時,有時候有些功能在當前的版本中并不提供,或由于某些其它原因,有些方法沒有完成,而留待以后完成,我們在javadoc中用@TODO來描述這一行為,下面用java注解來實現。
public @interface Todo { } // Todo.java如果你想讓這個注解類型能夠自省的話,給它加上@Todo注解,寫法如下:
@Todo
public @interface Todo{ }下面我們給這個注解接受參數的能力,代碼如下:
@Todo("Just articleware")
public @interface Todo{
public enum Priority { LOW, MEDIUM, HIGH }
String value();
String[] owners() default "";
Priority priority() default Priority.MEDIUM;
}
注意:注解類性所能接受的參數類型有著嚴格的規則:
a. 參數類型只能是:primitive, String, Class, enum, annotation, 或者是數組;
b. 參數值不能為空,因此每一個參數值都要定義一個缺省值;
c. 名字為value的參數可以用簡便的方法來設置;
d. 參數的寫法如同寫簡單方法(看如上代碼),不允許加入參數,不允許有throws子句等。
在上面的代碼中,我們為@Todo定義了3個參數, 分別是value, owners, priority. 注意:由于value的特殊性,它的的卻省值可以由上面代碼中的"Just articleware"來定義,當然你也可以單獨寫一個缺省值。
下面看一個應用@Todo注解的例子:
@Todo(
value="Class scope",
priority=Unfinished.Priority.LOW
)
public class TodoDemo {
@Todo("Constructor scope")//通過快捷方式,設置value的值
public TodoDemo() { }
@Todo(owner="Jason", value="Method scope")
public void foo() { }
}
上面的代碼很簡單,不多介紹。
下面我們想讓@Todo不能應用在fields, parameters, 或者local variables(因為這對我們來說沒有意義);它應當可以出現在javadoc中;在運行是具有持久性。要實現這些特性,就需要annotation包的支持啦。
2. 應用annotation包的支持1)@Documented
類和方法的annotation缺省情況下是不出現在javadoc中的,為了加入這個性質我們用@Documented
應用代碼如下(簡單,不多介紹):
package com.robin;
import java.lang.annotation.*;
@Todo("Just articleware")
@Documented
public @interface Todo{ ...
2)@Retention
用來表明你的annotation的有效期,可以有三種選擇(如圖所示):

以下示例代碼應用RUNTIME策略
package com.robin;
import java.lang.annotation.*;
@Todo("Just articleware")
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Todo{ ...
3) @Target
@Target注解表明某個注解應用在哪些目標上,可選擇如下范圍:
- ElementType.TYPE (class, interface, enum)
- ElementType.FIELD (instance variable)
- ElementType.METHOD ElementType.PARAMETER
- ElementType.CONSTRUCTOR
- ElementType.LOCAL_VARIABLE
- ElementType.ANNOTATION_TYPE (應用于另一個注解上)
- ElementType.PACKAGE
按我們的功能要求,代碼如下:
package com.robin;
import java.lang.annotation.*;
@Todo("Just articleware")
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD,
ElementType.CONSTRUCTOR,ElementType.ANNOTATION_TYPE,
ElementType.PACKAGE})
public @interface Todo{ ...
4) @Inherited
@Inherited表明是否一個使用某個annotation的父類可以讓此annotation應用于子類。
示例代碼如下:
package com.robin;
import java.lang.annotation.*;
@Todo("Just articleware")
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD,
ElementType.CONSTRUCTOR,ElementType.ANNOTATION_TYPE,
ElementType.PACKAGE})
@Inherited
public @interface Todo{
public enum Priority { LOW, MEDIUM, HIGH }
String value();
String[] owners() default "";
Priority priority() default Priority.MEDIUM;
}
注解(annotation)是J2SE 5.0的新內容,它給我們提供了很好的編程支持,下面介紹一下其內置的三種注解類型:
1. @Override@Override用在多態情況下,比如:
public abstract class Animal{
public void say(){
System.out.println("annimal is saying");
}
}
public class Cat extends Animal{
@Override
public void say(){
System.out.println("miao, miao");
}
}
通過@Override來告訴java編譯器,say方法是重載的父類的方法,這樣,當父類的say方法簽名改名的話,比如增加了一些參數,那么子類的Cat中的say方法編譯時就會報錯,說沒有正確的重載父類方法,所以,@Override可以幫我們驗證程序的正確性,這一點,很有用。
2. @Deprecated
@Deprecated的意思和JavaDoc中的@deprecated注釋在本質上是一樣的,使用如下:
public class DeprecatedExample {
@Deprecated
public static void badMethod() { }
}
public class DeprecatedUser {
public static void main(String[] args){
DeprecatedExample.badMethod();
}
}
上面的代碼如果用javac進行編譯的話,會打印出如下信息:
Note: DeprecatedUser.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
1 error
如果你按提示重新加-Xlint進行編譯,你就可以得到錯誤的詳細信息:
% javac -Xlint:deprecation
DeprecatedUser.java:3: warning: [deprecation] badMethod() in DeprecatedExample
has been deprecated
DeprecatedExample.badMethod();
需要注意的是:和javadoc中的@deprecated相比,@Deprecated并沒有強大多少,因為它不支持參數,而@deprecated后面還可以跟字符串來給一些相關的信息,但@Deprecated做不到,但它提供了運行時自省的功能,來提示錯誤,所以建議@Deprecated和@deprecated同時使用。
3. @SuppressWarnings
顧名思義,就是抑制警告信息的出現,使用如下:
public class DeprecatedExample2{
@Deprecated
public static void foo() { }
}
public class DeprecatedUser2 {
@SuppressWarnings(value={"deprecation"})
public static void main(String[] args) {
DeprecatedExample2.foo();
}
}
上述@SuppressWarnings(value={"deprecation"})的作用就是抑制編譯器報deprecation的錯。
@SuppressWarnings(value={"deprecation"})只支持一個參數,是數組類型,所以你可以不用加value, 寫成:@SuppressWarnings({"deprecation"});當想抑制多個類型的警告信息時,可寫:@SuppressWarnings({"unchecked","fallthrough",deprecation"}).
注意:在JDK1.5.0 release中,@SuppressWarnings還沒有得到完全支持,會在以后支持,但Sun并沒有給出具體的時間。