为什么在请求facelet时多次调用BackingBean方法? [英] Why is BackingBean method called multiple times when requesting facelet?

查看:126
本文介绍了为什么在请求facelet时多次调用BackingBean方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这些天我正在努力学习JSF + Facelets。我有一个BackingBean和一个Facelet xHTML页面。当我请求facelet页面(只有一次)时,多次调用backing-bean方法。

I'm working and learning about JSF + Facelets these days. I have a BackingBean and a Facelet xHTML page. When I request the facelet-page (only one time) the backing-bean-method is called multiple times.

这可能是什么原因?

我看不到任何特别的东西。提前致谢。

I can't see anything special. Thanks in advance.

这是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被多次调用:

And here is the backing-bean. The method getKunden is called multiple times:

@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;
    }

}


推荐答案

bean的getter只是从视图端访问模型数据。它们可以被多次调用。通常一两次,但这可能会增长到数百倍,尤其是在 UIData 组件中或在值以外的其他属性中使用时(如呈现已禁用等)。这通常不会造成伤害,因为它只是一个简单的方法调用,并且通常不会在getter中完成昂贵的数据加载逻辑或计算。预加载/初始化通常在bean构造函数和/或bean操作方法中完成。实际上,Getters只应返回数据(如果有必要,也可以延迟加载)。

The getters of a bean are just there to access model data from the view side. They can be called multiple times. Usually one or two times, but this can grow up to hundreds of times, especially when also used in UIData components or in other attributes than value (like rendered, disabled, etc). This does normally not harm, as it's just a simple method-invocation and doing expensive data loading logic or calculations is usually not to be done in the getters. Preloading/initializing is usually to be done in the bean constructor and/or bean action methods. Getters should in fact only return the data (if necessary also do lazy loading).

如果 getApplication()。getKunden(getNameFilterPattern()); 执行一项非常昂贵的任务,您应该将它移动到bean构造函数或bean @PostConstruct 方法,或bean初始化块,或bean操作方法,或在getter中引入延迟加载模式。这是一个显示如何执行此操作的示例:

If getApplication().getKunden(getNameFilterPattern()); is doing a pretty expensive task, you should really move it to either the bean constructor, or bean @PostConstruct method, or bean initialization block, or bean action method, or introduce lazy loading pattern in the getter. Here's an example which shows how to do this all:

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 (如果要从 GET 请求参数中获取 nameFilterPattern ),或者只需要bean动作方法(如果 nameFilterPattern 是从 POST 表单输入字段中获取)是合适的。

In your specific case, I think it's the @PostConstruct (if the nameFilterPattern is to be obtained from a GET request parameter), or just the bean action method (if nameFilterPattern is to be obtained from a POST form input field) is suitable.

要了解有关JSF生命周期的更多信息,您可以找到自我练习文章很有用。

To learn more about the JSF lifecycle, you may find this self-practice article useful.

这篇关于为什么在请求facelet时多次调用BackingBean方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆