这些天我正在努力学习JSF + Facelets。我有一个BackingBean和一个Facelet xHTML页面。当我请求facelet页面(只有一次)时,多次调用backing-bean方法。
这可能是什么原因?
我看不到任何特别的东西。提前谢谢。
这是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>
这是支持豆。方法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;
}
}
答案 0 :(得分:8)
bean的getter只是从视图端访问模型数据。它们可以被多次调用。通常一两次,但这可能会增长数百倍,尤其是在UIData
组件或value
以外的其他属性中使用时(例如rendered
,disabled
等)。这通常不会造成伤害,因为它只是一个简单的方法调用,并且通常不会在getter中进行昂贵的数据加载逻辑或计算。预加载/初始化通常在bean构造函数和/或bean操作方法中完成。事实上,Getters只应返回数据(如果有必要,还可以延迟加载)。
如果getApplication().getKunden(getNameFilterPattern());
执行相当昂贵的任务,您应该将它移动到bean构造函数,bean @PostConstruct
方法,bean初始化块或bean操作方法,或者引入 getter中的延迟加载模式。这是一个展示如何做到这一切的例子:
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操作方法(如果{{ 1}}将从nameFilterPattern
形式输入字段获得)是合适的。
要了解有关JSF生命周期的更多信息,您可能会发现此self-practice article非常有用。
答案 1 :(得分:2)
可以从JSF生命周期的不同phases调用它。我的赌注是阶段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
),并确保每次请求只加载一次数据。