27

我目前正在使用 RichFaces 评估 Java EE 6 / JSF 2.1。

一个被声明为的bean

@ManagedBean
@ViewScoped
  1. 获取一个 ID 集(准备例如删除操作)。
  2. 通过 JSF 会显示一个确认弹出窗口。
  3. 如果用户确认,则调用 delete 方法并删除在步骤 1 中为其存储 ID 的行。

由于 CDI bean 没有 ViewScope,我尝试将 bean 声明为:

@Named
@ConversationScoped

现在处理在步骤 3 中失败。因为在步骤 1 中设置的值(检查)不再可用。

我必须使用Conversation.begin()Conversation.end()方法吗?

如果是这样,哪里是调用它们的好地方?

4

5 回答 5

55

如果您可以升级到 JSF 2.2,请立即执行此操作。它@ViewScoped为 CDI 提供了原生注释。

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调用,通常是重定向到新视图的操作方法。begin()@PostConstructend()

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";
    }

}

也可以看看:

于 2013-01-17T17:33:55.913 回答
6

我认为您可以从 CDI 扩展中受益,以创建自己的范围,这样您就可以实现上下文并使用@NormalScope.

  • AfterBeanDiscoveryCDI在每次 bean 调用后触发一个事件
  • 您可以@Observes对此事件使用 CDI 扩展并添加您的上下文实现
  • 在您的范围实施中,您可以:
    1. 用于Contextual通过其名称获取您的 bean,并在每次 ajax 回调后FacesContext ViewRoot Map返回它
    2. 如果CreationalContext找不到第一步中的 bean 名称,则在FacesContext ViewRoot Map

对于更深入的解释,我推荐这个链接:http ://www.verborgh.be/articles/2010/01/06/porting-the-viewscoped-jsf-annotation-to-cdi/

于 2013-04-28T22:04:26.427 回答
3

将对话注入到您的 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";
    }

}
于 2013-01-17T17:39:39.697 回答
0

有一个项目对 Java EE 堆栈特性进行了扩展:DeltaSpike。它是 Seam 3、Apache CODI 的整合。最重要的是,它将@ViewScoped 包含在 CDI 中。这是一篇旧文章,现在已经到了 1.3.0 版本

于 2015-05-06T13:19:20.237 回答
-1

您可以使用:

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");
    }

}
于 2015-04-18T13:01:43.130 回答