第3课
与EJB互操作的Enterprise Bean

[<<返回] [目录] [下一个>>]

在第2课“简单entity bean”中, 由Servlet负责查找和创建Session Bean, 并进行bonus计算,然后查找和创建 entity bean并储存bonus 值和相关的社会安全号码。这一课对该范例进行了修 改,使session bean负责查找和创建entity bean。 由于session bean 和 entity bean是合作的关系,因此,它们被捆绑到一个JAR文件中进行部署。

注:有些人在学习这一课时,对如何在一个JAR 文件中处理2个Bean的问题感到困惑。如果你也出现这样问题,那么可以删除带有 两个bean的JAR文件,并将每个bean添加到它们各自的JAR文件中。在生成SQL和部 署之前,可能需要停止并且重新启动服务器。

修改Session Bean

在这一课中,如图14所显示的, entity bean是session hean的一个客户。这就是说,entity bean从session bean那里获 得数据,而不是像第2课中所介绍的那 样从 BonusServlet中获得数据。因此,可以将 session bean中的calcBonus方法进行修改,使用社会 安全号码作为参数,并创建entity bean。

 

图14 : 两个Bean的互操作

CalcHome

不修改CalcHome接口。 它具有相同的create 方法,返回一个远程接口的实例。

package Beans;

import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
public interface CalcHome extends EJBHome {
  public Calc create() 
        throws CreateException, RemoteException;
}

Calc

修改Calc接口中的CalcBean方法,使用社会安全号 码作为参数。这样才能够使CalcBean在计算出bonus值 后把bonus和社会安全号码传递给entity bean。还有新添加的一个getRecord 方法,使CalcBean能够通过它的主关键字(社会安全 号码)找到entity bean。

另一方面, calcBonus方法签名抛出DuplicateKeyExceptionCreateException。 这使BonusServlet 能够捕捉和处理这两种异常情况中的任何一种。DuplicateKeyException 来源于CreateException。如果你设计calcBonus 方法来抛出DuplicateKeyException, 但捕捉CreateException, 则DuplicateKeyException不会抛出。解决方法是, 让calcBonus同时抛出 DuplicateKeyExceptionCreateException

package Beans;

import javax.ejb.EJBObject;
import java.rmi.RemoteException;
import javax.ejb.DuplicateKeyException;
import javax.ejb.CreateException;
public interface Calc extends EJBObject {
  public Bonus calcBonus(int multiplier, 
                         double bonus, 
                         String socsec) 
               throws RemoteException,
                         DuplicateKeyException,
                         CreateException;
  public Bonus getRecord(String socsec) 
                throws RemoteException;
}

CalcBean

创建entity bean的代码从BonusServlet转移到 calcBonus方法中,以便在bonus被计算后,它的值和 社会安全号码能够被写入到entity bean中。homebonus 变量是实例变量,这样calcBonus方法可以使用它来查 找entity bean,getRecord方法可以使用它来确定社 会安全号码所对应的entity bean的位置。

package Beans;

import java.rmi.RemoteException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import javax.ejb.DuplicateKeyException;
import javax.ejb.CreateException;

public class CalcBean implements SessionBean {
  BonusHome homebonus;
//Throw DuplicateKeyException and CreateException
//so BonusServlet can catch and handle these
//exception conditions.
  public Bonus calcBonus(int multiplier, 
                  double bonus, String socsec)
                  throws DuplicateKeyException, 
                  CreateException {
    Bonus theBonus = null;
    double calc = (multiplier*bonus);
    try {
      InitialContext ctx = new InitialContext();
      Object objref = ctx.lookup("bonus");
      homebonus = (BonusHome)
                      PortableRemoteObject.narrow(
                      objref, BonusHome.class);
    } catch (Exception NamingException) {
      NamingException.printStackTrace();
    }
//Store data in entity bean
    try {
      theBonus = homebonus.create(calc, socsec);
    } catch (java.rmi.RemoteException e) {
      String message = e.getMessage();
      e.printStackTrace();
    }
    return theBonus;
  }

  public Bonus getRecord(String socsec) {
    Bonus record = null;
  //Use primary key to retrieve data from entity bean
     try {
       record = homebonus.findByPrimaryKey(socsec);
     } catch (java.rmi.RemoteException e) {
       String message = e.getMessage();
     } catch (javax.ejb.FinderException e) {
       e.printStackTrace();
     }
     return record;
  }
  public void ejbCreate() { }
  public void setSessionContext(
                SessionContext context){
  }
  public void ejbRemove() { }
  public void ejbActivate() { }
  public void ejbPassivate() { }
  public void ejbLoad() { }
  public void ejbStore() { }
}

修改Servlet

BonusServlet程序与第二课“简单 entity bean”initdoGet t方法修改后的版本很相似。本课中的init方法仅查找 CalcBean session bean。

public class BonusServlet extends HttpServlet {
  CalcHome homecalc;
//Need Bonus variables because CalcBean methods 
//called in the doGet method return instances 
//of type Bonus
  Bonus theBonus, record;

  public void init(ServletConfig config)
              throws ServletException{
    try {
      InitialContext ctx = new InitialContext();
      Object objref = ctx.lookup("calcs");
       homecalc = (CalcHome)
                      PortableRemoteObject.narrow(
                      objref, CalcHome.class);
    } catch (Exception NamingException) {
      NamingException.printStackTrace();
   }
  }

doGet方法中的try语句 用来计算bonus,创建session bean的home接口,并调用calcBonusgetRecord方法。如果这些方法调用成功,就会出现 一个HTML页面,显示从entity bean中检索到的数据。如果calcBonus 方法抛出DuplicateKeyException,就会返回一个HTML 页面显示所传入的社会安全号码和乘数,以及异常信息:“Duplicate primary key”。

同前面的第二课“简单的entity bean” 中一样,catch语句捕捉和处理重复的主关键字值(社 会安全号码)。

    try {
     Calc theCalculation;
//Retrieve Bonus and Social Security Information
     String strMult = request.getParameter(
                 "MULTIPLIER");//Calculate bonus
     Integer integerMult = new Integer(strMult);
     multiplier = integerMult.intValue();
     socsec = request.getParameter("SOCSEC");
//Calculate bonus
     double bonus = 100.00;
     theCalculation = homecalc.create();
//Call session bean
//Pass 3 parameters:multiplier, bonus, and socsec
     theBonus = theCalculation.calcBonus(
                  multiplier, bonus, socsec);
     record = theCalculation.getRecord(socsec);
//Display data returned by session bean
     out.println("<H1>Bonus Calculation</H1>");
     out.println("<P>Soc Sec retrieved: " +
                   record.getSocSec() + "<P>");
     out.println("<P>Bonus Amount retrieved: " +
                   record.getBonus() + "<P>");
     out.println("</BODY></HTML>");
   } catch (javax.ejb.DuplicateKeyException e) {
     String message = e.getMessage();
     out.println("<H1>Bonus Calculation</H1>");
     out.println("<P>Soc Sec passed in: " + socsec +
                  "<P>");
     out.println("<P>Multiplier passed in: " +
                  multiplier + "<P>");
     out.println("<P>Duplicate primary key<P>");
     out.println("</BODY></HTML>");
   } catch (Exception CreateException) {
     CreateException.printStackTrace();
 }

编译

首先,编译session bean和Servlet。参考第一课进行路径和类路径设置以及 放置源文件的位置信息。

编译Session Bean

Unix

#!/bin/sh
cd /home/monicap/J2EE
J2EE_HOME=/home/monicap/J2EE/j2sdkee1.2.1
CPATH=.:$J2EE_HOME/lib/j2ee.jar
javac -d . -classpath "$CPATH" Beans/CalcBean.java
         Beans/CalcHome.java Beans/Calc.java

Windows

cd \home\monicap\J2EE
set J2EE_HOME=\home\monicap\J2EE\j2sdkee1.2.1
set CPATH=.;%J2EE_HOME%\lib\j2ee.jar
javac -d . -classpath %CPATH% Beans/CalcBean.java
     Beans/CalcHome.java Beans/Calc.java

编译Servlet

Unix:

cd /home/monicap/J2EE/ClientCode 
J2EE_HOME=/home/monicap/J2EE/j2sdkee1.2
CPATH=.:$J2EE_HOME/lib/j2ee.jar:
       /home/monicap/J2EE
javac -d . -classpath "$CPATH" BonusServlet.java 

Windows:

cd \home\monicap\J2EE\ClientCode
set J2EE_HOME=\home\monicap\J2EE\j2sdkee1.2 
set CPATH=.;%J2EE_HOME%\lib\j2ee.jar:\home\monicap\J2EE
javac -d . -classpath %CPATH% BonusServlet.java

启动平台和工具

为了运行这个范例,需要启动J2EE服务器、部署工具和Cloudscape数据库。在 不同的窗口中,键入以下命令:

        j2ee -verbose
deploytool
cloudscape -start

如果不成功,则可从J2EE目录中键入。

Unix

j2sdkee1.2.1/bin/j2ee -verbose
j2sdkee1.2.1/bin/deploytool
j2sdkee1.2.1/bin/cloudscape -start

Windows

j2sdkee1.2.1\bin\j2ee -verbose
j2sdkee1.2.1\bin\deploytool
j2sdkee1.2.1\bin\cloudscape -start

装配应用

步骤为:

  • 创建J2EE应用
  • 创建新web组件
  • 将Session Bean 和entity bean捆绑到一个JAR文件中

创建新J2EE应用

同第1课和第2课中更新J2EE应用不同,这些步骤创建一个新的J2EE应用。

删除BonusApp:

  • 点击BonusApp
  • 选择从“编辑”菜单中“删除

创建2BeansApp :

  • 文件菜单中选择新应用
  • 应用显示名称域中点击鼠标右键。 2BeansApp作为显示名称。
  • 点击浏览按钮打开选择器,选择该应用EAR 文件的存储位置。

新应用文件选择器:

  • 确保应用EAR文件所在的目录。
  • 在这个实例中,该目录为/export/home/monicap/J2EE
  • 文件菜单域中,键入 2BeansApp.ear
  • 点击新应用
  • 点击OK

创建新Web组件

现在仔细回顾一下创建WAR文件的步骤。这些步骤在第一课中已经介绍过,下 面再对其进行总结。选择2BeansApp后,

文件菜单:

  • 选择“新Web组件”。

介绍 :

  • 阅毕,点击“下一步”。

WAR文件一般属性 :

  • 指定BonusWar为显示名称。
  • 点击“添加”。
  • 进入ClientCode目录,添加 bonus.html
  • 点击“下一步”。
  • 进入ClientCode目录,添加 BonusServlet.class
  • 点击“完成”。

WAR文件一般属性 :

  • 点击“下一步”

选择组件类型

  • 选定Describe a servlet
  • 点击“下一步”。

组件一般属性:

  • 使BonusServlet属于Servlet类。
  • 显示名称为BonusServlet
  • 点击“下一步”

组件初始化参数:

  • 点击“下一步”。

组件别名 :

  • 指定BonusAlias
  • 点击“完成”。

检查 窗口:

  • 选择Web上下文(context)。
  • 指定BonusRoot

将Session Bean 和entity bean捆绑到一个JAR文件中

在本课中,我们会将session bean和entity bean捆绑到同一个JAR文件中。为 此,首先要创建一个只带有session bean的JAR文件,然后将entity bean添加到 这个JAR文件中。

创建带有session bean的JAR文件

选定2BeansAppApp后,

文件菜单:

  • 选择“新 Enterprise Bean

介绍 :

  • 阅毕,点击“下一步”

EJB JAR :

  • 确保2BeansApp显示在“Enterprise Bean will go in”域中。
  • 指定2BeansJar为显示名称。
  • 点击“添加”(“内容”窗口 旁边的那一个)。
  • 使Beans目录显示其内容。
  • 选择Calc.class
  • 点击“添加”。
  • 选择CalcBean.class
  • 点击“添加”。
  • 选择CalcHome.class
  • 点击“添加”。

Enterprise Bean JAR类:

  • 确使能够在显示栏中看到“Beans/Calc.class, Beans/CalcHome.class”和 “Beans/CalcBean.class”。
  • 点击 “OK”。

EJB JAR :

  • 点击“下一步”。

一般项目 :

  • CalcBean 是类名称,Beans.CalcHome 是Home接口,Beans.Calc是远程接口。
  • 输入CalcBean作为显示名称。
  • 点击session和stateless。
  • 点击“下一步”。

环境项目:

  • 点击“下一步”。 这个简单的entity bean没 有使用这个属性(环境项目)。

Enterprise Bean 引用

  • 点击“下一步”。 在部署时处理该项而不是在 这里。

资源引用:

  • 点击“下一步”。 该简单Session Bean不查找 数据库或JavaMail会话对象。

安全:

  • 点击“下一步”。 该简单session bean不使用 安全角色。

事务管理 :

  • 选择Container-managed transactions (如果 还没有被选择)。
  • 在下面的列表中需要calcBonusgetRecord。 这就是说,容器在运行这些方法之前启动新的事务流程。这个事务流程正好在 这些方法结束后提交。可以在“Enterprise JavaBeans开发人员手册”中的第 六章中获得有关这些事务流程的更多信息 (java.sun.com/j2ee/j2sdkee/techdocs/guides/ejb/html/devGuideTOC.html)。
  • 点击“下一步”。

检查设置:

  • 点击“完成”。

本地应用:

  • 选择2BeansApp
  • 在检查窗口中,选择JNDI 名称。指定calcs 的JNDI名称为CalcBean,按下回车键。

添加entity bean

选定2BeanApp

文件菜单:

  • 选择“新Enterprise Bean”。

介绍 :

  • <阅毕,点击“下一步”。

EJB JAR :

  • 确保2BeanApp显示在“Enterprise Bean will go in ” 域中。这一步操作会将新的 bean添加到目前的JAR文件中而不是将这个新Bean 放入它自己的JAR文件中。
  • 点击“添加”(“内容”窗口旁边的那一个)。
  • 切换Beans目录使其显示相应内容。
  • 选择Bonus.class
  • 点击“添加”。
  • 选择BonusBean.class
  • 点击“添加”。
  • 选择BonusHome.class
  • 点击“添加”。

Enterprise Bean JAR类:

  • 确使能够在显示栏中看到“Beans/Bonus.class, Beans/BonusHome.class”和 “Beans/BonusBean.class”。
  • 点击 “OK”。

EJB JAR :

  • 点击“下一步”。

一般项目 :

  • <确使 Beans.BonusBean 是类名称, Beans.BonusHome 是Home接口,Beans.Bonus 是远程接口。
  • 输入BonusBean作为显示名称。
  • 点击Entity
  • 点击“下一步”。

Entity 设置:

  • 选择Container managed persistence
  • 在窗口底部,选定 bonussocsec。 主关键字类为java.lang.String,主关键字名称为 socsec。注意,主关键字必须是一个类类型。原始 类型对于主关键字无效。
  • 点击“下一步”。

环境项目:

  • 点击“下一步”。 这个简单的entity bean没有使用这个属性(环境项 目)。

Enterprise Bean 引用:

  • 点击“下一步”。 该简单entity bean不引用其enterprise bean。

资源引用:

  • 点击“下一步”。 该简单entity bean不查找数据库或JavaMail会话对象。

安全:

  • 点击“下一步”。 该简单entity bean不使用安全角色。

事务管理 :

  • 选择Container-managed transactions (如果 还没有被选择)。
  • 在下面的列表中需要create, findByPrimaryKey, getBonusgetSocSec。 这就是说,容器在运行这些方法之前启动新的事务流程。这个事务流程正好 在这些方法结束后提交。可以在“Enterprise JavaBeans开发人员手册”中 的第六章中获得有关这些事务流程的更多信息 (java.sun.com/j2ee/j2sdkee/techdocs/guides/ejb/html/devGuideTOC.html)。
  • 点击“下一步”。

检查设置:

  • 点击“完成”。

本地应用:

  • 选择2BeansApp
  • 在检查窗口中,选择JNDI 名称。使BonusBean 的JNDI名称为bonusCalcBean 的JNDI名称为calcs
  • 为每一个项目按下回车键使之生效。

在对J2EE应用部署之前,需要为entity bean指定部署方法,生成SQL。 具体 如下:

本地应用窗口:

  • 选择BonusBean

检查窗口:

  • 选择Entity
  • 点击右下方的Deployment Settings按钮。

部署设置窗口:

  • 指定jdbc/Cloudscape(Cloudscape中的C 为大写)为数据库JNDI名称。
  • 按下回车键。
  • 确保Create table on deploy和d delete table on Deploy已经被选定。
  • 点击Generate SQL
注: 如果出现连接被拒绝的错 误,则应按照“启动平台和工具”中描述的 方法启动数据库。

当生成SQL后,

  • 选择EJB方法框中的findByPrimaryKey方法。
  • 右侧会出现一个SQL语句,内容是:SELECT “socsec” FROM “BonusBeanTable” WHERE “socsec”=?。问号代表传递给 findByPrimaryKey方法的参数。
  • 点击“ok”。

验证和部署J2EE应用

在部署应用之前最好能够运行验证器。验证器将挑出应用组件中的错误,如编 译器未曾捕捉到的丢失的enterprise bean方法。

: 如果在验证或部署时出 现保存错误,则需要关闭一切程序,重新启动服务器和工具。

验证:

  • 选定2BeansApp,从“工具”菜单中选择“验证 器”。
  • 在弹出的对话框中,点击“OK”。 窗口将通知 你测试成功。
  • 关闭验证器窗口,准备部署应用。
注: 在Version 1.2.1软件中, 你可能会得到一个 tests app.WebURI的错误。这表明, 在WAR文件创建过程中,部署工具没有将 .war扩展名附给WAR文件。

部署:

  • 从“工具”菜单中选择“部署应用”。 一个“部署BonusApp” 对话框会弹出。
  • 验证“目标服务器”选项或者是本地主机或是运行J2EE服务器的主机的名称。
注: 不要选择“Return Client Jar”选项。只有在为客户程序部署独立的应用时才选择这个选项。本实例使用了 一个servlet和HTML页面,因此,不应该选择这个选项。若选择这个选项,会生成 一个带有独立式应用所需部署信息的JAR文件。
  • 点击“下一步”。
  • 确保CalcBean的JNDI名称为 calcsBonusBean的 JNDI名称为bonus。 如果不是,则需要将JNDI名称 键入,然后按下回车键。
  • <点击“下一步”。 确定“上下文根目录”名称显示为BonusRoot。 如果不是,则需要将其键入,然后按下回车键。
  • 点击“下一步”。
  • <点击“完成”开始部署。此时,会弹出一个显示部署操作状态的对话框。
  • 完成后,左侧的三个状态条都将阴

 

Deployment Progress
图15 : 部署应用

运行J2EE应用

web 服务器的运行端口默认为8000。若要打开bonus.html 页面,可进入以下地址, http://localhost:8000/BonusRoot/bonus.html, 这是部署工具放置HTML文件的位置。

  • 填入社会安全号码和乘数。
  • 点击“提交”按钮。BonusServlet处理你的数 据,并返回一个带bonus计算值的HTML页面。
Bonus Calculation

Soc Sec retrieved: 777777777
Bonus Amount Retrieved: 200.0

如果两次提交的社会安全号码相同,会出现类似于以下的信息:

Bonus Calculation

Soc Sec passed in: 777777777
Multiplier passed in: 2
Duplicate primary key

[TOP]

 

 

常见问答
下载中心
产品简介
 
 
Solaris论坛
 
   
 
null