如何在RequestScoped bean中调用@PostConstruct之前在SessionScoped bean中设置参数值

Sun*_*kia 2 jsf-2

非常感谢您帮助解决以下问题(JBoss 6.0,Mojarra - 2.2 Snapshot,facelet 1.1和PrimeFaces 3.0.M4:

问题是,在获取值集之前调用请求bean的post构造方法.我们如何确保首先设置会话bean上的参数值,然后调用请求bean的post构造方法.

问题#1:当点击"Next"时,这是一个ajax调用1. testRequestBB的"初始化"post构造方法被调用2. testSessionBB的"next"方法被调用来设置值

预期的行为应该是另一种方式,使用ajax调用在会话bean中设置值,然后应该初始化请求bean.

问题#2:请求bean的"初始化"后构造方法被调用两次.
- 是因为请求bean从基类扩展(尽管基类中没有post构造方法).

当显示test.xhtml页面时,可以采取哪些措施来解决获取post构造方法两次调用的问题?

这是代码:

test.xhtml

<h:dataTable id="testId" emptyMessage="#{messages.noData}" var="test" value="#{testList}">
....
<f:facet name="footer">
    <h:form id="pgId">                  
        <h:commandLink value="#{messages.next} ">
            <f:ajax listener="#{testSessionBB.next}" />
        </h:commandLink>
            .....
    </h:form>
</f:facet>
</h:dataTable>
Run Code Online (Sandbox Code Playgroud)

TestSessionBB.java

@Named("testSessionBB")
@SessionScoped
public class TestSessionBB implements Serializable
{
    private int testStartRow;
    .....

    public String next() 
    {
        if (this.getTestStartRow() + 5 > 15) // hard coded value for simplicity in this post
        {
            this.setTestStartRow(15);
        } else {
            this.setTestStartRow(this.getTestStartRow() + 5);
        }
        log.debug("next - testStartRow: " + this.getTestStartRow());

        return "";
    }
}
Run Code Online (Sandbox Code Playgroud)

TestRequestBB.java

@Named
@RequestScoped
public class TestRequestBB extends testBase implements Serializable {

    ....

    @PostConstruct
    public void initialize()
    {
        log.debug("Initializing TestRequestBB backing bean ...");

        setTestList(allTests()); // load initial list containing 5 rows of test data

        log.debug("Initializing TestRequestBB backing bean done ...");
    }

    @Produces
    @Named
    public List<Test> getTestList()
    {   
        return super.getTestList();
    }
    ....
}
Run Code Online (Sandbox Code Playgroud)

TestBase.java

public abstract class TestBase implements Serializable {

    ..... (contains all common code shared by other classes extending this base class)

    // does not contain any @PostConstruct method

}
Run Code Online (Sandbox Code Playgroud)

Bal*_*usC 5

@PostConstruct确实将不会获得更新模型值.它们仅在更新模型值阶段之后可用(因此,在调用操作和呈现响应阶段期间).将@PostConstruct永远不会intented对更新模型值执行操作,它intented对注入的依赖性,它们又被如有必要,还新构造,如执行操作@EJB,@Inject,@ManagedProperty.

你想要的是一个在调用动作阶段调用的方法.你需要要么做的ajax的侦听器方法内的工作TestSessionBB,而不是:

@Inject
private TestRequestBB testRequestBB;

public void next() { // No, no need to return String.
    // ...

    testRequestBB.initialize();
}
Run Code Online (Sandbox Code Playgroud)

或者添加<f:event type="preRenderView">到视图中.这允许您在渲染响应阶段之前的调用操作阶段的最后执行bean方法.把它放在你看来的某个地方:

<f:event type="preRenderView" listener="#{testRequestBB.initialize}" />
Run Code Online (Sandbox Code Playgroud)

不要忘记@PostConstruct从方法中删除注释.

至于@PostConstruct方法被调用两次的问题,那是因为每个都@Named导致一个完全独立的实例.你在@Named同一个类中有两个,一个在类本身,另一个在getter方法本身.我建议删除getter方法中的那个并#{testList}在你的视图中替换#{testRequestBB.testList}.

<h:dataTable value="#{testRequestBB.testList}" ...>
Run Code Online (Sandbox Code Playgroud)

如果你真的,真的,要抓住内的请求参数@PostConstruct,那么你可以手动抓住他们的ExternalContext#getRequestParameterMap():

@PostConstruct
public void initialize() {
    String foo = (String) FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("foo");
    // ...
}
Run Code Online (Sandbox Code Playgroud)

如果您使用的是JSF2 @ManagedBean注释而不是CDI @Named注释,那么您也可以使用@ManagedProperty它来代替:

@ManagedProperty("#{param.foo}")
private String foo;
Run Code Online (Sandbox Code Playgroud)

该值将在期间可用@PostConstruct.在CDI中没有这样的注释,但是如果有必要,你可以自己生成一个.

也可以看看: