如何使用@ConversationScoped处理多个后台Bean?(Java1.7/JSF2/JPA2/Hibernate4)
如何在多后台Bean场景下使用@ConversationScoped?
这个问题其实是@ConversationScoped的典型进阶用法——跨Bean共享会话上下文,我来给你一步步拆解怎么实现:
核心思路
@ConversationScoped的本质是基于一个唯一的conversationId绑定上下文,不管是哪个后台Bean,只要关联到同一个conversationId,就能共享这个作用域里的状态。所以我们要做的就是:在列表页启动会话、传递会话ID到编辑页、编辑页绑定到同一会话、完成后结束会话。
步骤1:在列表Bean中启动Conversation
列表Bean可以是@ViewScoped或@RequestScoped(不需要是@ConversationScoped,除非你需要在列表页保留会话状态),关键是在用户点击「编辑」按钮时启动会话,并把会话ID传递给编辑页。
首先注入Conversation对象:
@Named @ViewScoped public class ListBean implements Serializable { @Inject private Conversation conversation; @Inject private ItemService itemService; // 列表数据,省略加载逻辑 private List<Item> items; // 点击编辑按钮时触发的方法 public String editItem(Item item) { // 先结束可能存在的旧会话,避免冲突 if (!conversation.isTransient()) { conversation.end(); } // 启动新会话 conversation.begin(); // 把要编辑的条目ID存到会话中(也可以直接通过URL参数传递) FacesContext.getCurrentInstance().getExternalContext() .getSessionMap().put("editItemId", item.getId()); // 跳转到编辑页,通过URL参数传递conversationId(cid) return "editPage?faces-redirect=true&cid=" + conversation.getId(); } }
步骤2:编辑Bean绑定到同一会话
编辑Bean需要声明为@ConversationScoped,并通过传递的cid关联到列表页启动的会话。JSF会自动识别URL中的cid参数,但我们可以手动做校验,确保会话处于激活状态:
@Named @ConversationScoped public class EditBean implements Serializable { @Inject private Conversation conversation; @Inject private ItemService itemService; private Item item; @PostConstruct public void init() { // 校验会话是否有效 if (conversation.isTransient()) { String cid = FacesContext.getCurrentInstance().getExternalContext() .getRequestParameterMap().get("cid"); if (cid == null) { // 无有效会话,直接返回列表页 try { FacesContext.getCurrentInstance().getExternalContext() .redirect("listPage.xhtml"); } catch (IOException e) { // 处理异常 } return; } // 恢复会话 conversation.restore(cid); } // 从会话中取出要编辑的条目ID,加载数据 Long itemId = (Long) FacesContext.getCurrentInstance().getExternalContext() .getSessionMap().get("editItemId"); this.item = itemService.findById(itemId); } // 保存编辑内容的方法 public String saveItem() { itemService.save(item); // 编辑完成后结束会话,释放资源 conversation.end(); // 重定向回列表页 return "listPage?faces-redirect=true"; } }
步骤3:表单提交时保持会话激活
如果编辑页是通过表单提交(而不是直接跳转),要确保表单提交时带上cid,可以在表单中添加隐藏字段:
<h:form> <h:inputHidden value="#{conversation.id}" /> <!-- 其他编辑表单字段 --> <h:commandButton value="保存" action="#{editBean.saveItem}" /> </h:form>
这样表单提交时会自动携带cid,确保会话不会变成 transient 状态。
关键注意事项
- 会话生命周期管理:一定要记得在操作完成后调用
conversation.end(),否则会话会一直存在到超时(默认15分钟,可通过web.xml的javax.faces.CONVERSATION_TIMEOUT参数修改超时时间,单位是毫秒),容易造成内存泄漏。 - 避免存大对象:不要在会话中存储过大的对象,尽量只存必要的标识(比如条目ID),减少内存占用。
- 异常处理:如果用户直接关闭编辑页而没有触发
end(),JSF会在会话超时后自动清理,不用太担心,但最好在Bean的销毁方法里做兜底处理。
内容的提问来源于stack exchange,提问作者AlexSC
相关产品推荐
相关产品推荐

