在一个网站中,我们希望集成jsf应用程序提供的一些片段,比如仪表板应用程序或“门户灯”。在分析需求时,我们看到了Arjan Tjims在JSF2.3新特性上发表的一篇博文,他在文章中提到了一种新的“命名空间模式”:
在命名空间模式(它是专为Portlet设计的,但也可以在其他环境中使用)中,部分响应被赋予一个被视为“命名容器id”的id。所有预定义的回发参数名称(如"javax.faces.ViewState“、"javax.faces.ClientWindow”、"javax.faces.RenderKitId“等)都以此和命名分隔符(默认值":")作为前缀。例如,javax.faces.ViewState“变成"myname:javax.faces.ViewState”。当UIViewRoot实例实现NamingContainer接口时,名称空间模式被激活。
我们的应用程序可能是那种“命名空间模式”的实用程序,因此我们想尝试一下。
我们构建了一个MyUIViewRoot,实现了NamingContainer并封装了原始的UIViewRoot-instance。我们在faces-config.xml中注册了一个faces-config.xml,它处理ViewRoot的包装。在测试中,我们使用了一个简单的反应用程序和两个<h:form>-elements (似乎很重要)。
我们发现“命名空间模式”似乎被激活了,比如javax.faces.ViewState确实被某些名称空间所占据,并变成了j_id1:javax.faces.ViewState:0。但是这两种操作都不再起作用--回发请求不再恢复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-Implementation:
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;
}
}
}发布于 2020-05-15 09:35:45
您需要替换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>基本上仅此而已。另见这上面的莫贾拉。
https://stackoverflow.com/questions/61815731
复制相似问题