3

これf:viewParamをバインドして検証して auserIdをに変換しようとすると、予期しない結果Playerが得られました。

<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());
}
}

3 つのリンク (Harry、Tom、Peter) をクリックすると、コンバーターがうまく機能します。ID を変換playerし、マネージド Bean にバインドします。次に、テキストボックスに何かを入力してクリックします。最初は正常に機能し、入力した内容がボタンの横に表示されますが、入力内容を変更してもう一度Switchクリックすると、エラーメッセージが表示されます。これはエラーメッセージですのために。f:viewParam を取り出した場合、すべて正常に動作します。驚いたことに、f:viewParam から o:viewParam (OmniFaces) に切り替えると、うまく機能します。SwitchBad Request. Please use a link from within the systemrequiredf:viewParam

4

1 に答える 1

5

これは、<f:viewParam>がすべての HTTP リクエストで実行され、ポストバックでも実行されるためです。リンクで正確にそのパラメーターを渡しているため、プレーンな GET リンクの場合は問題なく機能します。ボタンでそのパラメーターを渡していないため、POST フォームの場合は失敗します。したがってnull、リクエストパラメーターマップになり、requiredバリデーターが作動するため、この検証エラーが発生します。

POST フォームでも満足を維持する<f:viewParam required="true">には、基本的<f:param>に、コマンド ボタン/リンクで最初のリクエスト パラメータを保持する必要があります。

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

<o:viewParam>ビュー スコープ Bean と組み合わせて使用​​するように設計されたOmniFacesには、isRequired()ゲッターに追加のチェックがあります (ソース コードはこちら)。

@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すべてのポストバックでバリデーターをスキップします (さらに、ステートレスな性質のため、すべてのポストバックでモデル値の設定もスキップします)。そのため、検証エラーは表示されず、適切なモデル値が引き続き保持されます (すべてのポストバックでリセットされるわけではありません)。

于 2012-05-10T02:18:47.590 に答える