?
?
WebService开发工具AXIS指南
?
?
本文档是开源文档,你可以自由使用和传播!
?
?
1?????? 介绍
?
Axis(Apache eXtensible Interaction System)是一款开源的WebService运行引擎,它是SOAP协议的一个实现,其本身来源于Apache的另一个项目Apache SOAP。 Axis分为1.x系列和Axis 2系列,两个系列体系结构和使用上有较大的区别,相对而言,Axis1.x更加稳定,文档也比较齐全,因此本文内容以Axis 1.x系列最新版本1.4为基础,Axis有C++和Java两个版本的实现,本文描述Java版的Axis。
?
采用Axis实现WebService时,只需要POJO即可,不要求实现特定的接口或继承特定的父类,不必为提高效率而购买专门的开发工具,在Eclipse中开发不需要添加任何插件。
?
Axis对运行环境的要求是只要支持Servlet2.3或以上即可,目前主要的应用服务器都可运行Axis,如Tomcat、JBoss、Websphere、WebLogic、Jetty。并且Axis可以很容易和应用程序整合在一个Web应用中,将应用程序的功能展示为 WebService。
?
此外,Axis的另一个好处就是不用和某个应用服务器绑定在一起,具有很好的可移植性,除配置文件可能要作小的修改外,服务的实现代码不需要做任何修改。
?
Axis官方网站为 http://ws.apache.org/axis
?
?
2?????? 环境配置
本文例子代码运行环境要求如下:
Windows XP SP2 中文版,JDK1.4或以上,Apache Axis1.4,Tomcat 4.1或其他任何支持Servlet2.3的应用服务器,本文以Tomcat 4.1为例,Java开发工具为 Eclipse3.1。
?
如果还没有安装JDK, 从http://java.sun.com/javase下载并安装到本地硬盘,以下用JAVA_HOME表示JDK安装在本地的路径。
?
从http://ws.apache.org/axis 下载Axis1.4,安装包是一个压缩文件,不用安装程序,直接解压到本地硬盘即可。以下用AXIS_HOME表示axis解压到本地的路径。
?
从http://tomcat.apache.org下载 Tomcat 4.1安装包,按Tomcat安装指南安装到本地,以下用TOMCAT_HOME表示Tomcat安装在本地的路径。安装完成后验证安装正确,缺省情况下输入http://localhost:8080可进入Tomcat页面。
?
下面在Tomcat中增加一个Web应用,并为其增对Axis支持:
在TOMCAT_HOME/webapps下创建一个新目录myservices,然后将AXIS_HOME/webapps/axis目录下的文件和子目录都复制到myservices目录下。并将AXIS_HOME/lib/axis-ant.jar 也复制到myservices/WEB-INF/lib目录下,该jar文件提供对ant脚本的支持。
?
启动Tomcat,然后在浏览器中输入http://localhost:8080/myservices,如果能显示下面的页面,则表示axis已成功安装到myservices应用中,下面创建的WebService都在该应用中运行。
?
?
进一步点击 Validation 可以显示运行环境信息,点击 List 可以列出Axis自带的两个WebService。 以后增加的WebService也显示在这里。
?
以下代码在Eclipse中开发,为此在 Eclipse创建一个java项目,名称为axis-guide,并将Axis的包加到项目的java build path中,如下图所示:Axis这些包位于Web引用myservices的WEB-INF/lib目录下。
?
3?????? 第一个WebService
3.1??? 服务端
准备好运行环境后,下面就开始开发WebService,该WebService名为EchoService,有一个方法echo,获得一个输入信息后,加入附加信息返回给调用者。原代码如下:
EchoService.java
?
package chen.axisguide.ch3;
?
public class EchoService { ?????? ?????? public String echo(String msg) {
?
????????????? return "your input message is " + msg; ?????? } }
?
|
?
可以看到该类是一个POJO,不需要其他任何附加说明来表明其是一个WebService实现。
?
为了让 Axis能识别服务,需要为服务提供一个描述文件,通常文件名为deploy.wsdd,因为该文件用于将服务部署到Axis引擎所在的Web应用中。deploy.wsdd文件格式为xml格式,EchoService的deploy.wsdd内容如下:
?
?
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
??????????? xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
???????????
??? <service name="EchoService" provider="java:RPC" >
?????? <parameter name="className" value="chen.axisguide.ch3.EchoService" />
?????? <parameter name="allowedMethods" value="*" />
??? </service>
?
</deployment>
?
|
?
service节点的name属性定义服务的名字,在客户端访问时会用到该名字,provider中定义WebService的提供方式为RPC。
第一个parameter用来描述服务实现类的类名,包括包名。第二个parameter参数描述类中哪些方法可以暴露为WebService方法,这里用*表示全部方法。
?
如果要卸载一个已部署的WebService,需要提供一个卸载描述文件,用Axis提供的工具读取该文件来卸载已部署的WebService。 上述deploy.wsdd对应的卸载文件为undeploy.wsdd,内容如下:
?
?
<undeployment xmlns="http://xml.apache.org/axis/wsdd/"
??????????? xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
???????????
??? <service name="EchoService"/>
???
</undeployment>
?
|
?
deploy.wsdd和undeploy.wsdd和原代码EchoService.java位于同一个目录中。
?
在项目axis-guide的根目录下创建一个Ant的build.xml来执行编译和部署任务。目录结构如下图所示:
?
?
build.xml内容如下:
?
<?xml version="1.0" encoding="utf-8"?> <project name="myservice" default="deployws"> ?????? <!-- If your Tomcat installation folder is another,replace below with yourself --> ?????? <property name="web.home" location="C:/Tomcat4.1/webapps/myservices" /> ?????? <property name="webclass.dir" location="${web.home}/WEB-INF/classes" /> ?????? <property name="weblib.dir" location="${web.home}/WEB-INF/lib" /> ?????? <property name="src.dir" location="src" /> ?????? ?????? <path id="lib.class.path"> ???????????????????? <fileset dir="${weblib.dir}"> ??????????????????????????? <include name="**/*.jar"/> ???????????????????? </fileset> ????????????? ?????? </path> ?????? ?????? <taskdef name="axis-admin" classname="org.apache.axis.tools.ant.axis.AdminClientTask"> ????????????? ??????? <classpath refid="lib.class.path"/> ?????? </taskdef> ?????? ?????? ?????? <target name="compile"> ????????????? <javac srcdir="${src.dir}" destdir="${webclass.dir}" source="1.4" compiler="javac1.4" debug="on"> ???????????????????? <classpath> ???????????????????? ??????? <path refid="lib.class.path"/> ???????????????????? </classpath> ???????????????????? <exclude name="**/*Test.java" /> ????????????? </javac> ?????? </target> ?????? ?????? <target name="deployws" depends="compile"> ????????????? <axis-admin url="http://localhost:8080/myservices/servlet/AxisServlet" ???????????????????? xmlfile="${src.dir}/chen/axisguide/ch3/deploy.wsdd"/> ????????????? ?????? </target> ?????? ?????? <target name="undeployws"> ????????????? <axis-admin url="http://localhost:8080/myservices/servlet/AxisServlet" ???????????????????? xmlfile="${src.dir}/chen/axisguide/ch3/undeploy.wsdd"/> ?????? </target> ?????? </project>
?
|
?
task-def定义了一个名为axis-admin的任务,该任务负责根据deploy.wsdd或undeploy.wsdd来部署或卸载WebService。此任务的实现类org.apache.axis.tools.ant.axis.AdminClientTask位于axis-ant.jar文件中。
?
服务实现类原代码编译后的.class文件放在myservices/WEB-INF/classes目录下,在build.xml的compile任务中实现。
?
在Eclipse环境中用Ant运行该build.xml,执行成功后在浏览器中输入http://localhost:8080/myservices/servlet/AxisServlet,可以看到如下的页面,表示EchoService已部署成功。
?
?
?
3.2??? 客户端
WebService部署成功后,下面开发客户端去调用WebService的方法,打印返回结果。
?
Client.java
?
package chen.axisguide.ch3;
?
import java.rmi.RemoteException;
?
import javax.xml.rpc.ParameterMode; import javax.xml.rpc.ServiceException;
?
import org.apache.axis.client.Call; import org.apache.axis.client.Service; import org.apache.axis.encoding.XMLType;
?
?
/** ?* 访问EchoService的客户端 ?* ?* ?*/ public class Client {
?
?????? /** ?????? ?* @param args ?????? ?* @throws ServiceException ?????? ?* @throws RemoteException ?????? ?*/ ?????? public static void main(String[] args) throws ServiceException,RemoteException { ????????????? // wsdl中address 节点的location属性 ????????????? String endpoint = "http://localhost:8080/myservices/services/EchoService"; ????????????? // 要调用的方法名 ????????????? String method = "echo"; ????????????? ????????????? Service service = new Service(); ????????????? Call call = (Call) service.createCall(); ????????????? // 设置客户端访问的远程端点 ????????????? call.setTargetEndpointAddress(endpoint); ????????????? // 设置输入参数类型 ????????????? call.addParameter("p1",XMLType.XSD_STRING,ParameterMode.IN); ????????????? // 设置返回值类型 ????????????? call.setReturnType(XMLType.XSD_STRING); ?????? ?????? ????????????? // 输入参数值 ????????????? String msg = "call from java"; ????????????? // 调用远程方法 ????????????? String result = (String)call.invoke(method,new Object[]{msg}); ????????????? ????????????? System.out.println(result);
?
?????? } ?????? }
?
|
确认Tomcat已启动,在Eclipse环境中运行Client,如果没有错误,在控制台将会打印从EchoService的echo方法获得的结果。
?
客户端访问WebService的主要步骤包括:
l???????? 创建Call对象,设置WebService的访问端点;
l???????? 注册序列化和反序列对象,详见下节;
l???????? 设置访问方法的参数类型以及返回值类型;
l???????? 初始化参数值;
l???????? 调用WebService的方法,获得返回结果。
?
JAX-RPC规范中定义了三种访问服务端的方法:
1.???????? 在客户端生成远程服务端的静态代理文件,编译后提供给客户端访问服务使用,Axis提供了工具可根据服务的wsdl生成静态代理文件。但这种方法会在客户端增加若干附加文件,服务端接口发生变化时需要重新在客户端生成文件。
2.???????? 根据服务端接口文件访问服务。这种方法要求服务实现一个接口,并且该接口要从java.rmi.Remote扩展,客户端通过获得该接口的代理来访问服务。这种方法需要在客户端保存一个服务的接口文件。
3.???????? 动态调用接口。客户端只须通过服务端口、访问方法名和参数类型即可访问服务的方法。访问方式类似于用反射来调用类方法。这种方法的客户端和服务端的耦合度比前两种要低,上面Cilent.java用的就是这种方法。 后面的例子也都采用这种方式访问服务端。
?
4?????? 序列化
Axis中客户端和服务器端之间的消息使用SOAP封装,java程序中的数据需要序列化后保存在XML文档中通过网络传输到接收方,接收方从XML文档中反序列化为java虚拟机可识别的数据对象。对java基本类型,Axis提供了默认的序列化和反序列化功能,不需要特别申明即可使用。对自定义类型,如果是JavaBean,则可用beanMapping在wsdd文件中申明该类型所需要的序列化和反序列化器即可。Axis已自带JavaBean的序列化和反序列化功能。 如果Axis自带的序列化和反序列化器不能对自定义对象进行序列化处理,你可以自定义序列化和反序列化器,然后用typeMappping在wsdd文件中申明即可。
在 Axis中, xml数据类型和java类型之间的映射关系如下:
XML类型
|
java类型
|
xsd:base64Binary
|
byte[]
|
xsd:boolean
|
boolean
|
xsd:byte
|
byte
|
xsd:date
|
java.util.Date
|
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
|
javax.xml.namespace.QName
|
xsd:short
|
short
|
xsd:string
|
java.lang.String
|
?
下面的例子中服务器端向客户端返回一个列表,列表中包含自定义的Book对象。
服务实现代码如下:因为只是说明对象的序列化方式,因此就直接创建对象放入列表对象中,没有从数据库中搜索数据。
LibraryService.java :对象序列化服务端代码
?
package chen.axisguide.ch4;
?
import java.util.ArrayList; import java.util.List;
?
public class LibraryService { ?????? ?????? // 返回一个包含Book对象的列表 ?????? public List query(String keyword) {
?
????????????? ????????????? Book book1 = new Book(); ????????????? book1.setAuthor("Jack Johnson"); ????????????? book1.setContent("about java development."); ????????????? book1.setIsbn("123-456-789"); ????????????? book1.setName("Java deplopment handbook"); ????????????? ????????????? Book book2 = new Book(); ????????????? book2.setAuthor("Kim Kent"); ????????????? book2.setContent("about ruby development."); ????????????? book2.setIsbn("123-654-897"); ????????????? book2.setName("ruby deplopment handbook"); ????????????? ????????????? List res = new ArrayList(); ????????????? res.add(book1); ????????????? res.add(book2); ????????????? ????????????? return res; ????????????? ?????? } }
?
|
服务端代码中不需要对序列化做特殊处理。
?
Book的定义如下:
Book.java
?
package chen.axisguide.ch4;
?
public class Book { ?????? private String isbn; ?????? private String name; ?????? private String author; ?????? private String content; ?????? ?????? public String getAuthor() { ????????????? return author; ?????? } ?????? public void setAuthor(String author) { ????????????? this.author = author; ?????? } ?????? public String getContent() { ????????????? return content; ?????? } ?????? public void setContent(String content) { ????????????? this.content = content; ?????? } ?????? public String getIsbn() { ????????????? return isbn; ?????? } ?????? public void setIsbn(String isbn) { ????????????? this.isbn = isbn; ?????? } ?????? public String getName() { ????????????? return name; ?????? } ?????? public void setName(String name) { ????????????? this.name = name; ?????? } ?????? ?????? }
?
|
?
?
序列化的处理在服务部署文件中定义:
deploy.wsdd :LibraryService描述文件
?
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
??????????? xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
???????????
??? <service name="LibraryService" provider="java:RPC" >
?????? <parameter name="className" value="chen.axisguide.ch4.LibraryService" />
?????? <parameter name="allowedMethods" value="*" />
??? ?????????????
?????? <beanMapping qname="myNS:Book" xmlns:myNS="LibraryService" languageSpecificType="java:chen.axisguide.ch4.Book"/>
??? </service>
?
</deployment>
?
|
?
beanMapping节点定义了Book对象的序列化和反序列化使用Axis自带的针对JavaBean的序列化和反序列化器来实现。
其中,xmlns定义命名空间为LibraryService,和服务同名,qname定义为命名空间myNS中的Book,与被序列化的类名相同,这种命名方式可使处理的对象一目了然。当然也可命名为其他名字。
?
下面看一下客户端代码中对序列化的处理。
Cilent.java :访问LibraryService客户端代码。
?
package chen.axisguide.ch4;
?
import java.rmi.RemoteException;
?
import javax.xml.namespace.QName; import javax.xml.rpc.ParameterMode; import javax.xml.rpc.ServiceException;
?
import org.apache.axis.client.Call; import org.apache.axis.client.Service; import org.apache.axis.encoding.XMLType;
?
/** ?* 访问LibraryService的客户端 ?* ?* ?*/ public class Client {
?
?????? /** ?????? ?* @param args ?????? ?* @throws ServiceException ?????? ?* @throws RemoteException ?????? ?*/ ?????? public static void main(String[] args) throws ServiceException,RemoteException { ????????????? // wsdl中address 节点的location属性 ????????????? String endpoint = "http://localhost:8080/myservices/services/LibraryService"; ????????????? // 要调用的方法名 ????????????? String method = "query"; ????????????? ????????????? Service service = new Service(); ????????????? Call call = (Call) service.createCall(); ????????????? // 设置客户端访问的远程端点 ????????????? call.setTargetEndpointAddress(endpoint); ????????????? ????????????? QName qn = new QName("LibraryService","Book");
?????? ??? call.registerTypeMapping(Book.class,qn, ?????? ????????????????????? new org.apache.axis.encoding.ser.BeanSerializerFactory(Book.class,qn),???????
?????? ????????????????????? new org.apache.axis.encoding.ser.BeanDeserializerFactory(Book.class,qn));
?????? ??????? ????????????? ????????????? // 设置输入参数类型 ????????????? call.addParameter("p1",ParameterMode.IN); ????????????? // 设置返回值类型 ????????????? call.setReturnType(XMLType.XSD_ANYTYPE); ????????????? ????????????? // 输入参数值 ????????????? String msg = "key word"; ????????????? // 调用远程方法 ????????????? Object[] result = (Object[])call.invoke(method,new Object[]{msg}); ????????????? ????????????? for(int i = 0; i < result.length; i++) { ???????????????????? Book bk = (Book)result[i]; ???????????????????? System.out.println("ISBN: " + bk.getIsbn() + " Book Name: " + bk.getName()); ????????????? }
?
?????? } ?????? }
?
|
在客户端,首先为Book定义一个QName对象,构造函数中的第一个参数值要和wsdd中beanMapping节点的xmlns:myNS属性值相同,第二个参数值要和beanMapping的qname属性值相同。然后在Call对象中注册自定义类型所用的序列化和反序列化器。通过以下语句来实现:
call.registerTypeMapping(Book.class, ?????? ????????????????????? new org.apache.axis.encoding.ser.BeanSerializerFactory(Book.class,??????? ?????? ????????????????????? new org.apache.axis.encoding.ser.BeanDeserializerFactory(Book.class,qn)); |
?
?
最后在build.xml中增加对deploy.wsdd文件的部署。内容如下:
?
?
<target name="deployws" depends="compile"> ????????????? <axis-admin url="http://localhost:8080/myservices/servlet/AxisServlet" ?????????????????????????????????? xmlfile="${src.dir}/chen/axisguide/ch4/deploy.wsdd"/> ????????????? </target>
?
|
?
5?????? 处理器(Handler)
Axis引擎在处理消息过程中,可以自定义处理器对请求或响应的消息进行拦截处理,处理器的动作对服务的实现部分透明。这种机制可以将日志、安全检查、加密解密等与业务无关的操作抽取出来单独处理,降低模块间的依赖关系。
?
自定义处理器时从org.apache.axis.handlers.BasicHandler继承,在方法invoke(MessageContext msgContext)进行拦截处理。消息等运行环境信息可以从msgContext得到。
?
自定义处理器要发挥作用,需要在wsdd文件中进行说明,方法如下:
1-??? 用<handler name=”handlername” type=”java:classname”> 定义处理器,如果要给处理器传递参数,可在<handler>下用<parameter name=”name” value=”value” />进行说明。 之后在自定义处理器类代码中用getOption(“name”)可得到value的值。
2-??? 在<service>中用<requestFlow>或<responseFlow>定义在请求消息流或返回消息流中要调用的处理器。如果有多个处理器,则按其在 <requestFlow>或<responseFlow>中排列顺序依次调用。格式如下:
<service>
?????? <requestFlow>
????????????? <handler type=”handlername” />
?????? </requestFlow>
</service>
?
?
下面的例子中服务器端和客户端代码使用第3节的代码,在请求消息流中增加两个处理器,第一个处理器在控制台打印出SOAP包的body内容,然后在MessageContext中设置一个属性值;第二个处理器从MessageContext中取出第一个处理器设置的属性值,在控制台打印出来。
?
第一个处理器原代码如下:
FirstHandler.java
package chen.axisguide.ch5;
?
import javax.xml.soap.SOAPException;
?
import org.apache.axis.AxisFault; import org.apache.axis.Message; import org.apache.axis.MessageContext; import org.apache.axis.handlers.BasicHandler; import org.apache.axis.message.SOAPBody;
?
public class FirstHandler extends BasicHandler {
?
?????? public void invoke(MessageContext msgContext) throws AxisFault { ????????????? ????????????? Message reqMsg = msgContext.getRequestMessage(); ????????????? ????????????? try { ???????????????????? SOAPBody reqBody = (SOAPBody) reqMsg.getSOAPBody(); ???????????????????? System.out.println("==================================="); ???????????????????? System.out.println("request SOAP body " + reqBody.getAsString()); ???????????????????? System.out.println("==================================="); ???????????????????? // 设置属性传递到下一个handler ???????????????????? msgContext.setProperty("handler1","handler1 processed"); ???????????????????? ????????????? } catch (SOAPException e) { ???????????????????? ???????????????????? e.printStackTrace(); ????????????? } catch (Exception e) { ???????????????????? ???????????????????? e.printStackTrace(); ????????????? } ????????????? ?????? }
?
}
?
|
?
?
第二个处理器原代码:
SecondHandler.java
?
package chen.axisguide.ch5;
?
import org.apache.axis.AxisFault; import org.apache.axis.MessageContext; import org.apache.axis.handlers.BasicHandler;
?
public class SecondHandler extends BasicHandler {
?
?????? public void invoke(MessageContext msgContext) throws AxisFault { ????????????? ????????????? System.out.println("Get data from previous handler : " + msgContext.getProperty("handler1"));
?
?????? }
?
}
?
|
?
?
wsdd文件内容如下:
deploy.wsdd
?
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
??? ????????xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
?? ?<handler name="handler1" type="java:chen.axisguide.ch5.FirstHandler" />
??? <handler name="handler2" type="java:chen.axisguide.ch5.SecondHandler" />
??????????
??? <service name="EchoService" provider="java:RPC" >
?????? <parameter name="className" value="chen.axisguide.ch5.EchoService" />
?????? <parameter name="allowedMethods" value="*" />
?????? <requestFlow>
?????????? <handler type="handler1" />
?????????? <handler type="handler2" />
?????? </requestFlow>
??? </service>
???
</deployment>
?
|
?
在build.xml中增加对deploy.wsdd文件的部署处理。内容如下:
?
<target name="deployws" depends="compile"> ????????????? <axis-admin url="http://localhost:8080/myservices/servlet/AxisServlet" ???????????????????????????????????????????????? xmlfile="${src.dir}/chen/axisguide/ch5/deploy.wsdd"/> </target>
?
|
?
服务端和客户端原代码和第3节相同,不再列出。
在Eclipse中用Ant运行build.xml,在Tomcat中重新载入Web应用,然后在Eclipse中运行Client.java,在Tomcat的控制台将会打印出SOAP body信息以及handler1属性值。
?
6?????? 访问控制
开发好WebService并向外暴露服务后,由于WebService访问协议都是公开的,客户端只要知道服务的wsdl,就可以访问WebService中的方法。为防止非法的访问,可以要求客户端访问WebService时提供用户名和口令,只有在服务端通过身份认证后才可继续访问方法,否则请求被拒绝。
下面看一下Axis中如何使用用户名、口令来控制对WebService 的访问。
在myservices/WEB-INF下创建一个名为users.lst的文本文件,一行表示一对用户名、口令,之间用空格分隔,内容如下:
user1 password1 user2 password2 |
?
实现一个WebService,它有一个foo()方法,该方法打印出通过身份认证的用户的用户名,代码如下:
SecurityService.java
?
package chen.axisguide.ch6;
?
import org.apache.axis.MessageContext;
?
public class SecurityService { ?????? public void foo() { ????????????? ????????????? MessageContext msgContext = MessageContext.getCurrentContext(); ????????????? System.out.println("你已通过身份认证!"); ????????????? System.out.println("你的用户名: " + msgContext.getUsername()); ????????????? ?????? } }
?
|
?
为了让 Axis知晓要对该服务的访问验证用户名和口令,需要在wsdd文件中增加一个Axis自带的处理器SimpleAuthenticationHandler,该处理器会从MessageContext中取出用户名和口令,并与users.lst中的用户名和口令进行比对,如果匹配,则通过验证,继续后面的处理,否则抛出(401)Unauthorized异常。
deploy.wsdd
?
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
??????????? xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
???????????
??? <service name="SecurityService" provider="java:RPC" >
?????? <parameter name="className" value="chen.axisguide.ch6.SecurityService" />
?????? <parameter name="allowedMethods" value="*" />
?????? <requestFlow>
?? ??????? <handler type="java:org.apache.axis.handlers.SimpleAuthenticationHandler" />
? ???? </requestFlow>
??? </service>
</deployment>
?
|
?
?
客户端在访问WebService时,需要在 Call对象中设置在users.lst文件中已有的用户名和对应的口令。客户端代码如下:
?
?
package chen.axisguide.ch6;
?
import java.rmi.RemoteException;
?
import javax.xml.rpc.ServiceException;
?
import org.apache.axis.AxisFault; import org.apache.axis.client.Call; import org.apache.axis.client.Service;
?
?
/** ?* 访问SecurityService的客户端 ?* ?* ?*/ public class Client {
?
?????? /** ?????? ?* @param args ?????? ?* @throws ServiceException ?????? ?* @throws RemoteException ?????? ?*/ ?????? public static void main(String[] args) throws ServiceException,RemoteException { ????????????? // wsdl中address 节点的location属性 ????????????? String endpoint = "http://localhost:8080/myservices/services/SecurityService"; ????????????? // 要调用的方法名 ????????????? String method = "foo"; ????????????? ????????????? Service service = new Service(); ????????????? Call call = (Call) service.createCall(); ????????????? // 设置客户端访问的远程端点 ????????????? call.setTargetEndpointAddress(endpoint); ????????????? // 设置用户名和口令 ????????????? call.setUsername("user1");
????????????? call.setPassword("password1");
?????? ????????????? ????????????? // 调用远程方法 ????????????? try{ ???????????????????? call.invoke(method,new Object[]{}); ????????????? }catch(AxisFault e) { ???????????????????? System.err.println(e.getFaultString()); ????????????? } ?????? }
?
} |
Call对象用setUserName()和setPassword()来设置用户名和口令。
Axis自带的身份认证功能比较简单,如果其安全性不能满足应用系统的要求,可以自定义一个处理器替代SimpleAuthenticationHandler,在自定义处理器中采用其他的安全框架(如Acegi http://www.acegisecurity.org/)来保护你的WebService。
?
7?????? 总结
从上面的实例可以看出,Axis在开发WebService方面具有如下优势:
l???????? 轻量级:Axis本身只需要Servlet容器就可运行,因此能够在大多数轻量级的Web应用服务器上运行;另外在Axis中服务的实现类只要求是一个POJO,没有强制要求实现特定接口或从特定父类继承,这使得开发和测试非常容易,不需要为提高开发效率而购置重量级的IDE。
?
l???????? 扩展性好:在Axis中,可以通过加入自定义处理器(Handler)方式来扩展Axis的功能,并且这种功能的增加对业务部分可以做到透明,即业务代码中不需要为使用增加的功能而修改代码。
?
l???????? 可移植性强:Axis可以在支持Servlet的容器中运行,运行于其中的WebService也就可以在现有的大多数的Web应用服务器上运行,不需要对服务的实现代码做任何的改动。
?