在Facelet模板中动态加载JSFbean

在Facelet模板中动态加载JSFbean,jsf,facelets,javabeans,Jsf,Facelets,Javabeans,我在程序中动态加载bean时遇到问题。我的facelet模板如下所示: <ui:define name="content"> <f:loadBundle var="Application" basename="start" /> <f:loadBundle var="Messages" basename="#{ApplicationController.bundleName}" /> <h:panelGro

我在程序中动态加载bean时遇到问题。我的facelet模板如下所示:

<ui:define name="content">
        <f:loadBundle var="Application" basename="start" />
        <f:loadBundle var="Messages" basename="#{ApplicationController.bundleName}" />
        <h:panelGroup rendered="#{ApplicationController.chosenBean.hasAccess}">
            <h:form>
                <h:outputText value="Error: #{ApplicationController.chosenBean.errorMessage}" id="outputErrorMessage2" /><br />
                  <h:outputText value="Report running: #{ApplicationController.chosenBean.runningReport}" /><br />
                  <ui:insert name="application-content" />
                  <h:commandButton action="#{ApplicationController.chosenBean.actionRunReport}" value="Create report"/>
               </h:form>
            </h:panelGroup>
            <h:panelGroup rendered="#{!ApplicationController.chosenBean.hasAccess}">
            <h:outputText value="Err" />
        </h:panelGroup>
</ui:define>
我所有的Javabeans都是ReportWeb类的子类,它是一个包含访问逻辑和其他方便方法的抽象类。最重要的方法是

public abstract String actionRunReport();
我所有的报告都实现了这一点。但是,在我的模板中,我无法通过以下操作调用此方法:

<h:commandButton action="#{ApplicationController.chosenBean.actionRunReport}" value="Create report"/>

我没有收到任何错误消息,但它就是不工作。我必须像这样硬编码Javabean名称:

<h:commandButton action="#{AntallHenvendelser.actionRunReport}" value="Create report"/>

一个女人知道为什么我的技术不起作用吗

编辑:
从不从动态加载bean的操作按钮调用该方法。

根本原因可能是因为在表单提交请求期间,操作组件(或其至少一个父组件)的
rendered
属性已评估
false
。这样就不会调用该操作。您需要确保在处理表单提交请求时,
rendered
属性不会计算
false

有关未调用操作组件的可能原因的概述,请参见


不管怎样,您所展示的方法显然是低效的。我将使
ApplicationController
请求的作用域限定,并按如下方式加载所选bean:

public class ApplicationController {

    private ReportWeb chosenBean;

    public ApplicationController() {
        chosenBean = findBean(getReportNameFromServletPath(), ReportWeb.class);
    }

    public static <T> T findBean(String managedBeanName, Class<T> beanClass) {
        FacesContext context = FacesContext.getCurrentInstance();
        return beanClass.cast(context.getApplication().evaluateExpressionGet(context, "#{" + managedBeanName + "}", beanClass);
    }

    // ...
}
公共类应用程序控制器{
私有报告网络chosenBean;
公共应用程序控制器(){
chosenBean=findBean(getReportNameFromServletPath(),ReportWeb.class);
}
公共静态T findBean(字符串managedBeanName,类beanClass){
FacesContext context=FacesContext.getCurrentInstance();
返回beanClass.cast(context.getApplication().evaluateExpressionGet(上下文“{”+managedBeanName+“}”,beanClass);
}
// ...
}
这样,每个请求只加载一次,而不是每个调用getter的EL表达式至少加载一次(在
rendered
属性中使用时,可以至少加载两倍)


通过这种方式,您还可以获取实际上由JSF管理的bean,而不是创建它(两次!)在getter中手动创建。如果JSF已经创建了一个实例,那么将返回这个实例。如果JSF还没有创建它,那么将创建一个新实例,并在返回之前将其相应地放入范围中。

不确定问题的原因,但是您是否意识到,通过这种方式,EL的每个getter调用都会返回一个不同的实例bean,甚至不是由JSF管理的bean?这是令人震惊的低效…至于故障排除问题,您是如何得出它“不工作”的结论的?
actionRunReport()
方法被调用了吗?谢谢你,巴卢斯克。我没有意识到这个方法效率低下。你对我如何获得托管bean的回报有什么建议吗?我所有的bean都在请求范围内,但我明白你的意思:)我已经发布了答案。顺便说一句,使用
@昵称
通知其他人关于非他们自己帖子的评论回复。另外,你也可以看到,你依赖于他们的热情来回过头来看这篇文章。这是有效的!因为您的方法通过FacesContext加载bean,所以我也可以通过bean运行操作!我在程序中所做的唯一修改就是采用findBean方法,而不是.newInstance()。非常感谢你!
public class ApplicationController {

    private ReportWeb chosenBean;

    public ApplicationController() {
        chosenBean = findBean(getReportNameFromServletPath(), ReportWeb.class);
    }

    public static <T> T findBean(String managedBeanName, Class<T> beanClass) {
        FacesContext context = FacesContext.getCurrentInstance();
        return beanClass.cast(context.getApplication().evaluateExpressionGet(context, "#{" + managedBeanName + "}", beanClass);
    }

    // ...
}