[在网站中,我们希望集成jsf-applications提供的一些代码片段,考虑使用dashboard-app或“ portal-light”。在分析需求时,我们遇到了Arjan Tjims在jsf 2.3 new features上的博客文章,他在其中提到了新的“命名空间模式”:
在命名空间模式下,该模式专门用于Portlet,但也可以在其他环境中使用,部分响应具有一个ID,该ID被视为“命名容器ID”。所有预定义的回发参数名称(例如“ javax.faces.ViewState”,“ javax.faces.ClientWindow”,“ javax.faces.RenderKitId”等)均带有此前缀和命名分隔符(默认为“:”)。例如javax.faces.ViewState”变为“ myname:javax.faces.ViewState”。当UIViewRoot实例实现NamingContainer接口时,将激活命名空间模式。
我们的应用程序可能是该“命名空间模式”的用例,因此我们想尝试一下。
我们构建了一个MyUIViewRoot
,在其中实现了NamingContainer
并包装了原始的UIViewRoot
实例。我们在MyViewHandler
中注册了faces-config.xml
,用于处理ViewRoot的环绕。为了进行测试,我们使用了带有两个<h:form>
元素的简单计数器应用(似乎很重要)。
[我们发现似乎已激活“命名空间模式”,例如javax.faces.ViewState
确实由某个命名空间添加,并变为j_id1:javax.faces.ViewState:0
。但是,这两个操作都不再起作用-回发请求不再恢复视图,而是创建一个新视图。因此,使用我们的简单方法,我们会丢失一些内容(顺便说一句,仅从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;
}
}
}
[在网站中,我们希望集成jsf-applications提供的一些代码片段,考虑使用dashboard-app或“ portal-light”。在分析需求时,我们遇到了Arjan Tjims的博客文章...
您需要替换UIViewRoot
而不要包裹它。