我在程序中动态加载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>
如您所见,我希望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"/>
anoyne知道为什么我的技术不起作用吗?
修改 永远不会从动态加载bean的动作按钮调用该方法。
答案 0 :(得分:1)
根本原因可能是因为在表单提交请求期间,操作组件(或至少其中一个父组件)的rendered
属性已评估false
。这样就不会调用该动作。在处理表单提交请求时,您需要确保rendered
属性未评估false
。
另请参阅this answer,了解未调用操作组件的可能原因。
无论如何,你所展现的方法效率很低。我将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);
}
// ...
}
这样每个请求只加载一次,而不是至少一次每 EL表达式调用getter(在rendered
属性中使用时至少两倍)。
这样你就可以抓住由JSF管理的实际的bean,而不是在getter中手动创建它(两次!)。如果JSF已经创建了一个实例,那么将返回这个实例。如果JSF尚未创建它,则会在返回之前创建一个新的并相应地放入范围。