dev2dev 首页 > 资源中心 > 技术文章
Beehive中的Web服务开发
时间:2005-04-18
作者:肖菁
浏览次数:
本文关键字: |
|
Beehive中的Web服务开发工作集中在JWS文件的处理上,极大的简化了Web服务的开发过程,降低了提供Web服务的门槛。作者在本文中以一个简单的例子详细的介绍了如何使用JWS文件来实现Web服务开发的过程。
关键词: Beehive Web服务
1 概述
通常一个Web服务的开发过程需要两个步骤:
1、 JavaBean编写
Web服务提供者编写一系列的JavaBean,实现需要发布为Web服务的功能,确定Web服务的需要接受的参数、返回参数类型等。
2、 发布Web服务
通常在编写完成后,还需要修改相关的配置文件声明将JavaBean中的某些方法发布为Web服务,这个过程工作比较多,下面的内容通常是需要准备的--发布JavaBean方法的元素、Web服务的输入参数、Web服务的输出参数,如果Web服务的输入、输出参数是Java类、集合类型等,还需要进行专门的映射元素的准备工作。
在Beehive框架中,Web服务的开发就简单多了,工作内容变成了维护一些JWS(Java Web Services)文件,发布Web服务所需要的配置文件的准备工作都是Beehive框架的编译过程自动完成的。
1.1 JWS文件
JWS(Java Web Service)是Beehive中Web服务的核心,一个JWS文件就是一个加入了一些注释的Java文件, Beehive框架下开发Web服务的所有工作都在这个文件中完成。
JWS文件中需要发布和不需要发布的方法的编写方式和普通的Java方法没什么不同,只是会加入一些注释信息,描述这些被发布方法在被发布时候的一些配置信息。
1.2 JWS文件中的注释信息
JWS中的注释信息分为四类:WSDL映射、SOAP绑定、安全和消息处理。简单的Web服务开发,我们只需要WSDL映射中的两个注释信息:@WebService和@WebMethod。
1.2.1 @WebService
这个注释放置在Java类生命的前面,声明这个类的部分方法可以被发布为Web服务,下面是后面例子中的代码片断:
@WebService(targetNamespace="http://www.vivianj.org/samples/wsm")
public class Service{ |
@WebService也有五个属性,用于设置Web服务被发布时的一些配置信息,常用的属性说明如下,讲叙如何开发Web服务的时候将详细解释如何使用这些属性:
1. name
Web服务的名字,WSDL中wsdl:portType元素的name属性和它保持一致,默认是Java类或者接口的名字。
2. serviceName
Web服务的服务名,WSDL中wsdl:service元素的name属性和它保持一致,默认是Java类的名字+”Service”。
3. targetNamespace
WSDL文件所使用的namespace,该Web服务中所产生的其他XML文档同样采用这个作为namespace。
1.2.2 @WebMethod
这个注释放在需要被发布成Web服务的方法前面,声明接下来的这个类将被发布成Web服务,下面是后面例子中的代码片断:
@WebMethod
public String sayHelloWorld() {
return "Hello World!";
} |
同样的,@Method也有自己的属性:action和operationName:operationName声明了wsdl文件中该方法对应的wsdl:operation元素的name属性的内容,默认是Java方法的名字;action用于说明SOAP绑定中SOAPAction的属性设置。
2 Web服务开发实例
我们将开发一个简单的Web服务,详细的演示如何使用JWS文件来实现Web服务的全过程,并且给出了如何生成客户端测试代码来测试被发布Web服务的过程,最后将测试我们发布的Web服务。
开发的Web服务模拟了Web服务中的主要场景:
1. 客户端向服务端发送无参数请求
2. 客户端向服务端发送携带简单类型参数的请求
3. 客户端向服务器发送携带Java类参数的请求
4. 服务器端向客户端发送基本类型的返回信息
5. 服务器端向客户端发送Java类的返回信息
6. 服务器端向客户端发送数组类型的返回信息
2.1 实例环境说明
作者的例子将从Beehive提供的例子wsm-blank应用开始,Web容器采用Tomcat,操作系统采用Windows2000。
本文中作者默认你的wsm-blank应用已经在Tomcat上配置完成上下文路径是wsm,并且能够正确运行。如果你的Web服务应用还没有能够运行起来,请参考作者的另一篇文章《Beehive入门》。
2.2 JWS文件分析
下面这个JWS文件是作者编写的一个JWS文件(保存在%tomcat_home%\webapps\wsm\WEB-INF\src\samples目录下),里面有五个被发布为Web服务的方法,分别演示上面列出的一种或者两种应用场景。
JWS文件的源代码如下,文件的注释部分分析了JWS的使用情况:
package samples;
import org.vivianj.beehive.samples.wsm.data.*;
import javax.jws.WebMethod;
import javax.jws.WebService;
/*
* 下面的@Service是JWS的注释信息
* 表明这个类中的某些方法可能被发布成Web服务
* 紧跟着括号内的部分表示设置@Service的targetNameSpace属性
*/
@WebService(targetNamespace="http://www.vivianj.org/samples/wsm")
public class Service{
/*
* 下面的@WebMethod是JWS的注释信息
* 表明这个紧跟着这个方法被发布成Web服务
* sayHelloWorld演示了客户端发送无参数请求、服务器端向客户端发送
* 基本类型(String)的返回信息的应用场景
*/
@WebMethod
public String sayHelloWorld() {
return "Hello World!";
}
/*
* sayHelloWorldTo
演示了客户端向服务端发送携带简单类型参数的请求、
*
服务器端向客户端发送基本类型(
String
)的返回信息的应用场景
*/
@WebMethod
public String sayHelloWorldTo(String who) {
return "Hello " + who + "!";
}
/*
* registerCustomer
演示了客户端向服务端发送携带
Java
类参数的请求的
*
应用场景
*/
@WebMethod
public void registerCustomer(Customer customer) {
CustomerHelper.add(customer);
}
/*
* getCustomer
演示了客户端向服务端发送携带简单类型参数的请求、
*
服务器端向客户端发送
Java
类(
Customer
)的返回信息的应用场景
*/
@WebMethod
public Customer getCustomer(int location) {
return CustomerHelper.getByLocation(location);
}
/*
* getAll
演示了服务器端向客户端发送
Java
类数组(
Customer[]
)的
*
返回信息的应用场景
*/
@WebMethod
public Customer[] getAll() {
return CustomerHelper.getAll();
}
}
2.3 Web服务发布
要发布这个开发的Web服务,只需要使用beehive中提供的编译这个Web应用就可以了,编译指令如下:
ant -f %BEEHIVE_HOME%\ant\buildWebapp.xml -Dwebapp.dir=%tomcat_home%\webapps\wsm
build.webapp
[注] 相应的工具准备和环境变量设置等工作请参考作者的另一篇文章《beehive入门》中的“让Web服务的例子跑起来”章节中的内容。
2.4 客户端代码生成
Web服务开发、发布已经完成,自己编写客户端访问代码是个麻烦的事情,还好beehive中已经提供了相应的通过JWS文件生成客户端访问代码的ant脚本文件。进入%tomcat_home%\webapps\wsm\WEB-INF目录下,可以看到里面有个client-build.xml,这个就是我们可以利用的ant脚本文件了。
默认情况下,这个xml文件的内容是这样的:
<?xml version="1.0" ?>
<project name="AddressBookClient" basedir="." default="all">
<property name="AddressBook.wsdl.url"
value="http://localhost:8080/wsm-blank/template/Blank.jws?wsdl"
/> |
<path id="jars">
<fileset dir="lib">
<include name="**/*.jar"/>
</fileset>
</path>
<taskdef name="wsdl2java" classname="org.apache.axis.tools.ant.wsdl.Wsdl2javaAntTask"
loaderref="axis" >
<classpath refid="jars"/>
</taskdef>
<target name="clean">
<delete dir="build" />
</target>
<target name="dirs">
<mkdir dir="build" />
<mkdir dir="build/generated"
/>
<mkdir dir="build/classes"
/>
</target>
<target name="all" depends="genClient,
compile, test"/>
<target name="genClient" depends="dirs">
<wsdl2java url="${AddressBook.wsdl.url}"
output="build/generated" testcase="yes">
</wsdl2java>
</target>
<target name="compile" depends="genClient">
<javac srcdir="build/generated"
destdir="build/classes" classpathref="jars" failonerror="true"
source="1.4" />
</target>
<target name="test" depends="compile">
<junit printsummary="yes"
haltonfailure="yes" showoutput="yes">
<classpath>
<pathelement location= "build/classes"/>
<path refid="jars"/>
</classpath>
<batchtest fork="yes" todir=".">
<fileset dir="build/classes">
<include name="**/*Test*.class"/>
</fileset>
</batchtest>
</junit>
</target>
</project>
这个脚本生成了客户端访问指定Web服务(由XML文件中的AddressBook.wsdl.urld的属性确定,见上面的灰色背景部分显示的内容)所需要的客户端代码,并且生成了一个junit测试,用于测试生成的Web服务。
我们要做的工作就是下面三个简单的步骤:
1. 启动Tomcat服务器
2. 修改XML中AddressBook.wsdl.urld的value属性为http://loclahost:8080/wsm/wsamples/Service.jws?wsdl
3. 执行ant任务
现在你可以进入%tomcat_home%\webapps\wsm\WEB-INF目录,执行下面的指令生成Web服务的客户端代码和测试代码:
Ant –f client-build.xml compile
生成的客户段访问代码和测试代码位于%tomcat_home%\webapps\wsm\WEB-INF\build\generated目录下。
[注] 执行compile任务的时候会编译生成的测试代码,所以你需要拷贝一个junit.jar到%tomcat_home%\webapps\wsm\WEB-INF\lib目录下。
2.5 测试
测试代码已经生成了(位于%tomcat_home%\webapps\wsm\WEB-INF\build\generated目录下),要运行测试代码,我们还需要下面几个步骤:
1、修改生成的测试代码
不过在运行之前还需要一些修改工作,因为自动生成的测试代码中没有加入测试用例和所需要的判断语句,下面是作者的修改过的测试代码,里面灰色背景的内容是在生成的测试代码基础上增加或者修改的:
/**
* ServiceServiceTestCase.java
*
* This file was auto-generated from WSDL
* by the Apache Axis 1.2RC1 Oct 29, 2004 (04:30:47 EDT) WSDL2Java emitter.
*/
package org.vivianj.www.samples.wsm;
public class ServiceServiceTestCase extends junit.framework.TestCase {
public ServiceServiceTestCase(java.lang.String name) {
super(name);
}
public void testServiceWSDL() throws Exception {
javax.xml.rpc.ServiceFactory serviceFactory
= javax.xml.rpc.ServiceFactory.newInstance();
java.net.URL url = new java.net.URL(new
org.vivianj.www.samples.wsm.ServiceServiceLocator().getServiceAddress() + "?WSDL");
javax.xml.rpc.Service service = serviceFactory.createService(url,
new org.vivianj.www.samples.wsm.ServiceServiceLocator().getServiceName());
assertTrue(service != null);
}
public void test1ServiceGetAll() throws Exception {
org.vivianj.www.samples.wsm.ServiceSoapBindingStub
binding;
try {
binding =
(org.vivianj.www.samples.wsm.ServiceSoapBindingStub)
new org.vivianj.www.samples.wsm.ServiceServiceLocator().getService();
}
catch (javax.xml.rpc.ServiceException
jre) {
if(jre.getLinkedCause()!=null)
jre.getLinkedCause().printStackTrace();
throw new
junit.framework.AssertionFailedError("JAX-RPC ServiceException caught:
" + jre);
}
assertNotNull("binding is null",
binding);
// Time out after a minute
binding.setTimeout(60000);
// Test operation
org.vivianj.beehive.samples.wsm.data.Customer[]
value = null;
value = binding.getAll();
// TBD - validate results
// 遍历服务器端返回的所有信息,打印 Customer 对象的 nickname
属性 // 根据实际情况可以增加 assertEquals 判断
If (value!=null){ For(int
I = 0;i<value.length;i++){
org.vivianj.beehive.samples.wsm.data.Customer
customer = (org.vivianj.beehive.samples.wsm.data.Customer) value[i];
System.out.println(“customer’s
nickname is ” + customer.getNickName());
}
} } |
public void test2ServiceSayHelloWorld() throws Exception
{
org.vivianj.www.samples.wsm.ServiceSoapBindingStub
binding;
try {
binding =
(org.vivianj.www.samples.wsm.ServiceSoapBindingStub)
new org.vivianj.www.samples.wsm.ServiceServiceLocator().getService();
}
catch (javax.xml.rpc.ServiceException
jre) {
if(jre.getLinkedCause()!=null)
jre.getLinkedCause().printStackTrace();
throw new
junit.framework.AssertionFailedError("JAX-RPC ServiceException caught:
" + jre);
}
assertNotNull("binding is null",
binding);
// Time out after a minute
binding.setTimeout(60000);
// Test operation
java.lang.String value = null;
value = binding.sayHelloWorld();
// TBD - validate results
String experted = “Hello World!”;
assertEquals(experted,value);
|
}
public void test3ServiceSayHelloWorldTo() throws Exception
{
org.vivianj.www.samples.wsm.ServiceSoapBindingStub
binding;
try {
binding =
(org.vivianj.www.samples.wsm.ServiceSoapBindingStub)
new org.vivianj.www.samples.wsm.ServiceServiceLocator().getService();
}
catch (javax.xml.rpc.ServiceException
jre) {
if(jre.getLinkedCause()!=null)
jre.getLinkedCause().printStackTrace();
throw new
junit.framework.AssertionFailedError("JAX-RPC ServiceException caught:
" + jre);
}
assertNotNull("binding is null",
binding);
// Time out after a minute
binding.setTimeout(60000);
// Test operation
java.lang.String value = null;
value = binding.sayHelloWorldTo(“ws”);
// TBD - validate results
String experted
= “Hello ws!”;
assertEquals(experted,value); |
}
public void test4ServiceRegisterCustomer() throws Exception
{
org.vivianj.www.samples.wsm.ServiceSoapBindingStub
binding;
try {
binding =
(org.vivianj.www.samples.wsm.ServiceSoapBindingStub)
new org.vivianj.www.samples.wsm.ServiceServiceLocator().getService();
}
catch (javax.xml.rpc.ServiceException
jre) {
if(jre.getLinkedCause()!=null)
jre.getLinkedCause().printStackTrace();
throw new
junit.framework.AssertionFailedError("JAX-RPC ServiceException caught:
" + jre);
}
assertNotNull("binding is null",
binding);
// Time out after a minute
binding.setTimeout(60000);
// Test operation
// 向服务器发送增加一个 Customer 对象的请求,参数为 Customer 实例
org.vivianj.beehive.samples.wsm.data.Customer customer = new org.vivianj.beehive.samples.wsm.data.Customer();
customer.setNickName(“vivianj”);
customer.setPassword(“wsm”);
binding.registerCustomer(customer); |
// TBD - validate results
}
public void test5ServiceGetCustomer() throws Exception {
org.vivianj.www.samples.wsm.ServiceSoapBindingStub
binding;
try {
binding =
(org.vivianj.www.samples.wsm.ServiceSoapBindingStub)
new org.vivianj.www.samples.wsm.ServiceServiceLocator().getService();
}
catch (javax.xml.rpc.ServiceException
jre) {
if(jre.getLinkedCause()!=null)
jre.getLinkedCause().printStackTrace();
throw new
junit.framework.AssertionFailedError("JAX-RPC ServiceException caught:
" + jre);
}
assertNotNull("binding is null",
binding);
// Time out after a minute
binding.setTimeout(60000);
// Test operation
org.vivianj.beehive.samples.wsm.data.Customer
value = null;
value = binding.getCustomer(0);
// TBD - validate results
String nickname = “vivianj”;
String password = “wsm”;
assertEquals(nickname,value.getNickName());
assertEquals(password,value.get Password ());
}
}
2. 准备环境
代码修改成功,还需要准备一下环境才能开始执行测试代码:因为junit不是ant的内置任务,所以你需要拷贝一份junit.jar到%ant_home%\lib目录下。
3. 运行测试任务
现在你可以运行下面的ant任务来完成测试工作:
Ant –f client-build.xml test
3 总结
Beehive中的Web服务开发非常简单和高效,Web服务的开发和发布过程被聚合到JWS文件的编写、编译中。
文章中简单的介绍了beehive中Web服务开发的核心部分—JWS文件,通过一个简单的例子,模拟了Web服务提供需要面对的常用应用场景,演示了如何编写、注释JWS文件来实现Web服务的全过程。

| 作者简介 |
 肖菁 |
肖菁 是唯J族(www.vivianj.org)创始人,BEA 杭州User Group负责人,自由撰稿人,开源项目BuildFileDesigner(buildfiledesign.sourceforge.net)和V-Security(v-security.sourceforge.net)创始人。 |
作者其它文章
|