使用Apache Axis实现Web服务

Apache Axis 是提交给 W3C 的一种 SOAP(Simple Object Access Protocol) 实现, Axis 在实现 Java Web 服务方面稳定可靠。许多公司在它们的产品中使用了 Axis 来支持 Web 服务,而且 Axis 还有一个非常活跃的用户区。 Axis 有两种版本,即 Axis1.x Axis2 Axis2 最近刚刚推出,与其前身相比, Axis2 Axis1.x 进行重新设计,并支持 SOAP1.2 REST 等交换协议。在 1.x 版本下, Axis 发布过好几个生产版本。在本节中,我们将使用 Axis1.3 ,您可以从 http://ws.apache.org/axis/java/releases.html 处下载。

契约最先式方法和契约最后式方法的比较

在实现 Web 服务时,我们通常有两种方法,即契约最先式和契约最后式方法。在契约最先式方法中,我们先开始编写 Web 服务的契约,即先开始设计 WSDL 文件;然后,我们使用一些工具根据 WSDL 文件生成 Java 代码,生成的 Java 代码包括 Java 接口及其实现类,另外,还包括一些与 Web 服务管道相关的代码。而在契约最后式的方法中,您先开始编写 Java 代码,然后,从这些代码中生成 WSDL 文件。

在定义和实现 Web 服务时,虽然我们需要考虑多种因素,如您要定义的 Web 服务上下文等,但是,在通常情况下,人们更偏爱使用契约最先式方法。但契约最先式方法的一个实际困难是,创建 WSDL 的过程并不是非常简单。因此,在没有特别工具支持的情况下,我们也许并不能轻易创建一个 WSDL 文件。为了解决这个难题,我们可以采用一种混合的方法,其具体步骤如下:

1) 先创建 Web 服务接口 ( Java 接口 )
2) 根据该接口生成 WSDL
3) 然后,您就可以按照契约最先式方法的正常步骤,继续我们的开发过程

在我们本节的例子中,我们将采用上面这种混合方法,因此,您只需要对本章中例子中的编译脚本稍加修改,您就可以将本例改为契约最先式或契约最后式方法实现的 Web 服务。

使用Apache Axis来实现Web服务

我们将使用 Axis1.3 来实现 Web 服务,您可以在 http://ws.apache.org/axis/java/releases.html 处免费下载,下载后,请将安装包解压到本地硬盘的合适目录,然后修改源代码 examples.PROPERTIES 文件中的 axis.home 属性,让它指向 Axis 的安装目录。

与本章前面的两个例子不同的是,我们将编译并对 Web 服务文件进行打包,让它成为一个标准的 Web 文档文件 (.war 文件 ) 。然后,我们需要 Web 服务器来部署该 war 文件,这里我们将使用 Apache Tomcat6.x ,您可以从 http://tomcat.apache.org/ 处下载 Tomcat6.x

服务器端和客户端端代码
我们将使用契约最先式方法实现服务器端,但由于我们不想手动编写 WSDL ,所以咱们就先来写一个 Java 接口。本例中所有的文件都位于 ch03/02_Axis/src 目录下 ( 译者注:本书代码请从 http://www.packtpub.com/files/code/3216_Code.zip 处下载 ) 。我们现在来逐个看看这些文件。

IHelloWeb.java
IHelloWeb是一个简单的Java接口,它只定义了一个业务方法:
  1. public interface IHelloWeb{ 
  2.    public String hello(String param); 

在契约最先式的实现方法中,我们先从WSDL开始,因为WSDL是一种平台中立的语言,这可以保证,使用契约最先式方法实现的客户端和服务器端可以相互交互。但本例中,我们先从Java接口开始,因此,为了保证生成的WSDL也满足可互操作性的标准。您需要注意,在您产生WSDL前,Java接口方法声明中包含的参数及返回类型,要能够和标准的可移植的WSDL相兼容。

HelloWebService.java

接下来我们需要实现Web服务,HelloWebService类的源码非常简单:

  1. public class HelloWebService implements IHelloWeb{ 
  2. private static int times; 
  3. public HelloWebService(){ 
  4.  System.out.println("Inside HelloWebService.HelloWebService..."); 
  5. public String hello(String param){ 
  6.  System.out.println("Inside HelloWebService.hello... - " + 
  7.  (++times)); 
  8.  return "Return From Server"

其实,我们可以生成一个Web服务实现类的模板,而不用从头开始实现它。在实现类模板中,您可以手动添加您的业务逻辑。您可以使用这种方法在真实的生产环境中部署Web服务,但在本例中,我们不用手动添加业务逻辑,而是只使用一个小巧的ant脚本自动实现所有步骤。

build.xml
build.xml文件非常重要,它将引导您一步一步地实现web服务,从Java接口开始,实现业务逻辑,然后打包为一个标准war文件。因此,我们将整个的编译脚本拷贝如下:

  1. <?xml version="1.0" ?>
  2. <project default="all">
  3.     <property file="../examples.properties" />
  4.     <property name="build" value="build" />
  5.     <property name="dist" value="dist" />
  6.     <property name="lib" value="lib" />
  7.     <property name="src" value="src" />
  8.     <property name="gensrc" value="gensrc" />
  9.     <property name="config" value="config" />
  10.     <property name="webapp.name" value="AxisEndToEnd" />
  11.     <property name="service.name" value="HelloWebService" />
  12.     <property name="wsdl" value="HelloWebService.wsdl" />
  13.     <property name="interface.package"
  14.         value="com.binildas.apache.axis.AxisEndToEnd" />
  15.     <property name="interface.path"
  16.         value="com/binildas/apache/axis/AxisEndToEnd" />
  17.     <property name="interface.class" value="IHelloWeb" />
  18.     <property name="implement.package"
  19.         value="com.binildas.apache.axis.AxisEndToEnd" />
  20.     <property name="implement.path"
  21.         value="com/binildas/apache/axis/AxisEndToEnd" />
  22.     <property name="implement.class" value="HelloWebService" />
  23.     <path id="classpath">
  24.         <pathelement path="./build" />
  25.         <fileset dir="${axis.home}/lib">
  26.             <include name="*.jar" />
  27.         </fileset>
  28.     </path>
  29.     <target name="all" depends=" deploy, compileclient"></target>
  30.     <target name="clean">
  31.         <delete dir="${build}" />
  32.         <delete dir="${dist}" />
  33.         <delete dir="${lib}" />
  34.         <delete dir="${gensrc}" />
  35.     </target>
  36.     <target name="init">
  37.         <mkdir dir="${build}" />
  38.         <mkdir dir="${dist}" />
  39.         <mkdir dir="${lib}" />
  40.         <mkdir dir="${gensrc}" />
  41.     </target>
  42.     <target name="copy">
  43.         <copy todir="${lib}">
  44.             <fileset dir="${axis.home}/lib">
  45.                 <include name="*.jar" />
  46.             </fileset>
  47.         </copy>
  48.     </target>
  49.     <target name="precompile" depends="clean, init">
  50.         <javac srcdir="${src}" destdir="build"
  51.             classpathref="classpath">
  52.             <exclude name="**/*Client*.java" />
  53.         </javac>
  54.     </target>
  55.     <target name="java2wsdl" depends="precompile">
  56.         <java classname="org.apache.axis.wsdl.Java2WSDL" fork="true"
  57.             failοnerrοr="true">
  58.             <arg value="-o" />
  59.             <arg value="${wsdl}" />
  60.             <arg
  61.                 value="-lhttp://localhost:8080/${webapp.name}/ 
  62. services/${service.name}" />
  63.             <arg value="${interface.package}.${interface.class}" />
  64.             <classpath>
  65.                 <path refid="classpath" />
  66.                 <pathelement location="${build}" />
  67.             </classpath>
  68.         </java>
  69.     </target>
  70.     <target name="wsdl2java" depends="java2wsdl">
  71.         <java classname="org.apache.axis.wsdl.WSDL2Java" fork="true"
  72.             failοnerrοr="true">
  73.             <arg value="-o" />
  74.             <arg value="${gensrc}" />
  75.             <arg value="-s" />
  76.             <arg value="-S" />
  77.             <arg value="no" />
  78.             <arg value="-c" />
  79.             <arg value="${implement.package}.${implement.class}" />
  80.             <arg value="${wsdl}" />
  81.             <classpath>
  82.                 <path refid="classpath" />
  83.                 <pathelement location="${build}" />
  84.             </classpath>
  85.         </java>
  86.     </target>
  87.     <target name="implement" depends="wsdl2java">
  88.         <delete>
  89.             <fileset dir="${gensrc}/${implement.path}"
  90.                 includes="${implement.class}.java" />
  91.         </delete>
  92.         <copy todir="${gensrc}/${implement.path}" overwrite="ture">
  93.             <fileset dir="${src}/${implement.path}">
  94.                 <include name="${implement.class}.java" />
  95.             </fileset>
  96.         </copy>
  97.     </target>
  98.     <target name="compile" depends="implement">
  99.         <javac srcdir="${gensrc}" destdir="build"
  100.             classpathref="classpath" />
  101.     </target>
  102.     <target name="compileclient">
  103.         <javac srcdir="${src}" destdir="build"
  104.             classpathref="classpath">
  105.             <include name="**/*Client*.java" />
  106.         </javac>
  107.     </target>
  108.     <target name="deploy" depends="compile, copy">
  109.         <move todir="${config}" flatten="yes">
  110.             <fileset dir="${gensrc}">
  111.                 <include name="**/*.wsdd" />
  112.             </fileset>
  113.         </move>
  114.         <java classname="org.apache.axis.utils.Admin" fork="true"
  115.             failοnerrοr="true" dir="config">
  116.             <arg value="server" />
  117.             <arg file="config/deploy.wsdd" />
  118.             <classpath>
  119.                 <path refid="classpath" />
  120.                 <pathelement location="build" />
  121.             </classpath>
  122.         </java>
  123.         <war destfile="dist/${webapp.name}.war"
  124.             webxml="config/web.xml">
  125.             <webinf dir="config">
  126.                 <include name="server-config.wsdd" />
  127.             </webinf>
  128.             <lib dir="lib" />
  129.             <classes dir="build" />
  130.         </war>
  131.         <delete dir="${lib}" />
  132.     </target>
  133. </project>

 

下面,我们来逐步理解一下上面这个Web服务的实现过程。按照上面脚本的顺序,我们执行以下ant任务。

clean任务:这个ant任务将删除所有临时目录及上次编译生成的所有文件;

init任务:这个ant任务将创建几个新的目录;

precompile任务:这个步骤将编译Java接口类;

java2wsdl任务:java2wsdl将从预先编译过的Java接口中生成WSDL,您可以浏览Apachehttp://ws.apache.org/axis/java/reference.html页面,了解上面脚本中java2wsdl任务中的一些选项的意义;

wsdl2java任务:我们现在开始实施契约最先式方法。一旦有了WSDL,我们就可以通过wsdl2java这个工具生成Web服务代码,包括Web服务的实现模板类,这些生成的文件都位于同一个目录中(如本例中的gensrc目录)。同时,本任务执行后也将产生一个用于部署Web服务的deploy.wsdd文件,和一个用于取消部署的undeploy.wsdd文件。在后面我们将通过这两个wsdd文件生成服务器端的配置;

implement任务:前面已经讲过,为了避免向生成的Web服务实现模板中手动添加代码,我们可以利用前面已经写好的一个与实现模板类同名的Java文件,这个文件中包含的类名与模板类也相同(HelloWebService),并且它实现了业务逻辑。因此,我们可以将前面准备好的实现类替换生成的模板类,这样做的效果就相当于向生成的模板类中添加了业务代码;

compile任务:我们将通过该任务编译所有生成的类,其中包含业务逻辑的Web服务实现类;

copy任务:该任务将所有需要的Axis库文件拷贝到一个临时目录(如本例中的lib)中,以便于打包只用;

deploy任务:在本任务中,我们使用org.apache.axis.utils.Admin类产生部署描述文件server.config.wsdd,这个类的输入为前面wsdl2java任务生成的deploy.wsdd。然后,我们接下来创建一个标准的Web归档文件(.war),这样,我们可以非常容易地将它部署到我们钟爱的Web服务器中;

complieclient:这是最后一个步骤,编译客户端代码。

RpcClient.java
RpcClient利用自动生成的客户端存根文件,按RPC风格调用远程Web服务。

  1. public class RpcClient {
  2.     private static String wsdlUrl = "http://localhost:8080/AxisEndToEnd/services/HelloWebService?WSDL";
  3.     private static String namespaceURI = "http://AxisEndToEnd.axis.apache.binildas.com";
  4.     private static String localPart = "IHelloWebService";
  5.     protected void executeClient(String[] args) throws Exception {
  6.         IHelloWebService iHelloWebService = null;
  7.         IHelloWeb iHelloWeb = null;
  8.         if (args.length == 3) {
  9.             iHelloWebService = new IHelloWebServiceLocator(args[0], new QName(
  10.                     args[1], args[2]));
  11.         } else {
  12.             iHelloWebService = new IHelloWebServiceLocator(wsdlUrl, new QName(
  13.                     namespaceURI, localPart));
  14.         }
  15.         iHelloWeb = iHelloWebService.getHelloWebService();
  16.         log("Response From Server : " + iHelloWeb.hello("Binil"));
  17.     }
  18.     public static void main(String[] args) throws Exception {
  19.         RpcClient client = new RpcClient();
  20.         client.executeClient(args);
  21.     }
  22. }

CallClient.java

这里,我们还提供了一段叫做CallClientWeb服务客户端代码,其中使用了AxisSOAP API,以面向文档的方式调用该Web服务。

  1. public class CallClient {
  2.     public static String wsURL = "http://localhost:8080/AxisEndToEnd/services/HelloWebService?WSDL";
  3.     public static String action = "HelloWebService";
  4.     // SOAP Request - Not shown fully
  5.     public static String msg = "<?xml version=/"1.0/" encoding=/"UTF-8/"?><soapenv:Envelope ...>";
  6.     public static void test() throws Exception {
  7.         InputStream input = new ByteArrayInputStream(msg.getBytes());
  8.         Service service = new Service();
  9.         Call call = (Call) service.createCall();
  10.         SOAPEnvelope soapEnvelope = new SOAPEnvelope(input);
  11.         call.setTargetEndpointAddress(new URL(wsURL));
  12.         if (action != null) {
  13.             call.setUseSOAPAction(true);
  14.             call.setSOAPActionURI(action);
  15.         }
  16.         soapEnvelope = call.invoke(soapEnvelope);
  17.         System.out.println("Response:/n" + soapEnvelope.toString());
  18.     }
  19.     public static void main(String args[]) throws Exception {
  20.         CallClient callClient = new CallClient();
  21.         if (args.length > 0) {
  22.             wsURL = args[0];
  23.         }
  24.         if (args.length > 1) {
  25.             action = args[1];
  26.         }
  27.         callClient.test();
  28.     }
  29. }
上面的Web服务请求并没有显示完全,其完全版本请参考本章源代码。

运行服务器和客户端

前面的build.xml文件有点长,这对于新手而言,执行前面的10个步骤来实现Web服务,并不是一件简单的事。但是,我们可以使用一个简单的Ant命令来完成上面所有步骤,因此,您可以把上面的build.xml文件保存下来,以备以后在您的项目中重用它们。要编译服务器端代码,请执行下列命令:

cd ch03/02_Axis
ant

下图显示了每一步编译执行的过程:

 

编译完成后,我们会在下面的文件夹中找到可部署的Web归档文件(AxisEndToEnd.war)

Ch03/02_Axis/dist

现在,您就可以把这个war文件拷贝到您的Web服务器的Webapps目录,然后,重启服务器。如果部署没有问题,您就可以访问http://localhost:8080/AxisEndToEnd/services/HelloWebService?WSDL获取该Web服务的WSDL

接下来您就可以执行客户端代码测试您的Web服务,因为我们提供了两个版本的客户端代码,因此,您测试Web服务时会有两个选择。要执行RpcClient,请使用下列命令:

cd ch03/02_Axis
ant runrpc

下图显示了RpcClient的执行过程,您会看到控制台上会打印出从服务器端接收到的应答。

 

要执行CallClient,请使用下列命令:

cd ch03/02_Axis
ant runcall

下图显示了CallClient的执行过程,您会看到控制台上会打印出从服务器端接收到的应答。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值