级别: 中级 Alec Go, 软件工程师 , IBM
2006 年 5 月 08 日 了解如何创建 Web 服务提供程序(包括部署描述符和 Java 类),学习如何使用 Java 编译器、Java2WSDL 和 WSDL2Java 命令行工具。
引言
尽管像 WebSphere® Studio Application Developer (Application Developer) 或 Rational® Application Developer 之类的集成开发环境 (IDE) 可以帮助创建 Web 服务,但有时候客户可能无法使用此类工具。本文说明如何在仅使用命令行工具的情况下创建 Web 服务提供程序,并在其中包含若干 Java 类和部署描述符。您将了解创建非常简单的 Web 服务所需的基本文件。在开发 Web 服务提供程序的过程中,您将使用随 WebSphere Application Server 一起提供的命令行工具,如 Java 编译器、WSDL2Java 和 Java2WSDL。本系列的第 2 部分将说明如何创建访问此 Web 服务的客户机。
仅使用命令行工具创建 Web 服务提供程序的基本步骤如下:
- 生成服务端点接口 (SEI)。
- 从 SEI 生成 Web 服务描述语言(Web Services Description Language,WSDL)文件。
- 从 WSDL 文件生成 Web 服务骨架。
- 打包 Web 存档 (WAR) 文件。
- 部署 Web 服务
本文假定已具备以下先决条件:
- 您使用的是 Microsoft® Windows®。
- 您已经安装了 WebSphere Application Server 5.x 或 6.x 许可版或试用版(有关如何获得 WebSphere Application Server 5.x 或 6.x 的信息,请参阅参考资料部分)。
创建 SEI
在本文中,Web 服务是以服务端点接口 (SEI) 为基础生成的。
SEI 是对 Web 服务函数概况的描述。编程接口常常用于描述分布式计算中的远程函数。例如,Enterprise JavaBeans 包含组件接口的概念,公共对象请求代理体系结构(Common Object Request Broker Architecture,CORBA®)包含接口定义语言(Interface Definition Language,IDL)文件的概念,而 Java RMI 则包含扩展 java.rmi.Remote 的 Java 接口的概念。J2EE Web 服务要求使用 SEI,因而也具有类似的模式。
对于“Hello World”Web 服务,相应的 SEI 将与以下所示内容类似:
package mypackage;
public interface HelloWorld extends java.rmi.Remote {
public java.lang.String sayHello() throws java.rmi.RemoteException;
}
|
这是一个非常简单的接口,包含一个名为 sayHello 的函数。此函数将返回一个 java.lang.String 对象。为了让接口成为有效的 SEI,该接口必须扩展 java.rmi.Remote,并且每个方法都应抛出 java.rmi.RemoteException。
请执行以下步骤:
- 创建起始目录 c:\temp\Server。在该目录中,创建一个名为 mypackage 的目录。该目录将保存 Web 服务的所有相关类文件。
- 在 c:\temp\Server\mypackage 内创建一个名为 HelloWorld.java 的文件。将以下代码复制粘贴到此文件中:
package mypackage;
public interface HelloWorld extends java.rmi.Remote {
public java.lang.String sayHello() throws java.rmi.RemoteException;
}
|
- WebSphere 命令行工具仅在类文件(而非源文件)上工作。为了继续下一步工作,必须将 Java 文件编译成类文件。打开新的命令行窗口。请确保在本教程的后续操作中都使用此命令行窗口。在该窗口中发出以下命令:
SET WAS_HOME=C:\Program Files\WebSphere\AppServer5.1
call "%WAS_HOME%\bin\setupcmdline.bat"
"%JAVA_HOME%\bin\javac" -extdirs "%WAS_CLASSPATH%;%WAS_EXT_DIRS%;." mypackage\*.java
|
第一行将 WAS_HOME 环境变量设置为安装 WebSphere Application Server 的位置。第二行调用一个脚本,以设置其他环境变量,如 JAVA_HOME。最后一行调用 Java 编译器来编译您创建的 SEI。
- 运行了这些命令后,应该已在 c:\temp\Server\mypackage 中创建了一个名为 HelloWorld.class 的新文件。请确保已创建了这个类文件。
从 SEI 生成 WSDL 文件
WSDL 文件描述 Web 服务。它定义 Web 服务和 Web 服务客户机之间的接口。尽管 SEI 也对 Web 服务进行描述,但其描述是特定于 Java 的,仅对 Java 程序具有可读性。而 WSDL 文件则是以独立于语言的方式对 Web 服务进行描述的。.NET 开发人员或 PHP 开发人员可以使用 WSDL 文件来开发各自的客户机。为了生成 Web 服务,您需要首先获得一个 WSDL 文件。WSDL 可以通过使用 Java2WSDL 命令从 SEI 生成,如下所示:
call "%WAS_HOME%\bin\Java2WSDL" -style document -use literal -verbose -location
http://localhost:9080/HelloWorldWAR/services/HelloWorld mypackage.HelloWorld
|
以下是有关各个选项的一些详细信息:
- style——可以为“document”或“rpc”。这与 SOAP 消息的格式设置有关。通常来说,document 比 rpc 的互操作性更强,因此这里选择 document。rpc 样式通常会导致出现数组方面的问题。
- literal——可以为“literal”或“encoded”。这与服务器和客户机如何解释 SOAP 消息中的信息相关。使用 encoded 几乎会始终出现互操作问题,因此选择 literal。
- verbose——针对执行的每个步骤都会有消息输出到控制台。
- location——这指定 Web 服务的端点。端点是 Web 服务客户机将用于发送其信息的位置。
- class——最后一个命令行参数是类名称。
运行 Java2WSDL 命令后,应该在控制台显示以下内容:
WSWS3429I: Binding-specific properties are {MIMEStyle=WSDL11, use=literal, debug=false,
style=document,
bindingName=HelloWorld, encodingStyle=http://schemas.xmlsoap.org/soap/encoding/,
verbose=true, wrapped=true, portTypeName=HelloWorld, servicePortName=HelloWorld,
intfNS=http://mypackage, location=
http://localhost:9080/HelloWorldWAR/services/HelloWorld,
soapAction=DEFAULT}
WSWS3010I: Info: Generating portType {http://mypackage}HelloWorld
WSWS3010I: Info: Generating message {http://mypackage}sayHelloRequest
WSWS3010I: Info: Generating message {http://mypackage}sayHelloResponse
WSWS3010I: Info: Generating binding {http://mypackage}HelloWorldSoapBinding
WSWS3010I: Info: Generating service {http://mypackage}HelloWorldService
WSWS3010I: Info: Generating port HelloWorld
|
请注意,从 Java2WSDL 生成的唯一文件就是相应的 WSDL 文件。
从 WSDL 生成服务器端构件和 SEI
WSDL 文件对于生成 Web 服务非常关键。J2EE Web 服务基本上就是类文件和部署描述符的集合。请使用 WSDL2Java 命令生成这些构件:
call "%WAS_HOME%\bin\WSDL2Java" -genJava overwrite -genXML overwrite
-role server -container web -verbose -output . HelloWorld.wsdl
|
应当在控制台显示以下内容:
WSWS3185I: Info: Parsing XML file: HelloWorld.wsdl
WSWS3282I: Info: Generating .\mypackage\HelloWorld.java.
WSWS3282I: Info: Generating .\mypackage\HelloWorldSoapBindingImpl.java.
WSWS3282I: Info: Generating .\WEB-INF\webservices.xml.
WSWS3282I: Info: Generating .\WEB-INF\ibm-webservices-bnd.xmi.
WSWS3282I: Info: Generating .\WEB-INF\ibm-webservices-ext.xmi.
WSWS3282I: Info: Generating .\WEB-INF\HelloWorld_mapping.xml.
|
请注意生成的各个文件。实际实现类是 HelloWorldSoapBindingImpl.java,该类包含以下内容:
package mypackage;
public class HelloWorldSoapBindingImpl implements mypackage.HelloWorld{
public java.lang.String sayHello() throws java.rmi.RemoteException {
return null;
}
}
|
sayHello 函数可以从远程客户机实际进行调用。请将此与 SEI (HelloWorld) 加以比较:
package mypackage;
public interface HelloWorld extends java.rmi.Remote {
public java.lang.String sayHello() throws java.rmi.RemoteException;
}
|
HelloWorldSoapBindingImpl 是实际的端点实现,而 HelloWorld 是接口。HelloWorldSoapBindingImpl 实现 HelloWorld。
WSDL2Java 生成 HelloWorldSoapBindingImpl,而后者实际上是实现的骨架。目前它不进行任何操作——sayHello 仅返回 null。开发人员应该在其中填写实现的代码。对于此示例,将“return null”行更改为返回一个字符串。将 HelloWorldSoapBindingImpl.java 更改为与以下所示内容类似:
package mypackage;
public class HelloWorldSoapBindingImpl implements mypackage.HelloWorld{
public java.lang.String () throws java.rmi.RemoteException {
return "Hello World";
}
}
|
现在已经完成了实现,接下来应当对所有 Java 类进行编译。发出以下命令:
"%JAVA_HOME%\bin\javac" -extdirs "%WAS_CLASSPATH%;%WAS_EXT_DIRS%;." mypackage\*.java
|
打包 WAR 文件
Web 服务是 J2EE 规范的一部分。服务要尽可能多地重用当前规范。实现此操作的一个方法是像 Servlet 一样打包成 Web 存档 (WAR) 文件。在 WAR 文件中,WEB-INF 目录用于存储公众不可直接访问的文件。对于 Web 服务 WAR 文件,通常的结构与以下所示类似:
- WEB-INF\classes\——保存已编译的类(例如,Web 服务实现和接口类)
- WEB-INF\wsdl\——保存 Web 服务 WSDL 文件
- WEB-INF\web.xml——WAR 文件部署描述符
- WEB-INF\webservices.xml——Web 服务部署描述符
请将所有这些元素放置在一起,以手动创建 Web 服务 WAR。
- 首先,在 WEB-INF 中创建一个名为 classes 的目录。将 mypackage 目录复制到 classes 目录中。应该具有以下目录结构:
WEB-INF\classes\mypackage\HelloWorld.class
WEB-INF\classes\mypackage\HelloWorld.java
WEB-INF\classes\mypackage\HelloWorldSoapBindingImpl.class
WEB-INF\classes\mypackage\HelloWorldSoapBindingImpl.java
|
- 然后,Java2WSDL 命令应该已创建了一个 wsdl 目录。将 WSDL 文件复制到 WEB-INF\wsdl\ 目录中。必须将 WDSL 文件放置到此位置。
- 在 WEB-INF 文件夹内创建 web.xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app id="WebApp">
<display-name>HelloWorldWAR</display-name>
<servlet>
<servlet-name>mypackage_HelloWorldSoapBindingImpl</servlet-name>
<servlet-class>mypackage.HelloWorldSoapBindingImpl</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
</web-app>
|
servlet 标记内的条目非常重要。此元素对 Web 服务端点实现进行描述。servlet-name 元素 (mypackage_HelloWorldSoapBindingImpl) 充当 Web 服务实现的标识符。“servlet-class”元素 (mypackage.HelloWorldSoapBindingImpl) 对 WEB-INF\classes 目录中将要作为实现使用的类文件进行标识。对 WEB-INF\webservices.xml 进行更改。该文件最初与以下所示内容类似:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE webservices PUBLIC "-//IBM Corporation, Inc.//DTD J2EE Web services 1.0//EN"
"http://www.ibm.com/webservices/dtd/j2ee_web_services_1_0.dtd">
<webservices>
<webservice-description>
<webservice-description-name>HelloWorldService</webservice-description-name>
<wsdl-file>WEB-INF/wsdl/HelloWorld.wsdl</wsdl-file>
<jaxrpc-mapping-file>WEB-INF/HelloWorld_mapping.xml</jaxrpc-mapping-file>
<port-component>
<port-component-name>HelloWorld</port-component-name>
<wsdl-port>
<namespaceURI>http://mypackage</namespaceURI>
<localpart>HelloWorld</localpart>
</wsdl-port>
<service-endpoint-interface>mypackage.HelloWorld</service-endpoint-interface>
<service-impl-bean>
<servlet-link>??SET THIS TO servlet-name ELEMENT OF web.xml??</servlet-link>
</service-impl-bean>
</port-component>
</webservice-description>
</webservices> |
- 需要加以考虑的元素是 servlet-link。将此值更改为 mypackage_HelloWorldSoapBindingImpl。这会将 Web 服务链接到 web.xml 文件中的一个条目。webservices.xml 文件现在应与以下所示内容类似:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE webservices PUBLIC "-//IBM Corporation, Inc.//DTD J2EE Web services 1.0//EN"
"http://www.ibm.com/webservices/dtd/j2ee_web_services_1_0.dtd">
<webservices>
<webservice-description>
<webservice-description-name>HelloWorldService</webservice-description-name>
<wsdl-file>WEB-INF/wsdl/HelloWorld.wsdl</wsdl-file>
<jaxrpc-mapping-file>WEB-INF/HelloWorld_mapping.xml</jaxrpc-mapping-file>
<port-component>
<port-component-name>HelloWorld</port-component-name>
<wsdl-port>
<namespaceURI>http://mypackage</namespaceURI>
<localpart>HelloWorld</localpart>
</wsdl-port>
<service-endpoint-interface>mypackage.HelloWorld</service-endpoint-interface>
<service-impl-bean>
<servlet-link>mypackage_HelloWorldSoapBindingImpl<servlet-link>
</service-impl-bean>
</port-component>
</webservice-description>
</webservices> |
- 创建 WAR 文件。使用您喜欢的 zip 程序来从 WEB-INF 目录创建 WAR 文件。如果您使用的是 WinZip,则可以执行以下步骤:
- 右键单击 WEB-INF 目录。
- 单击 WinZip --> Add to zip
- 将该文件命名为 HelloWorld.war。WAR 文件应与以下所示内容类似:
图 1. 管理控制台中的视图

 |

|
部署 Web 服务
在 WebSphere Application Server Administration Console 中安装这个新 WAR 文件。转到 Applications --> Enterprise Applications --> Install。将 Local Path 指定为 HelloWorld.war 的位置,而将 Context Root 指定为 HelloWorldWAR。
图 2. WinZip 中的视图
请注意,最初创建 WSDL 文件时,location 参数是设置为“http://localhost:9080/HelloWorldWAR/services/HelloWorld”的。因此,Context Root 必须为“HelloWorldWAR”,以便可以将 WSDL 文件用于生成客户机,而无需进行手动更改。
单击 Next 并继续单击 Next 通过所有的缺省设置。完成安装 WAR 文件。请记得保存所有更改,然后手动启动 HelloWorld 应用程序。
祝贺您!您已经成功地创建了一个 Web 服务提供程序!
结束语
在不使用 Application Developer 或 Rational Application Developer 之类的集成开发环境的情况下创建 Web 服务可能让人感到非常困难。不过,这对于了解在 IDE 向导背后实际发生的各个操作非常重要。在本系列的第 2 部分,您将创建一个 Web 服务客户机来调用此 Web 服务。
下载 | 描述 | 名字 | 大小 | 下载方法 |
|---|
| Hello World WAR file - the finished product | ws-noide1code.war | 6KB | HTTP |
|---|
参考资料 学习
获得产品和技术
讨论
关于作者  | |  | Alec Go 是 IBM WebSphere Application Server Level 2 Support 的一名软件工程师。他取得了宾夕法尼亚州立大学的计算机工程学士学位,并且以优异的成绩毕业。 |
对本文的评价
|