2007-03-15

[译] EJB 3.0 Enterprise Beans

关键字: Java EE, EJB 3.0, 入门

EJB 3.0 Enterprise Beans

预计时间: 30 分钟
本文将带你学习使用Java EE 5平台的EJB3.0技术来开发企业应用的一些基础知识。这篇文档将展示EJB3.0技术是如何简化企业应用开发过程的。本文使用的是NetBeans IDE 5.5 Release。

先决条件

本文假设你已经了解或具有下类技术开发经验:
  • Java 编程
  • NetBeans IDE

教程所需软件

你需要安装下列软件在你的计算机上:
  • NetBeans IDE 5.5 (download).
  • Java Standard Development Kit (JDK) version 5.0 or version 6.0 (download)
  • Sun Java System Application Server, Platform Edition 9 (download)
你需要在IDE中注册一个Sun Java System Application Server的本地实例。

教程练习

  • 建立企业应用项目
  • 编写EJB Module
  • 编写Web Module
  • 运行项目
  • 疑难解答

建立企业应用项目


    本练习目标是建立NewsApp企业应用项目,包含一个EJB模块和一个web模块。NewsApp应用程序使用消息驱动bean通过servlet接受和处理发送到队列的消息。该应用使用servlets发送消息到消息驱动bean并显示这些消息。
建立一个企业应用程序
  1. 在主菜单上选择 File > New Project (Ctrl-Shift-N)
  2. 在enterprise分类中选择Enterprise Application并点击Next
  3. 将项目命名为NewsApp并设置server为Sun Java System Appilcation Server.
  4. Set the J2EE Version to Java EE 5, and select Create EJB Module and Create Web Application Module, if unselected. 
  5. 设置J2EE Version为Java EE 5并选择Create EJB Module和Create Web Application Module如果它们未选中的话。
  6. 点击finish

总结

    在这个练习中我们创件了一个包含了EJB Module和Web Module的企业级应用项目。

编写EJB Module

    本练习中,我们将在EJB module中创建对象。我们将建立一个实体类,一个消息驱动bean和一个session facade。我们也将创建一个持久化单元为容器提供信息管理我们的实体和我们简要使用的消息驱动bean - Java消息服务(JMS)资源。
创件一个持久化单元
首先我们建立一个持久化单元,并定义数据源和我们的应用中使用的实体管理器。
  1. 右键单击EJB module并选择 New > File/Folder.
  2. 在persistence category中选择Persistence Unit并点next
  3. 保持默认的Persistence Unit 名称 
  4. Persistence Provider选择默认的TopLink 
  5. Data Source选择默认的数据源jdbc/sample
  6. 检查persistence unit使用了Java Transaction API并且Table Generation Strategy设置了Create,当应用程序部署的时候表会基于我们的实体类自动建立
  7. 点击next
当你点击Finish的时候,IDE会建立persistence.xml并在源码编辑中用设计视图打开。关闭persistence.xml
创建NewsEntity实体类

本练习我们将创建NewsEntity实体类。该实体类是一个简单的Java类。当你建立实体类的时候,IDE添加@Entity annotation去定义一个类为实体类。之后我们将在类中创建代表数据库表中数据的字段。
每一个实体类必须具有一个主键。当你建立一个实体类,IDE添加@Id annotation去声明字段被作为主键使用。IDE也会添加@Generated annotation去指定主键生成策略。

按照下面步骤创建NewsEntity类:
  1. 在项目窗口中右键单击EJB module选择 New > File/Folder去打开新建文件向导。
  2. 在persistence category选择Entity Class并点击Next。
  3. 键入NewsEntity作为类名,键入ejb为包名并让主键为Long。点击Finish。
当你点击了Finish,实体类NewsEntity.java在源码编辑器中打开。在编辑器中按照下列步骤来做:
  1. 在类中添加下面的字段声明
    String title;
    String body;
  2. 右键单击源码编辑器选择Refactor > Encapsulate Fields为每个字段生成getters和setters方法。在Encapsulate Fields对话框中,确定字段id, title和body的getter和setter复选框是选中的。
  3. 在encapsulate Fields对话框中点击Next并在Output window上的Refactoring标签页上点击Do Refactoring。IDE会为这些字段添加getter和setter方法并将字段的可见性改为private。
  4. 保存你的改变
下一步我们将创建NewMessage消息驱动bean。
创建NewMessage消息驱动bean
现在我们将在EJB module中创建NewMessage消息驱动bean。我们将使用新建Message-Driven Bean向导去创建bean和必须的JMS资源。
按照以下步骤来创建NewMessage消息驱动bean:
  1. 在项目窗口中右键单击EJB module选择New > File/Folder打开新建文件向导。
  2. 在enterprise分类中,选择Message-Driven Beans并点Next。
  3. 键入NewMessage作为类的名字。
  4. 从Package下拉列表中选择ejb
  5. 选择Queue作为Destination Type并点击Finish
    当你点击了Finish,新的消息驱动bean类NewMessage.java在源码编辑器中打开。你能看到类中有下面的annotation:
@MessageDriven(mappedName = "jms/NewMessage")
    这个annotation告诉容器这个组件是一个消息驱动bean并且使用了JMS资源。当IDE生成类时,资源映射名(jms/NewMessage)根据类名(NewMessage.java)就随之生成了。新建消息驱动bean向导已经为我们创建了JMS资源。EJB 3.0 API允许我们在类中根据JNDI命名空间查找对象所以我们不再需要配置部署描述文件去指定JMS资源。
    EJB 3.0 规范允许我们使用annotations直接引入资源进一个类中。我们将使用annotations去引入MessageDrivenContext资源进我们的类中,并且注入PersistenceContext资源,将被EntityManager API用来管理持久化实体的实例。
  1. 添加下面的注解字段(黑体),将MessageDrivenContext资源注入到类中
    java 代码
     
    1. public class NewMessage implements MessageListener {  
    2.   
    3. @Resource  
    4. private MessageDrivenContext mdc;  
  2. 右键单击代码并选择Persistence > Use Entity Manager,为类引入entity manager
    java 代码
     
    1. @PersistenceContext  
    2. private EntityManager em;  
    3. 并生成如下方法:  
    4. public void persist(Object object) {  
    5. // TODO:  
    6. // em.persist(object);  
    7. }  

  3. 像下面这样修改persist方法
    java 代码
     
    1. public void save(Object object) {  
    2.     em.persist(object);  
    3. }  

  4. 修改onMessage方法,在方法体中添加如下代码
    java 代码
     
    1. ObjectMessage msg = null;  
    2. try {  
    3.     if (message instanceof ObjectMessage) {  
    4.         msg = (ObjectMessage) message;  
    5.         NewsEntity e = (NewsEntity) msg.getObject();  
    6.         save(e);  
    7.     }  
    8. catch (JMSException e) {  
    9.     e.printStackTrace();  
    10.     mdc.setRollbackOnly();  
    11. catch (Throwable te) {  
    12.     te.printStackTrace();  
    13. }  
  5. 按Alt-Shift-F生成必要的import语句。在生成import语句时,我们要确定我们引入了jms和javax.annotation.Resource;类库。
  6. 保存文件。

创建会话bean

下一步我们为NewsEntity实体类创建一个session facade。按照下列步骤来做:
  1. 右键单击EJB module并选择New > File/Folder。
  2. 在persistence类别下,选择Session Beans for Entity Classes并点击Next。
  3. 在available entity classes列表中,选择NewsEntity并点击Add然后点击Next
  4. 检查Packages设定的是ejb、local interface
  5. 点击finish。
    当你点击Finish,session facade类NewsEntityFacade.java会被创建被在源码编辑器中打开。IDE同时会创建local interface NewsEntityFacadeLocal.java。
    EJB 3.0 技术减轻了代码量,简化了会话bean的建立过程。在session bean中你能看到annotation @Stateless被用来声明一个类是无状态会话bean组件,不再需要实现javax.ejb.SessionBean。利用EJB 3.0技术代码变得更简洁干净,业务方法不再需要用代码声明他们的已检查方法。
    当我们创建session facade时你能看到PersistenceContext资源被直接注入到会话bean组件。

总结

在这个练习中,我们在EJB module中编写了一个实体类和一个消息驱动bean。然后为实体类创建了一个session facade。我们同时也创建了JMS资源,将在我们的应用中使用。

编写Web Module


    我们现在将在web module中创建servlets ListNews和PostMessage。这些servlets将用来读写消息。
创建Servlet ListNews
在这个练习中我们将创建一个简单的servlet用来显示我们的数据。我们将使用annotations从servlet.listNews中调用实体类
  1. 右键单击web module项目并选择New > Servlet.
  2. 键入ListNews作为类名
  3. 输入web作为Package name并点击Finish.
当你点击了Finish,类ListNews.java在源码编辑器中打开。在编辑器中,按以下步骤来做:
  1. 右键单击源代码并选择Enterprise Resources > Call Enterprise Bean。
  2. 在call Enterprise Bean 对话框中,选择NewsEntityFacade并点击OK。实体类资源就通过@EJB annotation被注入到了servlet中。进入processRequest方法,反注释代码并添加以下黑体代码到方法体中:
    java 代码
     
    1. out.println(" 
    2.     Servlet ListNews at " + request.getContextPath () + " 
    3.     ");    
    4.       
    5.   List news = newsEntityFacade.findAll();    
    6.   for (Iterator it = news.iterator(); it.hasNext();) {    
    7.       NewsEntity elem = (NewsEntity) it.next();    
    8.       out.println(" "+elem.getTitle()+" ");    
    9.       out.println(elem.getBody()+" ");    
    10.   }    
    11.   out.println("Add new message");    
    12.      
    13.  out.println("");   
  3.  我们要从util包中引入类。按下Alt-Shif-F为类生成所有的import语句。
  4. 保存更改。

创建PostMessage Servlet

在这个练习里我们将创建PostMessage servlet,用来提交消息。我们使用annotations把建立好的JMS资源直接注入到servlet中,定义变量名和它映射的名称。我们然后会编写发送JMS消息的代码和添加新消息的HTML表单代码。
  1. 右键单击web module项目并选择New > Servlet。
  2. 键入PostMessage作为类名。
  3. 键入web为包名并点击Finish。
当你点击Finish后,类PostMessage.java在源码编辑器中打开。请按以下步骤来做:
  1. 用annotations注入ConnectionFactory和Queue资源,请添加以下字段声明
    java 代码
     
    1. public class PostMessage extends HttpServlet {    
    2.     @Resource(mappedName="jms/NewMessageFactory")    
    3.     private  ConnectionFactory connectionFactory;     
    4.     @Resource(mappedName="jms/NewMessage")     
    5.     private  Queue queue;  
  2. 在processRequest方法中添加如下代码发送JMS消息:
    java 代码
     
    1. response.setContentType("text/html;charset=UTF-8");    
    2.               
    3.           // Add the following code to send the JMS message    
    4.           String title=request.getParameter("title");    
    5.           String body=request.getParameter("body");    
    6.           if ((title!=null) && (body!=null)) {    
    7.               try {    
    8.                   Connection connection = connectionFactory.createConnection();    
    9.                   Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);    
    10.                  MessageProducer messageProducer = session.createProducer(queue);    
    11.              
    12.                  ObjectMessage message = session.createObjectMessage();    
    13.                  // here we create NewsEntity, that will be sent in JMS message    
    14.                  NewsEntity e = new NewsEntity();    
    15.                  e.setTitle(title);    
    16.                  e.setBody(body);    
    17.              
    18.                  message.setObject(e);    
    19.                  messageProducer.send(message);    
    20.                  messageProducer.close();    
    21.                  connection.close();    
    22.                  response.sendRedirect("ListNews");    
    23.              
    24.              } catch (JMSException ex) {    
    25.                  ex.printStackTrace();    
    26.              }    
    27.          }    
    28.              
    29.          PrintWriter out = response.getWriter();   
  3. 现在反注释打印HTML的代码并添加新增消息的web form。在processRequest方法中添加下面代码:
    java 代码
     
    1. out.println("Servlet PostMessage at " + request.getContextPath() + "");    
    2.      
    3.  // Add the following code to add the form to the web page    
    4.  out.println(" ");    
    5.  out.println("Title:  ");    
    6.  out.println("Message:  ");    
    7.  out.println(" ");    
    8.  out.println("");    
    9.  out.println("");   
  4.  按下Alt-Shif-F生成必须的import语句。选择java.jms类库中Connection, ConnectionFactory, Session和Queue。
  5. 保存所有更改。

运行项目


我们现在可以运行项目了。当项目运行时,我们要在浏览器中打开ListNews servlet。需要在企业应用项目的属性里指定URL。URL是你的应用上下文路径的相对路径。在你输入相对URL后,在项目窗口中,我们编译、部署并运行我们的应用。

请按照如下步骤来设置相对路径和运行应用程序。
  1. 在项目窗口中,右键单击NewsApp企业应用结点并在弹出菜单中选择属性。
  2. 选择”运行”。
  3. 在relative URL文本域中键入/ListNews。
  4. 在项目窗口中,右键单击NewsApp企业应用结点并选择运行项目。

当你运行了项目,ListNews servlet会在你的浏览器中打开并显示出数据库中的消息列表。第一次运行项目时,数据库是空的,但你可以点击Add Message去新增一条信息。

当你用PostMessage servlet添加一条信息时,这条信息就被送到消息驱动bean持久化,然后ListNews servlet会被调用显示数据库中的信息。ListNews取出数据库的消息列表经常会不包含最新的信息因为消息服务是异步的。


疑难解答



下面是一些你在创建项目时可能会遇到的问题。

JMS资源问题

当你用向导创建JMS资源时,你可能会看到下列在输出窗口中的服务器错误:

[com.sun.enterprise.connectors.ConnectorRuntimeException:  JMS resource not created : jms/Queue]                

这条信息可能意味着JMS资源没有被创建或者没有被服务器注册。你可以用Sun Java System Application Server的Admin Console来检查、创建和编辑JMS资源

按照下列步骤打开Admin Console:
  1. 展开IDE运行时的Servers结点,确认Sun Java System Application Server正在运行。Sun Java System Application Server旁的一个小的绿色箭头表示服务器正在运行。
  2. 右键单击 Sun Java System Application Server结点并选择查看Admin Console,在浏览器中打开登录窗口。
  3. 登录进入 Sun Java System Application Server。默认用户名和密码是admin和adminadmin
  4. 在浏览器中的Admin Console,展开左边框内的资源和JMS资源结点。
  5. 点击左边框中的Connection Factories和Destination Resources 链接,检查资源是否注册到服务器中和是否需要修改。若资源不存在,你可以创建一个。

你需要确定PostMessage Servlet中的JMS connection factory resource在Sun Java System Application Server注册的JMS connection factory resource中正确的映射了JNDI名称。

下面的资源应该在Sun Java System Application Server中注册:
  • 一个JNDI名为jms/NewMessage,类型为javax.jms.Queue的Destination resource
  • 一个JNDI名为jms/NewMessageFactory,类型为javax.jms.QueueConnectionFactory的Connection Factory resource
评论
tlg 2007-04-13
我在建 Session Beans for Entity Classes 时,在available entity classes列表中怎么没有已建的NewsEntity,里面是空的,没有任何实体类
发表评论

您还没有登录,请登录后发表评论

JeffreyHsu
搜索本博客
我的相册
7c1e255e-ee66-312a-80a1-c6f53a40fa2c-thumb
grid.png
共 11 张
存档
最新评论