Java EE状态会话Bean(EJB)示例
在本文中,我們將了解如何在簡單的Web應(yīng)用程序中使用狀態(tài)會話Bean來跟蹤客戶端會話中的狀態(tài)。
1.簡介
有狀態(tài)會話Bean通常保存有關(guān)特定客戶端會話的信息,并在整個會話中保留該信息(與無狀態(tài)會話Bean相對)。 有狀態(tài)EJB實例僅與一個客戶端耦合。 當(dāng)然,一個客戶端可以擁有許多EJB實例。
在此示例中,我們將創(chuàng)建一個簡單的Shopping Cart應(yīng)用程序。 會話bean將保存產(chǎn)品列表。 隨著客戶將更多產(chǎn)品添加到購物車中,此列表將相應(yīng)增加。 最終,客戶將能夠簽出他的訂單,并且上述列表中的產(chǎn)品將保存在MySQL數(shù)據(jù)庫中。
為了實現(xiàn)上述功能,我們將創(chuàng)建一個EAR項目和一個EJB項目來托管我們的會話Bean,并創(chuàng)建一個動態(tài)Web應(yīng)用程序來托管一個Servlet,以測試上述行為。 我們將使用Eclipse Java EE IDE 4,3 Kepler和Glassfish 4.0作為容器。 另外,我們將使用標(biāo)準(zhǔn)的JPA 2.o將我們的產(chǎn)品保存在在localhost上運行的MySQL 5.6.14數(shù)據(jù)庫中。 這是有關(guān)如何將MySQL與Glassfish集成的指南。
2.創(chuàng)建一個新的企業(yè)應(yīng)用程序項目
創(chuàng)建一個名為StatefulEJBEAR的新企業(yè)應(yīng)用程序項目。 在Eclipse IDE中,選擇File-> New-> Enterprise Application Project,填寫表單,然后單擊Finish:
3.創(chuàng)建一個新的EJB Projet
創(chuàng)建一個名為StatefulSessionBeansEJB的新EJB項目。 我們將基于此創(chuàng)建會話bean。 轉(zhuǎn)到文件->新建-> EJB項目并填寫表單。 請小心選擇“添加EAR項目”,然后選擇“ StatefulEJBEAR ”作為EAR項目名稱:
4.創(chuàng)建一個有狀態(tài)會話Bean
在項目資源管理器中打開StatefulSessionBeansEJB項目,并在文件夾ejbModule創(chuàng)建一個名為com.javacodegeeks.enterprise.ejb的新源包。 在該程序包中,創(chuàng)建一個新的Interface ,它將是EJB的本地視圖:
Cart.java:
package com.javacodegeeks.enterprise.ejb;import javax.ejb.Local;import com.javacodegeeks.enterprise.product.Product;@Local public interface Cart {void addProductToCart(Product product);void checkOut();}如您所見,我們聲明了兩種方法,一種方法是將產(chǎn)品添加到購物車,另一種方法是檢查訂單。
這是會話Bean:
CartBean.java:
package com.javacodegeeks.enterprise.ejb;import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit;import javax.annotation.PostConstruct; import javax.ejb.Stateful; import javax.ejb.StatefulTimeout; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext;import com.javacodegeeks.enterprise.product.Product;@Stateful @StatefulTimeout(unit = TimeUnit.MINUTES, value = 20) public class CartBean implements Cart {@PersistenceContext(unitName = "pu", type = PersistenceContextType.EXTENDED)private EntityManager entityManager;private List products;@PostConstructprivate void initializeBean(){products = new ArrayList<>();}@Overridepublic void addProductToCart(Product product) {products.add(product);}@Override@TransactionAttribute(TransactionAttributeType.REQUIRED)public void checkOut() {for(Product product : products){entityManager.persist(product);}products.clear();} }如您所見,我們的Session bean實現(xiàn)了我們的Cart接口,并簡單地保存了一個產(chǎn)品列表(稍后將在類Product上提供更多信息)。
在上面的代碼中注意:
- 我們使用@Stateful將類注釋為有狀態(tài)會話Bean。
- 我們使用@StatefulTimeout(unit = TimeUnit.MINUTES, value = 20)注釋聲明超時。 此超時表示bean應(yīng)該存在的時間,因此對于會話有效。 它應(yīng)該與HTTP會話超時值相對應(yīng)。
- 我們使用@PersistenceContext注入一個EntityManager來處理產(chǎn)品的持久性。
- 我們在private void initializeBean()方法上使用@PostConstruct批注。 這將指示EJB容器在bean初始化時執(zhí)行該方法。 您可以將其視為構(gòu)造函數(shù)。
- 我們在public void checkOut()方法上使用@TransactionAttribute(TransactionAttributeType.REQUIRED)批注。 需要使用此注釋來表示容器將要在事務(wù)上下文中調(diào)用業(yè)務(wù)方法。 您可以按照這種方法查看列表中的產(chǎn)品,并將它們保留在數(shù)據(jù)庫中。
5.產(chǎn)品實體類
這是代表我們購物車應(yīng)用程序中簡單產(chǎn)品的對象。 它由一個ID和一個類型組成。 就像我們說過的,當(dāng)結(jié)帳時,我們希望購物車上的產(chǎn)品能夠保存在數(shù)據(jù)庫中。 我們使用JPA 2.0批注將Product類映射到MySQL表。 對于此示例,我創(chuàng)建了一個簡單的數(shù)據(jù)庫,名為shop和表,其表名為product ,該腳本是使用以下腳本創(chuàng)建的:
MySQL產(chǎn)品表創(chuàng)建腳本:
CREATE TABLE `product` (`ID` int(11) NOT NULL AUTO_INCREMENT,`TYPE` varchar(256) COLLATE utf8_unicode_ci NOT NULL,PRIMARY KEY (`ID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8這是表格:
讓我們看一下Product類的代碼:
產(chǎn)品.java:
package com.javacodegeeks.enterprise.product;import java.io.Serializable;import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table;@Entity @Table(name = "PRODUCT", catalog = "shop") public class Product implements Serializable {private static final long serialVersionUID = 1L;@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Column(name = "ID", nullable = false)private int id;@Column(name = "TYPE", nullable = false)private String type;public int getId() {return id;}public String getType() {return type;}public void setType(String description) {this.type = description;}}以上注釋不言自明。 非常簡單地,我們使用:
- @Entity將類聲明為Entity。
- @Table(name = "PRODUCT", catalog = "shop")顯示該類將映射到名為shop的數(shù)據(jù)庫中名為product的表。
- @Id id , @Id @GeneratedValue(strategy = GenerationType.IDENTITY)聲明類Product的字段id將是相應(yīng)數(shù)據(jù)庫表的主鍵。
- @Column將類字段映射到表product的數(shù)據(jù)庫列。
最后,為了使持久性起作用,我們需要在ejbModule/META-INF文件夾內(nèi)創(chuàng)建一個persistence.xml文件。 該文件如下所示:
application.xml:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"version="2.0"><persistence-unit name="pu" transaction-type="JTA"><jta-data-source>jdbc/MySQLDataSource</jta-data-source> <class>com.javacodegeeks.enterprise.product.Product</class></persistence-unit></persistence>確保使用此隊列已將MySQL與Glassfish正確集成。 有關(guān)persistence.xml文件的更多信息,請參見此Oracle指南 。
因此, StatefulBeansEJB的最終項目結(jié)構(gòu)為:
6.創(chuàng)建一個新的動態(tài)Web項目
轉(zhuǎn)到文件->新建->動態(tài)Web項目。 填寫表單,確保您選中“將項目添加到EAR”,并將StatefulEJBEAR用作“ EAR項目名稱”:
單擊“完成”后,轉(zhuǎn)到項目資源管理器,然后右鍵單擊項目StatefulSessionBeansTest然后轉(zhuǎn)到“屬性”->“部署程序集”->“添加”->“項目”->“ StatefulEJB”:
7.創(chuàng)建一個新的Servlet
轉(zhuǎn)到StatefulSessionBeansTest Web項目并創(chuàng)建一個名為ShoppingCartServlet的新Servlet:
因此,這將是Web項目的最終結(jié)構(gòu):
這是Servlet的代碼:
ShoppingCartServlet.java:
package com.javacodegeeks.enterprise.servlet;import java.io.IOException;import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import com.javacodegeeks.enterprise.ejb.Cart; import com.javacodegeeks.enterprise.product.Product;@WebServlet("/ShoppingCartServlet") public class ShoppingCartServlet extends HttpServlet {private static final long serialVersionUID = 1L;private static final String CART_SESSION_KEY = "shoppingCart";public ShoppingCartServlet() {super();}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("Hello from servlet");Cart cartBean = (Cart) request.getSession().getAttribute(CART_SESSION_KEY);if(cartBean == null){// EJB is not yet in the HTTP session// This means that the client just sent his first request// We obtain a CartBean instance and add it to the session object.try {InitialContext ic = new InitialContext();cartBean = (Cart) ic.lookup("java:global/StatefulEJBEAR/StatefulSessionBeansEJB/CartBean!"+ "com.javacodegeeks.enterprise.ejb.Cart");request.getSession().setAttribute(CART_SESSION_KEY, cartBean);System.out.println("shoppingCart created");} catch (NamingException e) {throw new ServletException(e);}}String productName = request.getParameter("product");if(productName != null && productName.length() > 0){Product product = new Product();product.setType(productName);cartBean.addProductToCart(product);System.out.println("product "+productName+" added");}String checkout = request.getParameter("checkout");if(checkout != null && checkout.equalsIgnoreCase("yes")){// Request instructs to complete the purchasecartBean.checkOut();System.out.println("Shopping cart checked out ");}}}在上面的Serlvet中,當(dāng)用戶第一次發(fā)送GET請求時,將從容器中獲取一個新的CartBean實例并將其添加到會話中。 然后,解析product查詢參數(shù),如果它不為null,則將使用productName type的新Product并將其添加到會話bean中的產(chǎn)品列表中。
然后,分析checkout查詢參數(shù),如果將其評估為'yes' ,則會話Bean中的產(chǎn)品將被保留。
提示: 如果您在確定EJB PassivationObject的可移植JNDI名稱時遇到麻煩,請在部署項目時查看Glassfish的日志或輸出,您會發(fā)現(xiàn)類似以下內(nèi)容的行: 2013-12-13T18:22:28.598 + 0200 | INFO :EJB5181:EJB PassivationObject的便攜式JNDI名稱:(java:global / StatefulBeans / StatefulEJB / PassivationObject,java:global / StatefulBeans / StatefulEJB / PassivationObject!com.javacodegeeks.enterprise.ejb.Passivation)
8.測試
現(xiàn)在,我們僅要將Dynamic Web Application部署到Glassfish,并在購物車中添加一些產(chǎn)品。 然后,我們將要求結(jié)帳該訂單。
假設(shè)我們要添加一些產(chǎn)品,我們可以發(fā)出以下請求:
http://localhost:8080/StatefulSessionBeansTest/ShoppingCartServlet?product=ram http://localhost:8080/StatefulSessionBeansTest/ShoppingCartServlet?product=mouse http://localhost:8080/StatefulSessionBeansTest/ShoppingCartServlet?product=ssd發(fā)布這些請求時,這是控制臺的輸出:
2014-01-07T22:02:07.622+0200|INFO: Hello from servlet 2014-01-07T22:02:07.684+0200|INFO: shoppingCart created 2014-01-07T22:02:07.687+0200|INFO: product ram added 2014-01-07T22:02:12.236+0200|INFO: Hello from servlet 2014-01-07T22:02:12.237+0200|INFO: product mouse added 2014-01-07T22:02:24.851+0200|INFO: Hello from servlet 2014-01-07T22:02:24.851+0200|INFO: product ssd added現(xiàn)在要簽出訂單,您可以發(fā)出:
http://localhost:8080/StatefulSessionBeansTest/ShoppingCartServlet?checkout=yes這是控制臺的輸出:
2014-01-07T22:19:46.444+0200|INFO: Hello from servlet 2014-01-07T22:19:46.537+0200|INFO: Shopping cart checked out在這里您可以看到數(shù)據(jù)庫中的產(chǎn)品:
下載Eclipse項目
這是Java EE狀態(tài)會話Bean(EJB)上的示例。 這是此示例的Eclipse項目: StatefulEJBS.zip
翻譯自: https://www.javacodegeeks.com/2013/08/java-ee-stateful-session-bean-ejb-example.html
總結(jié)
以上是生活随笔為你收集整理的Java EE状态会话Bean(EJB)示例的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 无人机怎么备案登记(无人机怎么备案)
- 下一篇: Java 7 vs Groovy 2.1