Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/392.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么在请求facelet时多次调用BackingBean方法?_Java_Jsf_Facelets_Getter - Fatal编程技术网

Java 为什么在请求facelet时多次调用BackingBean方法?

Java 为什么在请求facelet时多次调用BackingBean方法?,java,jsf,facelets,getter,Java,Jsf,Facelets,Getter,这些天来,我一直在工作和学习JSF+Facelets。我有一个BackingBean和一个Facelet xHTML页面。当我请求facelet页面(仅一次)时,会多次调用backingbean方法 这可能是什么原因 我看不到什么特别的东西。提前谢谢 以下是facelet: <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

这些天来,我一直在工作和学习JSF+Facelets。我有一个BackingBean和一个Facelet xHTML页面。当我请求facelet页面(仅一次)时,会多次调用backingbean方法

这可能是什么原因

我看不到什么特别的东西。提前谢谢

以下是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;
    }

}
@ManagedBean
@会议范围
公共类KundenBackingBean扩展了AbstractBackingBean{
私有字符串名称过滤器模式;
公共列表getKunden(){
System.out.println(“getKunden”);
返回getApplication().getKunden(getNameFilterPattern());
}
公共字符串getNameFilterPattern(){
返回nameFilterPattern;
}
公共void setNameFilterPattern(字符串nameFilterPattern){
System.out.println(“名称过滤器:”+nameFilterPattern);
this.nameFilterPattern=nameFilterPattern;
}
}

可以从不同的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;
}
私有字符串名称过滤器模式;
私有字符串lastNameFilterPatternLoaded;
私人名单客户;
公共列表getKunden(){
System.out.println(“getKunden”);
if(nameFilterPattern.equals(lastNameFilterPatternLoaded))
{
clients=getApplication().getKunden(getNameFilterPattern());
lastNameFilterPatternLoaded=nameFilterPattern
}
返回客户;
}

或者,您可以使用
请求
bean(而不是
会话
),并确保每个请求只加载一次数据。

bean的getter仅用于从视图侧访问模型数据。可以多次调用它们。通常是一次或两次,但这可能会增加到数百次,尤其是在
UIData
组件或
value
以外的其他属性中使用时(如
渲染的
禁用的
等)。这通常不会造成伤害,因为这只是一个简单的方法调用,并且在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;
    }
公共类Bean{
私有字符串名称过滤器模式;
私人名单昆登;
//在bean构造期间加载。
公共豆(){
this.kunden=getApplication().getKunden(getNameFilterPattern());
}
//或在@PostConstruct期间加载(将在构造和资源注入后调用)。
@施工后
公共void init(){
this.kunden=getApplication().getKunden(getNameFilterPattern());
}
//或者在bean初始化期间(这在构造之前调用,并将应用于所有构造函数)。
{
this.kunden=getApplication().getKunden(getNameFilterPattern());
}
//或者在bean操作方法期间(从h:commandLink/Button调用)。
公共字符串提交(){
this.kunden=getApplication().getKunden(getNameFilterPattern());
返回“NavigationCaseOutput”;
}
//或者在getter方法中使用延迟加载模式。
公共列表getKunden(){
如果(this.kunden==null)
this.kunden=getApplication().getKunden(getNameFilterPattern());
}
把这个还给我,昆登;
}
在您的特定情况下,我认为是
@PostConstruct
(如果
nameFilterPattern
是从
GET
请求参数获得的),或者仅仅是bean操作方法(如果
nameFilterPattern
是从
POST
表单输入字段获得的)是合适的


要了解更多关于JSF生命周期的信息,您可能会发现这一点很有用。

它总是被调用相同的次数吗?您是使用IDE调试模式来验证方法被多次调用还是在日志中看到的?似乎在第一次请求时,它被调用了8次,之后被调用了21次。我使用eclipse+glassfish和starte在调试模式下加载它。我只是在方法中插入了一个sysout,并计算了控制台输出。感谢您的回答。我将bean更改为请求范围。行为是相同的。如何确保每个请求只加载一次数据?正如您在facelet中看到的,该方法只被引用一次。这是否与模板相关吃东西:ui:composition/ui:define?你接受的BalusC的答案涵盖了所有内容。我想你不需要进一步解释。回答不错,顺便说一句:)是的,这肯定不是我第一次这样回答:)我以前至少问过20次。不仅在这里,而且在forums.sun.com上