下载 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项重的名称为该服务的名称即Accountjava: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);

  }

}