这是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;
}
}
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;
}
}
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 >
< 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 " />
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);
}
}
{
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 >
< 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
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
& 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 " ); // 初始化
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( " 处理错误,这里忽略! " );
}
}
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 >
< 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);
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;
import org.apache.axis.configuration.FileProvider;
运行一下,返回 "ronghao" ,搞定!
注意:这次我把 OrderClient.class 的调用放到了一个 JSP 文件中而不是 jbuilder 中,因为有 client-config.wsdd ,所以你必须有完整的 WEB 程序发布到 TOMCAT 中,否则会报找不到
相应文件。
http://www.blogjava.net/ronghao 荣浩原创,转载请注明出处:)