Java SpringWebFlow如何在退出flow到外部重定向时添加flash属性

Java SpringWebFlow如何在退出flow到外部重定向时添加flash属性,java,jsp,spring-mvc,tiles,spring-webflow-2,Java,Jsp,Spring Mvc,Tiles,Spring Webflow 2,我是SpringWebFlow(2.3.1)的新手,这就是我要做的: 我有一个JSP页面,它在页面底部为页面顶部选择的作者列出了一个分页的图书表。我在顶部的“添加书籍”(就在作者下拉列表的下方)有一个按钮/链接,单击该按钮/链接将启动一个Spring web流,进入一个页面,用户可以在步骤1、2和3中输入书籍的详细信息(在3个不同的视图/页面中)。单击“保存”将创建新书,并应使用户返回带有分页图书列表的视图 现在,我想在保存操作之后添加一个flash属性(成功消息),并将用户带回图书页面(分页)

我是SpringWebFlow(2.3.1)的新手,这就是我要做的:

我有一个JSP页面,它在页面底部为页面顶部选择的作者列出了一个分页的图书表。我在顶部的“添加书籍”(就在作者下拉列表的下方)有一个按钮/链接,单击该按钮/链接将启动一个Spring web流,进入一个页面,用户可以在步骤1、2和3中输入书籍的详细信息(在3个不同的视图/页面中)。单击“保存”将创建新书,并应使用户返回带有分页图书列表的视图

现在,我想在保存操作之后添加一个flash属性(成功消息),并将用户带回图书页面(分页),预先选择“上一位”作者并显示成功消息

我为最终状态提供了以下web流XML:

<end-state id="home" view="externalRedirect:/books/" >
    <output name="author" value="book.author" />
</end-state>

“output”标记将用作在子流和父流调用者之间传输POJO的容器。但是,以下增强请求:

扩展了“output”标记的角色,以允许将flash变量从webflow的“结束状态”传输到springmvc控制器的flashMap

不幸的是,此增强没有包括您想要实现的功能,即通过externalRedirect从flow A->new flow A传递变量。因此,对于任何没有所需功能的第三方库。。。我们必须“破解”它

1。首先,您需要按照以下方式配置FlowHandlerAdapter,以利用上述增强功能: 设置为true的“SaveOutputOfLashScopeOnRedirect”是本次讨论的重要部分(默认设置为false)


2。您需要创建(扩展)和配置FlowExecutionListenerAdapter

import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;

import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.core.collection.SharedAttributeMap;
import org.springframework.webflow.definition.FlowDefinition;
import org.springframework.webflow.execution.FlowExecutionListenerAdapter;
import org.springframework.webflow.execution.RequestContext;

public class TestFlowExecutionListenerAdapter extends FlowExecutionListenerAdapter{
    @Override
    public void sessionCreating(RequestContext context, FlowDefinition definition) {

        MutableAttributeMap<Object> flashScopeWebFlow = context.getFlashScope();
        MutableAttributeMap<Object> flashMapWebFlow = context.getFlowScope();

        SharedAttributeMap<Object> sessionMap = context.getExternalContext().getSessionMap();
        MutableAttributeMap<Object> requestMap = context.getExternalContext().getRequestMap();

        HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getNativeRequest();
        Map<String, ?> flashMapMvc = RequestContextUtils.getInputFlashMap(request);

        if(flashMapMvc != null)
            putAllFlashMapToFlashScope(flashMapMvc,flashScopeWebFlow);   
        System.out.println("here");
    }

    public static void putAllFlashMapToFlashScope(Map<String, ?> map, MutableAttributeMap<Object> mutableAttributeMap) {
        for( Entry<String, ?> entry : map.entrySet()) {
            mutableAttributeMap.put(entry.getKey(), entry.getValue());
        }
    }
} 
import java.util.Map;
导入java.util.Map.Entry;
导入javax.servlet.http.HttpServletRequest;
导入org.springframework.web.servlet.support.RequestContextUtils;
导入org.springframework.webflow.core.collection.MutableAttributeMap;
导入org.springframework.webflow.core.collection.SharedAttributeMap;
导入org.springframework.webflow.definition.FlowDefinition;
导入org.springframework.webflow.execution.FlowExecutionListenerAdapter;
导入org.springframework.webflow.execution.RequestContext;
公共类TestFlowExecutionListenerAdapter扩展了FlowExecutionListenerAdapter{
@凌驾
public void sessionCreating(RequestContext上下文,FlowDefinition){
MutableAttributeMap flashScopeWebFlow=context.getFlashScope();
MutableAttributeMap flashMapWebFlow=context.getFlowScope();
SharedAttributeMap sessionMap=context.getExternalContext().getSessionMap();
MutableAttributeMap requestMap=context.getExternalContext().getRequestMap();
HttpServletRequest=(HttpServletRequest)context.getExternalContext().getNativeRequest();
Map flashMapMvc=RequestContextUtils.getInputFlashMap(请求);
如果(flashMapMvc!=null)
PutalFlashMapToFlashScope(flashMapMvc、flashScopeWebFlow);
System.out.println(“此处”);
}
public static void putAllFlashMapToFlashScope(映射映射,MutableAttributeMap MutableAttributeMap){
for(条目:map.entrySet()){
mutableAttributeMap.put(entry.getKey(),entry.getValue());
}
}
} 
初始化bean,如下所示:

    <webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
        <webflow:flow-execution-listeners>
            <webflow:listener ref="testFlowExecutionListenerAdapter" />          
        </webflow:flow-execution-listeners>
    </webflow:flow-executor>

<bean id="testFlowExecutionListenerAdapter" class="com.foo.bar.flowexeclisteners.TestFlowExecutionListenerAdapter"/>

注意:将“com.foo.bar.flowexeclisteners”更改为实际的包路径

3.上面的FlowExecutionListenerAdapter允许@Overriding某些方法来监视SpringWebFlow框架的生命周期事件。在我们的例子中,我选择@Override sessionCreating()方法,但是您可以使用许多不同的方法来满足您的用例或提高效率

鉴于上述配置,我们现在可以开始以两种方式传回变量。一个是通过sessionMap,另一个是通过“output”标记,该标记现在配置为存储在flashMap中(SpringMVC而不是flashScope)。下面是一个“结束状态”示例,演示了这一点

  <end-state id="home" view="externalRedirect:/books/">
        <on-entry>
            <evaluate expression="externalContext.sessionMap.put('author', 'William Brian Jennings')"/>
        </on-entry>
        <output name="responseMsg" value="'Added author to the sessionMap'"/>
  </end-state> 

4.触发此“结束状态”时(如果您在FlowExecutionListenerAdapter中放置断点),您将看到flashMapMvc将保存您的“responseMsg”变量,而“author”变量将位于sessionMap中。静态方法“putAllFlashMapToFlashScope”将自动使您的“responseMsg”可供视图使用,但对于sessionMap,您需要在接收流中显式提取变量,如下所示:

<set name="flowScope.author" value="externalContext.sessionMap.get('author')"/>

以下是一些注意事项:

  • 所有这一切的麻烦之处在于,我们必须将flashMapMvc转换为flashScopeWebFlow,因为它们不兼容(两个不同的容器)。我在FlowExecutionListenerAdapter类中使用了一个静态方法“putalFlashMaptoFlashScope()”来演示这一点。我不认为这是一个很好的实践,但我只是为了简单起见在这里这么做,这样你就可以看到问题到底是什么以及如何解决它们

  • sessionMap变量将在整个会话期间和所有流中保持不变。如果你使用这张地图,要注意这一点

  • 我在FlowExecutionListenerAdapter中包括了其他(未使用的)映射,以演示您可以访问的内容

  • 显然,这是一个黑客解决方案,真正需要做的是一个增强请求,以实现您的尝试(流a结束)->通过外部重定向将输出传递回->(新流a)

  • 由于这样的问题,我个人已经停止在所有用例中使用WebFlow,并将其仅限于简单的用例(即A->B->C页),现在我只在其他所有用例中使用SpringMVC
      <end-state id="home" view="externalRedirect:/books/">
            <on-entry>
                <evaluate expression="externalContext.sessionMap.put('author', 'William Brian Jennings')"/>
            </on-entry>
            <output name="responseMsg" value="'Added author to the sessionMap'"/>
      </end-state> 
    
    <set name="flowScope.author" value="externalContext.sessionMap.get('author')"/>