如何使用有状态会话 Bean 使数据跨页面持久化?
How to make data persistent across pages using a Stateful Session Bean?
我正在使用 JEE 开发购物车。我的 Web 应用程序由一个有状态会话 bean 和两个具有相应 JSP 页面的 servlet 组成。一个 servlet 允许将新项目添加到购物车,另一个允许列出购物车的内容。
有状态会话 bean 应该跨页面保存购物车的状态,但购物车总是显示为空。你能帮我找出我的代码有什么问题并解释为什么当前的实现不够吗?
将新商品添加到购物车的 Servlet:
package my.servlet;
import my.entity.BookEntity;
import my.entity.ItemEntity;
import my.session.BookBean;
import my.session.CartBean;
import javax.ejb.EJB;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
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 java.io.IOException;
@WebServlet("/item")
public class ItemServlet extends HttpServlet {
@EJB
private BookBean bookBean;
@EJB
private CartBean cartBean;
@PersistenceContext(unitName = "book-pu")
private EntityManager bookManager;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
ServletContext ctx = getServletContext();
long book = Long.parseLong(request.getParameter("book"), 10);
RequestDispatcher dispatcher = ctx.getRequestDispatcher("/jsp/item.jsp");
request.setAttribute("book", bookManager.find(BookEntity.class, book));
request.setAttribute("item", null);
dispatcher.forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
ServletContext ctx = getServletContext();
int qty = Integer.parseInt(request.getParameter("qty"), 10);
long book = Long.parseLong(request.getParameter("book"), 10);
RequestDispatcher dispatcher = ctx.getRequestDispatcher("/jsp/item.jsp");
ItemEntity item = new ItemEntity(bookManager.find(BookEntity.class, book), qty);
request.setAttribute("book", bookManager.find(BookEntity.class, book));
request.setAttribute("item", item);
cartBean.addItem(item);
dispatcher.forward(request, response);
}
}
用于列出购物车内容的 Servlet:
package my.servlet;
import my.session.CartBean;
import javax.ejb.EJB;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
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 java.io.IOException;
@WebServlet("/cart")
public class CartServlet extends HttpServlet {
@EJB
private CartBean cartBean;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
ServletContext ctx = getServletContext();
RequestDispatcher dispatcher = ctx.getRequestDispatcher("/jsp/cart.jsp");
request.setAttribute("items", cartBean.getAllItems());
dispatcher.forward(request, response);
}
}
有状态会话 Bean:
package my.session;
import java.util.ArrayList;
import java.util.Collection;
import javax.annotation.PostConstruct;
import javax.ejb.LocalBean;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.ejb.StatefulTimeout;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.concurrent.TimeUnit;
import my.entity.ItemEntity;
@LocalBean
@Stateful
@StatefulTimeout(unit = TimeUnit.MINUTES, value = 30)
public class CartBean implements CartItf {
private Collection<ItemEntity> items;
@PersistenceContext(unitName = "book-pu")
private EntityManager itemManager;
@PostConstruct
public void initialize() {
items = new ArrayList<ItemEntity>();
}
@Override
public void addItem(ItemEntity item)
{
items.add(item);
}
@Override
public Collection<ItemEntity> getAllItems()
{
return items;
}
@Remove
@Override
public void confirmOrder()
{
for (ItemEntity item : items) {
itemManager.persist(item);
}
}
}
您需要确保每次(每个 servlet)重用相同的有状态实例而不是新实例。您有多种选择:
- 添加@SessionScoped 并使用@Inject 代替@EJB
- 以编程方式查找 bean 实例 (new InitialContext()) 并将其放入 HttpSession
我正在使用 JEE 开发购物车。我的 Web 应用程序由一个有状态会话 bean 和两个具有相应 JSP 页面的 servlet 组成。一个 servlet 允许将新项目添加到购物车,另一个允许列出购物车的内容。
有状态会话 bean 应该跨页面保存购物车的状态,但购物车总是显示为空。你能帮我找出我的代码有什么问题并解释为什么当前的实现不够吗?
将新商品添加到购物车的 Servlet:
package my.servlet;
import my.entity.BookEntity;
import my.entity.ItemEntity;
import my.session.BookBean;
import my.session.CartBean;
import javax.ejb.EJB;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
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 java.io.IOException;
@WebServlet("/item")
public class ItemServlet extends HttpServlet {
@EJB
private BookBean bookBean;
@EJB
private CartBean cartBean;
@PersistenceContext(unitName = "book-pu")
private EntityManager bookManager;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
ServletContext ctx = getServletContext();
long book = Long.parseLong(request.getParameter("book"), 10);
RequestDispatcher dispatcher = ctx.getRequestDispatcher("/jsp/item.jsp");
request.setAttribute("book", bookManager.find(BookEntity.class, book));
request.setAttribute("item", null);
dispatcher.forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
ServletContext ctx = getServletContext();
int qty = Integer.parseInt(request.getParameter("qty"), 10);
long book = Long.parseLong(request.getParameter("book"), 10);
RequestDispatcher dispatcher = ctx.getRequestDispatcher("/jsp/item.jsp");
ItemEntity item = new ItemEntity(bookManager.find(BookEntity.class, book), qty);
request.setAttribute("book", bookManager.find(BookEntity.class, book));
request.setAttribute("item", item);
cartBean.addItem(item);
dispatcher.forward(request, response);
}
}
用于列出购物车内容的 Servlet:
package my.servlet;
import my.session.CartBean;
import javax.ejb.EJB;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
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 java.io.IOException;
@WebServlet("/cart")
public class CartServlet extends HttpServlet {
@EJB
private CartBean cartBean;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
ServletContext ctx = getServletContext();
RequestDispatcher dispatcher = ctx.getRequestDispatcher("/jsp/cart.jsp");
request.setAttribute("items", cartBean.getAllItems());
dispatcher.forward(request, response);
}
}
有状态会话 Bean:
package my.session;
import java.util.ArrayList;
import java.util.Collection;
import javax.annotation.PostConstruct;
import javax.ejb.LocalBean;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.ejb.StatefulTimeout;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.concurrent.TimeUnit;
import my.entity.ItemEntity;
@LocalBean
@Stateful
@StatefulTimeout(unit = TimeUnit.MINUTES, value = 30)
public class CartBean implements CartItf {
private Collection<ItemEntity> items;
@PersistenceContext(unitName = "book-pu")
private EntityManager itemManager;
@PostConstruct
public void initialize() {
items = new ArrayList<ItemEntity>();
}
@Override
public void addItem(ItemEntity item)
{
items.add(item);
}
@Override
public Collection<ItemEntity> getAllItems()
{
return items;
}
@Remove
@Override
public void confirmOrder()
{
for (ItemEntity item : items) {
itemManager.persist(item);
}
}
}
您需要确保每次(每个 servlet)重用相同的有状态实例而不是新实例。您有多种选择:
- 添加@SessionScoped 并使用@Inject 代替@EJB
- 以编程方式查找 bean 实例 (new InitialContext()) 并将其放入 HttpSession