5

这些天我在工作和学习 JSF + Facelets。我有一个 BackingBean 和一个 Facelet xHTML 页面。当我请求 facelet-page(仅一次)时,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 的 getter 只是用来从视图端访问模型数据。它们可以被多次调用。通常是一到两次,但这可能会增长到数百次,尤其是当也用于UIData组件或其他属性value(如rendereddisabled等)时。这通常不会造成伤害,因为它只是一个简单的方法调用,并且通常不会在 getter 中完成昂贵的数据加载逻辑或计算。预加载/初始化通常在 bean 构造函数和/或 bean 操作方法中完成。实际上,Getter 应该只返回数据(如果需要,还可以进行延迟加载)。

如果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 操作方法(如果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;
}

或者您可以使用requestbean(而不是session)并确保每次请求仅加载一次数据。

于 2010-02-16T11:08:17.340 回答