使用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.             failonerror="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.             failonerror="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.             failonerror="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,您可以浏览Apache的http://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

这里,我们还提供了一段叫做CallClient的Web服务客户端代码,其中使用了Axis和SOAP 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

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

使用Apache Axis实现Web服务_第1张图片

 

编译完成后,我们会在下面的文件夹中找到可部署的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的执行过程,您会看到控制台上会打印出从服务器端接收到的应答。

使用Apache Axis实现Web服务_第2张图片

 

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

cd ch03/02_Axis
ant runcall

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

 

使用Apache Axis实现Web服务_第3张图片

你可能感兴趣的:(java,apache,服务器,Build,web服务,任务)