Java EE状态会话Bean(EJB)示例

在本文中,我们将了解如何在简单的Web应用程序中使用状态会话Bean来跟踪客户端会话中的状态。

1.简介

有状态会话Bean通常保存有关特定客户端会话的信息,并在整个会话中保留该信息(与无状态会话Bean相对)。 有状态EJB实例仅与一个客户端耦合。 当然,一个客户端可以拥有许多EJB实例。

在此示例中,我们将创建一个简单的Shopping Cart应用程序。 会话bean将保存产品列表。 随着客户将更多产品添加到购物车中,此列表将相应增加。 最终,客户将能够签出他的订单,并且上述列表中的产品将保存在MySQL数据库中。

为了实现上述功能,我们将创建一个EAR项目和一个EJB项目来托管我们的会话Bean,并创建一个动态Web应用程序来托管一个Servlet,以测试上述行为。 我们将使用Eclipse Java EE IDE 4,3 Kepler和Glassfish 4.0作为容器。 另外,我们将使用标准的JPA 2.o将我们的产品保存在在localhost上运行的MySQL 5.6.14数据库中。 这是有关如何将MySQL与Glassfish集成的指南。

2.创建一个新的企业应用程序项目

创建一个名为StatefulEJBEAR的新企业应用程序项目。 在Eclipse IDE中,选择File-> New-> Enterprise Application Project,填写表单,然后单击Finish:

新耳计划

3.创建一个新的EJB Projet

创建一个名为StatefulSessionBeansEJB的新EJB项目。 我们将基于此创建会话bean。 转到文件->新建-> EJB项目并填写表单。 请小心选择“添加EAR项目”,然后选择“ StatefulEJBEAR ”作为EAR项目名称:

新项目

4.创建一个有状态会话Bean

在项目资源管理器中打开StatefulSessionBeansEJB项目,并在文件夹ejbModule创建一个名为com.javacodegeeks.enterprise.ejb的新源包。 在该程序包中,创建一个新的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();

}

如您所见,我们声明了两种方法,一种方法是将产品添加到购物车,另一种方法是检查订单。

这是会话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;

	@PostConstruct
	private void initializeBean(){
	   products = new ArrayList<>();
	}

	@Override
	public 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实现了我们的Cart接口,并简单地保存了一个产品列表(稍后将在类Product上提供更多信息)。

在上面的代码中注意:

  • 我们使用@Stateful将类注释为有状态会话Bean。
  • 我们使用@StatefulTimeout(unit = TimeUnit.MINUTES, value = 20)注释声明超时。 此超时表示bean应该存在的时间,因此对于会话有效。 它应该与HTTP会话超时值相对应。
  • 我们使用@PersistenceContext注入一个EntityManager来处理产品的持久性。
  • 我们在private void initializeBean()方法上使用@PostConstruct批注。 这将指示EJB容器在bean初始化时执行该方法。 您可以将其视为构造函数。
  • 我们在public void checkOut()方法上使用@TransactionAttribute(TransactionAttributeType.REQUIRED)批注。 需要使用此注释来表示容器将要在事务上下文中调用业务方法。 您可以按照这种方法查看列表中的产品,并将它们保留在数据库中。

5.产品实体类

这是代表我们购物车应用程序中简单产品的对象。 它由一个ID和一个类型组成。 就像我们说过的,当结帐时,我们希望购物车上的产品能够保存在数据库中。 我们使用JPA 2.0批注将Product类映射到MySQL表。 对于此示例,我创建了一个简单的数据库,名为shop和表,其表名为product ,该脚本是使用以下脚本创建的:

MySQL产品表创建脚本:

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类的代码:

产品.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的数据库中名为product的表。
  • @Id id@Id @GeneratedValue(strategy = GenerationType.IDENTITY)声明类Product的字段id将是相应数据库表的主键。
  • @Column将类字段映射到表product的数据库列。

最后,为了使持久性起作用,我们需要在ejbModule/META-INF文件夹内创建一个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正确集成。 有关persistence.xml文件的更多信息,请参见此Oracle指南

因此, StatefulBeansEJB的最终项目结构为:

ejb-项目结构

6.创建一个新的动态Web项目

转到文件->新建->动态Web项目。 填写表单,确保您选中“将项目添加到EAR”,并将StatefulEJBEAR用作“ EAR项目名称”:

新动态网络项目

单击“完成”后,转到项目资源管理器,然后右键单击项目StatefulSessionBeansTest然后转到“属性”->“部署程序集”->“添加”->“项目”->“ StatefulEJB”:

部门分配

7.创建一个新的Servlet

转到StatefulSessionBeansTest Web项目并创建一个名为ShoppingCartServlet的新Servlet:

新的servlet

因此,这将是Web项目的最终结构:

动态网络项目结构

这是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 purchase
		      cartBean.checkOut();
		      System.out.println("Shopping cart checked out ");
		 }

	}

}

在上面的Serlvet中,当用户第一次发送GET请求时,将从容器中获取一个新的CartBean实例并将其添加到会话中。 然后,解析product查询参数,如果它不为null,则将使用productName type的新Product并将其添加到会话bean中的产品列表中。

然后,分析checkout查询参数,如果将其评估为'yes' ,则会话Bean中的产品将被保留。

提示: 如果您在确定EJB PassivationObject的可移植JNDI名称时遇到麻烦,请在部署项目时查看Glassfish的日志或输出,您会发现类似以下内容的行: 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.测试

现在,我们仅要将Dynamic Web Application部署到Glassfish,并在购物车中添加一些产品。 然后,我们将要求结帐该订单。

假设我们要添加一些产品,我们可以发出以下请求:

http://localhost:8080/StatefulSessionBeansTest/ShoppingCartServlet?product=ram
http://localhost:8080/StatefulSessionBeansTest/ShoppingCartServlet?product=mouse
http://localhost:8080/StatefulSessionBeansTest/ShoppingCartServlet?product=ssd

发布这些请求时,这是控制台的输出:

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

现在要签出订单,您可以发出:

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

在这里您可以看到数据库中的产品:

mysql终端

下载Eclipse项目

这是Java EE状态会话Bean(EJB)上的示例。 这是此示例的Eclipse项目: StatefulEJBS.zip

翻译自: https://www.javacodegeeks.com/2013/08/java-ee-stateful-session-bean-ejb-example.html

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值