Динамическая загрузка компонентов JSF в шаблон Facelet - PullRequest
0 голосов
/ 29 декабря 2010

У меня проблема с динамической загрузкой bean-компонентов в моей программе.У меня есть свой шаблон лицевой стороны, подобный этому:

<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>

Как вы можете видеть, я хочу, чтобы ApplicationController решал, какой Javabean использовать.Это делается с помощью следующего кода:

 ApplicationController.java
public ReportWeb getChosenBean() {
    String reportName = getReportNameFromServletPath();
    //Make first character upper case
    String beanName = reportName.substring(0, 1).toUpperCase() + reportName.substring(1);
    logger.log(Level.INFO, "Loading bean with name : {0}", BEAN_PACKET_NAME + beanName);
    try {
        if (Class.forName(BEAN_PACKET_NAME + beanName).newInstance() instanceof ReportWeb) {
            chosenBean = (ReportWeb) Class.forName(BEAN_PACKET_NAME + beanName).newInstance();
        }
    } catch (ClassNotFoundException ex) {
        Logger.getLogger(ApplicationController.class.getName()).log(Level.SEVERE, null, ex);
    } catch (InstantiationException ex) {
        Logger.getLogger(ApplicationController.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
        Logger.getLogger(ApplicationController.class.getName()).log(Level.SEVERE, null, ex);
    }
    return chosenBean;
}

Все мои Javabeans подклассы класса ReportWeb, который представляет собой абстрактный класс, содержащий логику доступа и другие вспомогательные методы.Наиболее важным методом является

public abstract String actionRunReport();

Все мои отчеты реализуют этот.Однако в моем шаблоне я не могу вызвать этот метод, выполнив следующее:

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

Я не получаю сообщения об ошибке, но он просто не работает.Я должен жестко закодировать имя Javabean следующим образом:

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

Знает ли Анойн, почему моя техника не работает?

РЕДАКТИРОВАТЬ: Метод никогда не вызывается из кнопки действия, которая динамически загружает бин.

1 Ответ

1 голос
/ 29 декабря 2010

Основная причина, скорее всего, связана с тем, что атрибут rendered компонента действия (или хотя бы одного из его родителей) оценил false во время запроса отправки формы.Таким образом, действие не будет вызвано.Необходимо убедиться, что атрибут rendered не оценивает false, пока обрабатывается запрос на отправку формы.

См. Также этот ответ для обзора возможных причин.компонента действия не вызывается.


Несмотря на это, подход, как вы показали, далеко неэффективен.Я бы выделил область действия запроса ApplicationController и загрузил бы выбранный компонент следующим образом:

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

    // ...
}

Таким образом, он загружается только один раз за запрос вместо хотя бы одного на выражение ELкоторый вызывает метод получения (который может быть как минимум вдвое больше при использовании внутри атрибута rendered).

Таким образом, вы также получаете бин, который на самом деле управляется JSFвместо того, чтобы создавать его (дважды!) вручную внутри геттера.Если JSF уже создал экземпляр, будет возвращен именно этот.Если JSF еще не создал его, будет создан новый и помещен в область видимости, прежде чем он будет возвращен.

...