Enterprise JavaBeans Distilled
作者:罗时飞([email protected])
第二次:
设计实例的深入分析:
要求:
  本文假设读者对EJB技术有一定熟悉,对SQL有一定了解就可以了。由于EJB涉及到的技术很多,尽管每次只讲述一种技术,但各种技术是相关的,所以希望读者谅解,因为这样不是很好组织。
实例背景:
  数据库: SQL Server 2000
  操作系统: Windows 2000
  开发工具; JBuilder 7
  EJB服务器: WebLogic 7.0
       机器IP地址,10.11.12.58
    实例综述:通过无状态Session Beans得到容器管理的Entity Beans中的数据,然后把无状态Session Beans得到的数据给JSP页面,从而客户可以看到所要的结果。通过这样一种过程使得您知道编写EJB组件是多么简单的事情。
准备工作:
        配置好SQL Server 2000的JDBC驱动(微软网站有下载,或者用BEA提供的也可以!该例子中用的是微软的JDBC)、JBuilder 7 + WebLogic 7集成环境,其他的也可以。
开发过程:
1.  配置JDBC数据源:这个过程包括两个步骤,首先配置连接池(Connection Pools)。(为什么采用连接池:开发人员不想编写Database方面的代码、更换数据库系统变得简单、限制数据库的连接数量、不需要为每个客户建立新连接。这种池的概念在J2EE中有很多地方出现了,比如EJB本身)配置的参数如下:
          Name: cacd
                     URL: jdbc:microsoft:sqlserver://10.11.12.58:1433;user=sa;password=cacd;
Driver ClassName: com.microsoft.jdbc.sqlserver.SQLServerDriver
Initial Capacity: 3
Maximum Capacity: 10
       其次,配置JDBC数据源,在Tx Data Sources中配置的参数如下:
                Name: cacd
                JNDI Name: cacd
                Pool Name: cacd(要与前面的相匹配!)
       (Tx Data Sources与一般的Data Sources 区别何在?读给读者思考、讨论。)
其中,在URL中,你需要为SQL Server 2000配置一个用户名sa,密码为cacd,因为这里用的是Type 4的JDBC,所以需要将SQL Server 2000的用户认证修改为:NT+SQL Server 2000混合认证。2.  数据库的建立:Entity Beans代表了Database中的数据,所以需要数据库支持,但一般情况下,我们知道,可以根据容器管理的Entity Beans导出SQL DDL。另一方面,可以根据SQL DDL生成容器管理的Entity Beans。两种方法都可以。比如JBuilder 7两种方法都提供了。但我想,信息模型(数据库)的建立在编码之前就应该存在,所以建议采用第二种办法。当然有些时候第一种会较为合理些,因为并不是表中所有的字段都会映射到Entity Beans中。该例子中建立了这样这样一个Table:
  /*===================================================*/
/* Table : techniquespec                                        */
/*===================================================*/
create table techniquespec (
techniqueitem        char(100)            not null,
units                char(10)             null,
minvalue             decimal(16,6)        null,
maxvalue             decimal(16,6)        null,
types                char(1)              null,
signon               char(1)              null,
constraint PK_TECHNIQUESPEC primary key  (techniqueitem)
)
其中,开发人员在建表的过程中,不需要手工去写SQL DDL语句,一般都可以借助于工具进行,比如PowerDesigner、ERWin等工具。用用就会了,不要对工具产生不好的情绪,但前提是你熟悉数据库理论。用户建好Table后,可以填入数据,中文的也可以。3.  容器管理的Entity Beans的开发:JBuilder对EJB开发支持的比较好,提供了图形化的方式。由于我们已经建立好了Database,前面的techniquespec表,我们可以借助于Import Schema From Database,将SQL DLL引入进来。(由于这里不能贴出操作图片,所以只能用文字说明梗概,大家在设计过程中有什么问题,可以发邮件给我,我尽力而为。)在这个过程中,一定要注意JNDI的名字和数据源中的JNDI要一致。得到SQL DLL后,我们可以根据techniquespec表生成CMP 2.0 Entity Beans,在这里我们采用LocalHome访问Entity Beans,为什么采用?后续文章中都会详细阐述。现在想返回表techniquespec中列techniqueitem的所有内容。首先,真假一个findByTypes Finder方法,EJB QL语句为: SELECT OBJECT(p) from Techniquespec AS p,其中返回值为Collection。下面给出代码。
LocalHome接口:
package cacdsystem;
import javax.ejb.*;
import java.util.*;
public interface TechniquespecHome extends javax.ejb.EJBLocalHome
{
  public Techniquespec create(String techniqueitem) throws CreateException;
  public Collection findByTypes() throws FinderException;//添加的Finder方法
  public Techniquespec findByPrimaryKey(String techniqueitem) 
throws FinderException;
}
Local接口:
package cacdsystem;
import javax.ejb.*;
import java.util.*;
import java.math.*;
public interface Techniquespec extends javax.ejb.EJBLocalObject
{
  public String getTechniqueitem();
  public void setUnits(String units);
  public String getUnits();
  public void setMinvalue(BigDecimal minvalue);
  public BigDecimal getMinvalue();
  public void setMaxvalue(BigDecimal maxvalue);
  public BigDecimal getMaxvalue();
  public void setTypes(String types);
  public String getTypes();
  public void setSignon(String signon);
  public String getSignon();
}
bean类:
package cacdsystem;
import javax.ejb.*;
abstract public class TechniquespecBean implements EntityBean
{
 EntityContext entityContext;
  public java.lang.String ejbCreate(java.lang.String techniqueitem) 
throws CreateException {
    setTechniqueitem(techniqueitem);
    return null;
  }
  public void ejbPostCreate(java.lang.String techniqueitem) throws CreateException {
  }
  public void ejbRemove() throws RemoveException {
  }
  public abstract void setTechniqueitem(java.lang.String techniqueitem);
  public abstract void setUnits(java.lang.String units);
  public abstract void setMinvalue(java.math.BigDecimal minvalue);
  public abstract void setMaxvalue(java.math.BigDecimal maxvalue);
  public abstract void setTypes(java.lang.String types);
  public abstract void setSignon(java.lang.String signon);
  public abstract java.lang.String getTechniqueitem();
  public abstract java.lang.String getUnits();
  public abstract java.math.BigDecimal getMinvalue();
  public abstract java.math.BigDecimal getMaxvalue();
  public abstract java.lang.String getTypes();
  public abstract java.lang.String getSignon();
  public void ejbLoad()
  {
  }
  public void ejbStore()
  {
  }
  public void ejbActivate()
  {
  }
  public void ejbPassivate()
  {
  }
  public void unsetEntityContext()
  {
    this.entityContext = null;
  }
  public void setEntityContext(EntityContext entityContext)
  {
    this.entityContext = entityContext;
  }
}

解决方案 »

  1.   

    4.  无状态Session Beans的开发: 通过EJB 图形设计器,生成一个Session Bean,代码如下。
    Home接口:
    package cacdsystem;
    import javax.ejb.*;
    import java.util.*;
    import java.rmi.*;
    public interface VocHome extends javax.ejb.EJBHome {
      public Voc create() throws CreateException, RemoteException;
    }
    Remote接口:
    package cacdsystem;
    import javax.ejb.*;
    import java.util.*;
    import java.rmi.*;
    public interface Voc extends javax.ejb.EJBObject {
      public Collection getVocTechnique() throws RemoteException;
    }
    bean类:
    package cacdsystem;
    import javax.ejb.*;
    import java.util.*;
    public class VocBean implements SessionBean {
      SessionContext sessionContext;
      TechniquespecHome techniquespecHome;
      public void ejbCreate() throws CreateException {
      }
      public void ejbRemove() {
      }
      public void ejbActivate() {
      }
      public void ejbPassivate() {
      }
      public void setSessionContext(SessionContext sessionContext) {
        this.sessionContext = sessionContext;
        try
        {
           javax.naming.Context context = new javax.naming.InitialContext();
           techniquespecHome = (TechniquespecHome)context.lookup("Techniquespec");
        }
        catch (Exception ex) {
          System.out.println("Techniquespecs调用出错!");
          throw new EJBException(ex);
        }
      }
      public java.util.Collection getVocTechnique() {
        /**@todo Complete this method*/
        /**
         * 获得全部技术需求项函数!
         */
        System.out.println("调用getVocTechnique()!");
        java.util.Collection collection = null;
        java.util.List results = new ArrayList();
        try
        {
          collection= techniquespecHome.findByTypes();
          if(collection.size() > 0)
          {
              System.out.println(collection.size());
              Iterator iter = collection.iterator();
              String tempStr = null;
              Techniquespec techniqu = null;
              while(iter.hasNext())
              {
                 techniqu = (Techniquespec) iter.next();
                 tempStr = techniqu.getTechniqueitem();
                 tempStr = charASC.chinTOISO(tempStr);
                 results.add(tempStr);
              }
          }
        }
        catch (Exception ex) {
          ex.printStackTrace();
          throw new EJBException(ex);
        }
        return results;
      }
    }
    说明:(1)我们在Session Bean中添加了一个商务方法,getVocTechnique(),以获得techniqueitem中的全部内容。(2)setSessionContext中,我们完成了EJB的一些初始化工作。(3) charASC.chinTOISO是用于中文转换的静态方法,代码如下:
    package cacdsystem;
    public class charASC
    {
     static private String results = null;
     public charASC()
     {
      }
      static public String chinTOISO(String temp)
      {
        if(temp == null)
        {
          results = "";
       }
        else
        {
          try
          {
            results = new String(temp.getBytes("ISO-8859-1"),"gb2312");
            results = results.trim();
          }
          catch(Exception ee)
          {
            System.out.println("中文转换失败!");
          }
        }
        return results;
      }
    }
    5.  JSP页面的开发:针对Session Bean,我编写了一个JSP页面。
    <%@page contentType="text/html;charset=gb2312"%>
    <%@page import="java.text.*" %>
    <%@page import="java.util.*"%>
    <%@page import="java.sql.*" %>
    <%@page import="javax.naming.*" %>
    <%@page import="java.lang.*" %>
    <%@page import="javax.rmi.PortableRemoteObject" %>
    <%@page import="javax.ejb.* "%>
    <%@page import="cacdsystem.*"%>
    <html>
    <head>
    <title>产品技术需求提取</title>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
    </head>
    <body>
    <form id=form  name=form1 method=post>
    <input type=hidden id=pageFlag name=pageFlag value='input'>
    <table cellSpacing=0 cellPadding=0 width="98%" border=0 align=center >
      <tr height=30  class=titleFont>
        <td><font color='#0058a5'> 您所在位置:产品技术需求提取</font></td>
      </tr>
      <tr height=1  class=titleFont>
        <td></td>
      </tr>
    </table>
    <table width="98%" border="0"  bgcolor='#999999'  align=center>
        <tr>
          <td><b> <font color="#ffffff">产品技术需求提取</font></b></td>
      </tr>
    </table>
    <table width="98%" border="1" align=center  bgcolor="#f0f0f0" bordercolor='#ffffff' cellspacing=0 cellpadding=0  class=titleFont>
        <tr bgcolor='#e0e8f8'>
          <td>&nbsp;</td>
        </tr>
    <%
        InitialContext ctx = new  InitialContext();
    VocHome vocHome = 
    (VocHome)PortableRemoteObject.narrow(ctx.lookup("Voc"),VocHome.class);
        Voc voc = vocHome.create();
        Collection collection = voc.getVocTechnique();
        if(collection.size() > 0)
        {
          Iterator iters = collection.iterator();
          int i = 0;
          while(iters.hasNext())
          {
            ++i;
    %>
       <tr>
          <td><input type='checkbox' name=<%= "select"+i %>  
    value=<%= i %>><%= (String)iters.next() %><br></td>
       </tr>
    <%
          }
        }
    %>
    <%
       voc.remove();
    %>
        <tr bgcolor='#e0e8f8' align=middle>
          <td>
            <p align=left></p>&nbsp;
          </td>
        </tr>
       <tr align=middle>
        <td>
          <input type=submit id=submit1 name=submit1 value="提 交">
          <input type=reset id=submit1 name=submit value="重 置">
        </td>
      </tr>
    </table>
    </form>
    </body>
    </html>
    6.  系统Deploy: 到现在为止,我们实现了Entity Bean、Session Bean、JSP,从而实现了该实例所需要的代码。为使我们测试代码的正确性,我们来Deploy到服务器上。首先,由于在Session Bean中引用了Entity Bean,所以需要申明。
               <session>
                <display-name>Voc</display-name>
                <ejb-name>Voc</ejb-name>
                <home>cacdsystem.VocHome</home>
                <remote>cacdsystem.Voc</remote>
                <ejb-class>cacdsystem.VocBean</ejb-class>
                <session-type>Stateless</session-type>
                <transaction-type>Container</transaction-type>
                <ejb-local-ref>  //手工添加的配置描述符代码!
                    <description />
                    <ejb-ref-name>Techniquespec</ejb-ref-name>
                    <ejb-ref-type>Entity</ejb-ref-type>
                    <local-home>cacdsystem.TechniquespecHome</local-home>
                    <local>cacdsystem.Techniquespec</local>
                    <ejb-link>Techniquespec</ejb-link>
                </ejb-local-ref>
            </session>
              其次,需要将EJB的接口文件拷贝到web-inf\classes目录下。在这里由于是存在package cacdsystem中,需要把4个接口文件拷贝到web-inf\classes\cacdsystem中。第三,将EJB打包成.jar文件,JBuilder 7可以自动完成,记得要包括charASC.class文件。生成.jar后发布到服务器上可以通过JBuilder 7发布,也可以通过WebLogic提供的Builder工具,或者通过Console发布,或者通过将.jar拷贝到applications目录即达到发布的目的。
              最后,我们也可以通过把整个EJB、JSP打包成.ear文件,JBuilder工具提供了Wizard。
    总结:
    整个过程实现了EJB组件开发,从而对EJB有了一定的认识。接下来的文章中,我会继续深入讲述EJB技术涉及到的技术。谢谢大家看完我的写文章,也希望大家写信和我交流。
      

  2.   

    兄弟,有好消息,给我说一下,我也准备去北京work
      

  3.   

    使用是最好不要用 <ejb-local-ref> 这个描述符,不然以后维护、升级有你受的
      

  4.   

    MessageDrivenBean 在 EJB 2.0 中,对规范的一个基础性更改是添加了一种全新的企业级 bean 类型,即 MessageDrivenBean。MessageDrivenBean 专门设计来处理入网的 JMS 消息。对于许多开发人员来说,JMS 是一种新的范例,所以本文将花一些时间逐步说明对 JMS 的理解,以及它们在 EJB 2.0 中的用法。 
    什么是 JMS? JMS 是一种与厂商无关的 API,用来访问消息收发系统。它类似于 JDBC (Java Database Connectivity):这里,JDBC 是可以用来访问许多不同关系数据库的 API,而 JMS 则提供同样与厂商无关的访问方法,以访问消息收发服务。许多厂商目前都支持 JMS,包括 IBM 的 MQSeries、BEA 的 Weblogic JMS service 和 Progress 的 SonicMQ,这只是几个例子。 JMS 使您能够通过消息收发服务(有时称为消息中介程序或路由器)从一个 JMS 客户机向另一个 JML 客户机发送消息。消息是 JMS 中的一种类型对象,由两部分组成:报头和消息主体。报头由路由信息以及有关该消息的元数据组成。消息主体则携带着应用程序的数据或有效负载。根据有效负载的类型来划分,可以将消息分为几种类型,它们分别携带:简单文本 (TextMessage)、可序列化的对象 (ObjectMessage)、属性集合 (MapMessage)、字节流 (BytesMessage)、原始值流 (StreamMessage),还有无有效负载的消息 (Message)。 消息收发系统是异步的,也就是说,JMS 客户机可以发送消息而不必等待回应。比较可知,这完全不同于基于 RPC 的(基于远程过程的)系统,如 EJB 1.1、CORBA 和 Java RMI 的引用实现。在 RPC 中,客户机调用服务器上某个分布式对象的一个方法。在方法调用返回之前,该客户机被阻塞;该客户机在可以执行下一条指令之前,必须等待方法调用结束。在 JMS 中,客户机将消息发送给一个虚拟通道(主题或队列),而其它 JMS 客户机则预订或监听这个虚拟通道。当 JMS 客户机发送消息时,它并不等待回应。它执行发送操作,然后继续执行下一条指令。消息可能最终转发到一个或许多个客户机,这些客户机都不需要作出回应。 EJB 2.0 中的 JMS EJB 2.0 以两种方式支持 JMS 的集成:作为一种 bean 可用的资源,和作为一个 MessageDrivenBean。当将 JMS 用作一种资源时,使用 JMS API 的 bean 就是消息的产生者或发送者。在这种情况下,bean 将消息发送给称为主题或队列的虚拟通道。另一方面,MessageDrivenBean 则是消息的使用者或接收者。它监听特定的虚拟通道(主题或队列),并处理发送给该通道的消息。为了更好地理解消息产生者和消息使用者的作用,用 SessionBean bean 来发送一条使用 JMS 的消息,然后使用一个新的 MessageDrivenBean 来使用该同一条消息。 作为 EJB 2.0 资源的 JMS 会话 bean 和实体 bean 都是基于 RPC 的组件,为了将各种事务性的组件装配到一起,这是一种卓越的体系结构。但是,在某些情况下,RPC 的同步性质会成为一种障碍,这正是 EJB 1.1 中将对 JMS API 的访问作为一种资源包括在内的原因。利用 JNDI 环境命名的上下文,bean 可以获得一个 JMS 工厂,并将一条异步消息发送给主题或队列(也从 JNDI 获得),而不必等待回应。下面是 ShoppingCart bean 的一个例子,它使用 JMS 将 Order 的详细信息发送给消息收发主题。
      

  5.   

    public class ShoppingCartBean implements SessionBean { // 订单详细信息是一个可序列化的对象,它包含全部订单信息。 public OrderDetail orderDetail; public void processOrder(){ // 处理订单的逻辑从此处开始 .... // ... 处理订单以后,向其它系统发送有关此订单的一条消息 InitialContext jndiEnc = new InitialContext(); // 使用 JNDI ENC 获取 JMS 工厂和主题标识符 TopicConnectionFactory factory = jndiEnc.lookup(“java:comp/env/jms/topicfactory“); Topic orderTopic = jndiEnc.lookup(“java:comp/env/jms/ordertopic“); // 获得一个用来发送消息的发布者 TopicConnection con = factory.createTopicConnection(); TopicSession session = con.createTopicSession(false, Session.AUTO_ACKNOWLEDGE ); TopicPublisher publisher = session.createPublisher(orderTopic); // 将一个 ObjectMessage 发送给主题(虚拟通道) ObjectMessage message = session.createObjectMessage(); message.setObject(orderDetail); publisher.publish(message); con.close(); } ... } 
    在这种情况下,JMS 是用来通知另外的应用程序,订单已被处理。这些另外的应用程序对于处理订单来说并不重要,但它们会因为得到一个订单已被处理的通知而受益。这样的例子包括自动调整库存的库存系统,和能将客户添加进产品目录邮寄名单中的销售应用程序。 使用 JMS 使 bean 能够发布(发送)消息而不会发生阻塞。bean 并不知道谁将收到消息,因为它是将消息发送给某个主题(虚拟通道),而不是直接发送给另一个应用程序。应用程序可以选择预订该主题,并接收有关新订单的通知。这样就有可能动态地在虚拟通道中添加或删除应用程序,从而产生了一种更加灵活的系统。 预订了订单主题的应用程序将收到有关新订单的通知,应用程序可以使用它们认为合适的任何方式来处理这个通知。预订了各种主题的应用程序或者从各个队列中接收消息的应用程序可以是 Java 应用程序、EAI 系统(用于集成遗留系统和 ERP 系统)或者 MessageDrivenBean 组件,在 JMS 的术语中,它们全部被认为是 JMS 客户机。 
      

  6.   

    linden28()  看来你对 EJB2.0 localbean 不熟悉,你所说的是EJB 1.1  cmp or bmp,
    眼下流行的是 ejb2.0 jms ,当然我现在北京还没有发现有公司作这个业务的,你需要先熟悉
    一下j2ee的消息处理机制,然后再发言。
      

  7.   

    http://www.ccidnet.com/tech/focus/java_little_t/ImplementObserverPattern.zip
      

  8.   

    EntityBean 接口方法
      EjbCreate 方法:当客户端调用 create 方法时,EJB 容器调用相应的ejbCreate 方法。一个Entity组件的ejbCreate 方法要实现下列工作:
      · 插入Entity Bean 的状态到数据库中
      · 初始化实例变量
      · 返回主键。
    ejbPostCreate 方法
      对于每一个ejbCreate 方法,开发人员必须在Entity Bean中写一个ejbPostCreate 方法,EJB 容器在调用完ejbCreate 以后,就立即调用ejbPostCreate ,和 ejbCreate 方法不一样,ejbPostCreate 方法可以调用 getPrimaryKey 等方法,通常ejbPostCreate 方法是空的。  EjbLoad 方法和 ejbStore 方法
      EJB 容器需要维持 Entity Bean 的实例变量与数据库中相应值的同步,这需要调用 ejbLaod 方法和ejbStore 方法。ejbLoad 方法用数据库中的数据刷新变量的值,ejbStore 方法把变量的值写入到数据库中。客户端不能调用  
    ejbLoad 方法和ejbStore 方法。
      如果业务处理的方法关系到事物处理,EJB 容器要在业务处理方法调用之前调用 ejbLoad 方法刷新数据,业务处理方法执行之后,EJB 容器又立即调用 ejbStore 方法把数据存储到数据库中。因为 EJB 容器调用ejbLoad方法和ejbStore 方法,开发人员在业务处理方法中不必刷新和存储实例变量的值。
      如果ejbLoad 方法和ejbStore 方法不能在低层数据库中定位 Entity Bean,将执行 javax.ejb.NoSuchEntityException。
      在 AccountEJB 类中,ejbLoad 方法调用 loadRow 方法,loadRow 则发出一个 select 语句从数据库提取数据分配给实例变量;ejbStore 方法调用 storeRow 方法,storeRow 方法则用 update 语句把实例变量的值存储到数据库。代码如下:  public void ejbLoad(){
        try{
          loadRow();
        }catch (Exception ex){
          throw new EJBException ("ejbLoad:"+ex.getMessage());
        }
      }  public void ejbStore(){
        try{
          storeRow();
        }catch (Exception ex){
          throw new EJBException ("ejbStore:"+ex.getMessage());
        }
      }Finder 方法 :
      Finder 方法允许客户端查找 entity bean ,AccountClient 中有三种方法查找entity bean:
        Account jones = home.findByPrimaryKey("836");
        Collection c home.findByLastName("Smith");
        Collection c home.findInRange(20.00,99.00);
      Entity bean 类必须实现相应的方法,并且文件名以ejbFind 前缀开始,如:AccountEJB 类实现 ejbFindByLastName 的方法如下:
      public Collection ejbFinfBylastName(String lastName)
        throw FinderException {
        Collection result;
        Try {
          Result = selectByLastName(lastName);
        } catch (Exception ex) {
          throw new EJBException("ejbFindByLastName" + ex.getMessage());
        }
        if (result.isEmpty()){
          throw new ObjectNotFoundException("No row found.");
        }
        else {
          return result;
        }
      }应用系统中特定的 finder ,如 ejbFindByLastName 和ejbFindInRange,是可选的,但是必须含有 ejbFindByPrimaryKey 方法,ejbFindByPrimaryKey 方法用主键作参数,用来定位一个 entity bean 的状态数据,下面是 ejbFindByPrimaryKey 方法的代码:
      public String ejbFindByPrimaryKey(String primaryKey)
        throws FinderException {
        boolean result;    try {
          result = selectByPrimaryKey(primaryKey);
        } catch (Exception ex) {
          throw new EJBException("ejbFindByPrimaryKey: " + ex.getMessage());
        }    if (result) {
          return primaryKey;
        }
        else {
          throw new ObjectNotFoundException ("Row for id " + primaryKey + " not found.");
        }
      }
      
      

  9.   

    http://www.cn-java.com/target/news.php?news_id=2261
      

  10.   

    http://www.cn-java.com/target/news.php?news_id=188
    jboss的安装配置
      

  11.   

    http://www.csdn.net/Develop/article/18%5C18577.shtm
    jbuilder7整合websphere的步骤
      

  12.   

    有这么高么
    你的用j2ee都开发是的是哪些项目呀!
      

  13.   

    决定了
    现在先学学。net
    以后i在学java
      

  14.   

    又这么高嘛?在哪儿,我就是作j2ee的,好像没有这么高哦。我是在大连。收入低。
      

  15.   

    http://www.javaresearch.org/article/showarticle.jsp?column=151&thread=3998http://www.javaresearch.org/dn/JBuilder7-Weblogic7.rar