faceletを要求するときに、なぜバッキングBeanメソッドが複数回呼ばれているのですか?
質問
私は、これらの日の作業とJSF + Faceletsのについて学びました。私はBackingBeanとにfacelet XHTMLページを持っています。私は(一回のみ)にfaceletページを要求するとバッキング・ビーンメソッドが複数回呼び出されます。
この理由は何だろうか?
私は特別な何かを見ることができません。事前に感謝します。
ここにfaceletあります:
<?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>
そして、ここでは、バッキングBeanです。方法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;
}
}
解決
豆のゲッターは、ビュー側からのアクセスのモデルデータにだけ存在します。彼らは複数回呼び出すことができます。通常、1回または2回では、これもUIData
コンポーネントまたは(value
、rendered
、などなど)disabled
以外の属性で使用する場合は特に、数百倍まで成長することができます。それだけの簡単な方法-呼び出し、通常はゲッターに行われるようにされていない高価なデータ・ロード・ロジックや計算をやっているので、これは通常、害はありません。プリロード/初期化は、Beanコンストラクタおよび/または豆アクション方法で行われることが通常です。ゲッターべき事実で唯一のリターンのデータ(も行う必要があれば、の遅延ロードの)ます。
getApplication().getKunden(getNameFilterPattern());
はかなり高価なタスクを行っている場合、あなたは本当に豆のコンストラクタ、または豆@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
がnameFilterPattern
フォームの入力フィールドから取得される場合)だけBeanのアクションメソッドが適している、それはPOST
だと思いますます。
JSFのライフサイクルの詳細については、あなたがこの自己便利の練習の記事ます。
他のヒント
これは、異なるから<のhref = "http://www.javabeat.net/articles/54-request-processing-lifecycle-phases-in-jsf-1.html" のrel = "nofollowをnoreferrer" と呼ぶことができます> JSFのlifecylceのの段階。私は最近、JSFを使用していないので、私はこれを詳細に覚えていない - 私の賭けは、相がRestoreView
、その後RenderResponse
だろう。
あなたは、最新のフィルタパターンと対応するクライアントをキャッシュすることができます。あなたは、フィルタを変更する場合にのみ、クライアントを再ロードします。このように、あなたは、この特定の問題を解決するため、プラスのフィルタが変更されていない場合は、データを再ロードすることは避けてください。
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
の)session
Beanを使用して、リクエストごとに一度だけデータをロードすることを確認することができます。