Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/358.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 JSF-如何从支持bean操作方法内部确定当前JSP页面_Java_Jsf_Myfaces_Tomahawk - Fatal编程技术网

Java JSF-如何从支持bean操作方法内部确定当前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

我有一个JSF应用程序,其中包含两个JSP页面,这两个页面都显示来自会话范围的容器对象的一些相同数据。每个页面都以不同的方式显示数据,每个页面的数据表各不相同。到目前为止,这一切都正常工作

我的问题是,我一直在欺骗自己,弄清楚从我的backingbean操作方法中请求了什么页面。在每个页面上,我都为我的数据表使用了一个绑定

draftReport.jsp

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