JSF 中的导航有什么区别
FacesContext context = FacesContext.getCurrentInstance();
context.getApplication().getNavigationHandler().handleNavigation(context, null, url);
和重定向
HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
response.sendRedirect(url);
以及如何决定何时使用什么?
导航的问题是,除非将faces-redirect=true
页面 URL 添加到导航 URL 的查询字符串中,否则页面 URL 不会更改。但是,就我而言,如果我想重定向到非 JSF 页面(如纯 HTML 页面),则附加faces-redirect=true
会引发错误。
另一种选择是BalusC在JSF 2.0重定向错误中建议的那样
首先,术语"重定向"在Web开发世界中是向客户端发送空HTTP响应的操作,该响应只有一个Location
标头,其中包含客户端必须在其上发送全新GET请求的新URL。所以基本上:
- 客户端向
somepage.xhtml
发送 HTTP 请求。 - 服务器发送回带有
Location: newpage.xhtml
标头的 HTTP 响应 - 客户端向
newpage.xhtml
发送HTTP请求(这反映在浏览器地址栏中! - 服务器发回一个 HTTP 响应,其中包含
newpage.xhtml
的内容。
您可以使用网络浏览器的内置/插件开发人员工具集对其进行跟踪。在Chrome/IE9/Firebug中按F12并检查"网络"部分以查看它。
JSF 导航处理程序不发送重定向。相反,它使用目标页面的内容作为 HTTP 响应。
- 客户端向
somepage.xhtml
发送 HTTP 请求。 - 服务器发回一个 HTTP 响应,其中包含
newpage.xhtml
的内容。
然而,由于最初的HTTP请求是somepage.xhtml
,浏览器地址栏中的URL保持不变。如果您熟悉基本的 Servlet API,那么您应该了解这与 RequestDispatcher#forward()
具有相同的效果。
至于从JSF引擎盖下拉出HttpServletResponse
并调用sendRedirect()
是否是正确的用法;不,这不是正确的用法。您的服务器日志将变得杂乱无章IllegalStateException
因为这样您就不会告诉 JSF 您已经接管了对响应处理的控制,因此 JSF 不应该执行其默认的响应处理作业。实际上,您应该在之后执行FacesContext#responseComplete()
。
此外,每当您需要从 JSF 工件(如托管 Bean)中的包中javax.servlet.*
导入某些内容时,您绝对应该停止编写代码并三思而后行,如果您真的以正确的方式做事,并问问自己是否还没有"标准 JSF 方法"用于您要实现的任何目标和/或任务是否真的属于 JSF 托管 Bean(即在某些情况下,其中简单的 servlet 过滤器会是一个更好的地方)。
在 JSF 中执行重定向的正确方法是在操作结果中使用faces-redirect=true
查询字符串:
public String submit() {
// ...
return "/newpage.xhtml?faces-redirect=true";
}
或者,当您不在操作方法(如 ajax 或预呈现侦听器方法)中使用 ExternalContext#redirect()
:
public void listener() throws IOException {
// ...
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.redirect(ec.getRequestContextPath() + "/newpage.xhtml");
}
(是的,你不需要在IOException
上放一个try-catch
,只要让异常通过throws
,servletcontainer 会处理它)
或者,如果您使用的是 XML 导航案例和/或具有某些内置侦听器的自定义导航处理程序,则在特定情况下使用 NavigationHandler#handleNavigation()
:
public void listener() {
// ...
FacesContext fc = FacesContext.getCurrentInstance();
NavigationHandler nh = fc.getApplication().getNavigationHandler();
nh.handleNavigation(fc, null, "/newpage.xhtml?faces-redirect=true");
}
至于为什么导航处理程序对"纯 HTML"文件失败,那仅仅是因为导航处理程序只能处理 JSF 视图,而不能处理其他文件。你应该使用ExternalContext#redirect()
。
另请参阅:
- 如何在 JSF 中导航?如何使URL反映当前页面(而不是上一个页面)
- 什么时候应该使用 h:outputLink 而不是 h:commandLink?