2011-11-08 41 views
4

我有一個非常典型的CRUD情況,我正在努力,所以我認爲我必須誤解某些東西。我已經放了一個小演示程序來更好地解釋我的問題。感興趣的兩個文件如下所示:CDI @ConversationScoped with AJAX

PersonView - CDI Managed Bean的支持JSF頁面

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變量現在爲空,因此失敗並出現NullPointerException。

我意識到這不是創建對象的常用方式,但在我當前的應用程序中是有意義的,因爲我可以猜測新Person的一些值。它也很適合我想編輯的方式。

所以我的問題:爲什麼對話不會傳播? PersonView bean似乎一直處於請求範圍內。我已閱讀了關於JSF2中的@ViewScoped,但如果可能的話,我寧願堅持使用CDI。從我讀過的內容來看,我認爲問題是未能將CID名稱與請求一起傳遞,但我不知道如何使用AJAX做到這一點。

我想出的唯一解決方案是將PersonView移動到會話中,但感覺像是一個巨大的混亂。 e

+0

我不做CDI,但這聽起來非常像[這個問題與@ViewScoped ](http://balusc.blogspot.com/2011/09/communication-in-jsf-20.html#AjaxRenderingOfContentWhichContainsAnotherForm)。嘗試在'update'中明確引用其他''。例如。 ''用'''。 – BalusC

+0

有趣的是,我想你已經解釋了爲什麼上面的代碼在我使用@ViewScoped註釋bean時不起作用。儘管如此,我希望找到解決問題的CDI解決方案。我發現最好的是[這個問題](http://stackoverflow.com/questions/7061709/how-do-i-use-conversationscoped),它建議使用MyFaces CODI,它似乎按照我的想法做我想做的事情。 – wobblycogs

+0

我想CDI有同樣的問題,因爲它與JSF視圖狀態有關。您是否嘗試過直接更新「」而不是其子女或父母? – BalusC

回答

4

我得到這個工作的唯一方法是在MyFaces CODI中使用@ViewAccessScoped。 CDI允許可擴展性,所以您只需將CODI jar文件包含在您的應用程序中即可。即使您使用Mojarra而不使用MyFaces,這也可以工作。

所以,如果你想使用CDI註釋,那是我的建議。我嘗試了一段時間使用ConversationScoped註釋,但我無法讓它工作方便。一旦我開始使用CODI,我的所有問題都消失了。

0

好像你正在使用PrimeFaces,林不知道如何使Primefaces Ajax調用,所以我會告訴你如何與標準的JSF實現2.0

首先使用AJAX時,你必須通過每個AJAX請求都帶有cid。 嘗試添加以下到您ConversationScope託管Bean(你需要以某種方式將cid傳遞給視圖 - 的index.xhtml,那麼以後每AJAX調用會傳遞相同的cid回服務器):

@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