`

使用Axis开发WebService基础

    博客分类:
  • Axis
阅读更多

Axis  Web  Service开发指南

   这篇文章主要是翻译了Axis用户指南部分。介绍了如何使用Axis开发WebService。有些地方可能有出入,其中也省略了一部分,不过这都不影响你如何使用Axis开发WebService。    E-mailredogs@sian.com

1.1调用Axis上的Web服务

注意:程序源代码 请查看官方网站!

 

1.1.1一个简单的例子

执行一下命令部署服务:

启动服务器,默认端口8080。部署服务后需要重新启动服务器。

% java org.apache.axis.client.AdminClient  samples/example1/deploy.wsdd

%cp samples /axis/WEB-INF/classes/

首先让我们来看一个简单的webservice客户程序,它将调用Axis服务器上的一个echoString方法

  import org.apache.axis.client.Call;

2   import org.apache.axis.client.Service;

3   import javax.xml.namespace.QName;

4

5   public class TestClient {

6      public static void main(String [] args) {

7         try {

8           String endpoint =

9           " http://localhost:8080/axis/services/TestServer";

10

11           Service  service = new Service();

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

13

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

15           call.setOperationName(new QName("http://soapinterop.org/", echoString"));

16

17           String ret = (String) call.invoke( new Object[] { "Hello!" } );

18

19           System.out.println("Sent 'Hello!', got '" + ret + "'";

20        } catch (Exception e) {

21        System.err.println(e.toString());

22     }

23    }

24  }

你可以执行一下命令运行该程序

%javac samples.example1.TestClient.java

%java samples.example1.TestClient

Sent 'Hello!', got 'Hello!'

%

程序是如何调用服务运行的呢?在1112行我们创建了一个ServiceCall对象,它们都是用来存放关于服务调用数据的标准JAX-RPC对象。在14行我们提供了终端URL——它指定了我们SOAP信息的目的地。在15行我们指定了调用的webservice的方法.,并且在17行我们调用了我们期望的服务.,同时传递一个数组参数——这里只是一个String

 

你可以通过查看发送的SOAP请求来了解怎么传递这个参数。

 

 

    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

 

    <ns1:echoString xmlns:ns1="http://soapinterop.org/">

      Hello!

   

 

 

这里的String参数自动的被格式化为XML,服务端返回同样的String。就像我们上面看到的一样。

1.1.2为参数命名

在上面的例子中,Axis自动的把XML格式的参数在SOAP消息中直接命名为“arg0”,“agr1”,如果你想改变这一点,很容易,在你调用invoke()之前你需要对每一个参数调用addParametersetReturn,例如:

call.addParameter("testParam",org.apache.axis.Constants.XSD_STRING,

javax.xml.rpc.ParameterMode.IN);

call.setReturnType(org.apache.axis.Constants.XSD_STRING);

这样的话将把testParam分配给调用方法的第一参数,也同时定义了参数的类型,以及说明了是输入、输出或者是输入输出参数,这里是一个输入参数。运行程序你将得到如下消息:

 

 

    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

 

   

      Hello!

   

 

 

这的参数名称就是我们期望的testParam了。

 

1.1.3无类型”Server的互操作

在上面的例子中,我们已经映射了invoke()的返回类型到一个Object,我们知道echoString方法返回一个String,所以我们希望从client.invoke()这里返回一个String。现在让我们看一下这是怎么发生的。下面是一个典型的echoString方法的响应:

 

 

    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

 

   

      type="xsd:string">Hello!

   

 

 

请看我们加粗的部分——这个属性是一个schema 类型声明,Axis用它来指出那个元素内容是什么类型,这里将把它反串行化为一个JAVA String对象。但是在其他情况下会返回如下响应:

 

 

    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

 

   

      Hello, I'm a string!

   

 

 

消息中没有指定类型,我们是否知道元素的反串行化结果是个什么java 对象?答案就是原数据——数据的数据。在这种情况下我们就需要指定我们期望的返回类型。下面说明了Axis的客户端程序该怎么做。

   call.setReturnType( org.apache.axis.Constants.XSD_STRING );

这个方法将告诉Axis客户程序,如果返回的元素没有定义类型,那么它将等同于在SOAP中使用type属性做如下定义xsi:type="xsd:string"

   这里有个同样功能的方法,它允许你指定期望返回类型的Java类。

call.setReturnClass(String.class);

现在我们已经了解了一个客户程序访问一个SOAP服务的基本知识。下面我们将说明如何发布自己的服务。

 

1.2使用Axis发布服务

 

假如我们有一个象下面一样的简单类:

public class Calculator {

  public int add(int i1, int i2) {

    return i1 + i2;

  }

 

  public int subtract(int i1, int i2) {

    return i1 - i2;

  }

}

我们怎样才能使它通过SOAP访问呢?这里将有几种答案,但是我们将从Axis提供的最简单的方法开始,实现它可以说毫不费力。

 

1.2.1Jws文件——即时部署

第一步:复制上面的类到webapps目录,并重命名为Calcalator.jws。你将使用下面命令:

%copy  Calculator.java  /axis/Calculator.jws

第二步:你已经完成了部署。你可以通过下面的连接来访问服务:

http://localhost:8080/axis/Calculator.jws (这里假定你Axis服务端口8080

 

Axis将自动定位该文件,编译该文件,并且正确的转换SOAP调用到你的服务程序。

我们可以运行calculator客户端程序来测试结果:

% java samples.example2.CalcClient -p8080 add 2 5

Got result : 7

% java samples.example2.CalcClient -p8080 subtract 10 9

Got result : 1

%

注意:jws服务主要被简单服务使用,你不能使用包,你不能发现错误直到你服务部署之后,因为代码只有在运行的时候才去编译。

 

1.2.2自定义部署——wsdd

    Jws文件可以很快的把你的java类部署成web service,但是不是最好的选择。因为,你需要源代码——但是很多时候你可能想部署一个已经存在的没有源代码class文件。你可以做的配置比较有限,比如怎样访问一个服务是受限制的——你不能定义自定义类型的映射,或者不能控制调用那一个Handlers当用户调用服务时。

通过描述符文件来部署服务

为了更灵活的使用Axis,你应该熟悉Axis Web Service Deployment DescriptorWSDD)文件格式。下面我们来看一个基本服务的部署描述符。

 

    xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">

 

   

   

 

 

非常简单,最外层元素告诉引擎这是一个WSDD部署文件,并且定义了java的名字空间,接下来的service元素定义了我们的服务。一个服务就是一个targeted chain,意味着它将有下面的一个或多个:一个请求流,一个Handler,一个响应流。这里我们的providerAxis内置的javaRPC ,这说明这是一个Java RPC服务。为了让RPCProvider能够调用正确的方法,我们使用标签,一个参数定义服务的类名,另一个参数告诉引擎这个类的任何public方法都可以通过SOAP调用。

 

使用AdminClient

一旦我们有了wsdd文件,我们需要把它送给Axis服务器来具体的部署描述的服务,我们通过AdminClient,或者"org.apache.axis.client.AdminClient"来实现这一点,如果你的Axis不是部署在Tomcat中,你可能需要使用-p  参数。默认端口是8080AdminClient工具的一个典型调用如下:

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

Done processing

这个命令将使我们的服务可以通过SOAP来进行访问。可以通过运行客户程序来验证这一点:

% java samples.example3.MyClient -lhttp://localhost:8080/axis/services/MyService

"test me!"

You typed : test me!

%

你也可以使用下面命令来列出服务器上部署的所有的服务:

% java org.apache.axis.client.AdminClient list

 

 

更多的部署

现在让我们来了解Axis引擎更强大的特性,假设你想知道你的服务被调用了多少次,我们在sample/log下有一个简单的handler来实现这一点。要使用这个handler类,你需要首先部署它,然后你使用你给他指定的名字来部署服务,下面是一个简单的部署文件:

 

    xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">

 

 

   

  

 

 

 

   

     

   

 

   

   

 

 

 

第一部分定义了一个称作trackHandler,它是由LogHandler类实现的,我们同时使用了参数指定了写入log的文件。

这样我们就定义了一个web服务,LogTestService,它和我们看到的RPC服务是一样的。不同的地方是在元素内我们包含了元素——这意味着当你调用这个服务时需要执行一些Handlers。通过引入一个track,我们保证了每次调用服务都会写如日志。

 

1.3 Java数据类型如何映射到SOAP/XML类型

互操作性是SOAP实现的一种挑战,如果你想让你的服务可以和其他平台或其他语言实现的服务一起工作,那么你就需要了解这个问题。Java类型和WSDL/XSD/SOAP类型的之间的映射是由JAX-RPC定义的,下面是它们之间的简单关系:

WSDLJava标准映射

xsd:base64Binary

byte[]

xsd:boolean

boolean

xsd:byte

byte

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

 

1.3.1在严格的互操作下Axis能通过SOAP发送什么呢?

 

Java Collections

一些Collection类,比如hashtable,它确实用自己的serializers,但是没有和其他SOAP实现进行互操作的标准,并且没有任何关于转化复杂对象的SOAP标准。最可信赖的方法是通过数组来传递对象集合。

 

1.3.2通过SOAP Axis不能发送什么呢?

    任何没有预先注册的对象。

我们不能发送一个任意的Java对象,并且期望对方能够理解。使用RMI你可以发送和接收序列化的java对象,那是因为两端都使用的是JavaAxis只能发送那些能被注册的Axis序列化器序列化的对象。下面将介绍怎么使用BeanSerializer来序列化任意一个符合JavaBean格式的类。

1.3.3编写自己的Bean——使用BeanSerializer

Axis不需要你书写任何代码就有能力seriliae/deserialize任意一个符合get/set存取的JavaBeam格式的类。你需要做的就是告诉Axis把那一个java类映射到那一个XML Schema类型,设置一个bean映射看起来是这个样子:

 

 

languageSpecificType="java:my.java.type"/>

 

这里的标签映射一个java类到一个XML QName。你将注意到它有两个重要的属性,qnamelanguageSpecificType。这个例子中我们映射java:my.java.type类到XML QName [someNamespace]:[local]

 

现在来让我们看看在实际应用中它是怎么工作的。我们看例子samples/example5/BeanService.java,我们将看到服务方法的参数一个Order对象。因为Order对象不是Axis能理解的一个基本类型,如果不进行映射运行这个程序我们将得到一个fault。但是我们在我们的部署文件中加入beanMapping,它将能很好的运行。下面是运行的结果:

 

% java org.apache.axis.client.AdminClient -llocal:///AdminService deploy.wsdd

Done processing

% java samples.userguide.example5.Client -llocal://

Hi, Glen Daniels!

You seem to have ordered the following:

1 of item : mp3jukebox

4 of item : 1600mahBattery

If this had been a real order processing system, we'd probably have charged

you about now.

%

 

Bean不能满足你的需要时可以自定义序列化器,可以参考前面章节。

 

1.4使用AxisWSDL

9.1.4.1获取部署服务的WSDL

当你使用Axis发布一个服务,将会有唯一一个URL对应这个服务。对JWS文件来说,它的URL就是指向jws文件自己。对非jws服务,具体的URL就是:“http://:/axis/services/”。
     
如果你使用浏览器通过URL访问服务,你将看到一个信息指出这是一个Axis服务,并且你应该通过SOAP来访问它。如果你在URL后面加上“?wsdl”,Axis将自动生成服务的描述文件wsdl。你可以告诉你的在线伙伴通过这个连接来获取这个服务的WSDL,这样他们就能使用工具,比如.NETSOAP或者其他支持WSDL的工具来访问你的服务。

 

1.4.2 WSDL2Java :从WSDL来建立stubsskeletons和数据类型。

 

客户端bindings

AxisWSDLTOJava工具是"org.apache.axis.wsdl.WSDL2Java"。你可以使用下面方式调用工具:
       
% java org.apache.axis.wsdl.WSDL2Java (WSDL-file-URL)

这样就会产生客户程序需要的bindings,当从WSDL生成客户端的bindingsAxis遵守JAX-RPC标准。我们执行一下命令:

% cd samples/addr

% java org.apache.axis.wsdl.WSDL2Java AddressBook.wsdl

产生的文件存放在AddressFetcher2目录下,把它们放在这个目录下是因为把WSDL中的target namespace映射成了Java packages

至于WSDL的各各部分是怎么映射到响应的java程序,请看前面章节。我们这里只探讨一下复杂类型bean的映射过程。

WSDL类型生成的java类,将在使用WSDLtyep来命名。这个类一般来说就是一个Bean。例如下面的WSDL

 

 

   

   

   

 

 

WSDL2Java将产生下面代码:
public class Phone implements java.io.Serializable {

  public Phone() {...}

  public int getAreaCode() {...}

  public void setAreaCode(int areaCode) {...}

  public java.lang.String getExchange() {...}

  public void setExchange(java.lang.String exchange) {...}

  public java.lang.String getNumber() {...}

  public void setNumber(java.lang.String number) {...}

  public boolean equals(Object obj) {...}

  public int hashCode() {...}

}

其他元素的映射前面相关部分已经做过介绍。

 

1.4.3 Java2WSDL:从java程序生成WSDL

第一步:提供一个Java接口或着类。

写一个java接口或类,编译这个程序,这里是一个接口描述一个web服务。

package samples.userguide.example6;

 

/**

 * Interface describing a web service to set and get Widget prices.

 **/

public interface WidgetPrice {

  public void setWidgetPrice(String widgetName, String price);

  public String getWidgetPrice(String widgetName);

}

 

第二步:使用Java2WSDL生成WSDL

 

使用Java2WSDL工具从上面的接口生成WSDL。下面是调用这个工具的命令:
% java org.apache.axis.wsdl.Java2WSDL -o wp.wsdl

    -l"http://localhost:8080/axis/services/WidgetPrice"

    -n  "urn:Example6" -p"samples.userguide.example6" "urn:Example6"

    samples.userguide.example6.WidgetPrice

这里:

   指定了生成的WSDL文件名称

   l  指定了服务的位置

n  WSDL文件的target namespace

p  指定了从包名到namespace的映射

类指定了服务包含的接口。

 

生成的WSDL文档将包含相应的WSDL类型,消息,portTypebindings和支持SOAP RPC的服务描述,web服务的编码。如果你定义的接口方法引用了其他的类,Java2WSDL工具将生成相应的xml类型来替代这个类或任何嵌入或继承类型。这个工具支持JAX-RPC复杂类型(bean class),xtension classes, enumeration classes, arrays Holder classes.

 

第三步:使用WSDL2Java创建Bindings

 

使用生成的WSDL文件为web服务生成相应的client/server bindings

% java org.apache.axis.wsdl.WSDL2Java -o . -d Session -s -S true

-Nurn:Example6 samples.userguide.example6 wp.wsdl

这将生成下列文件

 

 

 

 

现在你拥有了部署服务,建立客户程序所需要的所有文件了。

 

注意:程序源代码 请查看官方网站!

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics