非常感谢您帮助解决以下问题(JBoss 6.0,Mojarra - 2.2 Snapshot,facelet 1.1和PrimeFaces 3.0.M4:
问题是,在获取值集之前调用请求bean的post构造方法。我们如何确保首先设置会话bean的参数值,然后调用请求bean的post构造方法。
问题#1:点击“下一步”时,这是一个ajax调用 1.调用testRequestBB的“初始化”post构造方法 2.调用testSessionBB的“next”方法来设置值
预期的行为应该是另一种方式,使用ajax调用在会话bean中设置值,然后应该初始化请求bean。
问题#2:请求bean的“初始化”post构造方法被调用两次 - 是因为请求bean从基类扩展(尽管基类中没有post构造方法)。
当显示test.xhtml页面时,可以采取哪些措施来解决获取post构造方法两次的问题?
以下是代码:
<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>
@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 "";
}
}
@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();
}
....
}
public abstract class TestBase implements Serializable {
..... (contains all common code shared by other classes extending this base class)
// does not contain any @PostConstruct method
}
答案 0 :(得分:5)
@PostConstruct
确实无法访问更新的模型值。它们仅在更新模型值阶段之后可用(因此,在调用操作和呈现响应阶段期间)。 @PostConstruct
从不打算对更新的模型值执行操作,它旨在对注入的依赖项执行操作,这些依赖项又在必要时进行了新构建,例如@EJB
,@Inject
,{ {1}}。
您想要的是在调用操作阶段调用的方法。你需要 在@ManagedProperty
的ajax监听器方法中完成工作:
TestSessionBB
或将@Inject
private TestRequestBB testRequestBB;
public void next() { // No, no need to return String.
// ...
testRequestBB.initialize();
}
添加到视图中。这允许您在渲染响应阶段之前的调用操作阶段的最后执行bean方法。把它放在你看来的某个地方:
<f:event type="preRenderView">
不要忘记从方法中删除<f:event type="preRenderView" listener="#{testRequestBB.initialize}" />
注释。
关于@PostConstruct
方法被调用两次的问题,那是因为每个@PostConstruct
都会产生一个完全独立的实例。你在同一个类上有两个@Named
,一个在类本身,另一个在getter方法本身。我建议删除getter方法中的那个,然后在@Named
的视图中替换#{testList}
。
#{testRequestBB.testList}
如果你真的,真的,需要在<h:dataTable value="#{testRequestBB.testList}" ...>
内抓取请求参数,然后你可以通过ExternalContext#getRequestParameterMap()
手动抓取它们:
@PostConstruct
如果您使用的是JSF2 @PostConstruct
public void initialize() {
String foo = (String) FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("foo");
// ...
}
注释而不是CDI @ManagedBean
注释,那么您也可以使用@Named
代替:
@ManagedProperty
此值将在@ManagedProperty("#{param.foo}")
private String foo;
期间提供。在CDI中没有这样的注释,但如果有必要,你可以自己homegrow。