我尝试像下面的示例一样构建一个ConversationScoped Bean。该示例摘自《 Java EE 8中的实用JSF》一书:
@Named
@ConversationScoped
public class BookEditor implements Serializable {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(BookEditor.class.getName());
private int counter = 0;
@Inject
Conversation _conversation;
public int getCounter() {
return counter;
}
public void setCounter(int counter) {
this.counter = counter;
}
@PostConstruct
private void init() {
logger.info("...init..");
loadOrCreateBook();
if (_conversation.isTransient()) {
_conversation.begin();
logger.info("...begin conversation..");
}
}
public void count() {
counter = counter + 1;
logger.info("...counter=" + counter);
}
private void loadOrCreateBook() {
counter = 0;
}
}
目标是此bean在页面中仅初始化一次。
示例页面:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
template="/layout/template.xhtml">
<ui:define name="content">
<p>Counter = #{bookEditor.counter}</p>
<h:form>
<h:commandLink styleClass="button" value="counter commandLink"
actionListener="#{bookEditor.count()}"
action="/pages/bookEditor.xhtml" />
</h:form>
</ui:define>
</ui:composition>
我在浏览器中打开带有链接../pages/bookEditor.xhtml的页面,然后多次单击按钮。 Bean创建完成,并开始新的对话。并且计数器增加。日志文件如下所示:
...init..
...begin conversation..
...counter=1
...counter=2
...counter=3
一切都很好。
但是:如果我将计数器信息放置在表单标签中,这是一个典型的用例。...
<ui:define name="content">
<h:form>
<p>Counter = #{bookEditor.counter}</p>
<h:commandLink styleClass="button" value="counter commandLink"
actionListener="#{bookEditor.count()}"
action="/pages/bookEditor.xhtml" />
</h:form>
</ui:define>
...现在,如果我第一次单击该按钮,则对话将第二次开始。日志文件如下所示
...init..
...begin conversation..
...init..
...begin conversation..
...counter=1
...counter=2
...counter=3
为什么会这样?我需要避免第二次初始化。到目前为止,我唯一的解决方案是避免使用@PostConstruct。