AXIS服务间传递JavaBean及其安全解决

这是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
    
& 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 主页,在问题列表中见到了完全一样问题的提交,但没有解答(晕!)
   
最后得到了结论: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.blogjava.net/ronghao 荣浩原创,转载请注明出处:)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值