Jsf Can';t从preRender导航后保留faces消息
在页面的预渲染代码中,我添加了faces消息,然后导航到另一个页面,如下所示:Jsf Can';t从preRender导航后保留faces消息,jsf,jsf-2,Jsf,Jsf 2,在页面的预渲染代码中,我添加了faces消息,然后导航到另一个页面,如下所示: if(error){ addMessageToComponent(null,"AN ERROR HAS OCCURRED"); FacesContext.getCurrentInstance().getExternalContext().getFlash() .setKeepMessages(true); navigateActionListener("myoutcome"); }
if(error){
addMessageToComponent(null,"AN ERROR HAS OCCURRED");
FacesContext.getCurrentInstance().getExternalContext().getFlash()
.setKeepMessages(true);
navigateActionListener("myoutcome");
}
<f:event type="postInvokeAction" listener="#{bean.init}" />
用于添加消息和导航的util方法有:
public static String getClientId(String componentId)
{
FacesContext context = FacesContext.getCurrentInstance();
UIViewRoot root = context.getViewRoot();
UIComponent c = findComponent(root, componentId);
return c.getClientId(context);
}
public static UIComponent findComponent(UIComponent c, String id)
{
if (id.equals(c.getId())) { return c; }
Iterator<UIComponent> kids = c.getFacetsAndChildren();
while (kids.hasNext())
{
UIComponent found = findComponent(kids.next(), id);
if (found != null) { return found; }
}
return null;
}
/**
* @param componentId
* : the id for the jsf/primefaces component without formId:
* prefix. <br>
* if you use null then the message will be added to the
* h:messages component.
**/
public static void addMessageToComponent(String componentId, String message)
{
if (componentId != null)
componentId = GeneralUtils.getClientId(componentId);
FacesContext.getCurrentInstance().addMessage(componentId,
new FacesMessage(message));
}
public static void navigateActionListener(String outcome)
{
FacesContext context = FacesContext.getCurrentInstance();
NavigationHandler navigator = context.getApplication()
.getNavigationHandler();
navigator.handleNavigation(context, null, outcome);
}
公共静态字符串getClientId(字符串组件ID)
{
FacesContext context=FacesContext.getCurrentInstance();
UIViewRoot root=context.getViewRoot();
UIComponent c=findComponent(根,componentId);
返回c.getClientId(上下文);
}
公共静态UIComponent findComponent(UIComponent c,字符串id)
{
if(id.equals(c.getId()){返回c;}
迭代器kids=c.getFacetsAndChildren();
while(kids.hasNext())
{
UIComponent found=findComponent(kids.next(),id);
if(found!=null){return found;}
}
返回null;
}
/**
*@param-componentId
*:不带formId的jsf/primefaces组件的id:
*前缀
*如果使用null,则消息将添加到
*h:消息组件。
**/
公共静态void addMessageToComponent(字符串组件ID,字符串消息)
{
if(componentId!=null)
componentId=GeneralUtils.getClientId(componentId);
FacesContext.getCurrentInstance().addMessage(组件ID,
新面孔信息(信息));
}
公共静态void navigateActionListener(字符串结果)
{
FacesContext context=FacesContext.getCurrentInstance();
NavigationHandler navigator=context.getApplication()
.getNavigationHandler();
导航器.手动导航(上下文,空,结果);
}
但是消息不会被保存,因此重定向后它不会出现
请建议如何解决此问题。在
渲染响应
阶段的最开始运行预渲染视图
事件。现在指示Flash
范围保存消息已经太晚了。您最迟可以在调用应用程序
阶段执行此操作
由于没有标准的JSF组件系统事件,因此您需要自制一个:
@NamedEvent(shortName="postInvokeAction")
public class PostInvokeActionEvent extends ComponentSystemEvent {
public PostInvokeActionEvent(UIComponent component) {
super(component);
}
}
要发布此内容,您需要一个相位侦听器
:
public class PostInvokeActionListener implements PhaseListener {
@Override
public PhaseId getPhaseId() {
return PhaseId.INVOKE_APPLICATION;
}
@Override
public void beforePhase(PhaseEvent event) {
// NOOP.
}
@Override
public void afterPhase(PhaseEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
context.getApplication().publishEvent(context, PostInvokeActionEvent.class, context.getViewRoot());
}
}
在faces config.xml
中按如下方式注册后:
<lifecycle>
<phase-listener>com.example.PostInvokeActionListener</phase-listener>
</lifecycle>
com.example.PostInvokeActionListener
您可以按如下方式使用新事件:
if(error){
addMessageToComponent(null,"AN ERROR HAS OCCURRED");
FacesContext.getCurrentInstance().getExternalContext().getFlash()
.setKeepMessages(true);
navigateActionListener("myoutcome");
}
<f:event type="postInvokeAction" listener="#{bean.init}" />
您只需要确保您至少有一个
,否则JSF根本不会进入调用阶段
JSF实用程序库已经支持此事件和
preInvokeAction
事件。另请参见,其中还演示了为重定向设置facesmessage。预渲染视图事件在渲染响应
阶段的最开始运行。现在指示Flash
范围保存消息已经太晚了。您最迟可以在调用应用程序
阶段执行此操作
由于没有标准的JSF组件系统事件,因此您需要自制一个:
@NamedEvent(shortName="postInvokeAction")
public class PostInvokeActionEvent extends ComponentSystemEvent {
public PostInvokeActionEvent(UIComponent component) {
super(component);
}
}
要发布此内容,您需要一个相位侦听器
:
public class PostInvokeActionListener implements PhaseListener {
@Override
public PhaseId getPhaseId() {
return PhaseId.INVOKE_APPLICATION;
}
@Override
public void beforePhase(PhaseEvent event) {
// NOOP.
}
@Override
public void afterPhase(PhaseEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
context.getApplication().publishEvent(context, PostInvokeActionEvent.class, context.getViewRoot());
}
}
在faces config.xml
中按如下方式注册后:
<lifecycle>
<phase-listener>com.example.PostInvokeActionListener</phase-listener>
</lifecycle>
com.example.PostInvokeActionListener
您可以按如下方式使用新事件:
if(error){
addMessageToComponent(null,"AN ERROR HAS OCCURRED");
FacesContext.getCurrentInstance().getExternalContext().getFlash()
.setKeepMessages(true);
navigateActionListener("myoutcome");
}
<f:event type="postInvokeAction" listener="#{bean.init}" />
您只需要确保您至少有一个
,否则JSF根本不会进入调用阶段
JSF实用程序库已经支持此事件和
preInvokeAction
事件。另请参见,其中还演示了如何为重定向设置facesmessage。postInvokeAction将等效于preRenderView事件?我要完成的是,当用户对页面发出get请求时,进行检查,如果失败,则添加错误消息,然后导航到另一个页面,因此我在preRenderView中执行此逻辑。这个新事件会产生同样的行为吗?它们不一样。postInvokeAction
在调用操作阶段结束时运行,这是在flash范围内设置消息的最佳时机。preRenderView
在渲染响应阶段的开始运行,这对于在flash范围内设置消息来说太晚了。这就是这个答案的全部要点。我在这里迷路了。我能在这个事件中进行检查吗?它在呈现页面之前运行吗?我也不明白你的意思。在将上述代码添加到您的环境(或将OmniFaces JAR文件放置在/WEB-INF/lib
中)之后,您只需将
替换为
,如果您没有任何代码,则在必要时添加一个虚拟
。showcase页面包含一个演示。postInvokeAction将等效于preRenderView事件?我要完成的是,当用户对页面发出get请求时,进行检查,如果失败,则添加错误消息,然后导航到另一个页面,因此我在preRenderView中执行此逻辑。这个新事件会产生同样的行为吗?它们不一样。postInvokeAction
在调用操作阶段结束时运行,这是在flash范围内设置消息的最佳时机。preRenderView
在渲染响应阶段的开始运行,这对于在flash范围内设置消息来说太晚了。这就是这个答案的全部要点。我在这里迷路了。我能在这个事件中进行检查吗?它在呈现页面之前运行吗?我也不明白你的意思。在将上述代码添加到您的环境(或将OmniFaces JAR文件放置在/WEB-INF/lib
中)之后,您只需将
替换为
,如果您没有任何代码,则在必要时添加一个虚拟
。showcase页面包含一个演示。