4.4 有状态会话EJB实例

  本小节演示如何开发和测试一个无状态会话EJB。本节提供的实例同样演示了一个简化的股票交易操作。示意图如图4-8所示。
  从上图看出,和上节的无状态EJB不同,每个客户端使用不同的TraderBean,TradeBean可以保存每个客户端的状态。
  通过这个实例,读者可以知道:
  ·如何定义有状态EJB的主接口,远程接口和如何编写EJB实现类。
  ·如何使用对象作为远程方法的返回值
  ·如何在ejb-jar.xml中定义和在无状态EJB中通过会话上下文使用环境参数
  ·如何在EJB中定义和使用异常

4.4.1 编写源文件

  这个例子的代码包括两个接口、三个类。我们把它们都定义在包examples.ejb.basic.statefulSession中,因此创建目录:C:\work\examples\ejb\basic\statefulSession。
  表4-2 有状态会话EJB文件列表
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  名称  类名  文件名  所在包
  ─────────────────────────────────
  主接口 TraderHome TraerHome.java examples.ejb.basic.statefulSession
  远程接口 Trader Traer.java examples.ejb.basic.statefulSession
  远程方法返回类 TraderResult TraerResult.java examples.ejb.basic.statefulSession
  Bean实现类 TraderBean TraderBean.java examples.ejb.basic.statefulSession
  用户定义异常 ProcessingErrorException ProcessingErrorException.java examples.ejb.basic.statefulSession
  客户端测试类 Client Client.java examples.ejb.basic.statefulSession
  Bean说明文件  ejb-jar.xml
  Bean部署文件  weblogic-ejb-jar.xml
  ─────────────────────────────────

  1. 主接口程序
  编辑文件TraderHome.java并保存到C:\work\src\examples\ejb\basic\statefulSession目录下(或从附带光盘的src\examples\ejb\basic\statefulSession目录拷贝),其源文件如下:

//定义本接口在包examples.ejb.basic.statefulSession中
package examples.ejb.basic.statefulSession;
//本接口用到的其他类
//javax.ejb.EJBHome定义了EJB主接口,被用户定义的主接口继承
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;

/**
* 这是TradeBean的主接口定义,这个接口是被EJB容器产生的类TraderBeanC实现的。
* 在这里只需定义EJB创建的方法,这些方法要和EJBean中的"ejbCreate"方法对应。
*/


//EJBean主接口必须继承javax.ejb.EJBHome接口
public interface TraderHome extends EJBHome {

/**
* 这个方法和"TraderBean.java"中定义的的Bean的"ejbCreate"方法相对应
* 这两个方法的参数应该相同。当客户端调用"TraderHome.create()"方法时,EJB容器
* 会找到EJBean的实例,并调用它的"ejbCreate()"方法。
*
* @返回 远程对象Trader
* @异常 RemoteException 当系统通讯发生故障时抛出
* @异常 CreateException 创建EJBean错误时抛出
* @参看 examples.ejb.basic.statefulSession.TraderBean
*/
Trader create() throws CreateException, RemoteException;
}

  2. 远程接口程序
  在远程接口中定义业务逻辑方法,这个接口中定义也三个业务逻辑方法,buy、sell和getBalance,分别对应股票交易中的买进、卖出和结算。
  编辑文件Trader.java并保存到C:\work\src\examples\ejb\basic\statefulSession目录下(或从附带光盘的src\examples\ejb\basic\statefulSession目录拷贝),其源文件如下:

//定义本接口在包examples.ejb.basic.statefulSession中
package examples.ejb.basic.statefulSession;
//本接口用到的其他类
//javax.ejb.*中定义了实现EJBean的接口。
import javax.ejb.*;
import java.rmi.RemoteException;

/**
* 这是TradeBean的远程接口定义。远程接口中定义了客户端能远程调用EJBean的方法。这些方法除了
* 要抛出异常java.rmi.RemoteException之外,和EJBean中的定义是一致的。但并不是EJBean来实
* 现这个接口,而是由容器自动产生的类TraderBeanE实现的。
*/
//这个接口必须继承javax.ejb.EJBObject接口
public interface Trader extends EJBObject {

/**
* 远程方法:购买指定用户和股票类别、数量的股票。
*
* @参数 customerName 顾客名
* @参数 stockSymbol 股票代码
* @参数 shares 购买股票的数量
* @返回 TradeResult 交易结果对象
* @异常 ProcessingErrorException
* 购买操作出错时抛出的异常
* @异常 RemoteException 当系统通讯发生故障时抛出
*/
public TradeResult buy(String customerName, String stockSymbol, int shares)
throws ProcessingErrorException, RemoteException;

/**
* 远程方法:出售指定用户和股票类别、数量的股票。
*
* @参数 customerName 顾客名
* @参数 stockSymbol 股票代码
* @参数 shares 出售股票的数量
* @返回 TradeResult Trade Result
* @异常 ProcessingErrorException
* 购买操作出错时抛出的异常
* @异常 RemoteException 当系统通讯发生故障时抛出
*/
public TradeResult sell(String customerName, String stockSymbol, int shares)
throws ProcessingErrorException, RemoteException;

/**
* 远程方法:返回本次交易的结算
*
* @返回 double 结算值
* @异常 RemoteException 当系统通讯发生故障时抛出 */
public double getBalance()
throws RemoteException;

}

  3. 远程方法返回结果类
   编辑文件TraderResult.java并保存到C:\work\src\examples\ejb\basic\statefulSession目录下(或从附带光盘的src\examples\ejb\basic\statefulSession目录拷贝),其源文件如下:

//定义本类在包examples.ejb.basic.statefulSession中
package examples.ejb.basic.statefulSession;

import java.io.Serializable;

/**
* 这个类代表买/卖股票的结果
*/
//远程方法使用的类必须实现Serializable接口
public final class TradeResult implements Serializable {
//定义买卖标志
public static final int SELL = 0;
public static final int BUY = 1;

private int numberTraded; // 真实的买卖数量
private int action; // 买卖动作变量
private double price; // 价格变量

/**
* 返回买卖交易数量和价格
* @参数 numberTraded int 交易数量
* @参数 price double 价格
* @参数 action int 动作
* @返回 TradeResult
*/
public TradeResult(int numberTraded, double price, int action) {
this.numberTraded = numberTraded;
this.price = price;
this.action = action;
}
//获取交易量
public int getNumberTraded() {
return numberTraded;
}
//获取动作,卖或买
public int getActionTaken() {
return action;
}
//获取价格
public double getPrice() {
return price;
}
//重载toString()方法。
public String toString() {
String result = numberTraded + " shares";
if(action == SELL) {
result += "sold";
} else {
result += "bought";
}
result += " at a price of " + price;
return result;
}
}

  4. Bean实现类
  Bean类用来实现在远程接口中定义的业务逻辑方法,这里简单地实现了buy、sell和getBalance方法。
  编辑文件TraderBean.java并保存到C:\work\src\examples\ejb\basic\statefulSession目录下(或从附带光盘的src\examples\ejb\basic\statefulSession目录拷贝),其源文件如下:

//定义本类在包examples.ejb.basic.statefulSession中
package examples.ejb.basic.statefulSession;
//本类用到的其他类。javax.ejb.*是开发EJB应用需要的类库。javax.naming.*是实现JNDI服务需要的类库。
import javax.ejb.CreateException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

/**
* TraderBean 是一个有状态EJB,它演示了如何:
* 在会话过程中如何自动保持用户的状态
* 从bean环境中获取参数
* 用户定义异常
*/
//这个类是会话Bean,因此必须实现接口 SessionBean

public class TraderBean implements SessionBean {
//设置是否打印控制台
static final boolean VERBOSE = true;
//声明会话上下文变量
private SessionContext ctx;
//声明环境上下文变量
private Context environment;
//声明与业务相关的变量:交易结算
private double tradingBalance;

/**
* 设置会话上下文变量
*
* @参数 ctx SessionContext Context for session
*/
public void setSessionContext(SessionContext ctx) {
log("setSessionContext called");
this.ctx = ctx;
}

/**
* 这是本类必须实现的方法,在本例中没有用到
*
*/
public void ejbActivate() {
log("ejbActivate called");
}

/**
* 这是本类必须实现的方法,在本例中没有用到
*/
public void ejbPassivate() {
log("ejbPassivate called");
}

/**
* 这是本类必须实现的方法,在本例中没有用到
*/
public void ejbRemove() {
log("ejbRemove called");
}

/**
* 这个方法与"TraderHome.java"中定义的主接口中的"create"方法相对应
* 两个方法的参数相同。当客户端调用主接口的"TraderHome.create()"方法时,
* 容器会分配一个EJBean实例,并调用它的"ejbCreate()"方法。
*
* @异常 javax.ejb.CreateException 创建EJBean出错时抛出的异常
* @参看 examples.ejb.basic.statefulSession.Trader
*/
public void ejbCreate() throws CreateException {
log("ejbCreate called");
try {
//初始化JNDI名称服务上下文
InitialContext ic = new InitialContext();
//从配置文件(ejb-jar.xml)中获取环境变量上下文,相当于初始化参数
environment = (Context) ic.lookup("java:comp/env");
} catch (NamingException ne) {
//如果名称服务器异常,则抛出 CreateException异常
throw new CreateException("Could not look up context");
}
//业务变量赋初值
this.tradingBalance = 0.0;
}

/**
* 购买指定用户和股票类别、数量的股票。
*
* @参数 customerName 顾客名
* @参数 stockSymbol 股票代码
* @参数 shares 购买股票的数量
* @返回 TradeResult 交易结果对象
* @异常 ProcessingErrorException
* 购买操作出错时抛出的异常
* @异常 RemoteException 当系统通讯发生故障时抛出
*/
public TradeResult buy(String customerName, String stockSymbol, int shares)
throws ProcessingErrorException
{
//控制台提示
log("buy (" + customerName + ", " + stockSymbol + ", " + shares + ")");
//从环境变量中获取价格参数
double price = getStockPrice(stockSymbol);
//计算本次交易结算
tradingBalance -= (shares * price); // subtract purchases from cash account
//返回本次交易结果对象
return new TradeResult(shares, price, TradeResult.BUY);
}

/**
* 出售指定用户和股票类别、数量的股票。
*
* @参数 customerName 顾客名
* @参数 stockSymbol 股票代码
* @参数 shares 出售股票的数量
* @返回 TradeResult Trade Result
* @异常 ProcessingErrorException
* 购买操作出错时抛出的异常
* @异常 RemoteException 当系统通讯发生故障时抛出
*/
public TradeResult sell(String customerName, String stockSymbol, int shares)
throws ProcessingErrorException
{
//控制台提示
log("sell (" + customerName + ", " + stockSymbol + ", " + shares + ")");
//从环境变量中获取价格参数
double price = getStockPrice(stockSymbol);
//计算本次交易结算
tradingBalance += (shares * price);
//返回本次交易结果对象
return new TradeResult(shares, price, TradeResult.SELL);
}

/**
* Returns the current balance of a trading session.
*
* @返回 double 结算值
*/
public double getBalance() {
return tradingBalance;
}

/**
* 返回给定股票的价格
*
* @参数 stockSymbol String 股票代号
* @返回 double 股票价格
* @异常 examples.ejb.basic.statefulSession.ProcessingErrorException
* 当获取参数发生异常时抛出
*/
public double getStockPrice(String stockSymbol)
throws ProcessingErrorException
{
try {
//从环境变量上下文中查找给定股票代号的股票价格
return ((Double) environment.lookup(stockSymbol)).doubleValue();
} catch (NamingException ne) {
//当出现问题时,生成自定义的异常实例ProcessingErrorException,并抛出
throw new ProcessingErrorException ("Stock symbol " + stockSymbol +
" does not exist");
} catch (NumberFormatException nfe) {
// ejb-jar.xml文件中含非有效数字时,抛出这个异常,
// 生成自定义的异常实例ProcessingErrorException,并抛出
throw new ProcessingErrorException("Invalid price for stock "+stockSymbol);
}
}
//控制台输出
private void log(String s) {
if(VERBOSE) {
System.out.println(s);
}
}
}

  5. 用户定义异常类
  编辑文件ProcessingErrorException.java并保存到C:\work\src\examples\ejb\basic\statefulSession目录下(或从附带光盘的src\examples\ejb\basic\statefulSession目录拷贝),其源文件如下:

//定义本类在包examples.ejb.basic.statefulSession中
package examples.ejb.basic.statefulSession;

/**
* 这是用户定义的异常类
*/
//用户定义的异常类必须继承Exception
public class ProcessingErrorException extends Exception {

/**
* 获取没有字符串参数的异常
*
*/
public ProcessingErrorException() {}

/**
* 用特定的字符串构造异常
*
* @参数 message Exception 消息
*/
public ProcessingErrorException(String message) {super(message);}
}

  6. 编辑部署文件
  会话EJB使用两个部署说明文件,ejb-jar.xml用来描述EJB的结构、类型、环境参数等。weblogic-ejb-jar.xml用来描述与部署相关的信息。
  编辑文件ejb-jar.xml和weblogic-ejb-jar.xml并一起保存到C:\work\src\examples\ejb\basic\statefulSession目录下(或从附带光盘的src\examples\ejb\basic\statefulSession目录拷贝)。ejb-jar.xml源文件如下:

<?xml version="1.0"?>

<!DOCTYPE ejb-jar PUBLIC '-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN' 'http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd'>

<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>statefulSession</ejb-name>
<home>examples.ejb.basic.statefulSession.TraderHome</home>
<remote>examples.ejb.basic.statefulSession.Trader</remote>
<ejb-class>examples.ejb.basic.statefulSession.TraderBean</ejb-class>
<session-type>Stateful</session-type>
<transaction-type>Container</transaction-type>
<env-entry>
<env-entry-name>BEAS</env-entry-name>
<env-entry-type>java.lang.Double </env-entry-type>
<env-entry-value>100.0</env-entry-value>
</env-entry>
<env-entry>
<env-entry-name>MSFT</env-entry-name>
<env-entry-type>java.lang.Double </env-entry-type>
<env-entry-value>150.0</env-entry-value>
</env-entry>
</session>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>statefulSession</ejb-name>
<method-intf>Remote</method-intf>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>

  ejb-jar.xml可以分为以下几个部分:
  <ejb-name>:定义这个EJB的名字,这里命名为statefulSession。
  <home>:指定主接口,这里指定为examples.ejb.basic.statefulSession.TraderHome。
  <remote>:指定远程接口,这里指定为examples.ejb.basic.statefulSession.Trader。
  <ejb-class>:指定EJB类,这里指定为examples.ejb.basic.statefulSession.TraderBean。
  <session-type>:定义会话类型,这里定义为Stateful,有状态。
  <env-entry>:定义环境参数名和值,可以通过EJB类中上下文对象的lookup方法获取。
  weblogic-ejb-jar.xml的源文件如下:

<?xml version="1.0"?>

<!DOCTYPE weblogic-ejb-jar PUBLIC '-//BEA Systems, Inc.//DTD WebLogic 5.1.0 EJB//EN' 'http://www.bea.com/servers/wls510/dtd/weblogic-ejb-jar.dtd'>

<weblogic-ejb-jar>
<weblogic-enterprise-bean>
<ejb-name>statefulSession</ejb-name>
<caching-descriptor>
<max-beans-in-cache>100</max-beans-in-cache>
</caching-descriptor>
<jndi-name>statefulSession.TraderHome</jndi-name>
</weblogic-enterprise-bean>
</weblogic-ejb-jar>

  weblogic-ejb-jar.xml文件主要定义了与EJB部署相关的信息,主要有:
  <ejb-name>:EJB的名字,这里是statefulSession。
  <caching-descriptor>:EJB缓冲池描述,这里定义了自由池的EJB实例数。
  7. 客户端测试程序代码编写
  编辑文件Client.java并保存到C:\work\src\examples\ejb\basic\statefulSession目录下(或从附带光盘的src\examples\ejb\basic\statefulSession路径下拷贝),其代码如下:

//定义本类在包examples.ejb.basic.statefulSession中
package examples.ejb.basic.statefulSession;
//本类用到的其他类
import java.rmi.RemoteException;
import java.util.Properties;
import javax.ejb.CreateException;
import javax.ejb.RemoveException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;

/**
* 这个类演示了如何调用一个会话,并进行如下操作:
* 创建一个Trader远程对象
* 使用Trader远程对象购买一定数量的股票
* 出售一定数量的股票
* 清除Trader远程对象
*/
public class Client {
//定义JNDI服务中EJB的名称
private static final String JNDI_NAME = "statefulSession.TraderHome";
//声明应用服务器的URL变量
private String url;
//声明主接口变量
private TraderHome home;

public Client(String url)
throws NamingException
{

this.url = url;
//寻找主接口
home = lookupHome();
}

/**
* 在命令行运行这个实例:
* java examples.ejb.basic.statefulSession.Client "t3://localhost:7001"
* 参数是可选的
*/
public static void main(String[] args) {
log("\nBeginning statefulSession.Client...\n");
//声明应用服务器地址变量
String url = "t3://localhost:7001";

// Parse the argument list
if (args.length != 1) {
//打印用法提示
System.out.println("Usage: java examples.ejb.basic.statefulSession.Client t3://hostname:port");
return;
} else {
url = args[0];
}

Client client = null;

try {
//创建客户端实例
client = new Client(url);
} catch (NamingException ne) {
System.exit(1);
}

try {
//调用测试方法
client.example();
} catch (Exception e) {
//异常处理
log("There was an exception while creating and using the Trader.");
log("This indicates that there was a problem communicating with the server: "+e);
}

log("\nEnd statefulSession.Client...\n");
}

/**
* 运行实例
*/
public void example()
throws CreateException, ProcessingErrorException, RemoteException,
RemoveException
{
//声明顾客名字变量
String customerName = "Matt";

// 创建远程对象
log("创建 trader\n");
Trader trader = (Trader) narrow(home.create(), Trader.class);

// 出售一些股票
//股票名
String stockName = "MSFT";
//股票数量
int numberOfShares = 200;
log("Selling " + numberOfShares + " of " + stockName);
//调用远程方法sell
TradeResult tr = trader.sell(customerName, stockName, numberOfShares);
log(tr.toString());

// 买进一些股票
//股票名
stockName = "BEAS";
//股票数量
numberOfShares = 250;
log("Buying " + numberOfShares + " of " + stockName);
//调用远程方法buy
tr = trader.buy(customerName, stockName, numberOfShares);
log(tr.toString());

// Get change in Cash Account from EJBean
log("Change in Cash Account: $" + trader.getBalance()
+ "\n");
log("Removing trader\n");
//清除远程对象
trader.remove();

}

/**
* 验证远程对象的类型
*/
private Object narrow(Object ref, Class c) {
return PortableRemoteObject.narrow(ref, c);
}

/**
* 从JNDI树中寻找EJB主接口
*/
private TraderHome lookupHome()
throws NamingException
{
// 获取JNDI服务上下文
Context ctx = getInitialContext();

try {
//获取名称对象
Object home = ctx.lookup(JNDI_NAME);
//获取主接口实例
return (TraderHome) narrow(home, TraderHome.class);
} catch (NamingException ne) {
//异常处理
log("The client was unable to lookup the EJBHome. Please make sure ");
log("that you have deployed the ejb with the JNDI name "+JNDI_NAME+" on the WebLogic server at "+url);
throw ne;
}
}

/**
* 使用属性对象获取JNDI服务上下文
* clients
*/
private Context getInitialContext() throws NamingException {

try {
// 声明属性对象
Properties h = new Properties();
h.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
h.put(Context.PROVIDER_URL, url);
//返回的特定属性的上下文对象
return new InitialContext(h);
} catch (NamingException ne) {
//异常处理
log("We were unable to get a connection to the WebLogic server at "+url);
log("Please make sure that the server is running.");
throw ne;
}
}

/**
* 这是获取上下文的第二个版本,依赖一个jndi.properties文件
*
*/
// private static Context getInitialContext()
// throws NamingException
// {
// return new InitialContext();
// }
//打印控制台输出
private static void log(String s) {
System.out.println(s);
}

}

4.4.2 编译与打包

  1. 编译代码
  ·打开命令窗口,进入c:\work\src\examples\ebj\basic\statefulSession目录。
  ·运行设置环境变量命令脚本setEnv.cmd:
  c:\work\src\examples\ejb\basic\statefulSession>c:\work\setEnv
  ·编译好的代码要放在build目录下,因此在编译之前要创建build目录:
  c:\work\src\examples\ebj\basic\statefulSession、>md build
  ·打开命令行窗口,进入c:\work\src\examples\ebj\basic\statefulSession目录,运行:
  c:\work\src\examples\ebj\basic\statefulSession>javac -d build Trader.java TraderHome.java TradeResult.java ProcessingErrorException.java TraderBean.java
  其中 -d build 表示编译后的字节码文件放在build子目录下。
  这个命令执行的结果是在build目录下生成examples目录。
  2. 打包
  打包之前,拷贝必要的文件到规定的目录。继续使用上面的步骤的命令窗口,运行如下命令:
  c:\work\src\examples\ejb\basic\statefulSession>mkdir build
  c:\work\src\examples\ejb\basic\statefulSession>mkdir build\META-INF
  c:\work\src\examples\ejb\basic\statefulSession>copy *.xml build\META-INF
  用jar命令打包,包括三部分文件,分别在build目录的三个子目录下:
  ·META-INF:xml部署文件
  ·examples:类文件
  在命令窗口中继续运行如下命令:
  c:\work\src\examples\ejb\basic\statefulSession>cd build
  c:\work\src\examples\ejb\basic\statefulSession>jar cv0f std_ejb_basic_statefulSession.jar META-INF examples
  这个命令执行的结果是在build目录下生成std_ejb_basic_statefulSession.jar文件。
  3.编译容器代码
  编译容器代码是个和应用服务器平台相关的一个操作。WebLogic Server 6.0自带了一个容器代码编译工具,weblogic.ejbc,这是个java程序,并包含在weblogic.jar包中。
  在命令窗口中继续运行如下命令:
  c:\work\src\examples\ejb\basic\statefulSession>java weblogic.ejbc -compiler javac build\std_ejb_basic_statefulSession.jar
  该命令生成的代码直接放到了该EJB部署的目录。
  4. 编译客户端代码
  这是个客户端程序,把客户端程序入在一个目录下,这里用c:\bea\wlserver6.0\config\mydomain\clientclasses。
   如果目录C:\bea\wlserver6.0\config\mydomain下没有子目录clientclasses,则创建子目录clientclasses。
  另外,为了让其它的的Servlet程序或JSP(例如第13章的XML示例)能够使用这个EJB,把EJB的客户端代码也放在C:\bea\wlserver6.0spl\config\mydomain\applications\DefaultWebApp_myserver\WEB-INF\class目录一份,因此,如果目录C:\bea\wlserver6.0\config\mydomain\DefaultWebApp_myserver\WEB-INF下没有子目录classes,则创建子目录classes。
  在命令窗口中继续运行如下命令:
  c:\work\src\examples\ejb\basic\statefulSession>javac -d %CLIENT_CLASSES% Trader.java TraderHome.java TradeResult.java ProcessingErrorException.java Client.java
  5. 脚本命令文件build.cmd
  上面在EJB的开发过程中使用命令行的方式,我们可以把所有这些命令行集中起来做成一个命令脚本文件,用这个命令脚本文件,可以一次性执行这些命令,而不必一个命令一个命令的执行。该文件名为build.cmd,放在C:\work\examples\ejb\basic\statefulSession目录。用户可以直接从光盘的\work\examples\ejb\basic\statefulSession目录中拷贝,也可以用文本编辑器编写。C:\work\examples\ejb\basic\statefulSession\build.cmd文件的内容为:

@REM 创建 build 目录,拷贝部署描述符文件
mkdir build
mkdir build\META-INF
copy *.xml build\META-INF

@REM 编译 EJB 类文件
javac -d build Trader.java TraderHome.java TradeResult.java ProcessingErrorException.java TraderBean.java

@REM 打包成 jar 文件,包括 XML 形式的部署文件
cd build
jar cv0f std_ejb_basic_statefulSession.jar META-INF examples
cd ..

@REM 运行 EJBC
java weblogic.ejbc -compiler javac build\std_ejb_basic_statefulSession.jar %WL_HOME%\config\%DOMAIN_NAME%\applications\ejb_basic_statefulSession.jar

@REM 确保 Servlets 和 Jsp能访问这个 EJB
javac -d %EX_WEBAPP_CLASSES% Trader.java TraderHome.java TradeResult.java ProcessingErrorException.java

@REM 编译客户端程序,确保客户端程序能访问这个 EJB
javac -d %CLIENT_CLASSES% Trader.java TraderHome.java TradeResult.java ProcessingErrorException.java Client.java

  这样,在程序代码文件编辑好的情况下,只运行这个命令脚本程序,就可完成EJB开发。
  注意 运行build.cmd之前,仍然要运行设置环境变量脚本命令servEnv.cmd:
  C:\work\src\examples\ejb\basic\statefulSession>c:\work\setEnv.cmd

4.4.3 运行测试

  首先,启动WebLogic Server 6.0的缺省服务器。运行测试程序。继续使用前几个步骤使用的命令窗口,执行:  C:\work\src\examples\ejb\basic\statefulSession>java examples.ejb.basic.statefulSession.Client t3://127.0.0.1:7001/
  观察命令窗口的运行情况,如图4-5所示。
  同时,在WebLogic服务器端的命令窗口,显示如图4-10所示。