EJB 3.0 Enterprise Beans(轉載)
Posted on 2007-05-07 23:19 網路冷眼@BlogJava 閱讀(386) 評論(0) 編輯 收藏 所屬分類: JavaEJB 3.0 Enterprise Beans
本文檔介紹了有關使用 EJB 3.0 技術(作為 Java EE 5 平臺的一部分)開發企業應用程序的基礎知識,同時說明了 EJB 3.0 技術是如何簡化企業應用程序的開發過程的。本文檔使用的是 NetBeans IDE 5.5 發行版本。
預計持續時間:30 分鐘
先決條件
本文檔假定您已具備了以下技術的一些基本知識或編程經驗:
- 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 模塊的 NewsApp 企業應用程序項目。NewsApp 應用程序使用消息驅動 Bean 接收和處理 Servlet 發送到隊列中的消息。該應用程序使用 Servlet 將消息發送到消息驅動 Bean 并顯示消息。
創建企業應用程序
- 從主菜單中選擇“文件”>“新建項目”(Ctrl-Shift-N)。
- 從“企業”類別中選擇“企業應用程序”,然后單擊“下一步”。
- 將項目命名為 NewsApp,并將服務器設置為 Sun Java System Application Server。
- 將 J2EE 版本設置為 "Java EE 5",然后選中“創建 EJB 模塊”和“創建 Web 應用程序模塊”(如果未選中)。
- 單擊“完成”。
小結
在本練習中,我們創建了包含一個 EJB 模塊和一個 Web 模塊的 Java EE 5 企業應用程序。
對 EJB 模塊進行編碼
在本練習中,我們將在 EJB 模塊中創建對象。我們將創建實體類、消息驅動 Bean 和會話 Facade。我們還將創建一個持久性單元,以便為容器提供用于管理實體的信息,以及消息驅動 Bean 將使用的 Java 消息服務 (Java Message Service, JMS) 資源。
創建持久性單元
首先,我們將創建一個持久性單元,它用于定義在應用程序中使用的數據源和實體管理器。
- 右鍵單擊 EJB 模塊,然后選擇“新建”>“文件/文件夾”。
- 從“持久性”類別中,選擇“持久性單元”,然后單擊“下一步”。
- 保留缺省的持久性單元名稱。
- 對于持久性提供程序,請選擇“TopLink(缺省)”。
- 對于數據源,請選擇缺省的數據源 jdbc/sample。
- 檢查是否為持久性單元選中了“使用 Java 事務 API”,以及“表生成策略”是否設置為“創建”,以便在部署應用程序時創建基于實體類的表。
- 單擊“完成”。
單擊“完成”后,IDE 將創建 persistence.xml,并在源代碼編輯器中將其打開。關閉 persistence.xml。
創建 NewsEntity 實體類
在本練習中,我們將創建 NewsEntity 實體類。實體類是一個簡單的 Java 類。在創建實體類時,IDE 會添加 @Entity 標注以將該類定義為實體類。當創建了類后,我們將在該類中創建字段以表示表中所需的數據。
每個實體類都必須具有一個主鍵。在創建實體類時,IDE 會添加 @Id 標注以聲明要用作主鍵的字段。此外,IDE 還會添加 @Generated 標注以指定主 Id 的鍵生成策略。
要創建 NewsEntity 類,請執行以下操作:
- 在“項目”窗口中右鍵單擊 EJB 模塊,然后選擇“新建”>“文件/文件夾”打開“新建文件”向導。
- 從“持久性”類別中,選擇“實體類”,然后單擊“下一步”。
- 鍵入 NewsEntity 作為類名,鍵入 ejb 作為包名,并將“主鍵類型”保留為 Long。單擊“完成”。
單擊“完成”后,將在源代碼編輯器中打開實體類 NewsEntity.java。在源代碼編輯器中,請執行以下操作:
- 將以下字段聲明添加到類中:
String title; String body;
- 在源代碼編輯器中單擊鼠標右鍵,然后選擇“重構”>“封裝字段”以便為每個字段生成 getter 和 setter。在“封裝字段”對話框中,確保選中了字段 id、title 和 body 的 getter 和 setter 復選框。
- 在“封裝字段”對話框中單擊“下一步”,然后在“輸出”窗口的“重構”標簽中單擊“執行重構”。IDE 將為各字段添加 getter 和 setter 方法,并將字段的可視性更改為 private。
- 保存對文件所做的更改。
在接下來的步驟中,我們將創建 NewMessage 消息驅動 Bean。
創建 NewMessage 消息驅動 Bean
現在我們將在 EJB 模塊中創建 NewMessage 消息驅動 Bean。我們將使用“新建消息驅動 Bean”向導來創建 Bean 和所需的 JMS 資源。
要創建 NewMessage 消息驅動 Bean,請執行以下操作:
- 在“項目”窗口中右鍵單擊 EJB 模塊,然后選擇“新建”>“文件/文件夾”以打開“新建文件”向導。
- 從“企業”類別中,選擇“消息驅動 Bean”,然后單擊“下一步”。
- 鍵入 NewMessage 作為類名。
- 從“包”下拉列表中選擇 "ejb"。
- 選擇“隊列”作為目標類型,然后單擊“完成”。
單擊“完成”后,將在源代碼編輯器中打開新建的消息驅動 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 將使用該資源來管理持久性實體實例。我們要在源代碼編輯器中將標注添加到類中。
- 通過在類中添加以下帶標注的字段(以粗體顯示),將 MessageDrivenContext 資源注入到類中:
public class NewMessage implements MessageListener { @Resource private MessageDrivenContext mdc;
- 在代碼中單擊鼠標右鍵,然后從彈出式菜單中選擇“持久性”>“使用實體管理器”,將實體管理器引入類中。
這會在源代碼中添加以下標注:@PersistenceContext private EntityManager em;
并在代碼中生成以下方法:public void persist(Object object) { // TODO: // em.persist(object); }
- 按如下所示修改 persist 方法:
public void save(Object object) { em.persist(object); }
- 通過將以下代碼添加到主體中來修改 onMessage 方法:
ObjectMessage msg = null; try { if (message instanceof ObjectMessage) { msg = (ObjectMessage) message; NewsEntity e = (NewsEntity) msg.getObject(); save(e); } } catch (JMSException e) { e.printStackTrace(); mdc.setRollbackOnly(); } catch (Throwable te) { te.printStackTrace(); }
- 按 Alt-Shift-F 組合鍵生成所有必要的 import 語句。在生成 import 語句時,我們需要確保導入 jms 和 javax.annotation.Resource; 庫。
- 保存該文件。
創建會話 Bean
接下來,我們將為 NewsEntity 實體類創建一個會話 Facade。要創建會話 Facade,請執行以下操作:
- 右鍵單擊 EJB 模塊,然后選擇“新建”>“文件/文件夾”。
- 從“持久性”類別中,選擇“實體類的會話 Bean”,然后單擊“下一步”。
- 從可用的實體類列表中,選擇 "NewsEntity",單擊“添加”,然后單擊“下一步”。
- 檢查是否將包設置為 ejb 以及是否選中了創建本地接口。
- 單擊“完成”。
單擊“完成”后,將創建會話 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。
- 右鍵單擊 Web 模塊項目,然后選擇“新建”> "Servlet"。
- 鍵入 ListNews 作為類名。
- 輸入 web 作為包名,然后單擊“完成”。
單擊“完成”后,將在源代碼編輯器中打開類 ListNews.java。在源代碼編輯器中,請執行以下操作:
- 在源代碼中,單擊鼠標右鍵,然后選擇“企業資源”>“調用 Enterprise Bean”。
- 在“調用 Enterprise Bean”對話框中,選擇 "NewsEntityFacade",然后單擊“確定”。單擊“確定”后,將使用 @EJB 標注在 Servlet 中注入實體 Bean 資源。
- 在 processRequest 方法中,對其進行如下修改:取消代碼注釋,然后將下面以粗體顯示的行添加到方法主體中。
out.println("<h1>Servlet ListNews at " + request.getContextPath () + "</h1>"); List news = newsEntityFacade.findAll(); for (Iterator it = news.iterator(); it.hasNext();) { NewsEntity elem = (NewsEntity) it.next(); out.println(" <b>"+elem.getTitle()+" </b><br />"); out.println(elem.getBody()+"<br /> "); } out.println("<a href='PostMessage'>Add new message</a>"); out.println("</body>");
- 按 Alt-Shift-F 組合鍵為類生成所有必要的 import 語句。在生成 import 語句時,我們希望從 util 包中導入類。
- 保存對文件所做的更改。
創建 PostMessage Servlet
在本練習中,我們將創建用于傳遞消息的 PostMessage Servlet。我們將使用標注將所創建的 JMS 資源直接注入 Servlet 中,并且指定變量名稱及其映射到的名稱。然后,添加用于發送 JMS 消息的代碼,以及用于在 HTML 表單中添加消息的代碼。
- 右鍵單擊 Web 模塊項目,然后選擇“新建”> "Servlet"。
- 鍵入 PostMessage 作為類名。
- 輸入 web 作為包名,然后單擊“完成”。
單擊“完成”后,將在源代碼編輯器中打開類 PostMessage.java。在源代碼編輯器中,請執行以下操作:
- 通過添加下面以粗體顯示的字段聲明,使用標注來注入 ConnectionFactory 和 Queue 資源:
public class PostMessage extends HttpServlet { @Resource(mappedName="jms/NewMessageFactory") private ConnectionFactory connectionFactory; @Resource(mappedName="jms/NewMessage") private Queue queue;
- 現在,通過將下面以粗體顯示的代碼添加到 processRequest 方法中,添加用于發送 JMS 消息的代碼:
response.setContentType("text/html;charset=UTF-8"); // Add the following code to send the JMS message String title=request.getParameter("title"); String body=request.getParameter("body"); if ((title!=null) && (body!=null)) { try { Connection connection = connectionFactory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer messageProducer = session.createProducer(queue); ObjectMessage message = session.createObjectMessage(); // here we create NewsEntity, that will be sent in JMS message NewsEntity e = new NewsEntity(); e.setTitle(title); e.setBody(body); message.setObject(e); messageProducer.send(message); messageProducer.close(); connection.close(); response.sendRedirect("ListNews"); } catch (JMSException ex) { ex.printStackTrace(); } } PrintWriter out = response.getWriter();
- 現在,將對輸出 HTML 的代碼取消注釋,并添加用于添加消息的 Web 表單。將下面以粗體顯示的代碼行添加到 processRequest 方法中:
out.println("Servlet PostMessage at " + request.getContextPath() + "</h1>"); // Add the following code to add the form to the web page out.println("<form>"); out.println("Title: <input type='text' name='title'><br/>"); out.println("Message: <textarea name='body'></textarea><br/>"); out.println("<input type='submit'><br/>"); out.println("</form>"); out.println("</body>");
- 按 Alt-Shift-F 組合鍵為類生成所有必要的 import 語句。在選擇 Connection、ConnectionFactory、Session 和 Queue 的 import 語句時,將導入 java.jms 庫。
- 保存對文件所做的更改。
運行項目
現在可以運行項目了。在運行項目時,我們希望瀏覽器打開包含 ListNews Servlet 的頁面。可以通過在企業應用程序的“屬性”對話框中指定該頁的 URL 來實現這一目的。該 URL 是應用程序的上下文路徑的相對 URL。輸入相對 URL 后,可以從“項目”窗口中生成、部署并運行應用程序。
要設置相對 URL 并運行應用程序,請執行以下操作:
- 在“項目”窗口中,右鍵單擊 "NewsApp" 企業應用程序節點,然后從彈出式菜單中選擇“屬性”。
- 在“類別”窗格中選擇“運行”。
- 在“相對 URL”文本字段中,鍵入 /ListNews。
- 單擊“確定”。
- 在“項目”窗口中,右鍵單擊 "NewsApp" 企業應用程序節點,然后選擇“運行項目”。
運行項目時,將在瀏覽器中打開 ListNews Servlet,該 Servlet 用于顯示數據庫中的消息列表。如果您是第一次運行項目,則數據庫為空,但是您可以單擊“添加消息”來添加消息。
當您使用 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 管理控制臺來檢查、創建以及編輯 JMS 資源。
要打開管理控制臺,請執行以下操作:
- 在 IDE 的“運行環境”中,展開“服務器”節點以確認 Sun Java System Application Server 正在運行。"Sun Java System Application Server" 節點旁邊的小綠色箭頭表示服務器正在運行。
- 右鍵單擊 "Sun Java System Application Server" 節點,然后選擇“查看管理控制臺”以在瀏覽器中打開登錄窗口。
- 登錄到 Sun Java System Application Server。缺省的用戶名為 admin,口令為 adminadmin。
- 在瀏覽器的管理控制臺中,依次展開左框架中的“資源”節點和“JMS 資源”節點。
- 在左框架中單擊“連接工廠”和“目標資源”鏈接以檢查是否在服務器中注冊了這些資源,并在必要時修改這些資源。如果這些資源不存在,您可以在管理控制臺中創建這些資源。
您需要確保將 PostMessage Servlet 中的 JMS 連接工廠資源映射到在 Sun Java System Application Server 中注冊的 JMS 連接工廠資源的對應 JNDI 名稱上。
應在 Sun Java System Application Server 中注冊以下資源:
- 具有 JNDI 名稱 jms/NewMessage 和類型 javax.jms.Queue 的目標資源
- 具有 JNDI 名稱 jms/NewMessageFactory 和類型 javax.jms.QueueConnectionFactory 的連接工廠資源
后續步驟
有關使用 NetBeans IDE 5.5 開發 Java EE 應用程序的更多信息,請參見以下資源:
您可以在 Java EE 5 教程中找到有關使用 EJB 3.0 Enterprise Beans 的詳細信息。
要發送意見和建議、獲得支持以及隨時了解 NetBeans IDE Java EE 開發功能的最新開發情況,請加入 nbj2ee 郵件列表。