4

この問題を、2 つの入力の合計を計算し、結果を outputText に出力する複合コンポーネントという単純な例に当てはめます。

メインの JSF ページ:

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ez="http://java.sun.com/jsf/composite/ezcomp/">
    <h:head></h:head>
    <h:body>
      <ez:Calculator />
      <br/>
      <br/>
      <ez:Calculator />
      <br/>
      <br/>
      <ez:Calculator />
    </h:body>
</html>

複合コンポーネント XHTML:

<!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:composite="http://java.sun.com/jsf/composite"
  xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>This content will not be displayed</title>
    </h:head>
    <h:body>
    <composite:interface componentType="calculator">
    </composite:interface>

    <composite:implementation>
      <h:form>
      <h:inputText id="first" value="#{cc.firstNumber}" /> 
      <h:commandButton value="+" action="#{cc.sum}"/>
      <h:inputText id="second" value="#{cc.secondNumber}" /> 
      </h:form>
      <h:outputText id="result" value="#{cc.result}" />
  </composite:implementation>

</h:body>
</html>

複合コンポーネント バッキング Bean:

package ez;


import javax.faces.component.FacesComponent;
import javax.faces.component.UINamingContainer;

@FacesComponent("calculator")
public class Calculator extends UINamingContainer  {

    private Long firstNumber;
    private Long secondNumber;
    private Long result;

    public Calculator() {
    }

    @Override
    public String getFamily() { 
      return "javax.faces.NamingContainer"; 
    }

    public void setFirstNumber(String firstNumber) {
      this.firstNumber = Long.parseLong(firstNumber);
    }

    public String getFirstNumber() {
      if(firstNumber == null) {
        return null;
      }
      return firstNumber.toString();
    }

    public void setSecondNumber(String secondNumber) {
      this.secondNumber = Long.parseLong(secondNumber);
    }

    public String getSecondNumber() {
      if(secondNumber == null) {
        return null;
      }
      return secondNumber.toString();
    }

    public String getResult() {
      if(result == null) {
        return null;
      }
      return result.toString();
    }

    public void setResult(String result) {
      this.result = Long.parseLong(result);
    }     

    public void sum() {
      this.result = this.firstNumber + this.secondNumber;
    }
}

したがって、すべて同じことを行う必要がある3つの複合コンポーネントがありますが、SUMボタンを押すと、サーバーがリクエストを処理した後、結果がページに出力されますが、他の2つのコンポーネントは値がクリアされます。

どうすればこれを防ぐことができますか? これらの値を保持するにはどうすればよいですか?

4

1 に答える 1

8

UIComponentインスタンスはリクエストごとに再作成されるため、毎回すべてのインスタンス変数が失われます。それらは基本的にリクエスト スコープのマネージド Bean のように動作しますが、それらをビュー スコープに含めることを意図しています。属性ごとにビュー ステートの保存を考慮する必要があります。これは通常、デフォルトで のすべての属性に対してすでに行われています#{cc.attrs}。したがって、可能であれば、それを利用してください:

<cc:interface componentType="calculator">
    <cc:attribute name="firstNumber" type="java.lang.Long" />
    <cc:attribute name="secondNumber" type="java.lang.Long" />
</cc:interface>
<cc:implementation>
    <h:form>
        <h:inputText id="first" value="#{cc.attrs.firstNumber}" /> 
        <h:commandButton value="+" action="#{cc.sum}"/>
        <h:inputText id="second" value="#{cc.attrs.secondNumber}" /> 
    </h:form>
    <h:outputText id="result" value="#{cc.attrs.result}" />
</cc:implementation>

これだけで(ヌルチェックは省略されています。required="true"入力で使用することをお勧めします)

@FacesComponent("calculator")
public class Calculator extends UINamingContainer {

    public void sum() {
        Long firstNumber = (Long) getAttributes().get("firstNumber");
        Long secondNumber = (Long) getAttributes().get("secondNumber");
        getAttributes().put("result", firstNumber + secondNumber);
    }

}

それ以外の場合は、すべての属性ゲッター/セッターを に委譲して、状態の保存を自分で考慮する必要がありますUIComponent#getStateHelper()。あなたが持っているものとまったく同じ Facelets コードに基づいて、バッキング コンポーネント全体は次のようになります。

@FacesComponent("calculator")
public class Calculator extends UINamingContainer {

    public void sum() {
        setResult(getFirstNumber() + getSecondNumber());
    }

    public void setFirstNumber(Long firstNumber) {
        getStateHelper().put("firstNumber", firstNumber);
    }

    public Long getFirstNumber() {
        return (Long) getStateHelper().eval("firstNumber");
    }

    public void setSecondNumber(Long secondNumber) {
        getStateHelper().put("secondNumber", secondNumber);
    }

    public Long getSecondNumber() {
        return (Long) getStateHelper().eval("secondNumber");
    }

    public void setResult(Long result) {
        getStateHelper().put("result", result);
    }

    public Long getResult() {
        return (Long) getStateHelper().eval("result");
    }

}

参照してください、もうローカル変数はありません。String-Long適切な getter の戻り値の型と setter の引数の型を宣言するだけで、これらの醜い手動変換の必要もなくなったことに注意してください。ConverterJSF/EL は、デフォルトのコンバーターまたはカスタムsに基づいて自動的に変換を行います。には既にデフォルトのものがあるLongため、カスタム を提供する必要はありませんConverter


具体的な問題とは関係なく、メソッドを安全に削除できますgetFamily()。はUINamingContainerすでにこれを正確に提供しています。代わりにインターフェースを実装している場合はNamingContainer、実際にそれを自分で提供する必要がありますが、ここではそうではありません。上記のバッキング コンポーネントの例では、既に削除されています。

于 2012-12-04T12:55:12.073 に答える