JSF - 如何从支持 bean 操作方法内部确定当前 JSP 页面
我有一个包含两个 JSP 页面的 JSF 应用程序,这两个页面都显示来自会话范围容器对象的一些相同数据。每个页面显示的数据都不同,每个数据表中的数据在页面之间也有所不同。到目前为止一切正常。
我的问题是,我在如何确定从我的支持 bean 操作方法内部请求的页面方面有点作弊。在每个页面上,我都使用了数据表的绑定。
draftReport.jsp:
<t:dataTable
border="1"
id="reportDraftDataTable"
binding="#{controller.reportDraftDataTable}"
value="#{sessionData.reportDraftAdapterList}"
var="currentRow"
rowClasses="dataTableOddRow, dataTableEvenRow">
report.jsp:
<t:dataTable
border="1"
id="reportDataTable"
binding="#{controller.reportDataTable}"
value="#{sessionData.reportAdapterList}"
var="currentRow"
rowClasses="dataTableOddRow, dataTableEvenRow">
我有一个请求范围的支持 bean(名为 Controller
),其中包含这些页面的一些操作方法。我不想在支持 bean 上重复代码(每个类似的 JSP 页面都有一个类似的方法),而是想弄清楚正在呈现哪个页面,并将其用作通用处理程序方法(可以处理两个页面的操作)的参数。支持豆。所以我作弊并这样做了:
public class Controller {
...
private HtmlDataTable preArrivalReportDataTable;
private HtmlDataTable preArrivalReportDraftDataTable;
private static enum ReportType {
NON_DRAFT,
DRAFT
}
...
private ReportType determineReportTypeFromControlBindings() {
Validate.isTrue(this.preArrivalReportDataTable != null ^
this.preArrivalReportDraftDataTable != null,
"Either preArrivalReportDataTable XOR " +
"preArrivalReportDraftDataTable must be null in " +
"determineReportTypeFromControlBindings()");
if (this.preArrivalReportDataTable != null) {
return ReportType.NON_DRAFT;
} else {
return ReportType.DRAFT;
}
}
...
public String actionOnReport() {
ReportType reportType = null;
reportType = determineReportTypeFromControlBindings();
handleReportAction(reportType);
return "REFRESH";
}
...
}
这在我的 Controller 类的操作方法中工作正常,但是随后我需要添加另一个方法,最终破坏了我的黑客代码:
public String getStyleClass() {
ReportType reportType = determineReportTypeFromControlBindings();
switch (reportType) {
case NON_DRAFT:
return "styleA";
case DRAFT:
return "styleB";
default:
return null;
}
}
在我的 JSP 中,JSF-EL 表达式位于我在支持 bean 中使用的数据表来确定我所在的页面。此时,defineReportTypeFromControlBindings()
在验证检查时抛出异常,可能是因为控件绑定尚未发生。
我对这种情况的发生并不感到惊讶。总感觉方式不对。但我的问题是:
从请求范围的支持 bean 操作方法确定当前请求的 JSP 页面的正确方法是什么?
如果相关,我正在使用 MyFaces 1.2 Tomahawk 标签库。
I have a JSF application containing two JSP pages that both display some of the same data from a session-scoped container object. Each page displays the data differently, each in a data table that varies between pages. This all works properly so far.
My problem is that I have been cheating a bit with how I figure out what page was requested from inside my backing bean action methods. On each page, I have used a binding for my data table.
draftReport.jsp:
<t:dataTable
border="1"
id="reportDraftDataTable"
binding="#{controller.reportDraftDataTable}"
value="#{sessionData.reportDraftAdapterList}"
var="currentRow"
rowClasses="dataTableOddRow, dataTableEvenRow">
report.jsp:
<t:dataTable
border="1"
id="reportDataTable"
binding="#{controller.reportDataTable}"
value="#{sessionData.reportAdapterList}"
var="currentRow"
rowClasses="dataTableOddRow, dataTableEvenRow">
I have a request-scoped backing bean (named Controller
) with some of the action methods for these pages. Rather than duplicate code on the backing bean (one similar method for each similar JSP page), I wanted to figure out what page was being rendered and use that as a parameter to a generic handler method (that can handle actions from both pages) on the backing bean. So I cheated and did this:
public class Controller {
...
private HtmlDataTable preArrivalReportDataTable;
private HtmlDataTable preArrivalReportDraftDataTable;
private static enum ReportType {
NON_DRAFT,
DRAFT
}
...
private ReportType determineReportTypeFromControlBindings() {
Validate.isTrue(this.preArrivalReportDataTable != null ^
this.preArrivalReportDraftDataTable != null,
"Either preArrivalReportDataTable XOR " +
"preArrivalReportDraftDataTable must be null in " +
"determineReportTypeFromControlBindings()");
if (this.preArrivalReportDataTable != null) {
return ReportType.NON_DRAFT;
} else {
return ReportType.DRAFT;
}
}
...
public String actionOnReport() {
ReportType reportType = null;
reportType = determineReportTypeFromControlBindings();
handleReportAction(reportType);
return "REFRESH";
}
...
}
This worked OK inside action methods in my Controller class, but then I needed to add another method that finally broke my hacky code:
public String getStyleClass() {
ReportType reportType = determineReportTypeFromControlBindings();
switch (reportType) {
case NON_DRAFT:
return "styleA";
case DRAFT:
return "styleB";
default:
return null;
}
}
In my JSP, the JSF-EL expression is located above the control binding for the data table that I'm using in the backing bean to determine what page I'm on. At that point the determineReportTypeFromControlBindings()
throws an exception at the Validate check, presumably because the control binding has not occurred yet.
I'm not surprised that this is happening. It always felt like the wrong way. But my question is:
What is the correct way to determine the currently requested JSP page from a request-scoped backing bean action method?
In case it is relevant, I'm using the MyFaces 1.2 Tomahawk tag library.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我可以想到几种方法,一种是主动的,其中页面告诉 bean 视图是什么,一种是被动的,其中 bean 推断视图。最后一个是拥有一个抽象 bean,其中包含草稿和非草稿的具体实现。
我更喜欢最后一种方法,它感觉最像Java,而且最不hacky。但这里有一些关于如何实现前两项的基本想法。
主动:在 renderResponse 阶段调用方法来设置报告类型。我只在会话范围的 bean 中完成了此操作,不确定它在请求范围内的工作效果如何,您可能需要检查其他阶段,或者可能只是应用它,而不管实际阶段如何。
Controller.java
draftReport.jsp
Reactive: 从请求中获取 URL。
控制器.java
I can think of a few approaches, one is proactive, where the page tells the bean what the view is, a reactive one, where the bean infers the view. And the last one would be to have an abstract bean with concrete implementations for draft and non-draft.
I prefer the last approach, it feels the most Java-like, and the least hacky. But here are some basic ideas on how to do the first two.
Proactive: Call a method during the renderResponse phase to set the report type. I've only done this in session scoped beans, not sure how well it will work in request scoped, you may need to check other phases, or possibly just apply it regardless of the actual phase.
Controller.java
draftReport.jsp
Reactive: Get the URL from the request.
Controller.java
因此,我最终通过检查在请求期间从
FacesContext
获取的UIViewRoot
对象来解决这个问题。我用RequestedPage
枚举替换了ReportType
枚举,因为它看起来更具可读性。然后我在
Controller
类中创建了几个字符串常量和一个新方法。UNKNOWN
枚举旨在覆盖我在操作方法中不关心其身份的所有页面。只要我遵守方法 Javadoc 注释中提到的约束,这似乎就可以正常工作。这种方法唯一令人失望的事情是我想在我的
Controller
类的初始化方法中进行RequestedPage
解析。不幸的是,这不起作用,因为初始化程序是在 RESTORE_VIEW 阶段开始之前调用的,因此 UIViewRoot 仍然为 null。这是无法工作的代码:
我可以接受这个,除非其他人有一个简单的替代方法来替代我的方法。
So I ended up solving this by inspecting the
UIViewRoot
object that is obtained from theFacesContext
during the request. I replaced myReportType
enum with aRequestedPage
enum because it seemed more readable.Then I created a couple String constants and a new method inside my
Controller
class.The
UNKNOWN
enum is meant to cover all the pages whose identity I don't care about in my action methods. As long as I obey the constraints that I mention in my method Javadoc comments, this seems to work fine.The only disappointing thing about this approach is that I wanted to do the
RequestedPage
resolution inside the initializer method for myController
class. Unfortunately, this won't work because the initializer is called before theRESTORE_VIEW
phase begins and therefore the UIViewRoot is still null.Here is the code that will NOT work:
I can live with this, unless someone else has a simple alternative to my approach.