Jsf omnifaces 1.10在OmniPartialViewContext#startDocument执行透明重定向时出现错误

Jsf omnifaces 1.10在OmniPartialViewContext#startDocument执行透明重定向时出现错误,jsf,tomcat,jsf-2.2,myfaces,omnifaces,Jsf,Tomcat,Jsf 2.2,Myfaces,Omnifaces,我正在使用以下堆栈: 第5.3.1条 MyFaces 2.2.8 OpenWebBeans 1.6.2 OmniFaces 1.10 德尔塔斯派克1.5.1 Tomcat 8.0.28 阿非亚人明白,只有我的面孔和全方位的面孔才是重要的 当ajax请求由会话已过期的客户端执行时,以及当对页面的访问由webapp web.xml中的 在这种情况下,OmniPartialViewContext#startDocument将执行“透明重定向”,以提供更好的解释(请参阅)(此函数从版本1.10到当前

我正在使用以下堆栈:

  • 第5.3.1条
  • MyFaces 2.2.8
  • OpenWebBeans 1.6.2
  • OmniFaces 1.10
  • 德尔塔斯派克1.5.1
  • Tomcat 8.0.28
阿非亚人明白,只有我的面孔和全方位的面孔才是重要的

当ajax请求由会话已过期的客户端执行时,以及当对页面的访问由webapp web.xml中的

在这种情况下,OmniPartialViewContext#startDocument将执行“透明重定向”,以提供更好的解释(请参阅)(此函数从版本1.10到当前的1.11保持不变)

这是一个问题,因为堆栈中较高的org.apache.myfaces.context.servlet.PartialViewContextImpl.processPartialRendering执行第466行和以下操作:

    {
        String currentEncoding = writer.getCharacterEncoding();
        writer.writePreamble("<?xml version=\"1.0\" encoding=\""+
            (currentEncoding == null ? "UTF-8" : currentEncoding) +"\"?>");
        writer.startDocument();

        writer.writeAttribute("id", viewRoot.getContainerClientId(_facesContext),"id");

我如何纠正这一点(从删除OmniFaces开始,这真的很酷,我真的很想保留它..-)?

最终,我使用了以下解决方案,这可以看作是一种解决办法,因为修补MyFaces或OmniFaces是我力所能及的

我正在处理链的顶端添加我自己的PartialViewContext。这样,当我看到ajax请求试图获取登录页面时,我可以对其执行干净的重定向

为此,必须:

  • 实现PartialViewContextFactory
  • 实现PartialViewContext
  • 在faces-config.xml文件中声明PartialViewContextFactory
因此,在我的webapp faces-config.xml中,我将:

<factory>
    <partial-view-context-factory>fr.senat.context.SenatPartialViewContextFactory</partial-view-context-factory>
</factory>    
PartialViewContext也很简单:

package fr.senat.context;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.PartialResponseWriter;
import javax.faces.context.PartialViewContext;
import javax.faces.context.PartialViewContextWrapper;
import javax.faces.event.PhaseId;
import javax.servlet.http.HttpServletRequest;
import lombok.Getter;
import org.apache.myfaces.context.servlet.PartialViewContextImpl;
import org.omnifaces.config.WebXml;
import static org.omnifaces.util.FacesLocal.getRequestAttribute;
import static org.omnifaces.util.FacesLocal.getViewId;
import static org.omnifaces.util.FacesLocal.normalizeViewId;

/**
 *
 * @author lpenet
 */
public class SenatPartialViewContext  extends PartialViewContextWrapper {

    @Getter
    private final PartialViewContext wrapped;

    public SenatPartialViewContext(PartialViewContext wrapped) {
            this.wrapped = wrapped;
    }

    private void processPartialRendering() throws IOException
    {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        UIViewRoot viewRoot = facesContext.getViewRoot();

        String loginURL = WebXml.INSTANCE.getFormLoginPage();
        if (loginURL != null) {
            String loginViewId = normalizeViewId(facesContext, loginURL);

            if (loginViewId.equals(getViewId(facesContext))) {
                    String originalURL = getRequestAttribute(facesContext, "javax.servlet.forward.request_uri");

                    if (originalURL != null) {
                        PartialResponseWriter writer = facesContext.getPartialViewContext().getPartialResponseWriter();
                        writer.startDocument();
                        HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest();
                        writer.redirect(request.getContextPath() + loginURL);
                        writer.endDocument();
                        return;
                    }
            }
        }

        wrapped.processPartial(PhaseId.RENDER_RESPONSE);
    }

    @Override
    public void processPartial(PhaseId phaseId)
    {
        if (phaseId == PhaseId.RENDER_RESPONSE)
        {
            try {
                processPartialRendering();
            }
        catch (IOException ex)
        {
            Logger log = Logger.getLogger(PartialViewContextImpl.class.getName());
            if (log.isLoggable(Level.SEVERE))
            {
                log.log(Level.SEVERE, "", ex);
            }

        }
        } else {
            wrapped.processPartial(phaseId);
        }
    }

}

酷,谢谢你的解决方案!我碰巧在你发布答案的同一时刻复制了这个问题。我将首先测试这是否也适用于Mojarra,如果适用,然后集成到OmniFaces 2.2中。是的,也适用于Mojarra。这将在totay的2.2快照中结束。在相关的记录单中,BalusC表示它也将在1.12中结束。
<factory>
    <partial-view-context-factory>fr.senat.context.SenatPartialViewContextFactory</partial-view-context-factory>
</factory>    
package fr.senat.context;

import javax.faces.context.FacesContext;
import javax.faces.context.PartialViewContext;
import javax.faces.context.PartialViewContextFactory;
import lombok.Getter;

/**
*
* @author lpenet
*/
public class SenatPartialViewContextFactory extends PartialViewContextFactory {
    @Getter
    private final PartialViewContextFactory wrapped;

    public SenatPartialViewContextFactory(PartialViewContextFactory wrapped) {
            this.wrapped = wrapped;
    }

    @Override
    public PartialViewContext getPartialViewContext(FacesContext context) {
            return new SenatPartialViewContext(wrapped.getPartialViewContext(context));
    }
}
package fr.senat.context;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.PartialResponseWriter;
import javax.faces.context.PartialViewContext;
import javax.faces.context.PartialViewContextWrapper;
import javax.faces.event.PhaseId;
import javax.servlet.http.HttpServletRequest;
import lombok.Getter;
import org.apache.myfaces.context.servlet.PartialViewContextImpl;
import org.omnifaces.config.WebXml;
import static org.omnifaces.util.FacesLocal.getRequestAttribute;
import static org.omnifaces.util.FacesLocal.getViewId;
import static org.omnifaces.util.FacesLocal.normalizeViewId;

/**
 *
 * @author lpenet
 */
public class SenatPartialViewContext  extends PartialViewContextWrapper {

    @Getter
    private final PartialViewContext wrapped;

    public SenatPartialViewContext(PartialViewContext wrapped) {
            this.wrapped = wrapped;
    }

    private void processPartialRendering() throws IOException
    {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        UIViewRoot viewRoot = facesContext.getViewRoot();

        String loginURL = WebXml.INSTANCE.getFormLoginPage();
        if (loginURL != null) {
            String loginViewId = normalizeViewId(facesContext, loginURL);

            if (loginViewId.equals(getViewId(facesContext))) {
                    String originalURL = getRequestAttribute(facesContext, "javax.servlet.forward.request_uri");

                    if (originalURL != null) {
                        PartialResponseWriter writer = facesContext.getPartialViewContext().getPartialResponseWriter();
                        writer.startDocument();
                        HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest();
                        writer.redirect(request.getContextPath() + loginURL);
                        writer.endDocument();
                        return;
                    }
            }
        }

        wrapped.processPartial(PhaseId.RENDER_RESPONSE);
    }

    @Override
    public void processPartial(PhaseId phaseId)
    {
        if (phaseId == PhaseId.RENDER_RESPONSE)
        {
            try {
                processPartialRendering();
            }
        catch (IOException ex)
        {
            Logger log = Logger.getLogger(PartialViewContextImpl.class.getName());
            if (log.isLoggable(Level.SEVERE))
            {
                log.log(Level.SEVERE, "", ex);
            }

        }
        } else {
            wrapped.processPartial(phaseId);
        }
    }

}