Liferay Portlet和JSF:在Render阶段重定向

5
我有一个问题需要实现简单的HTTP重定向。 我使用Liferay 6.0.6,我们的门户是使用JSF2.0/PortletFaces构建的。 我想在加载视图时调用重定向(而不是触发操作时)。目前,我的功能由PreRenderView监听器调用。
<f:metadata>
  <f:event listener="#{myControler.dispatch}" type="preRenderView" />
</f:metadata>
在这个函数中,我可以检查权限,做其他事情,在某些情况下,我想将用户重定向到一个新页面(不是另一个视图)。 我尝试了几种方法,但都没有成功。 具体来说,我认为这种方法会起作用:
getFacesContext().getExternalContext().redirect(url);
getFacesContext().responseComplete()
// => Can only redirect during ACTION_PHASE
这个错误是逻辑上的,但有没有解决方法来强制重定向?
它可以在另一个函数中实现,称为otherwise,我只需要Hibernate Session(在Render阶段开始时设置)。
你有解决这个问题的想法吗?
谢谢!
PS: <redirect />?faces-redirect在门户中不起作用。
3个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
10

根据设计,您无法在渲染阶段完成此操作。原因如下:

  • portlet 可能会异步渲染,因此当 portlet 正在渲染时页面可能已经显示出来了。
  • 页面的某些部分可能已经被传递到客户端,因此 HTTP 头已经发送 - 基于这个原因,在渲染阶段您没有访问它们的权限。
  • 如果同一页面上渲染的两个 portlet 决定转发到另一个页面,预期的结果将是什么?谁会获胜?

一个 hacky 的解决方法是渲染一些 JavaScript 重定向,但这非常不像门户网站,并且可能会破坏其他人的期望(同时,页面的某些部分可能已经被渲染,导致用户填写表单后被您的 JavaScript 例程重定向)。

请重新考虑问题并提出不同的解决方案 - 在门户环境中确实值得这样做。


1
谢谢您的解释。如果有必要,我会考虑另一种解决方案,并重构我的门户架构。 - Julien Lafont
另一个“hacky”的解决方法是使用PortalUtil.getHttpServletResponse来查找原始的HTTP请求,并在那里使用sendRedirect。 - Tobias Liefke
@TobiasLiefke 在我看来,这太过于hacky了 - 响应可能已经在渲染时提交。或者portlet可能通过Ajax交付,甚至不作为整个页面的一部分。它可能有效,但也可能现在有效,但在应用服务器的某些未来更新中会出现问题... - Olaf Kock
不是应用服务器,而是门户可能在未来版本中出现问题 - 应用服务器本身不会提交响应。 - Tobias Liefke
我曾经看到同一个应用程序服务器在不同操作系统上存在差异——缓冲可能并不依赖于应用程序服务器或门户,而是取决于其他我们甚至没有讨论过的因素。无论如何,如果我能预测问题出现的位置,它们现在就可以被解决了。但我无法预测这一点,因此我试图指出故障的可能性。它可能是门户,但也可能是其他任何东西。通过 Ajax 动态加载单个 portlet,并且您甚至不能期望它今天就能正常工作。不要假设您正在加载整个页面! - Olaf Kock

1
我使用这个,它对我有效:

    public void preRenderView() throws IOException {

        if (!checkUtente()) {  

              FacesContext fc = FacesContext.getCurrentInstance(); 

              NavigationHandler navigationHandler = fc.getApplication().getNavigationHandler();

              navigationHandler.handleNavigation(fc, null, "errore.xhtml?faces-redirect=true");

              fc.renderResponse(); 
        }

    }

0

使用下面的方法,它会起作用。

public static void redirect(final String url) throws IOException {

            final javax.portlet.PortletResponse portletResponse
            = getPortletResponse();

            if (portletResponse instanceof ActionResponse) {

                final javax.portlet.ActionResponse actionResponse
                = (javax.portlet.ActionResponse) portletResponse;

                actionResponse.sendRedirect(url);

            } else if (portletResponse instanceof ResourceResponse) {

                final FacesContext ctx = FacesContext.getCurrentInstance();
                if (ctx.getPartialViewContext().isPartialRequest()) {

                    final ResourceResponse portletResResp
                    = (ResourceResponse) portletResponse;
                    PartialResponseWriter pwriter;
                    final ResponseWriter writer = ctx.getResponseWriter();
                    if (writer instanceof PartialResponseWriter) {
                        pwriter = (PartialResponseWriter) writer;
                    } else {
                        pwriter = ctx.getPartialViewContext()
                        .getPartialResponseWriter();
                    }
                    portletResResp.setContentType(Constants.CONTENT_TYPE);
                    portletResResp.setCharacterEncoding(Constants.ENCODING_TYPE);
                    // addResponseHeader("Cache-Control", "no-cache");
                    pwriter.startDocument();
                    pwriter.redirect(url);
                    pwriter.endDocument();
                    ctx.responseComplete();
                } else {
                    throw new UnsupportedEncodingException(
                            "Can only redirect during RESOURCE_PHASE "
                            + "if a Partial-(JSF AJAX)-Request  has "
                            + "been triggered");
                }
            } else {
                throw new UnsupportedEncodingException(
                        "Can not redirect during the current phase: "
                        + portletResponse.getClass().getSimpleName());
            }
        }

抱歉,这不会起作用,因为我想在RenderPhase期间重定向(使用portletResponse istanceof RenderResponse)。因此,我将收到“无法在当前阶段重定向”的消息。 - Julien Lafont

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,