jsf - 如何在 "namespaced mode"中使用jsf

标签 jsf mojarra jsf-2.3

在我们想要集成 jsf 应用程序提供的一些片段的网站中,想想仪表板应用程序或“门户网站灯”。在分析需求时,我们看到了 Arjan Tjims 在 jsf 2.3 new features 上发表的一篇博文。 ,他提到了一个新的“命名空间模式”:

In namespaced mode, which is specifically intended for Portlets but can be used in other environments as well, the partial response is given an id that's taken to be the "naming container id". All predefined postback parameter names (such as "javax.faces.ViewState", "javax.faces.ClientWindow", "javax.faces.RenderKitId", etc) are prefixed with this and the naming separator (default ":"). e.g. javax.faces.ViewState" becomes "myname:javax.faces.ViewState". Namespaced mode is activated when the UIViewRoot instance implements the NamingContainer interface.

我们的应用程序可能是该“命名空间模式”的用例,因此我们想尝试一下。

我们构建了一个 MyUIViewRoot我们在哪里实现 NamingContainer并包装了原来的 UIViewRoot -实例。我们注册了一个MyViewHandlerfaces-config.xml它处理 ViewRoot 的包装。为了进行测试,我们使用了一个带有两个 <h:form> 的简单计数器应用程序。 -元素(似乎很重要)。

我们发现“命名空间模式”似乎被激活了,例如 javax.faces.ViewState indeed 被一些命名空间前缀并变为 j_id1:javax.faces.ViewState:0 .但是这两个操作都不再有效——回发请求不再恢复 View 而是创建一个新 View 。因此,通过我们简单的方法,我们遗漏了一些东西(顺便说一句,从 implements NamingContainer 中仅删除 MyUIViewRoot,计数器应用程序再次正常工作)。

  • 是否有一些文档、操作方法或工作示例被我们忽略了?
  • 如何正确激活“命名空间模式”?为了使回传再次工作,我们错过了什么?
  • 我们如何制作MyUIViewRoot在 ViewState 前添加 myNamespace

应用程序在 payara-5 应用程序服务器中运行。

我们的 index.xhtml :

<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
  xmlns:h="http://xmlns.jcp.org/jsf/html"
  xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head/>
<h:body>
  <h:form id="counterForm">
    <h:panelGrid columns="2">
      <h:outputLabel value="Counter" />
      <h:outputText value="#{counterUiController.counter}" />
    </h:panelGrid>
    <h:commandButton value="inc" action="#{counterUiController.incAction}">
      <f:ajax execute="@form" render="@form" />
    </h:commandButton>
  </h:form>
  <h:form id="resetForm">
    <h:commandButton value="reset" action="#{counterUiController.resetAction}">
      <f:ajax execute="@form" render=":counterForm" />
    </h:commandButton>
  </h:form>
</h:body>
</html>

CounterUiController:

@Named
@ViewScoped
public class CounterUiController implements Serializable {

    private int counter;

    public int getCounter() {
        return counter;
    }

    public void incAction() {
        counter++;
    }

    public void resetAction() {
        counter=0;
    }
}

我们的 UIViewRoot -实现:

public class MyUIViewRoot extends UIViewRoot implements NamingContainer, FacesWrapper<UIViewRoot> {

    private static final Logger LOG = Logger.getLogger(MyUIViewRoot.class.getName());

    private UIViewRoot wrapped;

    public MyUIViewRoot(UIViewRoot wrapped) {
        this.wrapped = wrapped;
        LOG.log(Level.INFO, "new instance created: {0}", this);
    }

    @Override
    public UIViewRoot getWrapped() {
        return wrapped;
    }

    @Override
    public String createUniqueId() {
        return wrapped==null ? null : wrapped.createUniqueId();
    }

    @Override
    public void setId(String id) {
        if( wrapped!=null ) {
            wrapped.setId(id);
        }
    }
    // all other methodes delegated to `wrapped` directly
}

我们的 ViewHandler :

public class MyViewHandler extends ViewHandlerWrapper {

    private static final Logger LOG = Logger.getLogger(MyViewHandler.class.getName());

    public MyViewHandler(ViewHandler wrapped) {
        super(wrapped);
    }

    @Override
    public UIViewRoot createView(FacesContext context, String viewId) {
        UIViewRoot retval = super.createView(context, viewId);
        retval = wrapIfNeeded(retval);
        LOG.log(Level.INFO, "view created: {0}", retval);
        return retval;
    }

    @Override
    public UIViewRoot restoreView(FacesContext context, String viewId) {
        UIViewRoot retval =  super.restoreView(context, viewId);
        retval = wrapIfNeeded(retval);
        LOG.log(Level.INFO, "view restored: {0}", retval);
        return retval;
    }

    private UIViewRoot wrapIfNeeded(UIViewRoot root) {
        if (root != null && !(root instanceof MyUIViewRoot)) {
            LOG.log(Level.INFO, "view wrapped: {0}, {1}", new Object[] { root, root.getId() });
            return new MyUIViewRoot(root);
        } else {
            return root;
        }
    }
}

最佳答案

您需要替换 UIViewRoot 而不是包装它。

public class NamespacedView extends UIViewRoot implements NamingContainer {
    //
}

然后在 faces-config.xml 中。

<component>
    <component-type>javax.faces.ViewRoot</component-type>
    <component-class>com.example.NamespacedView</component-class>
</component>

基本上就这些了。另见 the Mojarra IT on this .

关于jsf - 如何在 "namespaced mode"中使用jsf,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61815731/

相关文章:

jquery - Primefaces 6.0 对话框架和框架集

jsf - 如何在 Liferay JSF portlet 中创建一个弹出默认登录表单/portlet 的链接/按钮?

jsf - 为什么复合组件中某个方面内的 commandLink 会呈现错误?

jsf - com.sun.faces.config.ConfigureListener 的配置

cdi - JSF 2.3 FacesConverter 中未注入(inject) ApplicationScoped bean

JSF 2.3 具有泛型的自定义转换器

JSF:重定向到url,而不是GET

java 丢失来自 ManagedBeans 的值

java - Servlet Faces Servlet 的错误 StandardWrapperValve[Faces Servlet] :PWC1406: Servlet. service() 引发异常

jboss-eap-7 - EAP 7 上的 JSF 2.3