如何在 JSF 2.0/2.1 中用 CDI 替换 @ManagedBean / @ViewScope
Posted
技术标签:
【中文标题】如何在 JSF 2.0/2.1 中用 CDI 替换 @ManagedBean / @ViewScope【英文标题】:How to replace @ManagedBean / @ViewScope by CDI in JSF 2.0/2.1 【发布时间】:2013-01-01 07:18:10 【问题描述】:我目前正在使用 RichFaces 评估 Java EE 6 / JSF 2.1。
声明为
的 bean@ManagedBean
@ViewScoped
-
获取一个 ID 集(准备例如删除操作)。
通过 JSF 会显示一个确认弹出窗口。
如果用户确认,则调用 delete 方法并删除在步骤 1 中为其存储 ID 的行。
由于 CDI bean 没有 ViewScope,我尝试将 bean 声明为:
@Named
@ConversationScoped
现在第 3 步中的处理失败。因为在第 1 步中设置的值(已检查)不再可用。
我必须使用Conversation.begin()
和Conversation.end()
方法吗?
如果是这样,哪里是调用它们的好地方?
【问题讨论】:
供将来参考:在 JSF 2.2 中,核心 JSF 中有一个 CDI 兼容的视图范围。 【参考方案1】:如果您可以升级到 JSF 2.2,请立即升级。它为 CDI 提供原生 @ViewScoped
注释。
import javax.faces.view.ViewScoped;
import javax.inject.Named;
@Named
@ViewScoped
public class Bean implements Serializable
// ...
或者,安装 OmniFaces,它会带来自己的 CDI 兼容 @ViewScoped
,包括一个正常工作的 @PreDestroy
(在 JSF @ViewScoped
上已损坏)。
import javax.inject.Named;
import org.omnifaces.cdi.ViewScoped;
@Named
@ViewScoped
public class Bean implements Serializable
// ...
另一种选择是安装 MyFaces CODI,它将 JSF 2.0/2.1 @ViewScoped
透明地桥接到 CDI。这只会向 URL 添加一个自动生成的请求参数(就像 @ConversationScoped
一样)。
import javax.faces.bean.ViewScoped;
import javax.inject.Named;
@Named
@ViewScoped
public class Bean implements Serializable
// ...
如果你真的需要使用@ConversationScoped
,那么你确实需要手动开始和结束它。您需要在对话的最后一步中 @Inject
和 Conversation
并在 @PostConstruct
和 end()
中调用 begin()
,通常是重定向到新视图的操作方法。
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Named;
@Named
@ConversationScoped
public class Bean implements Serializable
@Inject
private Conversation conversation;
// ...
@PostConstruct
public void init()
conversation.begin();
public String submit()
// ...
conversation.end();
return "some.xhtml?faces-redirect=true";
另见:
How to choose the right bean scope?【讨论】:
感谢您的快速回复。尚未结束的对话会发生什么,例如用户只是导航到另一个页面? 它在会话结束时过期(顺便说一下,就像@ViewScoped
bean)。请注意,对话范围由特定的请求参数标识(在 Weld 中,即 cid
),因此它的行为不像会话范围的 bean。如果您使用该对话框创建新请求,即使旧对话尚未结束,也会开始新对话。【参考方案2】:
有一个项目包含对 Java EE 堆栈功能的扩展:DeltaSpike。它是 Seam 3、Apache CODI 的整合。最重要的是,它将@ViewScoped 包含在 CDI 中。这是一篇老文章,现在已经到了1.3.0版本
【讨论】:
【参考方案3】:你可以使用:
import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
@Named
@ViewScoped
public class PageController implements Serializable
private String value;
public void setValue(String value)
this.value = value;
public String getValue()
return value;
public void execute()
setValue("value");
@PostConstruct
public void init()
System.out.println("postcontructor");
【讨论】:
你**不能** jsf 2.1,这就是问题所在。因此,请增强您的答案,使其包含 JSF 2.2【参考方案4】:我认为您可以从 CDI 扩展中受益,创建自己的范围,这样您就可以实现上下文并使用 @NormalScope
。
AfterBeanDiscovery
您可以使用 CDI 扩展来 @Observes
此事件并添加您的上下文实现
在您的作用域实现中,您可以:
-
使用
Contextual
从 FacesContext
ViewRoot
Map
获取您的 bean 并在每次 ajax 回调后返回它
如果找不到第一步中的 bean 名称,请使用 CreationalContext
在 FacesContext
ViewRoot
Map
中创建它
更深入的解释,我推荐这个链接:http://www.verborgh.be/articles/2010/01/06/porting-the-viewscoped-jsf-annotation-to-cdi/
【讨论】:
【参考方案5】:将对话注入到您的 bean 中,如果对话是暂时的,则在 @PostConstructor
方法中启动对话。
删除记录后,结束对话并导航到目标页面。开始对话时。这是一个例子
public class BaseWebBean implements Serializable
private final static Logger logger = LoggerFactory.getLogger(BaseWebBean.class);
@Inject
protected Conversation conversation;
@PostConstruct
protected void initBean()
public void continueOrInitConversation()
if (conversation.isTransient())
conversation.begin();
logger.trace("conversation with id has started by .", conversation.getId(), getClass().getName());
public void endConversationIfContinuing()
if (!conversation.isTransient())
logger.trace("conversation with id has ended by .", conversation.getId(), getClass().getName());
conversation.end();
@ConversationScoped
@Named
public class yourBean extends BaseWebBean implements Serializable
@PostConstruct
public void initBean()
super.initBean();
continueOrInitConversation();
public String deleteRow(Row row)
/*delete your row here*/
endConversationIfContinuing();
return "yourDestinationPageAfter removal";
【讨论】:
以上是关于如何在 JSF 2.0/2.1 中用 CDI 替换 @ManagedBean / @ViewScope的主要内容,如果未能解决你的问题,请参考以下文章
无法将 JSF + CDI 项目从 Tomcat 迁移到 Wildfly
是否在会话范围的 JSF 支持 bean 中观察到 CDI 事件