Spring webflow SpringWebFlow2.x-如何将AlwaysGenerateNewExtKey设置为false以使用单个快照

Spring webflow SpringWebFlow2.x-如何将AlwaysGenerateNewExtKey设置为false以使用单个快照,spring-webflow,spring-webflow-2,Spring Webflow,Spring Webflow 2,团队,我们正在将SpringWebFlow从1.x升级到2.4 在SWF1.x中,我们在整个会话中只使用了一个flowExecutionKey,还禁用了反向导航 在SWF2.4中,我们希望有相同的行为 我们可以通过将最大执行快照配置为0来禁用快照,如下所示 <webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry"> <webflow:flow-execution-repository ma

团队,我们正在将SpringWebFlow从1.x升级到2.4

在SWF1.x中,我们在整个会话中只使用了一个flowExecutionKey,还禁用了反向导航

在SWF2.4中,我们希望有相同的行为

我们可以通过将最大执行快照配置为0来禁用快照,如下所示

<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
    <webflow:flow-execution-repository max-executions="1" max-execution-snapshots="0"/>
</webflow:flow-executor>

但在导航上,快照id不断增加
(如e1s1、e1s2…
,这是导致问题的原因,当我们对此进行调查时

AbstractFlowExecutionRepository
具有以下字段,该字段有助于在为true时为每个导航生成新的快照ID

AlwaysGenerateNewExtKey
默认为true

在SWF 1.x中,有一个选项可以通过
RepositoryType.SINGLEKEY
设置为false,但在SWF 2.4中,我们找不到任何等效的方法将该值设置为false


如果有办法覆盖“AlwaysGenerateNewExtKey”

请提供帮助现在我知道这很难看,但以下是您可以做的:

制作自己的
FlowExecutoryBean
FlowElementAttribute
副本,将它们命名为
MyFlowExecutoryBean
MyFlowElementAttribute
(将
MyFlowExecutoryBean
中的引用从
FlowElementAttribute
更改为
MyFlowElementAttribute

myflowExecutoryFactoryBean
中,在
executionRepository
上设置所需的属性,如
setAlwaysGenerateNewExtKey(true)

结果如下:

public class MyFlowExecutorFactoryBean implements FactoryBean<FlowExecutor>, ApplicationContextAware, BeanClassLoaderAware, InitializingBean {

    private static final String ALWAYS_REDIRECT_ON_PAUSE = "alwaysRedirectOnPause";

    private static final String REDIRECT_IN_SAME_STATE = "redirectInSameState";

    private FlowDefinitionLocator flowDefinitionLocator;

    private Integer maxFlowExecutions;

    private Integer maxFlowExecutionSnapshots;

    private Set<MyFlowElementAttribute> flowExecutionAttributes;

    private FlowExecutionListenerLoader flowExecutionListenerLoader;

    private ConversationManager conversationManager;

    private ConversionService conversionService;

    private FlowExecutor flowExecutor;

    private MvcEnvironment environment;

    private ClassLoader classLoader;

    /**
     * Sets the flow definition locator that will locate flow definitions needed for execution. Typically also a
     * {@link FlowDefinitionRegistry}. Required.
     * @param flowDefinitionLocator the flow definition locator (registry)
     */
    public void setFlowDefinitionLocator(FlowDefinitionLocator flowDefinitionLocator) {
        this.flowDefinitionLocator = flowDefinitionLocator;
    }

    /**
     * Set the maximum number of allowed flow executions allowed per user.
     */
    public void setMaxFlowExecutions(int maxFlowExecutions) {
        this.maxFlowExecutions = maxFlowExecutions;
    }

    /**
     * Set the maximum number of history snapshots allowed per flow execution.
     */
    public void setMaxFlowExecutionSnapshots(int maxFlowExecutionSnapshots) {
        this.maxFlowExecutionSnapshots = maxFlowExecutionSnapshots;
    }

    /**
     * Sets the system attributes that apply to flow executions launched by the executor created by this factory.
     * Execution attributes may affect flow execution behavior.
     * @param flowExecutionAttributes the flow execution system attributes
     */
    public void setFlowExecutionAttributes(Set<MyFlowElementAttribute> flowExecutionAttributes) {
        this.flowExecutionAttributes = flowExecutionAttributes;
    }

    /**
     * Sets the strategy for loading the listeners that will observe executions of a flow definition. Allows full
     * control over what listeners should apply to executions of a flow definition launched by the executor created by
     * this factory.
     */
    public void setFlowExecutionListenerLoader(FlowExecutionListenerLoader flowExecutionListenerLoader) {
        this.flowExecutionListenerLoader = flowExecutionListenerLoader;
    }

    /**
     * Sets the service type that manages conversations and effectively controls how state is stored physically when a
     * flow execution is paused.
     */
    public void setConversationManager(ConversationManager conversationManager) {
        this.conversationManager = conversationManager;
    }

    // implementing ApplicationContextAware

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        environment = MvcEnvironment.environmentFor(applicationContext);
    }

    // implement BeanClassLoaderAware

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    // implementing InitializingBean

    @Override
    public void afterPropertiesSet() throws Exception {
        Assert.notNull(flowDefinitionLocator, "The flow definition locator property is required");
        if (conversionService == null) {
            conversionService = new DefaultConversionService();
        }
        MutableAttributeMap<Object> executionAttributes = createFlowExecutionAttributes();
        FlowExecutionImplFactory executionFactory = createFlowExecutionFactory(executionAttributes);
        DefaultFlowExecutionRepository executionRepository = createFlowExecutionRepository(executionFactory);
        executionRepository.setMaxSnapshots(0);
        executionRepository.setAlwaysGenerateNewNextKey(false);
        executionFactory.setExecutionKeyFactory(executionRepository);
        flowExecutor = new FlowExecutorImpl(flowDefinitionLocator, executionFactory, executionRepository);
    }

    // implementing FactoryBean

    @Override
    public Class<?> getObjectType() {
        return FlowExecutor.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    @Override
    public FlowExecutor getObject() throws Exception {
        return flowExecutor;
    }

    private MutableAttributeMap<Object> createFlowExecutionAttributes() {
        LocalAttributeMap<Object> executionAttributes = new LocalAttributeMap<Object>();
        if (flowExecutionAttributes != null) {
            for (MyFlowElementAttribute attribute : flowExecutionAttributes) {
                executionAttributes.put(attribute.getName(), getConvertedValue(attribute));
            }
        }
        putDefaultFlowExecutionAttributes(executionAttributes);
        return executionAttributes;
    }

    private void putDefaultFlowExecutionAttributes(LocalAttributeMap<Object> executionAttributes) {
        if (!executionAttributes.contains(ALWAYS_REDIRECT_ON_PAUSE)) {
            Boolean redirect = environment != MvcEnvironment.PORTLET;
            executionAttributes.put(ALWAYS_REDIRECT_ON_PAUSE, redirect);
        }
        if (!executionAttributes.contains(REDIRECT_IN_SAME_STATE)) {
            Boolean redirect = environment != MvcEnvironment.PORTLET;
            executionAttributes.put(REDIRECT_IN_SAME_STATE, redirect);
        }
    }

    private DefaultFlowExecutionRepository createFlowExecutionRepository(FlowExecutionFactory executionFactory) {
        ConversationManager conversationManager = createConversationManager();
        FlowExecutionSnapshotFactory snapshotFactory = createFlowExecutionSnapshotFactory(executionFactory);
        DefaultFlowExecutionRepository rep = new DefaultFlowExecutionRepository(conversationManager, snapshotFactory);
        if (maxFlowExecutionSnapshots != null) {
            rep.setMaxSnapshots(maxFlowExecutionSnapshots);
        }
        return rep;
    }

    private ConversationManager createConversationManager() {
        if (conversationManager == null) {
            conversationManager = new SessionBindingConversationManager();
            if (maxFlowExecutions != null) {
                ((SessionBindingConversationManager) conversationManager).setMaxConversations(maxFlowExecutions);
            }
        }
        return this.conversationManager;
    }

    private FlowExecutionSnapshotFactory createFlowExecutionSnapshotFactory(FlowExecutionFactory executionFactory) {
        if (maxFlowExecutionSnapshots != null && maxFlowExecutionSnapshots == 0) {
            maxFlowExecutionSnapshots = 1;
            return new SimpleFlowExecutionSnapshotFactory(executionFactory, flowDefinitionLocator);
        } else {
            return new SerializedFlowExecutionSnapshotFactory(executionFactory, flowDefinitionLocator);
        }
    }

    private FlowExecutionImplFactory createFlowExecutionFactory(AttributeMap<Object> executionAttributes) {
        FlowExecutionImplFactory executionFactory = new FlowExecutionImplFactory();
        executionFactory.setExecutionAttributes(executionAttributes);
        if (flowExecutionListenerLoader != null) {
            executionFactory.setExecutionListenerLoader(flowExecutionListenerLoader);
        }
        return executionFactory;
    }

    // utility methods

    private Object getConvertedValue(MyFlowElementAttribute attribute) {
        if (attribute.needsTypeConversion()) {
            Class<?> targetType = fromStringToClass(attribute.getType());
            ConversionExecutor converter = conversionService.getConversionExecutor(String.class, targetType);
            return converter.execute(attribute.getValue());
        } else {
            return attribute.getValue();
        }
    }

    private Class<?> fromStringToClass(String name) {
        Class<?> clazz = conversionService.getClassForAlias(name);
        if (clazz != null) {
            return clazz;
        } else {
            try {
                return ClassUtils.forName(name, classLoader);
            } catch (ClassNotFoundException e) {
                throw new IllegalArgumentException("Unable to load class '" + name + "'");
            }
        }
    }

    class MyFlowElementAttribute {

        /**
         * The name of the attribute.
         */
        private String name;

        /**
         * The value of the attribute before type-conversion.
         */
        private String value;

        /**
         * The attribute type, optional, but necessary for type conversion.
         */
        private String type;

        public MyFlowElementAttribute(String name, String value, String type) {
            Assert.hasText(name, "The name is required");
            Assert.hasText(value, "The value is required");
            this.name = name;
            this.value = value;
            this.type = type;
        }

        public String getName() {
            return name;
        }

        public String getValue() {
            return value;
        }

        public String getType() {
            return type;
        }

        public boolean needsTypeConversion() {
            return type != null && type.length() > 0;
        }
    }
}
公共类MyFlowExecutorFactoryBean实现FactoryBean、ApplicationContextAware、BeanClassLoaderware、InitializingBean{
私有静态最终字符串始终\u重定向\u ON\u PAUSE=“AlwaysDirectionPause”;
私有静态最终字符串REDIRECT_IN_SAME_STATE=“redirectInSameState”;
专用FlowDefinitionLocator FlowDefinitionLocator;
私有整数maxFlowExecutions;
私有整数maxFlowExecutionSnapshots;
私有设置FlowExecutionAttribute;
私有FlowExecutionListenerLoader FlowExecutionListenerLoader;
私人会话管理器会话管理器;
私有转换服务转换服务;
私有流执行器流执行器;
私人环境;
私有类加载器;
/**
*设置流定义定位器,该定位器将定位执行所需的流定义。通常也是
*{@link FlowDefinitionRegistry}。必需。
*@param flowDefinitionLocator流定义定位器(注册表)
*/
public void setFlowDefinitionLocator(FlowDefinitionLocator FlowDefinitionLocator){
this.flowDefinitionLocator=flowDefinitionLocator;
}
/**
*设置每个用户允许的最大流执行数。
*/
公共void setMaxFlowExecutions(int maxFlowExecutions){
this.maxFlowExecutions=maxFlowExecutions;
}
/**
*设置每次流执行允许的最大历史快照数。
*/
public void setMaxFlowExecutionSnapshots(int-maxFlowExecutionSnapshots){
this.maxFlowExecutionSnapshots=maxFlowExecutionSnapshots;
}
/**
*设置应用于此工厂创建的执行器启动的流执行的系统属性。
*执行属性可能会影响流执行行为。
*@param flowExecutionAttributes流执行系统属性
*/
public void setFlowExecutionAttributes(设置flowExecutionAttributes){
this.flowExecutionAttributes=flowExecutionAttributes;
}
/**
*设置加载将观察流定义执行情况的侦听器的策略。允许完全
*控制哪些侦听器应应用于由创建的执行器启动的流定义的执行
*这家工厂。
*/
public void setFlowExecutionListenerLoader(FlowExecutionListenerLoader FlowExecutionListenerLoader){
this.flowExecutionListenerLoader=flowExecutionListenerLoader;
}
/**
*设置服务类型,该服务类型用于管理会话,并有效地控制状态在会话发生时的物理存储方式
*流执行已暂停。
*/
公共无效设置ConversationManager(ConversationManager ConversationManager){
this.conversationManager=conversationManager;
}
//实现ApplicationContextAware
@凌驾
public void setApplicationContext(ApplicationContext ApplicationContext)抛出BeansException{
environment=MVCEnEnvironment.environmentFor(applicationContext);
}
//实现BeanClassLoaderware
@凌驾
公共类加载器(类加载器类加载器){
this.classLoader=classLoader;
}
//实现初始化bean
@凌驾
public void afterPropertieSet()引发异常{
notNull(flowDefinitionLocator,“需要流定义定位器属性”);
if(conversionService==null){
conversionService=新的DefaultConversionService();
}
MutableAttributeMap executionAttributes=createFlowExecutionAttributes();
FlowExecutionImpactFactory executionFactory=createFlowExecutionFactory(executionAttributes);
DefaultFlowExecutionRepository executionRepository=createFlowExecutionRepository(executionFactory);
executionRepository.setMaxSnapshots(0);
executionRepository.setAlwaysGenerateNewExtKey(false);
setExecutionKeyFactory(executionRepository);
flowExecutor=新的FlowExecuteImpl(flowDefinitionLocator、executionFactory、executionRepository);
}
//实现FactoryBean
@凌驾
公共类getObjectType(){
返回FlowExecutor.class;
}
@凌驾
公共布尔isSingleton(){
返回true;
}
@凌驾
公共FlowExecut
<bean id="flowExecutor" class="com.example.MyFlowExecutorFactoryBean ">
  <property name="flowDefinitionLocator" ref="flowRegistry" />
  <property name="flowExecutionListenerLoader">
    <bean class="org.springframework.webflow.config.FlowExecutionListenerLoaderFactoryBean">
      <property name="listeners">
        <map>
          <entry key-ref="yourFirstListener" value="*" />
          <entry key-ref="yourSecondListener" value="*" />
        </map>
      </property>
    </bean>
  </property>
</bean>
<bean id="flowExecutionRepository" class="com.custom.module.SingleFlowExecutionRepository">
    <constructor-arg index="0" ref="conversationManager"/>
    <constructor-arg index="1" ref="snapshotFactory"/>
</bean>

<bean id="flowExecutor" class="org.springframework.webflow.executor.FlowExecutorImpl">
    <constructor-arg index="0" ref="flowRegistry"/>
    <constructor-arg index="1" ref="executionFactory" name="executionFactory"/>
    <constructor-arg index="2" ref="flowExecutionRepository" name="executionRepository"/>
</bean>
public SingleFlowExecutionRepository(ConversationManager conversationManager,
        FlowExecutionSnapshotFactory snapshotFactory) {
    super(conversationManager, snapshotFactory);        
    /**
     * Set to maintain single snapshot for a session.
     */
    super.setAlwaysGenerateNewNextKey(false);
}