Java JSF-如何从支持bean操作方法内部确定当前JSP页面
我有一个JSF应用程序,其中包含两个JSP页面,这两个页面都显示来自会话范围的容器对象的一些相同数据。每个页面都以不同的方式显示数据,每个页面的数据表各不相同。到目前为止,这一切都正常工作 我的问题是,我一直在欺骗自己,弄清楚从我的backingbean操作方法中请求了什么页面。在每个页面上,我都为我的数据表使用了一个绑定 draftReport.jsp:Java JSF-如何从支持bean操作方法内部确定当前JSP页面,java,jsf,myfaces,tomahawk,Java,Jsf,Myfaces,Tomahawk,我有一个JSF应用程序,其中包含两个JSP页面,这两个页面都显示来自会话范围的容器对象的一些相同数据。每个页面都以不同的方式显示数据,每个页面的数据表各不相同。到目前为止,这一切都正常工作 我的问题是,我一直在欺骗自己,弄清楚从我的backingbean操作方法中请求了什么页面。在每个页面上,我都为我的数据表使用了一个绑定 draftReport.jsp: <t:dataTable border="1" id="reportDraftDataTable" bind
<t:dataTable
border="1"
id="reportDraftDataTable"
binding="#{controller.reportDraftDataTable}"
value="#{sessionData.reportDraftAdapterList}"
var="currentRow"
rowClasses="dataTableOddRow, dataTableEvenRow">
<t:dataTable
border="1"
id="reportDataTable"
binding="#{controller.reportDataTable}"
value="#{sessionData.reportAdapterList}"
var="currentRow"
rowClasses="dataTableOddRow, dataTableEvenRow">
这在我的控制器类中的内部操作方法中运行正常,但随后我需要添加另一个方法,该方法最终打破了我的hacky代码:
public String getStyleClass() {
ReportType reportType = determineReportTypeFromControlBindings();
switch (reportType) {
case NON_DRAFT:
return "styleA";
case DRAFT:
return "styleB";
default:
return null;
}
}
在我的JSP中,JSF-EL表达式位于数据表的控件绑定之上,我在支持bean中使用该数据表来确定我在哪个页面上。此时,determinateReportTypeFromControlBindings()
在验证检查时抛出异常,可能是因为控件绑定尚未发生
我对这种情况并不感到惊讶。总觉得这样做不对。但我的问题是:
从请求范围的支持bean操作方法确定当前请求的JSP页面的正确方法是什么?
如果相关的话,我将使用MyFaces 1.2 Tomahawk标记库。我可以想出几种方法,一种是主动的,页面告诉bean视图是什么,另一种是被动的,bean推断视图。最后一个是有一个抽象bean,其中包含草稿和非草稿的具体实现 我更喜欢最后一种方法,它感觉最像Java,最不粗糙。但是这里有一些关于如何做前两个的基本想法 主动式:在renderResponse阶段调用方法以设置报告类型。我只在会话范围的bean中完成了这项工作,不确定它在请求范围内的工作情况如何,您可能需要检查其他阶段,或者可能只是应用它,而不管实际的阶段如何 Controller.java
public void draftInitializer(PhaseEvent event) {
if (event.getPhaseId().equals(PhaseId.RENDER_RESPONSE)) {
reportType = DRAFT;
}
}
private String getRequestURL(){
HttpServletRequest request = (HttpServletRequest)FacesContext.getExternalContext().getRequest();
return request.getRequestURL();
}
private boolean isDraft() {
return getRequestURL().contains(DRAFT_URL_IDENTIFIER);
}
draftReport.jsp
<f:view beforePhase="#{controller.draftInitializer}">
因此,我最终通过检查请求期间从
FacesContext
获取的UIViewRoot
对象来解决这个问题。我用RequestedPage
enum替换了我的ReportType
enum,因为它看起来更可读
public static enum RequestedPage {
REPORT,
REPORT_DRAFT,
UNKNOWN
}
然后我在我的Controller
类中创建了一对字符串常量和一个新方法
private final static String REPORT_DRAFT_JSP_NAME = "draftReport.jsp";
private final static String REPORT_JSP_NAME = "report.jsp";
/**
* This method should only be invoked from inside an action method.
* An exception will be thrown if the method is called when either
* the FacesContext or UIViewRoot are not available. This is normally
* the case outside of an active request or before the RESTORE_VIEW
* phase has been completed.
*
* @return A non-null RequestedPage reference
*/
private RequestedPage determineRequestedPageFromViewId() {
FacesContext facesContext = FacesContext.getCurrentInstance();
Validate.notNull(facesContext);
UIViewRoot uiViewRoot = facesContext.getViewRoot();
Validate.notNull(uiViewRoot);
String viewId = uiViewRoot.getViewId();
logger.info("view id: " + viewId);
RequestedPage requestedPage = null;
if (viewId.contains(REPORT_DRAFT_JSP_NAME)) {
requestedPage = RequestedPage.REPORT_DRAFT;
} else if (viewId.contains(REPORT_JSP_NAME)) {
requestedPage = RequestedPage.REPORT;
} else {
requestedPage = RequestedPage.UNKNOWN;
}
return requestedPage;
}
UNKNOWN
enum用于覆盖我在操作方法中不关心其标识的所有页面。只要我遵守我在方法Javadoc注释中提到的约束,这似乎工作得很好
这种方法唯一令人失望的地方是,我想在我的控制器类的初始化器方法中执行RequestedPage
解析。不幸的是,这不起作用,因为初始化器是在RESTORE\u VIEW
阶段开始之前调用的,因此UIViewRoot仍然为空
以下是将不起作用的代码:
@PostConstruct
public void init() {
logger.info("init() has been invoked");
RequestedPage requestedPage =
determineRequestedPageFromViewId();
// An exception is always thrown before I get here...
this.theRequestedPage = requestedPage;
logger.info("init() finished");
}
我可以接受这一点,除非其他人有一个简单的方法来替代我的方法。+1谢谢你的建议。我决定转向另一个类似于“反应式”方法的方向,但使用UIViewRoot而不是请求URL?一个清晰的MVC设计几乎肯定比在您的模型上安装控制器要好。
@PostConstruct
public void init() {
logger.info("init() has been invoked");
RequestedPage requestedPage =
determineRequestedPageFromViewId();
// An exception is always thrown before I get here...
this.theRequestedPage = requestedPage;
logger.info("init() finished");
}