posts - 193,  comments - 520,  trackbacks - 0

          這是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>

                  
           
          二、客戶端(區別就在這里,注意?。。?/span>
            
          首先在這里要說一下,客戶端代碼編寫困擾了我很長一段時間(整整一天),因為它并不象我想象的那么簡單,當然解決起來還是挺簡單的:)問題的解決經歷了三個階段
            
            
          第一階段:
             
          在這個階段我想當然的在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
              
          &apos;newProfileReturn&apos;:  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主頁,在問題列表中見到了完全一樣問題的提交,但沒有解答(暈?。?/span>
             
          最后得到了結論:callsetClientHandlers()方法只有當call處理簡單的數據類型,如String,int等等才能正常使用!
             
          (當然,如果你對這個問題有不同的見解,歡迎和我聯系?;蛟S我錯了,但程序不運行是真的:))
             
            
          第二階段:
              
          開始在google上找問題的解決方法,這也是我的習慣:)。找了一個類似問題的討論,地址如下:
              http://marc.theaimsgroup.com/?l=axis-user&m=111259980822735&w=2
              
          他們的解決方法是Handler繼承于javax.xml.rpc.handler.Handler,然后在程序里動態注冊而在我的ws-axis.jarHandler繼承于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.aygfsteel.com/ronghao 榮浩原創,轉載請注明出處:)
          posted on 2007-06-12 16:25 ronghao 閱讀(5337) 評論(3)  編輯  收藏 所屬分類: SOA、BPM

          FeedBack:
          # re: AXIS服務間傳遞JavaBean及其安全解決
          2007-06-14 00:11 | IT進行時
          收藏  回復  更多評論
            
          # re: AXIS服務間傳遞JavaBean及其安全解決
          2009-03-19 21:31 | yefriendly
          我按照你的做過,已HelloWorld服務為例,能實現加密和解密,請求方可以簽名,服務方簽名驗證失敗。出現異常:impleDeserializer encountered a child element, which is NOT expected, in something it was trying to deserialize.

          客戶端調用時String result=(String)call.invoke(new Object[]{str});此處有問題(str為傳入的參數).  回復  更多評論
            
          # re: AXIS服務間傳遞JavaBean及其安全解決
          2012-12-18 17:28 | 過客
          感謝您,幫了我大忙,總算解決了問題  回復  更多評論
            
          <2007年6月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          1234567

          關注工作流和企業業務流程改進。現就職于ThoughtWorks。新浪微博:http://weibo.com/ronghao100

          常用鏈接

          留言簿(38)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          常去的網站

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 白银市| 惠来县| 游戏| 来宾市| 耿马| 元江| 故城县| 宣汉县| 延寿县| 红安县| 黄山市| 泗水县| 莱阳市| 信宜市| 宁乡县| 阜康市| 肥乡县| 秀山| 凌云县| 新宁县| 宁化县| 赤峰市| 珲春市| 彩票| 宣汉县| 乌拉特中旗| 木兰县| 游戏| 浦东新区| 长阳| 宁海县| 内江市| 漳平市| 绵阳市| 临城县| 建昌县| 泌阳县| 平度市| 丘北县| 双江| 马尔康县|