2012-05-10 35 views
3

我有這個f:viewParam,我嘗試綁定驗證,並轉換成userIdPlayer,我得到了一個意想不到的結果F:viewParam與轉換器和ViewScoped例外出來的時候調用第二Ajax請求

<f:metadata> 
    <f:viewParam name="userId" value="#{myBean.selectedPlayer}" converter="pConverter" 
     converterMessage="Bad Request. Unknown User" required="true" 
     requiredMessage="Bad Request. Please use a link from within the system" /> 

</f:metadata> 
<h:body> 
    <p:messages id="msgs"/>   
    <h:form> 
     <ul> 
      <li><a href="index2.xhtml?userId=1">Harry</a></li> 
      <li><a href="index2.xhtml?userId=2">Tom</a></li> 
      <li><a href="index2.xhtml?userId=3">Peter</a></li> 
     </ul>    
    </h:form> 
    <h:form> 
     <h:panelGrid columns="2" rendered="#{not empty myBean.selectedPlayer}"> 

      <h:outputText value="Id: #{myBean.selectedPlayer.id}"/> 

      <h:outputText value="Name: #{myBean.selectedPlayer.name}"/> 

     </h:panelGrid> 
    </h:form> 
    <h:form id="testForm"> 
     <h:inputText value="#{myBean.text}"/> 
     <p:commandButton value="Switch" update=":msgs testForm"/> 
     <h:outputText value="#{myBean.text}" rendered="#{not empty myBean.text}"/> 
    </h:form>  
</h:body> 

我轉換這個樣子的

@FacesConverter(value="pConverter") 
public class PConverter implements Converter { 
private static final List<Player> playerList; 
static{ 
    playerList = new ArrayList<Player>();   
    playerList.add(new Player(1, "Harry")); 
    playerList.add(new Player(2, "Tom")); 
    playerList.add(new Player(3, "Peter")); 
} 

@Override 
public Object getAsObject(FacesContext fc, UIComponent uic, String value) { 
    if(value == null || !value.matches("\\d+")){ 
     return null; 
    } 
    long id = Long.parseLong(value); 
    for(Player p : playerList){ 
     if(p.getId() == id){ 
      return p; 
     } 
    } 
    throw new ConverterException(new FacesMessage("Unknown userId: " + value)); 

} 

@Override 
public String getAsString(FacesContext fc, UIComponent uic, Object value) { 
    if(!(value instanceof Player) || value == null){ 
     return null; 
    } 
    return String.valueOf(((Player)value).getId()); 
} 
} 

當我點擊三個連桿(哈利,湯姆,彼得),轉換器的工作很大。它轉換ID並將player綁定回我的託管bean。然後我在文本框中輸入東西,然後點擊Switch,第一次工作正常,我鍵入的內容出現在按鈕旁邊,但是然後我改變我輸入的內容,然後再次點擊Switch,然後出現錯誤信息Bad Request. Please use a link from within the system,這是required的錯誤消息爲f:viewParam。如果我把f:viewParam取出,那麼一切正常。令人驚訝的是,如果我從f:viewParam切換到o:viewParam(OmniFaces),那麼它很好用。

回答

4

這是因爲<f:viewParam>在每個HTTP請求上運行,也在回發上運行。它適用於簡單GET鏈接的情況,因爲您在鏈接中正確傳遞該參數。在您的情況下,POST表單失敗,因爲您沒有在按鈕中傳遞該參數。因此它在請求參數映射中變爲null,並且驗證程序將進入並因此驗證錯誤。

要保持<f:viewParam required="true">在POST表單上也很開心,您基本上需要在命令按鈕/鏈接中保留<f:param>的初始請求參數。

<p:commandButton value="Switch" update=":msgs testForm"> 
    <f:param name="userId" value="#{param.userId}" /> 
</p:commandButton> 

的OmniFaces <o:viewParam>,其目的是在組合使用與圖作用域豆,具有在isRequired()吸氣劑的額外的檢查(source code here):

@Override 
public boolean isRequired() { 
    // The request parameter get lost on postbacks, however it's already present in the view scoped bean. 
    // So we can safely skip the required validation on postbacks. 
    return !FacesContext.getCurrentInstance().isPostback() && super.isRequired(); 
} 

所以,這跳過required驗證在每一次回傳中(此外,由於其無狀態特性,它還會在每次回傳中跳過設置模型值)。這就是爲什麼你沒有看到驗證錯誤,並且你仍然擁有合適的模型值(在每次回發中都沒有重置)。

+0

非常感謝。 Omnifaces非常棒,BalusC。我有一個關於'o:viewParam'的問題,在你的博客中,你說omnifaces每次調用一個Ajax請求時都會避免調用'Converter',但是,它總是在getAsString()方法內部。所以我想知道這種行爲是否正確。我知道'getAsObject'是設置模型的值,所以不要調用'getAsObject'是一個很大的改進。我爲此感謝你。 –

+1

當對象需要轉換爲字符串(以呈現在生成的HTML中)時,將調用'getAsString()'。但它應該是一個相當便宜的工作,因爲它應該是其中一個屬性的字符串值。你已經掌握了這個對象,所以不需要昂貴的數據庫工作。 – BalusC

+0

非常感謝。 –

相關問題