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;@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实现了我们的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 purchasecartBean.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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/366934.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

起点海外版 Hybrid App-内嵌页优化实践

本文作者&#xff1a;刘文涛 原创声明&#xff1a;本文为阅文前端团队 YFE 成员出品&#xff0c;请尊重原创&#xff0c;转载请联系公众号 (id: yuewen_YFE) 获取授权&#xff0c;并注明作者、出处和链接。 今年年初我司开启了起点品牌的海外之旅&#xff0c;名为「 Webnovel 」…

aix 卸载mysql_AIX 删除数据库及集群软件

一、 删除数据库1、用dbca自动删库在CRT上无法打开dbca图形界面&#xff0c;要安装一个Xmanage软件&#xff0c;用Xstart连接终端&#xff0c;并修改oracle用户的.profile&#xff0c;加上“export DISPLAY192.168.8.120:0.0”Xstart配置信息如下&#xff1a;2、手工删除数据库…

如何在github中的readme.md加入项目截图

1. 先在之前的本地项目文件夹里创建一个存放截图的文件夹。&#xff08;如img文件夹&#xff09; 2. 将新增的内容通过github desktop上传到github中 3. 在github中立马能看到刚刚上传的图片&#xff0c;打开图片&#xff0c;点击Download 4. 直接复制地址栏的网址 5. 最后在RE…

记表格设计规范整理与页面可视化生成工具开发

前言 公司有一个项目在维护&#xff0c;大概有300左右&#xff0c;其中表单与表格的页面占比大概百分之五六十&#xff0c;为了节省开发时间&#xff0c;避免多人协作时&#xff0c;出现多套冗余代码&#xff0c;我们尝试写了一下表单和表格的生成工具&#xff0c;从梳理到规范…

java仿qq空间音乐播放_完美实现仿QQ空间评论回复特效

评论回复是个很常见的东西&#xff0c;但是各大网站实现的方式却不尽相同。大体上有两种方式1.像优酷这种最常见&#xff0c;在输入框中要回复的人&#xff0c;这种方式下&#xff0c;用www.cppcns.com户可以修改。新浪微博则是在这个基础上&#xff0c;弹出好友菜单。这种方式…

使用签名保护基于HTTP的API

我在EMC上的一个平台上可以构建SaaS解决方案。 与越来越多的其他应用程序一样&#xff0c;该平台具有基于RESTful HTTP的API。 使用像JAX-RS这样的开发框架&#xff0c;构建这样的API相对容易。 但是&#xff0c; 正确构建它们并不容易。 建立基于HTTP的API的问题 问题不仅…

Python开发【模块】:Celery 分布式异步消息任务队列

前言&#xff1a; Celery 是一个 基于python开发的分布式异步消息任务队列&#xff0c;通过它可以轻松的实现任务的异步处理&#xff0c; 如果你的业务场景中需要用到异步任务&#xff0c;就可以考虑使用celery&#xff0c; 举几个实例场景中可用的例子: 你想对100台机器执行一…

iOS开发者的一些前端感悟

很多前端工程师会把自己比作“魔法师”&#xff0c;而对于JavaScript这门语言&#xff0c;我也想把它唤作一门“有魔力的语言”。因为这群有无限想法的人&#xff0c;真的在用它创造各种让你惊叹的事物。 Web三件套一、前言 几年前&#xff0c;笔者还是一名初涉编程的学生&…

windows下github 出现Permission denied (publickey)

github教科书传送门:http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000 再学习到"添加远程仓库"的时候遇到了 Permission denied (publickey) 这个问题&#xff0c; 总结来说以前的步骤如下所示&#xff1a; 1、git config --glo…

[UE4]嵌套Canvas

转载于:https://www.cnblogs.com/timy/p/9090642.html

写博客的这几个月,获益良多

1.前言 也将近过年了&#xff0c;看了那么多人搞了年会总结。自己活跃社区这几个月&#xff0c;改变了不少&#xff0c;收获也不少。就想写下这段时间写文章的一些总结&#xff0c;统计下‘成绩’&#xff0c;说下感想&#xff0c;就写了这篇文章。这次总结的关键词就是&#x…

shiro 权限 URL 配置细节

转载于:https://www.cnblogs.com/hwgok/p/9100277.html

2016 年崛起的 JS 项目

本文是我对中文版 risingstars2016 的整理&#xff0c;而本人就是中文版的译者&#xff0c;首发于知乎专栏 前端周刊。共 21384 字&#xff0c;读完需 30 分钟&#xff0c;速读需 5 分钟。长江后浪推前浪&#xff0c;如果你能花 30 分钟读完我 6 个小时翻译的内容&#xff0c;相…

php 开启命令模式,如何启用PhpStorm中的命令行工具

本篇文章主要给大家介绍如何使用phpstorm中的命令行工具。PhpStorm下载地址&#xff1a;PhpStorm使用命令行工具&#xff0c;我们可以直接从IDE调用命令&#xff01;在我们使用任何命令行工具之前&#xff0c;我们必须在设置中启用它。涉及到的步骤如下&#xff1a;使用命令行工…

React Native项目自动化打包发布

今天这篇文章的目的是在rn项目的构建&#xff0c;并不会涉及到rn框架或者使用的讲解&#xff0c;说起构建&#xff0c;特别是前端构建大家应该很快会想到webpack、Grunt、 Gulp等。而这些工具在rn项目中就显得有些鸡肋。所以在此给大家分享一下不使用构建工具实现rn项目自动化打…

Python程序员之面试必回习题

写在前面 近日恰逢学生毕业季&#xff0c;课程后期大家“期待苦逼”的时刻莫过于每天早上内容回顾和面试题问答部分【临近毕业每天课前用40-60分钟对之前内容回顾、提问和补充&#xff0c;专挑班里不爱说话就的同学回答】。 期待的是可以检验自己学习的成功&#xff1b;苦逼的是…

SpringMVC原理MVC设计思想

什么是MVC&#xff1f; MVC是一种架构模式 --- 程序分层&#xff0c;分工合作&#xff0c;既相互独立&#xff0c;又协同工作 MVC是一种思考方式 --- 需要将什么信息展示给用户? 如何布局&#xff1f; 调用哪些业务逻辑&#xff1f; MVC流程图如下图所示&#xff1a; MVC核心思…

Hbase 的javaAPI基本操作用 在idea上的实现

1.保证集群开启&#xff1a; jps有如下进程 2.pom文件中的依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:sche…

旅行报告:JavaOne 2013 –重归荣耀

我已经回来几天了&#xff0c;需要赶上过去几天一直搁置的所有事情。 对我来说&#xff0c;这是一年中最忙的时间。 JavaOne和OpenWorld在旧金山的整整一周。 一个非常简短的旅行报告。 年度ACED简报 你们中许多人都知道我是Oracle社区认可计划&#xff08;称为“ ACE计划 ”&…

ElasticSearch 数据分片

一、ElasticSearch 分片 ElasticSearch集群中有许多个节点(Node)&#xff0c;每一个节点实例就是一个实例&#xff1b;数据分布在分片之间。集群的容量和性能主要取决于分片如何在节点上如何分配。将数据分片是为了提高可处理的容量和易于进行水平扩展&#xff0c;为分片做副本…