AXIS总结

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Apache Axis学习总结
1. 简介
在学习与使用Apache Axis过程中,阅读了一些网上的资料,结合自己在实际运用中遇到的一些问题,对Axis的使用作一些总结。

由于是刚刚接触到Axis,所以理论的东西不是很懂,只是写了一点。

网上有好多资料,写得很详细很不错,所以我只是把一些自己用到的基本实例做了记录,更多的资料请百度一下。

1.1Apache Axis
Axis是SOAP Engine----用来构造SOAP处理器,例如客户端,服务器端,网管等等。

Axis是使用Java实现的,本文主要介于Axis 1.4。

Axis 1.4的特性如下:
·兼容SOAP 1.1/1.2两个版本
·灵活的配置和发布
·支持JWS
·支持所有的基本类型,以及类型映射系统
·自动的Java Beans序列化/反序列化,包含自定义的Java属性-->XML元素/属性的映射·自动的Java集合与SOAP数组的双向转换。

·提供RPC和基于消息的SOAP服务
·由发布的服务自动生成WSDL
·WSDL2Java工具
·Java2WSDL工具
·基本的安全扩展,可以集成到Servlet 2.2的安全/角色中
·支持面向绘画的服务,通过使用HTTP Cookie或者独立于传输的SOAP Headers
·对SOAP with Attachments规范的初步支持
·基HTTP Servlet的传输
·基于JMS的支持
1.2 SOAP
SOAP:SOAP是基于XML的通信协议和编码格式,它用于交互应用程序通信。

现在的版本是SOAP 1.2,但是SOAP 1.1版本使用的更加广泛。

SOAP由W3C的XML协议工作组管理。

SOAP被广泛的认为是跨平台、跨语言的计算机应用和Web Service的核心。

2. Axis基础
2.1基础--Getting Started
2.1.1 简例
这是一个Web Service客户端,它调用了Axis服务器上的一个echoString方法。

1 import org.apache.axis.client.Call;
2 import org.apache.axis.client.Service;
3 import space.QName;
4
5 public class TestClient {
6 public static void main(String [] args) {
7 try {
8 String endpoint =
9 ":5049/axis/services/echo";
10
11 Service service = new Service();
12 Call call = (Call) service.createCall();
13
14 call.setTargetEndpointAddress( new .URL(endpoint) );
15 call.setOperationName(new QName("/",
echoString"));
16
17 String ret = (String) call.invoke( new Object[] { "Hello!" } );
18
19 System.out.println("Sent 'Hello!', got '" + ret + "'");
20 } catch (Exception e) {
21 System.err.println(e.toString());
22 }
23 }
24 }
What's happening here ? 第11和12行,new了Service和Call对象。

它们是标准的JAX-RPC对象,用于存储关于调用Service的一些元数据。

14行,设置了终端节点的URL---它是SOPA消息的目的地。

15行,定义了Web Service的一个方法名。

17行,调用Web Service,传递了一个对象数组作为参数---在此,对象数组中只包括一个字符串。

查看SOAP request的结构,如下图所示。

传递的字符串参数被自动的序列化成XML,服务器响应就是被反序列化出来的字符串。

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:xsd="/2001/XMLSchema"
xmlns:SOAP-ENV="/soap/envelope/"
xmlns:xsi="/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:echoString xmlns:ns1="/">
<arg0xsi:type="xsd:string">Hello!</arg0>
</ns1:echoString>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
2.1.2命名参数:
在上面的例子中,可以看到Axis自动的命名了SOAP消息中的XML参数为"arg0","arg1",以此类推(本例中只是"argo")。

如果想change它,在调用invoke()前,只需为每个参数调用addParameter方法,并且调用setReturnType方法设置返回类型,like so:
call.addParameter("testParam",
org.apache.axis.Constants.XSD_STRING,
javax.xml.rpc.ParameterMode.IN);
call.setReturnType(org.apache.axis.Constants.XSD_STRING);
指定了"testParam"为invoke的第一个(and only)参数名,Constants.XSD_STRING指定了参数类型为String,ParameterMode.IN指定了这是一个输入参数,最后一行指定了返回类型也是String。

这样设置后,SOAP请求是这样的:(参数名已经变成了"testParam")。

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:xsd="/2001/XMLSchema"
xmlns:SOAP-ENV="/soap/envelope/"
xmlns:xsi="/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:echoString xmlns:ns1="/">
<testParam xsi:type="xsd:string">Hello!</testParam>
</ns1:echoString>
</SOAP-ENV:Body>
2.1.3 与"untyped" Servers的互操作
在上面的例子中,我们把invoke()方法的返回类型强制转换了,本来返回类型是Object 的,被转转成实际类型String。

查看一下echoString方法的响应信息:
<SOAP-ENV:Body>
<ns1:echoStringResponse xmlns:ns1="/">
<result xsi:type="xsd:string">Hello!</result>
</ns1:echoStringResponse>
</SOAP-ENV:Body>
紫色的部分包含了一个类型声明,Axis使用它来决定将元素的内容反序列化成什么类型的Java对象,本例中将其反序列化成一个Java String对象。

许多工具把这种XML格式的类型定义成为"自描述"。

有些工具也会返回如下的响应:
<SOAP-ENV:Body>
<ns1:echoStringResponse xmlns:ns1="/">
<result>Hello, I'm a string!</result>
</ns1:echoStringResponse>
</SOAP-ENV:Body>
响应消息中并没有类型定义,那么<result>元素会被反序列化成什么Java 对象呢?The answer is metadata(元数据--data about data)。

这种情况下,需要一个服务描述来决定返回类型。

在Axis客户端需要这样做:
call.setReturnType( org.apache.axis.Constants.XSD_STRING );
这个方法会告诉Axis客户端,如果返回元素没有被定义类型,那么它应该将返回值的xsi:type属性设置成预定义的SOAP String类型。

一个类似的方法也可以指定返回类型为那种Java Class:
call.setReturnClass(String.class);
2.2 发布our own Service
一个非常简单的类
public class Calculator {
public int add(int i1, int i2) {
return i1 + i2;
}
public int subtract(int i1, int i2) {
return i1 - i2;
}
}
如何让这个类可以通过SOAP访问呢?简单介绍Axis的几种方式。

2.2.1 瞬时部署--JWS(Java Web Service)文件
JWS web服务是目的在于实现简单的web服务,不能使用package,略过。

2.2.2 定制部署--WSDD
1)通过描述文件部署
灵活运用Axis,需要熟悉Axis Web Service Deployment Descriptor(WSDD)。

部署描述文件包含了需要部署到Axis中的内容,即Axis Engine需要使用的内容。

从做基本的服务开始了解wsdd,一个部署描述文件的简单例子:
<deployment xmlns="/axis/wsdd/"
xmlns:java="/axis/wsdd/providers/java">
<service name="MyService" provider="java:RPC">
<parameter name="className"
value="erguide.example3.MyService"/>
<parameter name="allowedMethod s" value="*"/>
</service>
</deployment>
最外层节点告诉Axis引擎,这是一个wsdd部署,并且定义了Java命名空间。

Service 节点定义了服务,一个Service就是一个目标链,可以包括以下内容:request flow, pivot Handler(对于Service来说叫做provider),response flow。

本例中,provider是"java:RPC",它建立在Axis中,表明了这是一个Java RPC服务。

实际的hanlder类是org.apache.axis.provider.java.RPCProvider。

为了使RPCProvider能正确地实例化MyService( erguide.example3.MyService) 类及调用它,需要包含<parameter>标签,第一个Parameter指定了Service的类名,第二个parameter指定了可以通过SOAP被调用的公共方法有哪些("*"--代表所有公共方法)。

指定多个方法时,可以用空格或者逗号隔开。

2)服务范围
Axis支持三种方式的Service对象:Request scope,Session scope,Applicationscope。

"Resquest" scope 是默认的,为每一个SOAP请求创建一个新的对象;
"Application" scope,为所有的请求创建一个共享的单例对象;
"Session" scope, 为每个允许使用session的客户端创建一个对象。

指定服务范围,需要增加一个<parameter>, like this:
<service name="MyService"...>
<parameter name="scope" value="value"/>
...
</service>
3)使用AdminClient
org.apache.axis.client.AdminClient类来将wsdd文件发送到Axis服务器,以便真正的部署服务。

如果将Axis部署到不是tomcat的服务器上的话,需要使用-p<port>参数,默认的是8080,一个典型的调用AdminClient的方式是:
% java org.apache.axis.client.AdminClient deploy.wsdd
这个命令会发布web service服务,然后就可以在客户端调用该服务了。

4)Handler and Chains
Handler可以让我们在服务被访问前或访问后做一些事情,例如计算服务被访问了多少次。

一个简单的包含了Handler的例子,如下图所示:首先定义了一个名为"track"的Handler,它是类erguide.example4.LogHandler。

然后定义了一个参数,指定它的消息被写往何处。

然后定义了一个服务--LogTestService,包含了<requestFlow>节点,这个节点指定了服务被provider调用时需要首先调用的Handler。

通过引用Handler "track ",可以确保每一次服
务被调用的时候,将消息记录到日志里。

<deployment xmlns="/axis/wsdd/"
xmlns:java="/axis/wsdd/providers/java">
<!-- define the logging handler configuration -->
<handler name="track" type="java:erguide.example4.LogHandler">
<parameter name="filename" value="MyService.log"/>
</handler>
<!-- define the service, using the log handler we just defined -->
<service name="LogTestService" provider="java:RPC">
<requestFlow>
<handler type="track"/>
</requestFlow>
<parameter name="className" value="erguide.example4.Service"/>
<parameter name="allowedMethods" value="*"/>
</service>
</deployment>
5)远程管理
默认情况下,Axis server被配置成不支持远程管理,如果希望远程管理,可以在WEB-INF 目录下的"server-config.wsdd"文件中增增加AdminService:
<service name="AdminService" provider="java:MSG">
<parameter name="className" value="org.apache.axis.util.Admin"/>
<parameter name="allowedMethods" value="*"/>
<parameter name="enableRemoteAdmin" value="true"/>
</service>
WARNING:远程管理涉及到安全问题,不建议使用。

6)服务方式--Service Sytles
Axis 支持四种服务方式:RPC,Document,Wrapped,Message。

RPC services是Axis 默认的。

不大懂,不详细介绍。

请参考:/view/32726.htm?fr=ala0_1_1 2.3 XML---Java 类型映射
JAX-RPC定义了Java类型和WSDL/XSD/SOAP间的映射。

以下是一些基本映射:
xsd:base64 Binary byte[]
xsd:boolean boolean
xsd:byte byte
xsd:dateTime java.util.Calendar
xsd:decimal java.math.BigDecimal
xsd:double double
xsd:float float
xsd:hexBinary byte[]
xsd:int int
xsd:integer java.math.BigInteger
xsd:long long
xsd:QName space.QName
xsd:short short
xsd:string ng.String
WSDL中定义的int,double,float等类型,Axis会自动将他们转换成对应的封装类。

2.3.1通过SOAP能发送什么
能发送Collection类。

一些Collection类,比如hashtable,它确实用自己的serializers,但是没有和其他SOAP实现进行互操作的标准,并且没有任何关于转化复杂对象的SOAP 标准。

最可信赖的方法是通过数组来传递对象集合。

2.3.2通过SOAP不能发送什么
没有预先注册的对象。

我们不能发送一个任意的Java对象,并期望对方能理解。

使用RMI可以发送和接受序列化的Java对象,那是因为两端都是使用的Java。

Axis只能发送那些能被注册的Axis序列化器序列化的对象。

下面介绍如何使用BeanSerializer来序列化任意一个符合JavaBean格式的类。

2.4 编写自己的Bean--使用BeanSerializer
Axis已经包括了序列化和反序列化功能。

任何符合标准JavaBean规范的Java类都能被序列化与反序列化。

我们要做的就是告诉Axis Java类与XML Schema类型之间的映射。

可以像这样配置Bean的映射:
<beanMapping qname="ns:local" xmlns:ns="someNamespace"
languageSpecificType="java:my.java.thingy"/>
<beanMapping>将Java类映射成XML QName。

这里有两个重要的属性"qname"和"languageSpecificType"。

这个例子中将"my.java.thingy"映射QName"[someNamespace][local]"。

2.5 Java2WSDL 与WSDL2Java工具
Java2WSDL和WSDL2Java工具使得部署一个新的web service变得简单。

下面的内容介绍了由Java接口建立web service的步骤。

Step 1:提供Java接口或类
编写并编译一个描述web service的Java接口(或类),这个接口描述了一个用来设置和获得Widget价格的web service,具体如下:
package erguide.example6;
/**
* Interface describing a web service to set and get Widget prices.
**/
public interface WidgetPrice {
public void setWidgetPrice(String widgetName, String price);
public String getWidgetPrice(String widgetName);
}
Setp 2:使用Java2WSDL创建WSDL
使用Java2WSDL工具根据上面的Java Interface来创建一个WSDL文件。

执行下面的命令后会产生一个wsdl文件(wp.wsdl)。

命名如下:
% java org.apache.axis.wsdl.Java2WSDL -o wp.wsdl
-l "http://localhost:8080/axis/services/WidgetPrice"
-n "urn:Example6" -p "erguide.example6" "urn:Example6"
erguide.example6.WidgetPrice
Where:
-o 指定输出WSDL文件名
-l 指定服务的位置
-n WSDL文件的目标命名空间
-p 将包映射为一个命名空间。

可以有多个映射
-最后一行就是那个Java接口
产生的WSDL文档会包含WSDL类型、消息、端口类型等服务描述信息。

这个工具支持JAX-PRC复杂类型(Bean classes),枚举类型,数组类型等。

Note:一定要进入WidgetPrice.class所在目录运行该命令
Setp 3:使用WSDL2Java创建绑定
使用刚才建立的WSDL文件为这个web service建立客户端/服务器绑定。

% java org.apache.axis.wsdl.WSDL2Java -o . -d Session -s -S true
-Nurn:Example6 erguide.example6 wp.wsdl
这条命令会创建如下的文件:
WidgetPriceSoapBindingImpl.java : 包含WidgetPrice Web Service 默认服务端实现的
Java文件;
WidgetPrice.java: 包含一些java.rmi.Remote用例的新接口;
WidgetPriceService.java: 包含客户端服务接口的Java文件;
WidgetPriceServiceLocator.java:包含客户的服务实现类的Java文件;
WidgetPriceSoapBindingSkeleton.java: 服务端Skeleton;
WidgetPriceSoapBindingStub.java: 客户端Stub;
deploy.wsdd: Deployment 描述符;
undeploy.wsdd: Undeployment 描述符;
(数据类型):这些Java文件包含了该web Service所必需的数据类型。

3. Axis实例
3.1准备工作
1)开发工具及Jar包
开发工具及环境:MyEclipse 6.0 +AXIS 1.4 + WebLogic 8.1+JDK 1.4;
所需AXIS jar包:axis.jar, activation.jar, axis-ant.jar, commons-discovery-0.2.jar,
Commons-logging-1.0.4.jar, jaxrpc.jar, log4j-1.2.8.jar, mail.jar, saaj.jar, wsdl4j-1.5.1.jar, xmlsec-1.4.2.jar
2)设置环境变量
我将Axis1.4的jar包全保存在了D:\axis-1.4\lib\目录下了。

配置环境变量:
变量名:AXIS_HOME
变量值:D:\axis-1.4
变量名:AXIS_LIB
变量值:%AXIS_HOME%\lib
变量名:AXISCLASSPA TH
变量值: .;%AXIS_LIB%\axis.jar;
%AXIS_LIB%\activation.jar;
%AXIS_LIB%\axis-ant.jar;
%AXIS_LIB%\commons-discovery-0.2.jar;
%AXIS_LIB%\commons-logging-1.0.4.jar;
%AXIS_LIB%\jaxrpc.jar;
%AXIS_LIB%\log4j-1.2.8.jar;
%AXIS_LIB%\mail.jar;
%AXIS_LIB%\saaj.jar;
%AXIS_LIB%\wsdl4j-1.5.1.jar;
%AXIS_LIB%\xmlsec-1.4.0.jar;
%AXIS_LIB%\dom4j-1.6.1.jar;
变量名:CLASSPA TH
变量值:%AXISCLASSPA TH%
以上Jar包缺一不可。

3)创建web工程
创建web工程,工程名为server_axis,在web.xml文件中的<web-app>添加如下内容:
<servlet>
<servlet-name>AxisServlet</servlet-name>
<display-name>Apache-Axis Servlet</display-name>
<servlet-class>org.apache.axis.transport.http.AxisServlet</servlet-class> </servlet>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/servlet/AxisServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>*.jws</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<mime-mapping>
<extension>wsdl</extension>
<mime-type>text/xml</mime-type>
</mime-mapping>
<mime-mapping>
<extension>xsd</extension>
<mime-type>text/xml</mime-type>
</mime-mapping>
在WEB-INF目录下增加server-congfig.wsdd文件,添加如下内容(也可以用deploy.wsdd 部署文件来生成,只是这样直接粘简单明了):
然后将Axis1.4的Jar包拷贝到WEB-INF/lib目录下,并Build Path。

3.2 Hello W orld
目的是将类HelloWorld中的方法作为服务发布出去。

a. HelloWorld Service
package anni;
public class HelloWorld {
public String sayHello(String name) {
return "hello world! "+name+"!";
}
}
b. 在server-config.xml 中部署HelloWorld 服务,只需添加<service>节点。

c. 启动服务器,在浏览器中输入
这时会看到我们发布的所有服务,如下图:
点击
HelloWorld 后面的wsdl ,可以看到这个服务的详细描述信息
d. 在浏览器上调用服务 在浏览器中输入如下URL(method是方法名,后面是参数,如果有多个参数可以用“&”连接)
可以看到如下结果,这是SOAP响应信息:
<service name="HelloWorld " provider="java:RPC"> <!—这里的ClassName 就是我的服务类--> <parameter name="className" value="anni.HelloWorld"/> <parameter name="allowedMethods" value="*"/> <parameter name=”scope ” value=”Request ”/> </service> http://localhost:7001/server_axis/services
And now... Some Services HelloWorld (wsdl) o sayHello
http://localhost:7001/server_axis/services/HelloWorld?method=sayHello&name=quzhimin <?xml version="1.0" encoding="UTF-8" ?>
- <soapenv:Envelope xmlns:soapenv="/soap/envelope/" xmlns:xsd="/2001/XMLSchema"
xmlns:xsi="/2001/XMLSchema-instance">
<soapenv:Body>
<sayHelloResponse soapenv:encodingStyle="/soap/encoding/">
<sayHelloReturn
xsi:type="s oapenc:string "
xmlns:soapenc="/soap/encoding/">helloworld!quzhimin! </sayHelloReturn>
</sayHelloResponse >
</soapenv:Body>
e.在客户端调用服务
package anni;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
public class HelloClient {
public static void main(String [] args) throws Exception {
String endpoint = "http://localhost:7001/server_axis/services/HelloWorld";
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress(new .URL(endpoint));
call.setOperationName("sayHello");
String res = (String) call.invoke(new Object[]{"zhuzhimin"});
System.out.println(res);
}
}
这里,只是设置了服务的方法名,而参数类型,返回值类型都没有设定,对于int,double,....String这些类型,Axis不要求指定参数类型和返回值类型。

f. end,这样一个HelloWorld webservice就完成了。

3.3 增加一个小方法
如果是参数中或返回值是List,V ector,Map等集合类,在客户端调用的时候就不能像上边那样随便了。

A.首先在上面的HelloWorld类中增加一个方法,如下:
public List getList(ArrayList alist){
List ls = new ArrayList();
ls = alist;
System.out.println("服务端");
for(int i = 0;i<ls.size();i++){
ls.set(i, i+2+"");
System.out.println(ls.get(i).toString());
}
return ls;
}
B. 在server-config.xml中配置
对于List,V ector,Map这种集合类是不需要在server-config.xml中增加额外配置,实在想配置的话可以像这样(蓝色的部分为增加的部分):
<service name="HelloWorld" provider="java:RPC">
<parameter name="allowedMethods" value="*"/>
<parameter name="scope" value="Request"/>
<parameter name="className" value="anni.HelloWorld"/>
<operation name="getList" returnType="xsd:anytype">
<parameter qname="alist" type="xsd:anytype" mode="in"/>
</operation>
</service>
C. 客户端调用
package anni;
public class HelloClient {
public static void main(String [] args) throws Exception {
String endpoint = "http://localhost:7001/server_axis/services/HelloWorld";
Service service = new Service();
Call call = (Call) service.createCall();
call.setT argetEndpointAddress(new .URL(endpoint));
call.setOperationName(new QName("HelloWorld","getList"));
call.addParameter("ss",XMLT ype.XSD_ANYTYPE,
ParameterMode.IN);
call.setReturnClass(ArrayList.class);
List list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
List obj = (ArrayList) call.invoke(new Object[]{list});
System.out.println("客户端");
for(int i=0;i<obj.size();i++){
System.out.println(obj.get(i).toString());
}
}
}
彩色的部分是必须的。

绿色的"HelloWord"是随便起的名字,后面的getList是方法名,这个不能随便。

3.4 自定义类型的映射
如果我们要传递自定义类型数据,则需要配置类型映射,可以直接利用Axis自带的序列化与反序列化器。

A. 一个自定义类Order
package anni;
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) {
=name;
}
public String getName() {
return name;
}
}
B. 一个使用了Order类的服务。

如果传入的Order的id是1就把名字设为lingo,否则anni
package anni;
public class OrderService {
public Order returnOrder(Order order) {
Order newOrder = new Order();
if(order.getId().equals("1"))
newOrder.setName("lingo");
else newOrder.setName("anni");
return newOrder;
}
}
C. 发布webservice
<service name="OrderService" provider="java:RPC">
<parameter name="allowedMethods" value="*"/>
<parameter name="className" value="anni.OrderService"/>
<beanMapping languageSpecificType="java:anni.Order"
qname="ns1:Order"
xmlns:ns1="urn:BeanService"/> </service>
紫色的部分完成了类型的映射。

qname="ns1:Order",红色的部分应该和自定义的类名相一致。

languageSpecificType也得注意下格式,java:表示这是一个java语言写的类,
后面再加上具体的类。

其它自定义类完全可以参考这个写法。

为了直观的反映服务的操作方法,还可以在service节点中增加operation节点,如下内容:
<service name="OrderService" provider="java:RPC">
<parameter name="allowedMethods" value="*"/>
<parameter name="className" value="anni.OrderService"/>
<beanMapping languageSpecificType="java:anni.Order" qname="ns1:Order"
xmlns:ns1="urn:BeanService"/>
<operation name="returnOrder" returnT ype="ns1:Order">
<parameter name="bean" type="ns1:Order" />
</operation>
</service>
D. 客户端调用webservice,运行后客户端会输出“lingo”
public class OrderClient {
public static void main(String args[]) throws Exception {
Order order = new Order(); // JavaBean
order.setId("1");
String endpoint = "http://localhost:7001/server_axis/services/OrderService";
Service service = new Service();
Call call = (Call) service.createCall();
//注册javaBean 注意和server-config.wsdd保持一致
QName qn = new QName("urn:BeanService", "order");
call.registerT ype Mapping(Order.class, qn, new BeanSerializerFactory(
Order.class, qn), new BeanDeserializerFactory(Order.class, qn));
String name = "no!";
try {
call.setT argetEndpointAddress(new URL(endpoint));
call.setOperationName(new QName("order", "returnOrder"));
call.addParameter("arg1", qn, ParameterMode.IN);
call.setReturnT ype(qn, Order.class);
Order result = (Order) call.invoke(new Object[] { order });
if (result != null)
name = result.getName();
} catch (Exception ex) {
//System.err.println(ex);
}
System.out.println(name);
彩色的部分都是必须的。

3.5 用户验证的一个简单实现
主要原理就是在服务上保存一个属性文件,其中有预设的用户名和密码。

客户端在调用服务的时候,先设置一下SOAP消息的头信息,然后服务接到请求时会读取头信息中的验证信息,与属性文件的值进行比较。

这里要用到Axis的Handler。

仍然以上面的HelloWorld服务为例,需要增加一下内容:
er.properties属性文件
username = zhangwuji
password = qiankundanuoyi
将属性文件放在HelloWorld所在包下。

放在哪里无所谓,关键是以后用的时候把路径写对。

B.
Package anni;
public class HelloWorldUserHandler extends Basic Handler {
public void invoke(MessageContext arg0) throws AxisFault {
// TODO Auto-generated method stub
String username = arg0.getRequestMessage()
.getSOAPEnvelope().getHeaderByName("Authorization", "username")
.getValue();
String password = arg0.getRequestMessage()
.getSOAPEnvelope().getHeaderByName("Authorization", "password")
.getValue();
if (checkUser(username.trim(), password.trim()) == false) {
throw new AxisFault("用户名或密码错误!");
}
}
其中的checkUser方法:
/**
* 判断客户端是否有权限调用该接口
*
* @return true 允许调用该接口<br>
* false 禁止调用
*/
public boolean checkUser(String userName, String userPw) {
boolean flag = false; // 默认禁止调用该接口
/* 当前类物理路径+ 配制文件在服务器上的相对位置*/
String path = HelloWorldUserHandler.class.getResource("").toString() +
"/user.properties";
path = path.replaceAll("file:", "");
FileInputStream input = null;
try {
File file = new File(path);
input = new FileInputStream(file);
Properties p = new Properties();
p.load(input);
if(p.getProperty("username").trim().toUpperCase().equals(userName.toUpperCase())
&&
p.getProperty("password").trim().toUpperCase().equals(userPw.toUpperCase())) {
flag = true;
}
} catch (FileNotFoundException e) {
System.out.println("指定文件不存在!" + e.toString());
} catch (IOException e) {
System.out.println("文件读取失败!" + e.toString());
} finally {
if (null != input){
try {
input.close();
} catch (IOException e) {
System.out.println("关闭文件流时出错!" + e.toString());
}
}
}
return flag;
}
}
C. 修改service配置文件
<handler name="HelloWorldUserHandler"
type="anni.HelloWorldUserHandler" />
<service name="HelloWorld" provider="java:RPC">
<requestFlow>
<handler type="HelloWorldUserHandler" />
</requestFlow>
<parameter name="allowedMethods" value="*"/>
<parameter name="scope" value="Request"/>
<parameter name="className" value="anni.HelloWorld"/>
</service>
D. 客户端调用
因为增加了权限验证,所以客户端调用的时候需要在SOAP的头消息中加入用户名和密码用以验证。

需要增加如下两句:
call.addHeader(new
SOAPHeaderElement("Authorization", "username",
"zhangwuji"));
call.addHeader(new
SOAPHeaderElement("Authorization", "password",
"qiankundanuoyi"));
3.6 Stub方式调用WebService
还是以HelloWorld为例,这次改用Stub的方式来调用服务。

(这都是客户端的事)
A. 利用WSDL2Java工具生成服务对应的调用类,这个在客户端是很有用的。

当你只能从服务端拿到wsdl文档而不能拿到任何的代码或类文件时就得靠它了!这个工具会根据wsdl 文档的定义生成一些对应的类,如复杂类型定义就会生成对应的javaBean..
编辑一个WSDL2Java.bat,Axis_Lib为axis.jar路径。

内容如下:
set Axis_Lib=D:\axis-1.4\lib
set Java_Cmd=java -Djava.ext.dirs=%Axis_Lib%
set Output_Path=E:\Workplace\client_axis\src
set Package=anni
%Java_Cmd% org.apache.axis.wsdl.WSDL2Java -o %Output_Path%
-p %Package% http://localhost:7001/server_axis/services/HelloWorld?wsdl
pause
保存为.bat格式文件,双击运行后会在anni包下生成四个文件
Where:
HelloWorld_PortType.java : 这是一个接口,描述服务端能干什么,即该服务有些方法,对应于wsdl:portType;
HelloWorldService.java: 这是一个接口,相当于wsdl中的wsdl:service节点
HelloWorldServiceLocator.java:实现了HelloWorldService接口,这个类的作用是直接与服务器端通信,建立与服务器端的连接,实例化stub.然后客户端就可以通过stub与服务器通信了.
HelloWorldSoapBingStub.java : 这个类实现了HelloWorld_PortType接口,作为服务器在客户端的存根,也就是一个stub.在客户端,对服务器的所有调用,本质上都是对stub的调用。

B. 调用WebService
public class HelloClient {
public static void main(String [] args) throws Exception {
/*
* Stub方式调用
*/
HelloWorldService service = new HelloWorldServiceLocator();
HelloWorld_PortType client =service.getHelloWorld();
String retValue ="zhangwuji";
try {
//调用服务的sayHello方法,获得结果
String returnList = client.sayHello(retValue) ;
System.out.println("start");
System.out.println(returnList);
/*
* 调用HelloWorld服务的getList方法
* 需要注意的地方是,客户端getList方法传入的是Object[]
* 类型
* 在Axis中,服务中的List类型与客户端的Object[]类型是相对应的
*/
Object[] alist = {"1","2"};
Object[] returnValues = client.getList(alist);
System.out.println("客户端:");
if(returnValues!=null){
for(int i=0;i<returnValues.length;i++){
System.out.println(returnValues[i]);
}
}
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
4. 参考资料
参考资料:
1. Axis官方用户指南
/axis/java/user-guide.html
2. 发布webservice的相关例子
/topic/193363
/kay5804/archive/2008/05/04/2382428.aspx
/meiqingsong/archive/2005/04/04/336057.aspx
3. 生成客户端Stub
/shanshuijoy/blog/item/6766673e4d2a1e3570cf6cf9.html。

相关文档
最新文档