最近公司的项目中有一个应用:网络银行系统向网银中绑定动态口令成功的客户发一条短信息,而我所在的银行为了集成各个渠道的应用访问,开发了一套EAI系统,将需要的接口都以webservice的形式发布到EAI上,供银行统一规划调度。
进过这段时间开发中的瞎摸乱撞,对使用axis2开发webservice有了一点初步的认识:
首先,本篇博客对于webservice和axis2的文字解释就不再赘述,google百度有很多,也很官方,我只是说一下我自己的理解:
webservice是目前实现异构系统之间相互调用和访问的机制(传输的协议是SOAP,传输内容的格式是xml),.NET框架已经封装了WebService实现,axis和axis2是基于java语言的开源WebService实现(axis1.3是soap1.2协议的一个实现框架)
对于你而言,你不用太关注webservice本身的理论和核心机制,你如果用.net,只需要看看Visual Studio中webservice是如何编程实现的即可,如果用J2EE,只需要看看Axis的部署说明就可以了
好,我们言归正传,我下面的文章建立在对上面两个概念有一个初步认识的前提下,一步步的开发一个基于axis2的webservice实例应用
J2SE SDK 1.3 or 1.4: 我使用 1.4.2 ,Tomcat 5.0
1搭建axis2环境
把axis2.war拷贝到Tomcat 5.0\webapps\目录下
启动Tomcat,访问http://localhost:8080/axis2/
显示Welcome to the new generation of Axis. If you can see this page you have successfully deployed the Axis2 Web Application
在此页面点击Validate,将到达 Axis2 Happiness Page,则说明你的axis2部署成功
2开发工具
环境搭建好了,下面就该是找到一个合适的开发利器了,我使用的是MyEclipse6.0.1,在这里我之所以废话说我开发的IDE,原因有2:首先,我比较懒,懒得连插件都不想去下载安装,MyEclipse中自带的Ant能很大程度上减少我们程序员的重复代码量,而且Ant通过build.xml生成的文件又标准又容易控制,第二,对于服务器而言,我们公司通用的开发IDE是IBM的WSAD6.0也叫RAD(Rational Application Developer),使用他开发起来实在是麻烦,而且集成的WebSphere远远不如Tomcat对初学者来说使着顺手快捷
3配置好build.xml
我这个例子的配置文件如下:
<!--
~ Licensed to the Apache Software Foundation (ASF) under one
~ or more contributor license agreements. See the NOTICE file
~ distributed with this work for additional information
~ regarding copyright ownership. The ASF licenses this file
~ to you under the Apache License, Version 2.0 (the
~ "License"); you may not use this file except in compliance
~ with the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<project name="quickstartadb" basedir="." default="generate.service">
<property environment="env"/>
<property name="AXIS2_HOME" value="D:\workspace_MyEclipse6.0.1\BWS"/>
<property name="service.target" value="build/service"/>
<property name="client.target" value="build/client"/>
<property name="build.dir" value="build"/>
<property name="wsdl.uri" value="${build.dir}/TestQuery.wsdl"/>
<path id="axis2.classpath">
<fileset dir="${AXIS2_HOME}/lib">
<include name="*.jar"/>
</fileset>
</path>
<path id="client.class.path">
<fileset dir="${AXIS2_HOME}/lib">
<include name="*.jar" />
</fileset>
<fileset dir="${build.dir}/client/build/lib" >
<include name="*.jar" />
</fileset>
</path>
<target name="init">
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.dir}/service"/>
<mkdir dir="${build.dir}/client"/>
</target>
<target name="compile.pojo">
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.dir}/classes"/>
<!--First let's compile the classes-->
<javac debug="on"
fork="true"
destdir="${build.dir}/classes"
srcdir="${basedir}/src"
classpathref="axis2.classpath">
</javac>
</target>
<target name="generate.wsdl" depends="compile.pojo">
<taskdef name="java2wsdl"
classname="org.apache.ws.java2wsdl.Java2WSDLTask"
classpathref="axis2.classpath"/>
<java2wsdl className="cn.com.leadmind.cbhb.webservice.server.TestQuery"
outputLocation="${build.dir}"
targetNamespace="http://server.webservice.cbhb.leadmind.com.cn"
schemaTargetNamespace="http://server.webservice.cbhb.leadmind.com.cn">
<classpath>
<pathelement path="${axis2.classpath}"/>
<pathelement location="${build.dir}/classes"/>
</classpath>
</java2wsdl>
</target>
<target name="generate.service">
<delete dir="${service.target}"/>
<mkdir dir="${service.target}"/>
<mkdir dir="${service.target}/classes"/>
<java classname="org.apache.axis2.wsdl.WSDL2Java" fork="true" classpathref="axis2.classpath">
<arg line="-uri ${wsdl.uri}"/>
<arg line="-s"/>
<arg line="-ss"/>
<arg line="-sd"/>
<arg line="-ssi"/>
<arg line="-ap"/>
<arg line="-ns2p http://quickstart.samples/xsd=samples.quickstart.service.adb.xsd"/>
<arg line="-l java"/>
<arg line="-p cn.com.leadmind.cbhb.webservice.server"/>
<arg line="-d adb"/>
<arg line="-o ${build.dir}/service"/>
</java>
<mkdir dir="${service.target}/src/META-INF"/>
<!--ant dir="${build.dir}/service">
<property name="axis2.home" value="../../${AXIS2_HOME}"/>
</ant>
<copy file="${basedir}/build/service/build/lib/StockQuoteService.aar"
toDir="${basedir}/../../repository/services"
overwrite="yes">
</copy-->
</target>
<target name="compile.service" >
<!--depends="generate.service"-->
<mkdir dir="${service.target}/classes"/>
<!--First let's compile the classes-->
<javac debug="on"
fork="true"
destdir="${service.target}/classes"
srcdir="${service.target}/src"
classpathref="axis2.classpath">
</javac>
<mkdir dir="${service.target}/classes/META-INF"/>
<copy file="${service.target}/resources/services.xml"
toDir="${service.target}/classes/META-INF"
overwrite="yes">
</copy>
</target>
<target name="aar.service" depends="compile.service">
<!--aar them up -->
<jar destfile="${build.dir}/billService.aar">
<fileset excludes="**/Test.class" dir="${service.target}/classes"/>
</jar>
</target>
<target name="generate.client">
<delete dir="${client.target}"/>
<mkdir dir="${client.target}"/>
<java classname="org.apache.axis2.wsdl.WSDL2Java" fork="true" classpathref="axis2.classpath">
<arg line="-uri ${wsdl.uri}"/>
<arg line="-s"/>
<arg line="-u"/>
<arg line="-ns2p http://quickstart.samples/xsd=samples.quickstart.service.adb.xsd"/>
<arg line="-l java"/>
<!--arg line="-p samples.quickstart.service.adb"/-->
<arg line="-d adb"/>
<arg line="-o ${build.dir}/client"/>
</java>
<!--copy file="${basedir}/src/samples/quickstart/clients/ADBClient.java"
toDir="${build.dir}/client/src/samples/quickstart/clients/"
overwrite="yes">
</copy-->
<!--ant dir="${build.dir}/client">
<property name="axis2.home" value="../../${AXIS2_HOME}"/>
</ant-->
</target>
<target name="generate.all" depends="generate.service, generate.client"/>
<target name="run.client" depends="generate.client">
<java classname="samples.quickstart.clients.ADBClient">
<classpath refid="client.class.path" />
</java>
</target>
<target name="clean">
<delete dir="${build.dir}"/>
</target>
</project>
别看他挺长挺吓人的,其实仔细看起来并不复杂,无外乎就是些你axis2的lib包的路径,或是你生成wsdl文件对应的java类的路径之类的
4生成wsdl文件
一个基本的pojo类A,含一些成员和方法(将来会在客户端调这几个方法),在build.xml的Outline视图中右键generate.wsdl,按要求修改wsdl文件,比如修改生成的客户端或服务端的类名等
我这里的pojo例子如下:
package cn.com.leadmind.cbhb.webservice.server;
public class TestQuery {
String billno;
public String getBillno() {
return billno;
}
public void setBillno(String billno) {
this.billno = billno;
}
}
5生成server端的.java文件
在build.xml的Outline视图中右键generate.service,控制台显示build successful后会生成对应于A的一些service提供类(服务提供类包括目录结构也和A完全一样)
在例子中,我们生成了如下的一些类:
ExtensionMapper.java
GetBillnoResponse.java
SetBillno.java
SetBillno.java
TestQueryMessageReceiverInOnly.java
TestQueryMessageReceiverInOut.java
TestQuerySkeletonInterface.java
TestQuerySkeleton.java
嘿嘿,是不是爽啊,一个字不敲,生成了这么多服务端的类,替你完成了很多工作,比如拆解soap信封,对象封装之类,而你需要关注的,也只有一个类:那就是TestQuerySkeleton.java,下面,就轮到我们程序员出马拉~~
6webservice服务端编程
我们先来个简单的HAxis2 Hello例子
TestQuerySkeleton.java代码如下:
package cn.com.leadmind.cbhb.webservice.server;
public class TestQuerySkeleton implements TestQuerySkeletonInterface {
public void setBillno(
cn.com.leadmind.cbhb.webservice.server.SetBillno setBillno1) {
}
public cn.com.leadmind.cbhb.webservice.server.GetBillnoResponse getBillno() {
GetBillnoResponse s = new GetBillnoResponse();
s.set_return("TestQuerySkeleton.java Say:Axis2 Hello!");
return s;
}
}
7将服务程序打包为aar文件并部署在服务器上
在build.xml的Outline视图中右键aar.service,会在项目中生成service提供类的aar文件,启动服务器(前提是已经在服务器中部署了axis2的环境),然后访问IE:http://localhost:8080/axis2/,点击页面的Administration,输入用户名admin密码axis2,选择左侧的Tools中的Upload Service,Upload刚才生成的aar文件(忙活半天其实就是把这个aar文件拷贝到Tomcat服务器目录的Tomcat 5.0\webapps\axis2\WEB-INF\services目录下),这样,webservice的service端就已经就绪
8生成client端的.java文件
服务已经提供好了,下面该是如何调用这个服务了
在build.xml的Outline视图中右键generate.client,控制台显示build successful后会生成对应于A的一些webservice服务的客户端调用类(目录结构和A完全一样)。在client端建立一个项目(什么都行),将刚才生成的webservice服务的客户端调用类连同目录结构一并拷贝过来,然后开始webservice客户端编程
9webservice客户端编程
在生成的服务调用类中,最重要的是*Stub.java类,其他生成的类都是对应与这个类中的各个方法的,将生成的所有服务调用类放于client端的项目中,Stub就相当于一个存根,当client端调用webservice端的方法时,首先会调用client端本地项目的Stub.java中的对应方法,然后Stub在通过soap以信封xml的方式通过网络发到服务器即server端,aar文件中对应于刚才调用方法名字的*Skeleton.java类的对应方法就会执行,如果方法是InOut模式,还将返回一个值给客户端
例子中,我的调用测试类如下:
package cn.com.leadmind.cbhb.webservice.server;
public class Test {
public static void main(String[] args)throws Exception{
TestQueryStub tqs = new TestQueryStub();
GetBillnoResponse s = tqs.getBillno();
System.out.println(s.get_return());
}
}
10成果
刚才的步骤5已经将webservice服务的aar文件发布到Tomcat中去了,现在启动Tomcat,相当于webservice服务已经开启。在客户端运行的你的程序,调用你本地项目的*Stub.java类的方法,这个过程就完成了webservice通讯