下载 Apache Axis 用来实现 SOAP( 简单对象访问协议 ) 。 http://ws.apache.org/axis/

目前最稳定的版本是 1.1

 

SOAP 是用于在分散的或者分布式的环境中交换信息的一个轻量级协议。 SOAP 基于 XML ,由三部分组成:一个必须的 SOAP 封装,一个可选的 SOAP 头和一个必须的 SOAP 体。

通常情况下, SOAP = HTTP + RPC + XML 。 即: SOAP 以 HTTP 作为底层通信协议,以 RPC 作为交互方式,以 XML 作为数据传送的格式。

 

Web Service 开发所需要掌握的技能:

JAVA ,线程,同步, Classloader ,错误排除,知道 NPE(NullPointerException) 和其他一些常见的错误,并能够处理, Servlet ,如何发布 Web 应用到应用服务器 (Tomcat 等 )

TCP/IP,socket API , XML...多得吓人啊!要学习啊:(

 

1 安装配置 Axis

 

~~安装 Tomcat 4.X 以上版本 (4.X 后的版本都带 XML 的解析器 )

~~解压 Axis1.1.zip 包,找到 webapps 目录下的 axis 文件夹,拷贝 axis 文件夹到 Tomcat 中的 webapps 文件夹下。

~~将 Tomcat 中的 axis 目录下的 WEB-INF\lib 中的所有的文件 copy 到 Tomcat 的 common\lib 目录中。 ( 以后凡是要在 axis 的 lib 中添加 jar 文件,都要 copy 一份到 Tomcat 的 common\lib 目录下 ) 。

~~我的电脑 -> 属性 -> 高级 -> 环境变量 -> 系统变量中添加:

AXIS_HOME
%TOMCAT_HOME%\webapps\axis(TOMCAT
的目录
)

AXIS_LIB
%AXIS_HOME%\lib

AXISCLASSPATH
%AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery.jar; %AXIS_LIB%\commons-logging.jar;%AXIS_LIB%\jaxrpc.jar; %AXIS_LIB%\saaj.jar;%AXIS_LIB%\log4j-1.2.8.jar; %AXIS_LIB%\xml-apis.jar;%AXIS_LIB%\xercesImpl.jar

修改 CLASSPATH ,在末尾加上:
%AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery.jar; %AXIS_LIB%\commons-logging.jar;%AXIS_LIB%\jaxrpc.jar; %AXIS_LIB%\saaj.jar;%AXIS_LIB%\log4j-1.2.8.jar; %AXIS_LIB%\xml-apis.jar;%AXIS_LIB%\xercesImpl.jar

 

注意检查 CLASSPATH 是否正确:(有些软件会在用户变量区设置一个 classpath ,会有影响,如 :XMLSPY )

在 DOS 方式下

输命令: Echo %CLASSPATH%

~~检查配置:

启动 Tomcat ,访问 http://localhost:8080/axis/ ,

 

验证 axis 的是否工作: http://localhost:8080/axis/happyaxis.jsp 如果正常显示表示正常。

 

 

上图中 倒数第 3 行字“ The core axis libra…. ”,要保证 core axis libraries are present ,如果有任何 core library is missing ,就到其提供的相应的链接上找到对应的 jar 文件,并 copy 到 tomcat 目录里面的 axis 文件夹 WEB-INF\lib 中,别忘了 Tomcat 自己的 common\lib 也 copy 一份。

直到所有的 core library are present.

 

好啦基本上都配置好了。现在我们开始做一个有点模样的 web Service 的例子啦。一步一步来:)

 

目标:模拟一个银行存取款系统,存取款的具体实现作为服务来提供

Axis 提供了两种服务发布方式,一种是即时发布( Instant Deployment ),一种是定制发布( Custom Deployment )。

1. 使用即时发布 Java Web Service(JWS)

  “对即时发布的支持是 Axis 的特色之一,使用即时发布使用户只需有提供服务的 Java 类的源代码,即可将其迅速发布成 Web 服务。每当用户调用这类服务的时候, Axis 会自动进行编译,即使服务器重启了也不必对其做任何处理,使用非常简单快捷。”

使用即时发布首先需要一个实现服务功能的 Java 源文件,将其扩展名改为 .jws ( Java Web Service 的缩写),然后将该文件放到 Tomcat 下面的 webapps\axis 目录下即可。但是 JWS 的 web 服务发布是一个很简单的 Web 服务发布方式,在页面中你不能使用包,而且由于代码是在运行期被编译的,所以在部署之后,你也很难找到错误所在。

就是不好罗,但是我们还是来看一个例子:大家在 Tomcat 的 webapps\axis 下找到 Calculate.jws 文件,然后打开看看。不用编译的。

发布吧: http://localhost:8080/axis/Distance.jws?wsdl 如果你看到下面的 WSDL 描述表示你已经发布成功啦:

 

 

怎么使用这个服务呢?大家到

Tomcat 5.0\webapps\axis\WEB-INF\classes\samples\userguide\example2

里面是不是看到一个 CalcClient.class 的文件啊?这个文件就是对应的 axis 提供的 calculate 的客户端的例子。在 dos 方式,到 Tomcat 5.0\webapps\axis\WEB-INF\classes\ 目录下:

java samples.userguide.example2.CalcClient add 3 4

是不是得到 7 了啊?如果出现 NoDefClass 的错误的话就用 echo 检查各个环境变量吧。一般都错在这里。

Calculator 对应的源代码在下载的 axis.zip 里面的 samples\userguide\example2 里面。

 

2. 使用定制发布 Web Service Deployment Descriptor(WSDD)

  “即时发布是一项令人激动的技术,它使 Web 服务的开发变得如此简单;然而即时发布并不总是最好的选择,比如有些应用系统是第三方提供的,我们没有购买源代码,只有 .class 文件,但我们又希望将这个应用系统的一些功能对外发布成 Web 服务,使其能够在更大范围内产生作用,这个时候即时发布技术就无能为力了。此外,即时发布技术并不灵活,无法进行更多的服务配置,这使得它并不能满足一些特定系统的需求。”

      好啦 到我们啦,我先不说定制发布有什么好,大家先往下看,自然会有体会的:)

首先给出我们的模拟银行存取款的 java 文件:

Account.java

 

package com.duckur;

public class? Account

{

          /*************************************************************

          /* 从随机数中获取帐户(一次性有效) */

          public static int fund = (int)(java.lang.Math.random()*10000);

          // 模拟,大家可以从文件中读取数据,或者从数据库中取出这个 fund 值

           /*************************************************************

            /* 检查输入的有效性 */

           public boolean checkInput(int money)// 只能取整数

           {

            if(money > fund)

            {

                  return false;

             }

             else

             {

                 return true;

               }

            }

           /*************************************************************

           /* 存款 */

           public int deposit(int money)

          {

                 fund? = fund + money;

                return fund;

           }

          /*************************************************************

          /* 取款 */

          public int withdraw(int money)

          {

                    if(checkInput(money))

                     {

                              fund = fund - money;

                     }

                     return fund;

           }

          /*************************************************************

           /* 获取当前的帐户值 */

           public int getAccount()

           {

                     return fund;

          }

}

 

    然后编译,通过后生成的class文件应该放在Tomcat下的webapps\axis\WEB-INF\com\duckur\下面。

下面发布:

     在Tomcat下的webapps\axis\WEB-INF\com\duckur\目录下新建一个deploy.wsdd文件描述服务的名称、入口等信息:

wsdd文件的显示有问题下载吧
 

其中service项重的名称为该服务的名称即Account,java:RPC指明了一个JAVA RPC服务,做这个处理的类是org.apache.axis.providers.java.RPCProvider。

   “我们是通过一个标签告诉RPC服务应该调用的类,而另外一个标签则告诉引擎,它可以调用这个类中的任何的Public方法。你也可以指定通过使用名字空间或者一些可以调用的方法列表,来指明那些方法可以被调用。”

     当然也可以用Axis提供的一个客户端管理工具——AdminClient来完成服务的定制发布。这里不说:)

  

然后在DOS下到该目录下,

java org.apache.axis.client.AdminClient deploy.wsdd

如果出现:

Processing file deploy.wsdd
Doneprocessing

这表明Capacity服务定制发布完成。

好现在你就可以通过http://localhost:8080/axis/services/Account?wsdl来查看WSDL描述了。

 

Web Service发布好了现在调用它吧.

这里说一个最基本的调用需要用的类和方法:

(取出当前的金额)

...

//新建一个服务对象

Service service = new Service();??

//调用服务对象的createCall()方法返回一个命令

Call call = (Call) service.createCall();??

// Sets the address of the target service endpoint.

call.setTargetEndpointAddress(new java.net.URL("http://localhost:8080/axis/services/LxAccount"));

//?Sets the name of the operation to be invoked using this Call instance

call.setOperationName(“getAccount”);

//Convenience method to invoke a //method with a default (empty) namespace

Integer myFund = (Integer) call.invoke(new Object[] {});

...

 

详细函数可以参考开发API在下载的axis.zip中的docs里面。

下面是详细的代码:

编译后执行就可以。

 

LxClient.java

 

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

 

import org.apache.axis.client.Call;

import org.apache.axis.client.Service;

import org.apache.axis.encoding.XMLType;

import org.apache.axis.utils.Options;

 

import javax.xml.rpc.ParameterMode;

import javax.xml.namespace.QName;

 

public class LxClient

extends JFrame {

  JTextField jTextField1 = new JTextField();

  JLabel jLabel3 = new JLabel();

  JLabel jLabel1 = new JLabel();

  JButton jButton1 = new JButton();

  JButton jButton2 = new JButton();

  JButton jButton3 = new JButton();

  JLabel jLabel2 = new JLabel();

  JTextField jTextField2 = new JTextField();

 

  public LxClient() {

    try {

       jbInit();

    }

     catch (Exception e) {

       e.printStackTrace();

     }

  }

 

  public static void main(String args[]){

    LxClient myframe=new LxClient();

    myframe.setSize(400,200);

    myframe.setVisible(true);

 

  }

 

 private void jbInit() throws Exception {

    this.getContentPane().setLayout(null);

    jTextField1.setText("");

    jTextField1.setBounds(new Rectangle(131, 51, 80, 24));

    jLabel3.setText("A0317286 李迅");

    jLabel3.setBounds(new Rectangle(102, 15, 108, 17));

    jLabel1.setText("填入金额:");

    jLabel1.setBounds(new Rectangle(64, 54, 55, 21));

    jButton1.setBounds(new Rectangle(50, 96, 58, 23));

    jButton1.setText("存款");

    jButton1.addActionListener(new LxClient_jButton1_actionAdapter(this));

    jButton2.setBounds(new Rectangle(126, 96, 63, 23));

    jButton2.setText("取款");

    jButton2.addActionListener(new LxClient_jButton2_actionAdapter(this));

    jButton3.setBounds(new Rectangle(205, 94, 81, 24));

    jButton3.setText("查看金额");

    jButton3.addActionListener(new LxClient_jButton3_actionAdapter(this));

    jLabel2.setText("当前的金额:");

    jLabel2.setBounds(new Rectangle(59, 136, 74, 21));

    jTextField2.setEditable(false);

    jTextField2.setText("");

    jTextField2.setBounds(new Rectangle(127, 133, 85, 25));

    this.getContentPane().add(jTextField1, null);

    this.getContentPane().add(jLabel3, null);

    this.getContentPane().add(jLabel1, null);

    this.getContentPane().add(jButton2, null);

    this.getContentPane().add(jButton1, null);

    this.getContentPane().add(jButton3, null);

    this.getContentPane().add(jLabel2, null);

    this.getContentPane().add(jTextField2, null);

   }

 

 /***************************************************************************

 调用WebService* /

 存款*/

  void jButton1_actionPerformed(ActionEvent e) {

    try {

    String endpoint = "http://localhost:8080/axis/services/LxAccount";

    String method = "deposit";

    Integer i = Integer.valueOf(jTextField1.getText());

    Service service = new Service();

    Call call = (Call) service.createCall();

 

    call.setTargetEndpointAddress(new java.net.URL(endpoint));

    call.setOperationName(method);

 

    Integer myFund = (Integer) call.invoke(new Object[] {i});

    //更新数据

    jTextField2.setText(myFund.toString());

    jLabel1.updateUI();

    }

    catch (Exception ex) {

    System.err.println(ex.toString());

    }

  }

 /***************************************************************************

   取款*/

  void jButton2_actionPerformed(ActionEvent e) {

    try {

    String endpoint = "http://localhost:8080/axis/services/LxAccount";

    String method = "withdraw";

    Integer i = Integer.valueOf(jTextField1.getText());

    Service service = new Service();

    Call call = (Call) service.createCall();

 

        call.setTargetEndpointAddress(new java.net.URL(endpoint));

        call.setOperationName(method);

 

            Integer myFund = (Integer) call.invoke(new Object[] {i});

        //更新数据

        jTextField2.setText(myFund.toString());

        jLabel1.updateUI();

       }

        catch (Exception ex) {

        System.err.println(ex.toString());

    }

  }

  /***************************************************************************

   显示当前金额*/

  void jButton3_actionPerformed(ActionEvent e) {

    try {

        String endpoint = "http://localhost:8080/axis/services/LxAccount";

        String method = "getAccount";

 

        Service service = new Service();

        Call call = (Call) service.createCall();

 

        call.setTargetEndpointAddress(new java.net.URL(endpoint));

        call.setOperationName(method);

 

        Integer myFund = (Integer) call.invoke(new Object[] {});

        //更新数据

        jTextField2.setText(myFund.toString());

        jLabel1.updateUI();

    }

    catch (Exception ex) {

        System.err.println(ex.toString());

    }

  }

}

 

class LxClient_jButton1_actionAdapter

     implements java.awt.event.ActionListener {

  LxClient adaptee;

 

  LxClient_jButton1_actionAdapter(LxClient adaptee) {

      this.adaptee = adaptee;

  }

 

  public void actionPerformed(ActionEvent e) {

     adaptee.jButton1_actionPerformed(e);

  }

}

 

class LxClient_jButton2_actionAdapter

     implements java.awt.event.ActionListener {

 LxClient adaptee;

 

 LxClient_jButton2_actionAdapter(LxClient adaptee) {

     this.adaptee = adaptee;

 }

 

 public void actionPerformed(ActionEvent e) {

     adaptee.jButton2_actionPerformed(e);

  }

}

 

class LxClient_jButton3_actionAdapter

    implements java.awt.event.ActionListener {

 LxClient adaptee;

 

   LxClient_jButton3_actionAdapter(LxClient adaptee) {

    this.adaptee = adaptee;

  }

 

  public void actionPerformed(ActionEvent e) {

      adaptee.jButton3_actionPerformed(e);

  }

}