5

私は最近JSF+Faceletsについて働いて学んでいます。BackingBeanとFaceletxHTMLページがあります。facelet-pageを(1回だけ)要求すると、backing-bean-methodが複数回呼び出されます。

これの理由は何でしょうか?

特別なものは何も見えません。前もって感謝します。

フェイスレットは次のとおりです。

<?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:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Insert title here</title>
</head>
<body>
<ui:composition template="index.xhtml">
    <ui:define name="content">
        <h:form>Name: <h:inputText id="nameFilterPattern" value="#{kundenBackingBean.nameFilterPattern}" /><h:commandButton value="Suchen"/></h:form>
        <h:dataTable var="kunde" value="#{kundenBackingBean.kunden}" rowClasses="rowHighlight, rowOrdinary">
            <h:column> 
                <f:facet name="header">
                    <h:outputText value="Kundennr" />
                </f:facet>
                <h:outputText value="#{kunde.kundenNr}"/>
            </h:column>
            <h:column>
                <f:facet name="header">
                    <h:outputText value="Name" />
                </f:facet>
                <h:outputText value="#{kunde.name}"/>
            </h:column>
            <h:column>
                <f:facet name="header">
                    <h:outputText value="Vorname" />
                </f:facet>
                <h:outputText value="#{kunde.vorname}"/>
            </h:column>
            <h:column>
                <h:outputLink>Details</h:outputLink>
            </h:column>
        </h:dataTable>
    </ui:define>
</ui:composition>
</body>
</html>

そして、これがバッキングビーンです。getKundenメソッドは複数回呼び出されます。

@ManagedBean
@SessionScoped
public class KundenBackingBean extends AbstractBackingBean {

    private String nameFilterPattern;

    public List<Kunde> getKunden(){
        System.out.println("getKunden");
        return getApplication().getKunden(getNameFilterPattern());
    }

    public String getNameFilterPattern() {
        return nameFilterPattern;
    }

    public void setNameFilterPattern(String nameFilterPattern) {
        System.out.println("Name filter: " + nameFilterPattern);
        this.nameFilterPattern = nameFilterPattern;
    }

}
4

2 に答える 2

8

Beanのゲッターは、ビュー側からモデルデータにアクセスするためだけにあります。それらは複数回呼び出すことができます。通常は1〜2回ですが、特にUIDataコンポーネントやその他の属性valuerendereddisabledなど)でも使用される場合、これは数百倍に達する可能性があります。これは単純なメソッド呼び出しであり、高価なデータ読み込みロジックや計算を実行することは通常、ゲッターで実行されないため、通常は害はありません。プリロード/初期化は通常、Beanコンストラクターおよび/またはBeanアクションメソッドで実行されます。ゲッターは実際にはデータのみを返す必要があります(必要に応じて遅延読み込みも行います)。

非常にコストのかかるタスクを実行している場合getApplication().getKunden(getNameFilterPattern());は、実際にBeanコンストラクター、Bean@PostConstructメソッド、Bean初期化ブロック、またはBeanアクションメソッドのいずれかに移動するか、ゲッターに遅延読み込みパターンを導入する必要があります。これをすべて行う方法を示す例を次に示します。

public class Bean {
    private String nameFilterPattern;
    private List<Kunde> kunden;

    // Load during bean construction.
    public Bean() {
        this.kunden = getApplication().getKunden(getNameFilterPattern());
    }

    // OR load during @PostConstruct (will be invoked AFTER construction and resource injection.
    @PostConstruct
    public void init() {
        this.kunden = getApplication().getKunden(getNameFilterPattern());
    }

    // OR during bean initialization (this is invoked BEFORE construction and will apply to ALL constructors).
    {
        this.kunden = getApplication().getKunden(getNameFilterPattern());
    }

    // OR during bean action method (invoked from h:commandLink/Button).
    public String submit() {
        this.kunden = getApplication().getKunden(getNameFilterPattern());
        return "navigationCaseOutcome";
    }

    // OR using lazy loading pattern in getter method.
    public List<Kunde> getKunden() {
        if (this.kunden == null) 
            this.kunden = getApplication().getKunden(getNameFilterPattern());
        }
        return this.kunden;
    }

あなたの特定のケースでは、それは@PostConstruct(リクエストパラメータnameFilterPatternから取得される場合GET)、または単にBeanアクションメソッド(フォーム入力フィールドnameFilterPatternから取得される場合)が適切であると思います。POST

JSFライフサイクルの詳細については、この自習記事が役立つ場合があります。

于 2010-02-16T11:46:21.060 に答える
2

これは、JSFライフサイクルのさまざまなフェーズから呼び出すことができます。私の賭けはフェーズRestoreViewであり、それからRenderResponse-私は最近JSFを使用していないので、これを詳細に覚えていません。

最新のフィルターパターンと対応するクライアントをキャッシュできます。フィルタが変更された場合にのみ、クライアントをリロードします。このようにして、この特定の問題を解決し、さらにフィルターが変更されなかった場合にデータを再ロードすることを回避します。

private String nameFilterPattern;
private String lastNameFilterPatternLoaded;
private List<Kunde> clients;

public List<Kunde> getKunden(){
    System.out.println("getKunden");
    if( nameFilterPattern.equals( lastNameFilterPatternLoaded ) )
    {
        clients = getApplication().getKunden(getNameFilterPattern());
        lastNameFilterPatternLoaded = nameFilterPattern
    }
    return clients;
}

requestまたは、 (の代わりに)Beanを使用して、sessionリクエストごとに1回だけデータをロードするようにすることもできます。

于 2010-02-16T11:08:17.340 に答える