這是AXIS學習筆記的最后一篇。在前面我們討論了最簡單的HelloWorld服務,客戶端并沒有向服務器端傳遞參數,現在我們來傳JavaBean。當然,也可以傳遞你自己定義的JAVA類,但那樣你必須自己創建專門的XML序列化器和反序列化器;而對JavaBean,AXIS提供了現成的序列化器。(有人說:懶惰是程序員最大的美德)
一、服務器端
1、CLASS類兩個Order.class,OrderTest.class,位于%TOMCAT_HOME%\webapps\axis\WEB-INF\classes下
這兩個類都直接給出源碼,不再說明
Order.java
public class Order {
private String id;
private String name;
public void setId(String id){
this.id=id;
}
public String getId(){
return id;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
}
OrderTest.java
public class OrderTest {
public Order returnOrder(Order order){
Order newOrder=new Order();
if(order.getId().equals("1"))
newOrder.setName("ronghao");
else newOrder.setName("haorong");
return newOrder;
}
}
2、修改服務器端配置文件server-config.wsdd
在server-config.wsdd中相應位置添加以下代碼
<service name="Order" provider="java:RPC">
<parameter name="allowedMethods" value="returnOrder"/>
<parameter name="className" value="OrderTest"/>
<beanMapping languageSpecificType="java:Order" qname="ns1:Order"
xmlns:ns1="urn:BeanService"/>
</service>
可以看到和前面的發布服務代碼相比僅多了一行代碼
<beanMapping languageSpecificType="java:Order" qname="ns1:Order"
xmlns:ns1="urn:BeanService"/>
languageSpecificType屬性指定JavaBean類文件位置,例如:
languageSpecificType="java:com.ronghao.axis.Order"
qname屬性指定JavaBean類的名字
其他是固定的。
二、客戶端
客戶端類文件一個OrderClient.class,代碼如下(變化的部分加注釋):
public class OrderClient
{
public static void main(String args[])
throws Exception
{
String endpoint = "http://localhost:8080/axis/services/Order"; //服務所在位置
Order order=new Order(); //JavaBean
order.setId("1");
Service service = new Service();
Call call = (Call)service.createCall();
//注冊JavaBean,注意和server-config.wsdd中的配置代碼比較
QName qn = new QName("urn:BeanService", "Order");
call.registerTypeMapping(Order.class, qn, new BeanSerializerFactory(Order.class, qn),
new BeanDeserializerFactory(Order.class, qn));
String name="no!";
try
{
call.setTargetEndpointAddress(new URL(endpoint));
//調用的服務器端方法
call.setOperationName(new QName("Order", "returnOrder"));
//設定傳入的參數,這里qn即Order.class
call.addParameter("arg1", qn, ParameterMode.IN);
//設定返回的參數是Order.class
call.setReturnType(qn, Order.class);
Order result = (Order)call.invoke(new Object[] {
order
});
if(result != null)
name = result.getName();
}
catch(Exception e)
{
System.err.println(e);
}
System.out.println(name);
}
}
OK!運行一下,就可以看到返回了"ronghao"。
和上一篇文章一樣,我們不容許在網絡中傳遞XML是明文,于是需要加密和驗證。這里我們繼續采用上次所講的框架。(已打包成ws-axis.jar)
一、修改服務器端配置文件server-config.wsdd(和上一文章一模一樣!不再羅嗦)
在server-config.wsdd中相應位置添加以下代碼
<requestFlow>
<handler type="soapmonitor"/>
<handler type="java:com.ronghao.WSAxis.WSServerRequestHandler">
<parameter name="keyStoreFile" value="f:\server.keystore"/>
<parameter name="trustStoreFile" value="f:\server.truststore"/>
<parameter name="keyStorePassword" value="changeit"/>
<parameter name="keyAlias" value="Server"/>
<parameter name="keyEntryPassword" value="changeit"/>
<parameter name="trustStorePassword" value="changeit"/>
<parameter name="certAlias" value="clientkey"/>
</handler>
</requestFlow>
<responseFlow>
<handler type="soapmonitor"/>
<handler type="java:com.ronghao.WSAxis.WSServerResponseHandler">
<parameter name="keyStoreFile" value="f:\server.keystore"/>
<parameter name="trustStoreFile" value="f:\server.truststore"/>
<parameter name="keyStorePassword" value="changeit"/>
<parameter name="keyAlias" value="Server"/>
<parameter name="keyEntryPassword" value="changeit"/>
<parameter name="trustStorePassword" value="changeit"/>
<parameter name="certAlias" value="clientkey"/>
</handler>
</responseFlow>
二、客戶端(區別就在這里,注意!!)
首先在這里要說一下,客戶端代碼編寫困擾了我很長一段時間(整整一天),因為它并不象我想象的那么簡單,當然解決起來還是挺簡單的:)問題的解決經歷了三個階段
第一階段:
在這個階段我想當然的在OrderClient.class中加入了如下代碼:
WSClientHandler handler=new WSClientRequestHandler();//注意新加的HANDLER
handler.setInitialization("f:/client.keystore","changeit","Client","changeit",
"f:/client.truststore","changeit","serverkey");//初始化
WSClientHandler handlee=new WSClientResponseHandler();//注意新加的HANDLER
handlee.setInitialization("f:/client.keystore","changeit","Client","changeit",
"f:/client.truststore","changeit","serverkey");//初始化
call.setClientHandlers(handler,handlee);//添加Handler
這個方法也是我在上一文章里介紹的,結果拋出以下異常:
faultString: org.xml.sax.SAXException: Deserializing parameter
'newProfileReturn': could not find deserializer for type
{urn:BeanService Order}SerializableProfile
也就是說不能正常解析XML文件,于是理所當然的郁悶了,覺得代碼中肯定漏設了CALL的一個屬性,于是查看AXIS的源代碼,沒有結果!轉機出現在下面一行代碼,在不斷的拋出異常中我修改了代碼
將call.setClientHandlers(handler,handlee);改為
call.setClientHandlers(null,null);
結果程序還是拋出同樣的異常,于是意識到這可能是AXIS的一個BUG,為證明這一點,我將下面的Handler初始化代碼刪除
WSClientHandler handler=new WSClientRequestHandler();//注意新加的HANDLER
handler.setInitialization("f:/client.keystore","changeit","Client","changeit",
"f:/client.truststore","changeit","serverkey");//初始化
WSClientHandler handlee=new WSClientResponseHandler();//注意新加的HANDLER
handlee.setInitialization("f:/client.keystore","changeit","Client","changeit",
"f:/client.truststore","changeit","serverkey");//初始化
結果還是拋出同樣的異常,果然是BUG!得到這個結論后去了apache AXIS主頁,在問題列表中見到了完全一樣問題的提交,但沒有解答(暈!)
最后得到了結論:call的setClientHandlers()方法只有當call處理簡單的數據類型,如String,int等等才能正常使用!
(當然,如果你對這個問題有不同的見解,歡迎和我聯系。或許我錯了,但程序不運行是真的:))
第二階段:
開始在google上找問題的解決方法,這也是我的習慣:)。找了一個類似問題的討論,地址如下:
http://marc.theaimsgroup.com/?l=axis-user&m=111259980822735&w=2
他們的解決方法是Handler繼承于javax.xml.rpc.handler.Handler,然后在程序里動態注冊而在我的ws-axis.jar里Handler繼承于org.apache.axis.handlers.BasicHandler。當然,
javax.xml.rpc.handler.Handler是org.apache.axis.handlers.BasicHandler的老爸,但在程序里老爸和兒子之間卻不能很好的兼容,這也許就是所謂的代溝??無奈中重新寫了Handler,但在運行中卻拋出異常,提示message在被invoke的時候已被更改。Handler的作用就是來更改message的啊!
我知道很多程序采用的就是這種方法,但我好象怎么修改都拋出上述異常。
第三階段
既然在程序里動態注冊Handler行不通,于是決定寫個單獨的配置文件來注冊Handler。如果這種方法不幸失敗就返回第二階段。好馬為什么不吃回頭草??
1、ws-axis.jar中修改WSClientHandler.class,修改后如下,我想你一看就明白為何修改
public class WSClientHandler extends BasicHandler{
protected String keyStoreFile ;
protected String keyStoreType ="JKS";
protected String keyStorePassword ;
protected String keyAlias ;
protected String keyEntryPassword ;
protected String trustStoreFile ;
protected String trustStoreType = "JKS";
protected String trustStorePassword ;
protected String certAlias ;
public void init() {
keyStoreFile = (String)getOption("keyStoreFile");
if(( keyStoreFile== null) )
System.err.println("Please keyStoreFile configured for the Handler!");
trustStoreFile = (String)getOption("trustStoreFile");
if(( trustStoreFile== null) )
System.err.println("Please trustStoreFile configured for the Handler!");
keyStorePassword = (String)getOption("keyStorePassword");
if(( keyStorePassword== null) )
System.err.println("Please keyStorePassword configured for the Handler!");
keyAlias = (String)getOption("keyAlias");
if(( keyAlias== null) )
System.err.println("Please keyAlias configured for the Handler!");
keyEntryPassword = (String)getOption("keyEntryPassword");
if(( keyEntryPassword== null) )
System.err.println("Please keyEntryPassword configured for the Handler!");
trustStorePassword = (String)getOption("trustStorePassword");
if(( trustStorePassword== null) )
System.err.println("Please trustStorePassword configured for the Handler!");
certAlias = (String)getOption("certAlias");
if ((certAlias==null))
System.err.println("Please certAlias configured for the Handler!");
if ((getOption("keyStoreType")) != null)
keyStoreType = (String)getOption("keyStoreType");
if ((getOption("trustStoreType")) != null)
trustStoreType = (String)getOption("trustStoreType");
}
public void invoke(MessageContext messageContext) throws AxisFault {
//do nothing now!
}
public void onFault(MessageContext msgContext) {
System.out.println("處理錯誤,這里忽略!");
}
}
2、寫客戶端的配置代碼client-config.wsdd,如下:
<?xml version="1.0" encoding="UTF-8"?>
<deployment name="defaultClientConfig"
xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<transport name="http"
pivot="java:org.apache.axis.transport.http.HTTPSender"/>
<transport name="local"
pivot="java:org.apache.axis.transport.local.LocalSender"/>
<transport name="java"
pivot="java:org.apache.axis.transport.java.JavaSender"/>
<globalConfiguration>
<requestFlow>
<handler type="java:com.ronghao.WSAxis.WSClientRequestHandler">
<parameter name="keyStoreFile" value="D:\Tomcat5.5\webapps\axis\WEB-INF\client.keystore"/>
<parameter name="keyEntryPassword" value="changeit"/>
<parameter name="certAlias" value="serverkey"/>
<parameter name="trustStorePassword" value="changeit"/>
<parameter name="trustStoreFile" value="D:\Tomcat5.5\webapps\axis\WEB-INF\client.truststore"/>
<parameter name="keyAlias" value="Client"/>
<parameter name="keyStorePassword" value="changeit"/>
</handler>
</requestFlow>
<responseFlow>
<handler type="java:com.ronghao.WSAxis.WSClientResponseHandler">
<parameter name="keyStoreFile" value="D:\Tomcat5.5\webapps\axis\WEB-INF\client.keystore"/>
<parameter name="keyEntryPassword" value="changeit"/>
<parameter name="certAlias" value="serverkey"/>
<parameter name="trustStorePassword" value="changeit"/>
<parameter name="trustStoreFile" value="D:\Tomcat5.5\webapps\axis\WEB-INF\client.truststore"/>
<parameter name="keyAlias" value="Client"/>
<parameter name="keyStorePassword" value="changeit"/>
</handler>
</responseFlow>
</globalConfiguration>
</deployment>
同樣不再解釋,不明白可以參考我的上一篇文章
3、修改OrderClient.class
在OrderClient.class中加入了如下代碼:
EngineConfiguration conf =
new FileProvider("F:\\Tomcat\\webapps\\axis\\WEB-INF\\client-config.wsdd");//位置
Service service = new Service(conf);
當然記得導入
import org.apache.axis.EngineConfiguration;
import org.apache.axis.configuration.FileProvider;
運行一下,返回"ronghao",搞定!
注意:這次我把OrderClient.class的調用放到了一個JSP文件中而不是jbuilder中,因為有client-config.wsdd,所以你必須有完整的WEB程序發布到TOMCAT中,否則會報找不到
相應文件。
http://www.tkk7.com/ronghao 榮浩原創,轉載請注明出處:)
posted on 2007-06-12 16:25
ronghao 閱讀(5334)
評論(3) 編輯 收藏 所屬分類:
SOA、BPM