如何利用现有 Java 类开发 Web 服务
最初撰稿时间:2004 年 11 月 4 日
最后更新时间:2006 年 1 月 18 日
作者:Jon Maron
简介
- 创建一个服务接口。该接口将公开服务提供的功能和操作。
- 创建一个服务实现类。该类只为服务接口中声明的每个方法提供实现。在本示例中,实现类将实例化一个底层 Bank 对象,并将方法调用委托给该对象。
- 生成 Web 服务的 WSDL 文件及其关联的产物(映射文件等)。WSDL 文件是基于所提供的服务接口生成的,这样现在可以创建客户端来访问该 Web 服务。
- 将服务打包为应用程序模块。服务类和所有关联的生成产物都被打包为标准的 J2EE 部署模块。
- 部署服务。将服务模块部署到 Oracle 应用服务器。
- 生成客户端代理。利用 WSDL 文件为已部署的服务生成客户端代理/存根。
- 编写客户端应用程序。编写一个利用客户端代理调用远程服务操作的应用程序。
前提条件
知识准备
软件需求
- 安装了 OracleAS 10.1.3(可以从
OTN 获得)
- Sun JDK 1.4.2_03 或更高版本(可以在
此处获得)
- Apache Ant 1.6.2 或更高版本,用于构建应用程序(可以从
此处获得)
符号
- %ORACLE_HOME% — 安装 OC4J 或 Oracle 应用服务器的目录
- %JAVA_HOME% — 安装 JDK 的目录
构建应用程序
现有的 Bank 实现
public class BankMemDB implements Bank{
public static BankMemDB newInstance();
public String addNewAccount(String name,float initBalance) throws AccountException;
public Account getAccount(String id);
public List getAccounts();
}
public class BankFactory {
public BankFactory();
public Bank createBank();
}
将 Bank 公开为 Web 服务
为了将现有 Bank 的实例公开为 Web 服务,我们将执行以下操作:
- 创建一个服务接口。该服务接口表示我们希望提供给客户端应用程序的功能和操作:
interface BankService extends java.rmi.Remote{
String createAccount(String acctName,float initBalance)
throws RemoteException, AccountException;
void deposit(String acctID, float amount)
throws RemoteException, AccountException;
void withdraw(String acctID, float amount)
throws RemoteException, AccountException;
float getBalance(String acctID, String acctName)
throws RemoteException, AccountException;
String getAccountID(String acctName)
throws RemoteException, AccountException;
}
您将注意到,该服务接口扩展了 java.rmi.Remote 接口,并且所有方法都抛出(至少是)java.rmi.RemoteException 异常(这是 JAX-RPC 规范的要求)。
- 创建一个服务实现。实现类 (BankServiceImpl) 将实现服务接口 (BankService),并将各种调用委托给它创建的 Bank 实例。例如,createAccount() 方法只调用底层 Bank 的 addNewAccount() 方法(m_bank 是从 BankFactory 获得的 BankMemDB 的实例):
public String createAccount(String acctName,float initBalance) throws RemoteException,AccountException {
return
m_bank.addNewAccount(acctName,initBalance);
}
创建客户端应用程序
生成、编译和部署应用程序m_endpoint
void demoGoodAccount() throws Exception {
String accountID =
m_endpoint.createAccount(DEMO_USER1,2000.50f);
// ... print statements removed for clarity ...
m_endpoint.deposit(accountID,500.50f);
float balance =
m_endpoint.getBalance(accountID,DEMO_USER1);
System.out.println("Current balance is now " + balance);
System.out.println("Withdrawing $250.00 from account");
m_endpoint.withdraw(accountID,250.00f);
balance =
m_endpoint.getBalance(accountID,DEMO_USER1);
}
here 运行示例
在本示例中,我们将创建一个将其功能包装并委托给底层 Bank 对象的银行 Web 服务。
检查方法文档分发
方法文档 zip 文件应包含以下内容:
- bottomup/src/ — 包含用于示例的所有 Java 源代码。
- client/bottomup/client
- BankAccountClient.java — 调用银行服务方法的客户端应用程序。
- service/bottomup/service
- Account.java — 银行帐户对象。
- AccountException
.java — 用于指示帐户违规的异常(资金不足、超出最大取款金额等)。
- Bank
.java — 由服务实现包装的 Bank 对象所公开的接口。
- BankFactory.java — 实例化实现 Bank 接口的对象的工厂。
- BankMemDB.java — Bank 接口的内存中实现。
- BankService.java — 银行 Web 服务的实现(实现 BankServiceInterface)。
- BankServiceInteface.java — 银行 Web 服务公开的接口。
- bottomup/
bottomup-how-to.html — 本文档。
- bottomup/build.xml — Ant 构建文件。
- bottomup/ant-oracle.xml — build.xml 使用它执行编译和部署 Web 服务与客户端所需的各种 Oracle 应用服务器任务。
- botomup/ant-oracle.properties — 正确处理示例的编译脚本所需的属性。
设置应用程序
请检查以确保以下属性在示例分发根目录下的
ant-oracle.properties 文件中配置正确(注意:某些属性将默认为相应环境变量的值,如下所示。如果您已经在环境中设置了这些变量,则不必在文件中更改这些值)。如果有必要,将这些变量修改为环境的相应值:
- oracle.home — oracle 安装的根目录。默认为 ORACLE_HOME 环境变量。
- java.home — JDK 安装的根目录。默认为 JAVA_HOME 环境变量。
- oracleas.host — 运行 OC4J 实例的平台的主机名。默认为 localhost。
- oracleas.http.port — OC4J HTTP 监听器监听的端口。默认为
8888。
- oracleas.admin.port — OC4J 管理处理器监听的端口。默认为
23791。
- oracleas.admin.user — OC4J 管理员的名称。默认为“
oc4jadmin”。
- oracleas.admin.password — OC4J 管理员的口令。默认为“
welcome”。
- oracleas.binding.module — 已部署应用程序绑定到的 HTTP Web 站点的名称。默认为“
default-web-site”。
此外,请确保与 OC4J ant 版本关联的 ant 命令位于执行路径 (
%ORACLE_HOME%/ant/bin) 中。
为受管理的 OracleAS 实例配置环境
如果您运行的是 Oracle 应用服务器 10
g 的受管理版本并且要使用 OPMN,则必须更改以下值以符合您的配置:
- oracleas.http.port — Oracle HTTP Server (OHS) 监听的端口。
- oracleas.admin.port — OPMN 请求端口,正如在 opmn.xml 中所指定的,默认值为 6003。还可以使用以下命令检查 OPMN 请求端口:
%ORACLE_HOME%/opmn/bin/opmnctl status -port
- oracleas.admin.user — OC4J 管理员的名称。默认为“
oc4jadmin”。
- oracleas.deployer.uri — 用于执行不同管理操作(部署、取消部署)的 URI。由于应用程序的拓扑结构不同,文件会包含不同的 URI:独立的 OC4J、受管理的单个节点或者受管理的集群。只需去掉与您的拓扑的 URI 相匹配的注释。
- oracleas.oc4j.instance — 这是受管理的 OC4J 实例,应用程序将在其中部署或取消部署。
此外,请确保与 OC4J ant 版本关联的 ant 命令位于执行路径 (
%ORACLE_HOME%/ant/bin) 中。
运行 OC4J 实例
g 生成、编译和部署应用程序
要生成、编译和部署该应用程序的组件,只需在示例根目录的命令提示符下键入以下命令:
要执行所提供的 build.xml 文件中默认的“所有”目标,请执行以下步骤:
- 编译
src/service 子目录中的所有 Web 服务源文件(银行和服务接口与实现)。
- 生成 WSDL 文件和关联产物(JAX-RPC 映射文件等)。该生成过程是通过
assemble ant 任务执行的:
serviceName="${app.name}"
interfaceName="bottomup.service.BankService"
className="bottomup.service.BankServiceImpl"
input="${bld.webservice.dir}"
output="${out.dir}"
ear="${lib.dir}/${ear.name}.ear">
- 部署应用程序模块。现在,使用
ant deploy ant 任务将上一步中生成的 .ear 文件部署到服务器:
host="${oc4j.host}"
port="${oc4j.admin.port}"
userId="${oc4j.admin.user}"
password="${oc4j.admin.password}"
file="${lib.dir}/${app.name}.ear"
deploymentName="${app.name}"
logFile="deploy-ear.log"/>
此外,为了使您能够通过 Oracle 应用服务器的 Web 层访问该服务,必须将其绑定到一个网站:
host="${oc4j.host}"
port="${oc4j.admin.port}"
userId="${oc4j.admin.user}"
password="${oc4j.admin.password}"
webModule="${web.name}"
webSiteName="${oc4j.binding.module}"
contextRoot="/${app.name}"/>
- 创建客户端代理源文件。一旦服务被部署并且可用,就可以通过可用的 WSDL 文件生成客户端代理(通过使浏览器指向 http://<OC4J host>:<OC4J http port>/bank/bank?wsdl 位置,您可以实际看到生成的 WSDL 服务文件)。
genProxy ant 任务就用于实现此目的:
output="${src.cli.dir}"
packageName="bottomup.client.proxy"
>
- 编译客户端应用程序和关联的代理文件。您需要编译上一步中生成的代理文件以及利用代理进行远程通信的客户端应用程序,并将它们放到
build/bank/bank-client 目录中。
运行应用程序
既然 Web 服务已经部署,并且客户端已经生成并编译,我们就可以运行应用程序了。在示例根目录的命令提示符下,只需键入以下命令:
该命令执行的客户端应用程序将执行以下操作和信息交换(下面的信息交换图是由 JDeveloper 10g TCP Packet Monitor 捕获的,用于说明在执行远程服务调用期间执行的底层信息交换):
- 最初使用 2000.50 美元为 DemoUser1 创建一个帐户:
- 向 DemoUser1 的帐户中再存入 500.50 美元:
- 从 DemoUser1 的帐户中提取 250.00 美元:
- 尝试用 0.00 美元为 DemoUser2 创建一个帐户。这个尝试将失败,因为金额不足:
- 最初使用 3000.00 美元为 DemoUser3 创建一个帐户:
- 尝试从 DemoUser3 的帐户中提取 2500.00 美元。这个尝试将失败,因为提取额超出了最大允许金额 2000.00 美元:
run:
[java] Created an account for DemoUser1 with $2000.50
[java] AccountID for DemoUser is 138.2.8.242_DemoUser1
[java] Depositing $500.50 into account.
[java] Current balance is now 2501.0
[java] Withdrawing $250.00 from account
[java] Attempting to create an account for DemoUser2 with no initial funds
[java] Could not createAccount for DemoUser2
[java] Insufficient funds for new account. You must start an account with more than $0
[java] Created an account for DemoUser3 with $3000.00
[java] Attempting to withdraw 2500.00 from the account. The account cap is 2000.00
[java] Unable to withdraw funds.
[java] Exceeded maximum withdrawal of $2000.00
BUILD SUCCESSFUL
总结
本方法文档详细说明了如何利用 Web 服务接口轻松地访问现有 Java 类。我们已经看到该过程包括:
- 创建一个公开所需功能的服务接口。
- 创建服务接口的一个实现,以利用现有类的实例服务于请求。
- 生成必需的服务产物(最重要的是描述服务的 WSDL 文件)。
- 将服务部署到 Oracle 应用服务器。
- 基于服务 WSDL 文件生成客户端代理代码。
- 编写一个利用客户端代理与已部署服务交互的客户端应用程序。