我有一个非常典型的CRUD情况,我正在努力,所以我认为我必须误解一些东西。我已经整理了一个小的演示应用程序来更好地解释我的问题。感兴趣的两个文件如下所示:
PersonView - 支持JSF页面的CDI Managed Bean
package example
import java.io.Serializable;
import java.util.List;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.inject.Named;
@ConversationScoped @Named
public class PersonView implements Serializable {
private Person selectedPerson;
@Inject private PersonService personService;
@Inject private Conversation conversation;
public PersonView() {}
public List<Person> getPeople() { return personService.findAll(); }
public void beginConversation() { if( conversation.isTransient() ) {conversation.begin();} }
public void endConversation() { if( !conversation.isTransient() ) { conversation.end();} }
public void createPerson() {
beginConversation();
setSelectedPerson( new Person() );
}
public void addPerson() {
personService.addPerson( getSelectedPerson() );
endConversation();
}
public void updatePerson() { personService.updatePerson( getSelectedPerson() ); }
public Person getSelectedPerson() { return selectedPerson; }
public void setSelectedPerson(Person selectedPerson) { this.selectedPerson = selectedPerson; }
}
index.xhtml - 操纵人物的JSF页面
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>CRUD Example</title>
</h:head>
<h:body>
<h:form prependId="false">
<p:dataTable var="p" value="#{personView.people}" id="person_table" rowKey="#{p.id}" selection="#{personView.selectedPerson}">
<p:column selectionMode="single"/>
<p:column><f:facet name="header">ID</f:facet>#{p.id}<p:column>
<p:column><f:facet name="header">Name</f:facet>#{p.name}</p:column>
<f:facet name="footer">
<p:commandButton value="Create Person" onclick="create_dialog.show();" actionListener="#{personView.createPerson}"/>
<p:commandButton value="Edit Person" onclick="edit_dialog.show();" update="edit_panel"/>
</f:facet>
</p:dataTable>
</h:form>
<p:dialog header="Create Person" id="create_dialog" widgetVar="create_dialog" modal="true" width="750" height="300">
<h:form prependId="false">
<p:panel id="create_panel">
<p>Name: <p:inputText value="#{personView.selectedPerson.name}" required="true"/></p>
<p><p:commandButton value="Add" actionListener="#{personView.addPerson}" oncomplete="create_dialog.hide();" update="person_table" /></p>
</p:panel>
</h:form>
</p:dialog>
</h:body>
在索引页面上,向用户显示一个数据表,其中包含系统知道的所有人员。然后,他们按下表格底部的“创建人员”按钮。我已经检查过这是否正确调用了createPerson方法,并且会话显然已经开始了。然后显示create_dialog,用户可以在其中输入名称。当用户单击“添加”按钮时出现问题。 JSF尝试存储人员名称,但selectedPerson变量现在为null,因此它失败并出现NullPointerException。
我意识到这不是创建对象的常用方法,但在我当前的应用程序中是有意义的,因为我可以猜测一个新Person的一些值。它也非常适合我想要编辑的方式。
所以我的问题:为什么对话不会传播? PersonView bean似乎始终处于请求范围内。我在JSF2中读过@ViewScoped,但如果可能的话我宁愿坚持使用CDI。根据我的阅读,我认为问题是未能通过请求传递CID名称,但我不知道如何使用AJAX来做到这一点。
我提出的唯一解决方案是将PersonView移动到会话中,但这感觉就像一个巨大的kludge。 ë
答案 0 :(得分:4)
我使用它的唯一方法是在MyFaces CODI中使用@ViewAccessScoped。 CDI允许扩展,因此您所要做的就是将CODI jar文件包含在您的应用程序中。即使您使用的是Mojarra而不是MyFaces,这也有效。
因此,如果您想使用CDI注释,那是我的建议。我尝试使用ConversationScoped注释一段时间,但我无法让它方便地工作。一旦我开始使用CODI,我的所有问题就消失了。
答案 1 :(得分:0)
好像你正在使用PrimeFaces,我不知道如何使用Primefaces进行ajax调用,所以我将向您展示它如何使用标准JSF 2.0
首先,当使用AJAX时,您必须在每个AJAX请求中传递cid
。
尝试将以下内容添加到ConversationScope受管Bean(您需要以某种方式将cid
传递给视图 - index.xhtml,然后每个后续的AJAX调用都会将相同的cid
传递回服务器:< / p>
@Named
@ConversationScoped
public class PersonView implements Serializable {
public List<Person> getPeople() {
return personService.findAll();
}
@Inject
private Conversation conversation;
//Start the conversation once the
//bean is created and all injection is done on the bean
//I typically use this in the case of AJAX
@PostContruct
public void beginConversation() {
if( conversation.isTransient() ) {
conversation.begin();
}
}
public void endConversation() {
if( !conversation.isTransient() ) {
conversation.end();
}
}
// This will be used in the view (index.xhtml)
public String getConversationId() {
return conversation.getId();
}
public void createPerson() {
setSelectedPerson( new Person() );
}
public void addPerson() {
personService.addPerson( getSelectedPerson() );
endConversation();
// beginConversation(); //might need to start a new conversation once old one is done
}
}
现在在您的视图中,您通常会执行以下操作:
<h:commandButton action="#{personView.createPerson}" value="Create Person">
<!-- passing the cid -->
<f:param name="cid" value="#{personView.conversationId}" />
<f:ajax execute="@form" />
</h:commandButton>
<h:commandButton action="#{personView.addPerson}" value="Add">
<!-- passing the cid -->
<f:param name="cid" value="#{personView.conversationId}" />
<f:ajax execute="@form" render=":person_table" />
</h:commandButton>
只要所有后续调用都是AJAX,这都有效。如果您开始将其与正常呼叫混合,则会话丢失。另一方面,这是您正在进行的非AJAX呼叫列表,cid
将自动传递给您
答案 2 :(得分:0)
将@ConversationScoped与<f:ajax>
标记结合使用,需要将会话ID传递给commandButton和commandLink元素。
见这个例子:
<h:commandLink value="update"
actionListener="#{myController.updateSomething(myData)}">
<f:ajax render="...."/>
<f:param name="cid" value="#{myController.getCID()}" />
</h:commandLink>