先决条件

本文档假定您已具备了以下技术的一些基本知识或编程经验:

    * Java 编程
    * NetBeans IDE

本教程所需的软件

在学习本教程之前,您需要在计算机中安装以下软件:

    * NetBeans IDE 5.5(下载)
    * Java Standard Development Kit (JDK) 版本 5.0 或版本 6.0(下载)
    * Sun Java System Application Server Platform Edition 9(下载)

在学习本教程之前,您需要在 IDE 中注册 Sun Java System Application Server 的本地实例。
教程练习

    * 建立企业应用程序项目
    * 对 EJB 模块进行编码
    * 对 Web 模块进行编码
    * 运行项目
    * 疑难解答


建立企业应用程序项目

本练习的目的是:创建包含一个 EJB 模块和一个 Web 模块的 NewsApp 企业应用程序项目。NewsApp 应用程序使用消息驱动 Bean 接收和处理 Servlet 发送到队列中的消息。该应用程序使用 Servlet 将消息发送到消息驱动 Bean 并显示消息。
创建企业应用程序

   1. 从主菜单中选择“文件”>“新建项目”(Ctrl-Shift-N)。
   2. 从“企业”类别中选择“企业应用程序”,然后单击“下一步”。
   3. 将项目命名为 NewsApp,并将服务器设置为 Sun Java System Application Server。
   4. 将 J2EE 版本设置为 "Java EE 5",然后选中“创建 EJB 模块”和“创建 Web 应用程序模块”(如果未选中)。
   5. 单击“完成”。

小结

在本练习中,我们创建了包含一个 EJB 模块和一个 Web 模块的 Java EE 5 企业应用程序。
对 EJB 模块进行编码

在本练习中,我们将在 EJB 模块中创建对象。我们将创建实体类、消息驱动 Bean 和会话 Facade。我们还将创建一个持久性单元,以便为容器提供用于管理实体的信息,以及消息驱动 Bean 将使用的 Java 消息服务 (Java Message Service, JMS) 资源。
创建持久性单元

首先,我们将创建一个持久性单元,它用于定义在应用程序中使用的数据源和实体管理器。

   1. 右键单击 EJB 模块,然后选择“新建”>“文件/文件夹”。
   2. 从“持久性”类别中,选择“持久性单元”,然后单击“下一步”。
   3. 保留缺省的持久性单元名称。
   4. 对于持久性提供程序,请选择“TopLink(缺省)”。
   5. 对于数据源,请选择缺省的数据源 jdbc/sample。
   6. 检查是否为持久性单元选中了“使用 Java 事务 API”,以及“表生成策略”是否设置为“创建”,以便在部署应用程序时创建基于实体类的表。
   7. 单击“完成”。


单击“完成”后,IDE 将创建 persistence.x ml,并在源代码编辑器中将其打开。关闭 persistence.x ml。
创建 NewsEntity 实体类

在本练习中,我们将创建 NewsEntity 实体类。实体类是一个简单的 Java 类。在创建实体类时,IDE 会添加 @Entity 标注以将该类定义为实体类。当创建了类后,我们将在该类中创建字段以表示表中所需的数据。

每个实体类都必须具有一个主键。在创建实体类时,IDE 会添加 @Id 标注以声明要用作主键的字段。此外,IDE 还会添加 @Generated 标注以指定主 Id 的键生成策略。

要创建 NewsEntity 类,请执行以下操作:

   1. 在“项目”窗口中右键单击 EJB 模块,然后选择“新建”>“文件/文件夹”打开“新建文件”向导。
   2. 从“持久性”类别中,选择“实体类”,然后单击“下一步”。
   3. 键入 NewsEntity 作为类名,键入 ejb 作为包名,并将“主键类型”保留为 Long。单击“完成”。

单击“完成”后,将在源代码编辑器中打开实体类 NewsEntity.java。在源代码编辑器中,请执行以下操作:

   1. 将以下字段声明添加到类中:

      String title;
      String body;

   2. 在源代码编辑器中单击鼠标右键,然后选择“重构”>“封装字段”以便为每个字段生成 getter 和 setter。在“封装字段”对话框中,确保选中了字段 id、title 和 body 的 getter 和 setter 复选框。
   3. 在“封装字段”对话框中单击“下一步”,然后在“输出”窗口的“重构”标签中单击“执行重构”。IDE 将为各字段添加 getter 和 setter 方法,并将字段的可视性更改为 private。
   4. 保存对文件所做的更改。

在接下来的步骤中,我们将创建 NewMessage 消息驱动 Bean。
创建 NewMessage 消息驱动 Bean

现在我们将在 EJB 模块中创建 NewMessage 消息驱动 Bean。我们将使用“新建消息驱动 Bean”向导来创建 Bean 和所需的 JMS 资源。

要创建 NewMessage 消息驱动 Bean,请执行以下操作:

   1. 在“项目”窗口中右键单击 EJB 模块,然后选择“新建”>“文件/文件夹”以打开“新建文件”向导。
   2. 从“企业”类别中,选择“消息驱动 Bean”,然后单击“下一步”。
   3. 键入 NewMessage 作为类名。
   4. 从“包”下拉列表中选择 "ejb"。
   5. 选择“队列”作为目标类型,然后单击“完成”。

单击“完成”后,将在源代码编辑器中打开新建的消息驱动 Bean 类 NewMessage.java。您可以看到该类具有以下标注:

      
@MessageDriven(mappedName = "jms/NewMessage")

此标注向容器说明:该组件是一个消息驱动 Bean 并且该 Bean 使用 JMS 资源。当 IDE 生成类时,将从类 (NewMessage.java) 名称派生资源的映射名 (jms/NewMessage)。JMS 资源被映射到目标的 JNDI 名称,Bean 从该目标中接收消息。“新建消息驱动 Bean”向导已为我们创建了 JMS 资源。通过 EJB 3.0 API,我们可以从 Bean 类中查找 JNDI 名称空间中的对象,这样就不需要配置部署描述符来指定 JMS 资源了。

EJB 3.0 规范允许您使用标注将资源直接引入类中。现在,我们准备使用标注将 MessageDrivenContext 资源引入类中,然后注入 PersistenceContext 资源,EntityManager API 将使用该资源来管理持久性实体实例。我们要在源代码编辑器中将标注添加到类中。

   1. 通过在类中添加以下带标注的字段(以粗体显示),将 MessageDrivenContext 资源注入到类中:

java 代码
 
  1. public class NewMessage implements MessageListener {  
  2.   
  3. @Resource  
  4. private MessageDrivenContext mdc;  


   2. 在代码中单击鼠标右键,然后从弹出式菜单中选择“持久性”>“使用实体管理器”,将实体管理器引入类中。
      这会在源代码中添加以下标注:

java 代码
 
  1. @PersistenceContext  
  2. private EntityManager em;  
  3.   
  4. 并在代码中生成以下方法:  
  5.   
  6. public void persist(Object object) {  
  7.     // TODO:  
  8.     // em.persist(object);  
  9. }  

   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 实体类创建一个会话 Facade。要创建会话 Facade,请执行以下操作:

   1. 右键单击 EJB 模块,然后选择“新建”>“文件/文件夹”。
   2. 从“持久性”类别中,选择“实体类的会话 Bean”,然后单击“下一步”。
   3. 从可用的实体类列表中,选择 "NewsEntity",单击“添加”,然后单击“下一步”。
   4. 检查是否将包设置为 ejb 以及是否选中了创建本地接口。
   5. 单击“完成”。

单击“完成”后,将创建会话 Facade 类 NewsEntityFacade.java,并在源代码编辑器中将其打开。IDE 还将创建本地接口 NewsEntityFacadeLocal.java。

EJB 3.0 技术通过减少所需的代码量来简化会话 Bean 的创建。您可以看到,标注 @Stateless 用于将类声明为无态会话 Bean 组件,并且该类不再需要实现 javax.ejb.SessionBean 的语句。此外,代码也更为简洁了,因为利用 EJB 3.0 技术,业务方法不再需要使用代码来声明其抛出了所检查到的异常。

您会看到,在创建会话 Facade 时,PersistenceContext 资源已直接注入到会话 Bean 组件中。
小结

在本练习中,我们已对 EJB 模块中的实体类和消息驱动 Bean 进行了编码,然后为实体类创建了会话 Facade。此外,我们还创建了应用程序使用的 JMS 资源。
对 Web 模块进行编码

现在,我们将在 Web 模块中创建 Servlet ListNews 和 PostMessage。这些 Servlet 将用于读取和添加消息。
创建 ListNews Servlet

在本练习中,我们将创建一个用于显示数据的简单 Servlet。我们将使用标注从 Servlet 中调用实体 Bean。

   1. 右键单击 Web 模块项目,然后选择“新建”> "Servlet"。
   2. 键入 ListNews 作为类名。
   3. 输入 web 作为包名,然后单击“完成”。

单击“完成”后,将在源代码编辑器中打开类 ListNews.java。在源代码编辑器中,请执行以下操作:

   1. 在源代码中,单击鼠标右键,然后选择“企业资源”>“调用 Enterprise Bean”。
   2. 在“调用 Enterprise Bean”对话框中,选择 "NewsEntityFacade",然后单击“确定”。单击“确定”后,将使用 @EJB 标注在 Servlet 中注入实体 Bean 资源。
   3. 在 processRequest 方法中,对其进行如下修改:取消代码注释,然后将下面以粗体显示的行添加到方法主体中。
java 代码
 
  1. out.println("

    Servlet ListNews at " + request.getContextPath () + "

    "
    );  
  2.   
  3. List news = newsEntityFacade.findAll();  
  4. for (Iterator it = news.iterator(); it.hasNext();) {  
  5.     NewsEntity elem = (NewsEntity) it.next();  
  6.     out.println("+elem.getTitle()+);  
  7.     out.println(elem.getBody()+");  
  8. }  
  9. out.println(");  
  10.   
  11. out.println("");  

                         

   4. 按 Alt-Shift-F 组合键为类生成所有必要的 import 语句。在生成 import 语句时,我们希望从 util 包中导入类。
   5. 保存对文件所做的更改。

创建 PostMessage Servlet

在本练习中,我们将创建用于传递消息的 PostMessage Servlet。我们将使用标注将所创建的 JMS 资源直接注入 Servlet 中,并且指定变量名称及其映射到的名称。然后,添加用于发送 JMS 消息的代码,以及用于在 HTML 表单中添加消息的代码。

   1. 右键单击 Web 模块项目,然后选择“新建”> "Servlet"。
   2. 键入 PostMessage 作为类名。
   3. 输入 web 作为包名,然后单击“完成”。

单击“完成”后,将在源代码编辑器中打开类 PostMessage.java。在源代码编辑器中,请执行以下操作:

   1. 通过添加下面以粗体显示的字段声明,使用标注来注入 ConnectionFactory 和 Queue 资源:

java 代码
 
  1. public class PostMessage extends HttpServlet {                 
  2.     @Resource(mappedName="jms/NewMessageFactory")  
  3.     private  ConnectionFactory connectionFactory;  
  4.   
  5.     @Resource(mappedName="jms/NewMessage")  
  6.     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 表单。将下面以粗体显示的代码行添加到 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.   
  10. out.println("");  
  11.                   


   4. 按 Alt-Shift-F 组合键为类生成所有必要的 import 语句。在选择 Connection、ConnectionFactory、Session 和 Queue 的 import 语句时,将导入 java.jms 库。
   5. 保存对文件所做的更改。

运行项目

现在可以运行项目了。在运行项目时,我们希望浏览器打开包含 ListNews Servlet 的页面。可以通过在企业应用程序的“属性”对话框中指定该页的 URL 来实现这一目的。该 URL 是应用程序的上下文路径的相对 URL。输入相对 URL 后,可以从“项目”窗口中生成、部署并运行应用程序。

要设置相对 URL 并运行应用程序,请执行以下操作:

   1. 在“项目”窗口中,右键单击 "NewsApp" 企业应用程序节点,然后从弹出式菜单中选择“属性”。
   2. 在“类别”窗格中选择“运行”。
   3. 在“相对 URL”文本字段中,键入 /ListNews。
   4. 单击“确定”。
   5. 在“项目”窗口中,右键单击 "NewsApp" 企业应用程序节点,然后选择“运行项目”。

运行项目时,将在浏览器中打开 ListNews Servlet,该 Servlet 用于显示数据库中的消息列表。如果您是第一次运行项目,则数据库为空,但是您可以单击“添加消息”来添加消息。


当您使用 PostMessage Servlet 添加消息时,消息会发送到消息驱动 Bean 以写入到持久性存储中,并会调用 ListNews Servlet 来显示数据库中的消息。由 ListNews 检索的数据库中的消息列表通常不包含新消息,这是因为消息服务是异步的。
评论
julycn
搜索本博客
我的相册
E09a394b-4b16-328b-8e1d-9ef916ee23c2-thumb
seam.jpg
共 13 张
存档
最新评论