(點選上方公眾號,可快速關註)
來源:袁鳴凱 ,
blog.csdn.net/lifetragedy/article/details/7786894
一、總結前一天
前一天中我們講述瞭如何生成一個Axis2的WebService, 如何佈署以及4種不同的客戶端, 它們是: 傳統式, 非阻塞式, 雙工樣式, 雙工非阻塞。
並且我們看到了一個Axis2的Web Service的佈署描述:
org.sky.axis2.helloworld.HelloWorld
urn:sayHello
這個描述代表我們的這個Web Service的方法有一進一齣兩個引數,且是Axis2特有的” OMElement”型別。
那麼,我們想要一個public String sayHello(String name)這樣的一種簡單的java型別來書寫我們的WebService可以嗎?
當然,只不過我們的佈署描述和我們的客戶端呼叫傳回值上稍稍有一些不一樣。
二、使用簡單Java型別書寫我們的WebService
HelloJava類:
package org.sky.axis2.helloworld.javatype;
import javax.xml.stream.XMLStreamException;
import org.apache.axiom.om.OMElement;
public class HelloJava {
public String sayHello(String name) throws XMLStreamException {
StringBuffer hello = new StringBuffer();
hello.append(“hello: “);
hello.append(name);
return hello.toString();
}
}
Service描述檔案:
此時我們相應的佈署檔案就是service.xml檔案內容稍稍不一樣,來看
org.sky.axis2.helloworld.javatype.HelloJava
class=”org.apache.axis2.rpc.receivers.RPCMessageReceiver” />
我們把這個WebService佈署入Tomcat後啟動起來看
是不是多了一個Service叫”HelloJava”。
我們把這個Service的wsdl地址匯入SOAP UI工具並生成模擬客戶端,然後再來看看它的呼叫與傳回值。
註意這個傳回值:
hello: Simon Shen
標有紅色加粗的部分,反正一粗,就有用就是好東西(我喜歡粗,YEAH)。
再來比較一下昨天我們用“org.apache.axis2.receivers.RawXMLINOutMessageReceiver”這個Service描述生成的傳回值
org.apache.axis2.receivers.RawXMLINOutMessageReceiver
Monica
看到區別沒有?於是,更改我們的客戶端呼叫程式碼如下,在此我們使用非同步雙工樣式:
org.sky.axis2.helloworld.javatype.HelloJavaWithReturnDualNonBlock
package org.sky.axis2.helloworld.javatype;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
public class HelloJavaWithReturnDualNonBlock {
private static EndpointReference targetEPR = new EndpointReference(
“http://localhost:8080/Axis2Service/services/HelloJava”);
public static boolean finish = false;
public void sayHello() {
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace omNs = fac.createOMNamespace(
“http://javatype.helloworld.axis2.sky.org”, “”);
OMElement method = fac.createOMElement(“sayHello”, omNs);
OMElement name = fac.createOMElement(“name”, omNs);
name.setText(“ymk”);
method.addChild(name);
method.build();
Options options = new Options();
options.setTo(targetEPR);
options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
options.setUseSeparateListener(true);
options.setAction(“urn:sayHello”);
ServiceClient sender = null;
HelloJavaNonBlockCB callback = new HelloJavaNonBlockCB();
try {
sender = new ServiceClient();
sender.engageModule(Constants.MODULE_ADDRESSING);
sender.setOptions(options);
sender.sendReceiveNonBlocking(method, callback);
synchronized (callback) {
try {
callback.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
sender.cleanup();
} catch (Exception e) {
}
}
}
public static void main(String[] args) {
HelloJavaWithReturnDualNonBlock testClient = new HelloJavaWithReturnDualNonBlock();
testClient.sayHello();
}
}
相關的CallBack類,org.sky.axis2.helloworld.javatype.HelloJavaNonBlockCB:
package org.sky.axis2.helloworld.javatype;
import java.util.Iterator;
import javax.xml.namespace.QName;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMNode;
import org.apache.axis2.client.async.AxisCallback;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.databinding.utils.BeanUtil;
import org.apache.axis2.engine.DefaultObjectSupplier;
public class HelloJavaNonBlockCB implements AxisCallback {
private boolean complete = false;
public void onMessage(MessageContext msgContext) {
System.out.println(msgContext.getEnvelope().getBody());
OMElement element = msgContext.getEnvelope().getBody()
.getFirstElement();
OMElement result = element.getFirstChildWithName(new QName(
“http://javatype.helloworld.axis2.sky.org”, “return”));
System.out.println(result.getText());
synchronized (this) {
this.notify();
}
}
public boolean isComplete() {
return complete;
}
public void onFault(MessageContext msgContext) {
System.out.println(msgContext.getEnvelope().getBody().getFault().toString());
synchronized (this) {
this.notify();
}
}
public void onError(Exception e) {
e.printStackTrace();
synchronized (this) {
this.notify();
}
}
public void onComplete() {
this.complete = true;
synchronized (this) {
this.notify();
}
}
}
下麵是客戶端執行後的輸出:
註意在CallBack類中的這一句:
OMElement result = element.getFirstChildWithName(new QName(
“http://javatype.helloworld.axis2.sky.org”,”return”));
和下麵這個SOAP UI的傳回值來作個比較“註意這個Return”
“
hello: Simon Shen ”
三、深入理解Axis2的API的寫法
我們一邊看著SOAP UI給我們生成的呼叫端和結果來看這些個API。
Axis2中的一切都是一種OMElement,它其實就是一個“XML”結構的Java物件。
3.1 先來看呼叫端的生成
下麵是Soap UI幫我們生成的客戶端
Simon Shen
透過上述的內容我們可以知道,呼叫一個以wsdl方式暴露的Web Service的客戶端需要下麵這些元素:
1) 呼叫地址 end point
private static EndpointReference targetEPR = new EndpointReference(
“http://localhost:8080/Axis2Service/services/HelloJava”);
2) Web Service方法,註意service.xml描述中的這一行
urn:sayHello
這個被稱為我們的Web Method,它指向了我們在類中的:
public String sayHello(String name) throws XMLStreamException {
該方法有一個傳回,一個進參,傳回已經我們的service.xml描述中用:
class=”org.apache.axis2.rpc.receivers.RPCMessageReceiver” />
它的進參我們假設是一個String型別的。
這樣一個Web Method的原始呼叫(其實我們把它稱為SOAP呼叫)應該是如SOAP UI工具中給我們生成的陳述句那樣:
Simon Shen
因此,為了生成上述的SOAP陳述句,我們採Axis2的API書寫如下,下麵的程式碼的效果將會在程式執行時產生等同於上面的SOAP呼叫陳述句,一起來看看:
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace omNs = fac.createOMNamespace(
“http://javatype.helloworld.axis2.sky.org”, “”);
OMElement method = fac.createOMElement(“sayHello”, omNs);
OMElement name = fac.createOMElement(“name”, omNs);
name.setText(“ymk”);
method.addChild(name);
method.build();
當”method.build()”命令發出後,上述這些API就生成SOAP呼叫陳述句,去呼叫”sayHello”這個方法,然後往裡面傳入了一個String型別的值。
可以看到,這個API非常像dom4j的陳述句,只是這邊不是一個document型別而是一個類XML的OMElement結構體,都是addChild, setText之類的,對吧?
再繼續往下看我們的API
Options options = new Options();
options.setTo(targetEPR);
options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
options.setUseSeparateListener(true);
options.setAction(“urn:sayHello”);
1) 將該web method的呼叫指向指定的end point
2) 開啟雙工樣式
3) 因為是雙工樣式,需要在client端開啟一個監聽器
4) 設定呼叫的web method為”urn:sayHello”
sender = new ServiceClient();
sender.engageModule(Constants.MODULE_ADDRESSING);
sender.setOptions(options);
sender.sendReceiveNonBlocking(method, callback);
1) 生成呼叫控制代碼
2) 由於我們採用的是雙工樣式,因此需要定址:engageModule
這個engageModule就是需要訪問你的工程的WEB-INF\modules\目錄下的一個叫addressing-1.4.mar的檔案。
因此在呼叫engageModule陳述句之間有兩種方式來呼叫你的WEB-INF\modules目錄下的addressing-1.4.mar檔案。
第一種方式:
ConfigurationContext sysContext = ConfigurationContextFactory
.createConfigurationContextFromFileSystem(
“D:\\wspace\\Axis2Service\\WebContent\\WEB-INF”,
null);
sender = new ServiceClient(sysContext, null);
sender.engageModule(Constants.MODULE_ADDRESSING);
第二種方式:
sender = new ServiceClient(sysContext, null);
sender.engageModule(Constants.MODULE_ADDRESSING);
在第二種方式中,不需要為new ServiceClient()指定第一個sysContext引數,但是,你必須把WEB-INF\modules\addressing-1.4.mar指定到你的工程的classpath中去,如下圖
要不然執行時會丟擲下麵這個exception:
org.apache.axis2.AxisFault:Unable to engage module : addressing
1) 使用非阻塞方式呼叫:sendReceiveNonBlocking(方法, callback類)
最後我們在CallBack具體的實類中我們巧妙使用了執行緒的wait()和notify()來實現“阻塞”。
3.2 再來看如何解析傳回的值
由於傳回的值也是一個OMElement結構體,來看SOAP UI工具中給我們生成的傳回結果
hello: Simon Shen
其實,我們需要做的就是解析這個SOAP的傳回包(soap response)。
public void onMessage(MessageContext msgContext) {
System.out.println(msgContext.getEnvelope().getBody());
OMElement element = msgContext.getEnvelope().getBody()
.getFirstElement();
OMElement result = element.getFirstChildWithName(new QName(
“http://javatype.helloworld.axis2.sky.org”, “return”));
System.out.println(result.getText());
synchronized (this) {
this.notify();
}
}
在SOAP的世界中,這個namespace很重要,相當於一個頭標記,如果我們在呼叫下麵這句話時
OMElement result = element.getFirstChildWithName(new QName(
“http://javatype.helloworld.axis2.sky.org”, “return”));
沒有加http://javatype.helloworld.axis2.sky.org,那麼這段soapresponse將無法被正確定位到
hello: Simon Shen
那麼你將得到NullPointerException。
相信,經過這樣的講解,因該能夠使你看得懂一個Axis2的API客戶端了吧,從此處我們可以發覺,很多陳述句都是“固化”的,和EJB的呼叫一樣,一堆固化的陳述句,寫多了,理解起來就並不難了,呵呵。
四、複雜型別的Webservice
更多的時候,我們的Service需要傳回類似於List
下麵是Service端:
org.sky.axis2.javacomplextype.PersonService
package org.sky.axis2.javacomplextype;
import org.apache.axiom.om.OMElement;
import org.apache.axis2.databinding.utils.BeanUtil;
import java.util.*;
import javax.xml.namespace.QName;
public class PersonService {
public OMElement getPersons(OMElement person) {
Person man = new Person();
List
list = new ArrayList (); man.setName(“Wallance Shao”);
man.setAge(“25”);
list.add((Person) man.clone());
man.setAge(“11”);
man.setName(“Hong Wayne”);
list.add((Person) man.clone());
OMElement omElement = BeanUtil.getOMElement(new QName(“root”),
list.toArray(), new QName(“person”), false, null);
return omElement;
}
}
它生成了一個List
org.sky.axis2.javacomplextype.Person
package org.sky.axis2.javacomplextype;
import java.io.*;
public class Person implements Serializable,Cloneable{
private String name=””;
private String age=””;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public Object clone(){
Object o = null;
try{
o=super.clone();
}catch(Exception e){
e.printStackTrace();
o=null;
}
return o;
}
}
然後我們編寫我們的service.xml檔案
它的內容如下:
org.sky.axis2.javacomplextype.PersonService
urn:getPersons
把它佈署進我們的tomcat,啟動後可以得到一個新的service
書寫我們的客戶端,此處我們使用非阻塞式寫法。
註意:
把Server端的Person.java複製一份到客戶端的package中去,一定記得,要不然造型時會出錯
org.sky.axis2.javacomplextype.PersonServiceClient
package org.sky.axis2.javacomplextype;
import java.util.Iterator;
import javax.xml.namespace.QName;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.client.async.AxisCallback;
import org.apache.axis2.context.MessageContext;
public class PersonServiceClient {
private static EndpointReference targetEPR = new EndpointReference(
“http://localhost:8080/Axis2Service/services/PersonService”);
public void getPersons() {
Options options = new Options();
options.setAction(“urn:getPersons”);
options.setTo(targetEPR);
options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
options.setUseSeparateListener(true);
ServiceClient sender = null;
try {
PersonCallBack callback = new PersonCallBack();
sender = new ServiceClient();
sender.setOptions(options);
sender.engageModule(Constants.MODULE_ADDRESSING);
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace omNs = fac.createOMNamespace(
“http://javacomplextype.axis2.sky.org”, “”);
OMElement method = fac.createOMElement(“getPersons”, omNs);
OMElement person = fac.createOMElement(“person”, omNs);
person.setText(“”);
method.addChild(method);
sender.sendReceiveNonBlocking(method, callback);
synchronized (callback) {
try {
callback.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (Exception e) {
System.out.println(“——-Error Occured——-“);
e.printStackTrace();
} finally {
try {
sender.cleanup();
} catch (Exception e) {
}
}
}
public static void main(String[] args) {
PersonServiceClient testClient = new PersonServiceClient();
testClient.getPersons();
}
}
由於是非阻塞式,因此需要寫CallBack具體實現類,下麵是我們的CallBack具體實現類,註意紅色加粗部分為我們的核心程式碼。
org.sky.axis2.javacomplextype.PersonCallBack
package org.sky.axis2.javacomplextype;
import java.util.Iterator;
import javax.xml.namespace.QName;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMNode;
import org.apache.axis2.client.async.AxisCallback;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.databinding.utils.BeanUtil;
import org.apache.axis2.engine.DefaultObjectSupplier;
public class PersonCallBack implements AxisCallback {
public void onMessage(MessageContext msgContext) {
OMElement result = msgContext.getEnvelope().getBody().getFirstElement();
System.out.println(“result====” + result);
if (result == null) {
return;
}
Iterator iterator = result.getChildElements();
while (iterator.hasNext()) {
OMNode omNode = (OMNode) iterator.next();
if (omNode.getType() == OMNode.ELEMENT_NODE){
OMElement omElement = (OMElement) omNode;
if (omElement.getLocalName().toLowerCase().equals(“person”)) {
try {
Person person = (Person) BeanUtil.processObject(
omElement, Person.class, null, true,
new DefaultObjectSupplier());
System.out.println(“person name=” + person.getName()
+ ” person age=” + person.getAge());
} catch (Exception e) {
System.out.println(“——-Error Occured——-“);
e.printStackTrace();
}
}
}
}
synchronized (this) {
try {
this.notify();
} catch (Exception e) {
}
}
}
public void onFault(MessageContext msgContext) {
System.out.println(msgContext.getEnvelope().getBody().getFault()
.toString());
synchronized (this) {
try {
this.notify();
} catch (Exception e) {
}
}
}
public void onError(Exception e) {
synchronized (this) {
try {
this.notify();
} catch (Exception ex) {
}
}
e.printStackTrace();
}
public void onComplete() {
synchronized (this) {
try {
this.notify();
} catch (Exception e) {
}
}
}
}
執行我們的PersonServiceClient類,得到輸出如下:
完成我們Axis2的第二天的課程!!!
系列
看完本文有收穫?請轉發分享給更多人
關註「ImportNew」,提升Java技能