Spring Web Flow从流退出到外部重定向时如何添加Flash属性 [英] Spring web flow how to add flash attribute when exiting from flow to external redirect

查看:80
本文介绍了Spring Web Flow从流退出到外部重定向时如何添加Flash属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Spring Web Flow(2.3.1)的新手,这就是我想要做的事情:

I'm new to Spring Web Flow (2.3.1) and this is what I'm trying to do:

我有一个JSP页面,该页面在页面底部列出了分页的Books表,在页面顶部选择了Author.我在顶部的添加书"(位于作者"下拉列表的下方)上单击按钮/链接,该按钮/链接启动了一个Spring网络流程,该流程转到一个页面,用户可以在其中进行第1、2和第2步的操作,输入该书的详细信息. 3(在3个不同的视图/页面中).单击保存"将创建新的书",并应将用户带到带有书的分页列表的视图.

I have a JSP page which lists a paginated table of Books at the bottom of the page for the Author selected at the top of the page. I have a button/link at the top 'Add Book' (just below the Author drop-down) clicking which launches a Spring web flow that takes to a page where user can enter details of the Book in steps 1, 2 & 3 (in 3 different views/pages). Clicking Save creates the new Book and should take the user back to the view with paginated list of books.

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

Now, I want to add a flash attribute (success message) after the Save action and take user back to Books page (paginated), have the 'previous' author pre-selected and show the success message.

对于结束状态,我具有以下Web流XML:

I have the following the web flow XML for the end state:

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

我执行externalRedirect的原因是,我希望读取URL,就像用户在添加新书后刚刚单击书清单"页面一样.如果我不执行重定向,而是指向tile.xml中的视图名称,则可以正确看到Flash消息,但URL仍显示网络流,例如?execution=e1s1.在这两种情况下,都不会自动选择作者.

The reason I'm doing the externalRedirect is that I want the URL to read as if the user just clicked on the Books listing page after adding a new Book. If I don't do the redirect but instead point to the view name from tiles.xml I see the flash message correctly but the URL still shows the web flow e.g., ?execution=e1s1. In both cases the author is not automatically selected.

如何在重定向后保留Flash成功消息和作者"选择?

How do I preserve the flash success message AND the Author selection after a redirect?

output变量在外部重定向中是否有任何意义?

Does output variable have any meaning in an external redirect?

我还在保存"操作中设置了以下内容:

I'm also setting the following in the Save action:

    requestContext.getFlowScope().put("authorId", book.getAuthorId());

推荐答案

输出"标记旨在用作在子流流和父流调用者之间传递pojo的容器.但是,以下增强请求:

the 'output' tag is meant to be used as a container to transfer pojos between subflows flows and the parent flow callers. However, the following enhancement request:

https://jira.spring.io/browse/SWF-1561

扩展了输出"标签的作用,以允许将Flash变量从Webflow的结束状态"传输到Spring MVC控制器的flashMap.

expanded the role of the 'output' tag to allow the transfer of flash variables from the 'end-state' of a webflow to a spring MVC controller's flashMap.

不幸的是,此增强功能未包括要实现的目标,即要通过flowA-> new Flow A的externalRedirect传递变量.因此,对于任何不具备所需功能的第三方库,我们将不得不对其进行破解".

Unfortunately, this enhancement did NOT include what you want to achieve which is passing variables via an externalRedirect from flow A -> new Flow A. So as with any 3rd party lib that doesn't have the desired functionality... we're going to have to 'hack' it.

1..首先,您需要像这样配置FlowHandlerAdapter才能利用上面的增强功能: 设置为true的"saveOutputToFlashScopeOnRedirect"是此讨论的重要部分(默认设置为false).

1. First you need to have your FlowHandlerAdapter configured like this to utilize the enhancement above: the "saveOutputToFlashScopeOnRedirect" set to true is the important part for this discussion (set to false by default).

<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
    <property name="flowExecutor" ref="flowExecutor"/>
    <property name="saveOutputToFlashScopeOnRedirect" value="true"/>
</bean> 

2..您将需要创建(扩展)并配置FlowExecutionListenerAdapter.

2. You will need to create (extend) and configure a 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());
        }
    }
} 

然后像这样初始化bean:

And init the bean like this:

    <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"更改为实际的包路径.

Note: Change "com.foo.bar.flowexeclisteners" to your actual package path.

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

3. The FlowExecutionListenerAdapter above allows to to monitor life cycle events of Spring Webflow framework by @Overriding certain methods. In our case, I chose to @Override the sessionCreating() method but you can use from many different methods to meet your use case or to increase efficiency.

http://docs.spring.io/spring-webflow/docs/current/api/org/springframework/webflow/execution/FlowExecutionListenerAdapter.html

因此,鉴于上述配置,我们现在可以开始以两种方式传递变量.一个通过sessionMap或两个通过'output'标记,现在已配置为存储在flashMap中(Spring MVC而不是flashScope).这是一个演示结束状态"的示例.

So given the above configuration we can now begin passing back variables in 2 ways. One via sessionMap or Two via the 'output' tag which is now configured to be stored in the flashMap (of Spring MVC not flashScope). Here is an example 'end-state' demonstrating this.

  <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,您将需要像这样在接收流中显式提取变量:

4. When this 'end-state' is triggered (if you place a break point inside our FlowExecutionListenerAdapter) you will see that flashMapMvc will hold your 'responseMsg' variable and that 'author' variable will be in the sessionMap. The static method 'putAllFlashMapToFlashScope' will automatically make your 'responseMsg' avaliable for consumption by your view but for the sessionMap you will need to explicitly extract your variable out in your receiving flow like so:

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

一些注意事项:

  1. 所有这些的不足之处是我们必须将flashMapMvc转换为flashScopeWebFlow,因为它们不兼容(2个不同的容器).我在FlowExecutionListenerAdapater类中使用了静态方法'putAllFlashMapToFlashScope()'进行了演示.我认为这不是一个好的做法,但是为了简洁起见,我只是在这里这样做,因此您可以确切地了解问题所在以及如何解决这些问题.

  1. The hacky part of all this is we have to convert the flashMapMvc to flashScopeWebFlow because they are not compatible (2 different containers). I used a static method 'putAllFlashMapToFlashScope()' within the FlowExecutionListenerAdapater class to demonstrate this. I don't think this is a good practice but I just did it here for brevity so you can see what exactly what the issues are and how to solve them.

sessionMap变量将在整个会话期间和所有流中保留.如果您使用此地图,请注意这一点.

sessionMap variables will stay during the entire session and across all flows. If you use this map becareful of this point.

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

I included other (unused) maps in the FlowExecutionListenerAdapter to demonstrate what you have access to.

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

Obviously this is a hack solution and what really needs to happen is an enhancement request to achieve what your trying to do (flow A ends) -> pass output back to -> (new flow A) via external redirect.

由于这样的问题,我本人已停止在所有用例中使用WebFlow,并将其仅限于简单用例(即A页-> B页-> C页),现在我将Spring MVC专门用于所有其他情况用例.

Because of issues like this I've personally stopped using WebFlow for all use cases and have limited it only to simple cases (i.e page A -> Page B -> page C) and now I use Spring MVC exclusively for all other use cases.

很抱歉,答案很长,但这不是一个小问题:)

Sorry for the long answer but this is not a trivial issue :)

这篇关于Spring Web Flow从流退出到外部重定向时如何添加Flash属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆