4

I encounter a very strange issue in my project using spring web flow 2.4.0. In the documentation of web-flow project we can read on chapter 2 the following statement:

By default Web Flow does a client-side redirect upon entering every view state.

My concern is when i submit a form web flow do not make redirection that implies a new form submission is made if user reload or refresh the page. This is very boring. I tried many things and found a couple of solutions on the web for example make the redirection programmaticaly with the following code :

context.getExternalContext().requestFlowExecutionRedirect(); 

And i finally found an attribute "redirect" for the tag view-state in flow configuration. when it is set to true everything works fine.

Since web flow documentation mentions that this behavior (redirect automatically ) is the default one , does anyone heard about a better way to do this after form submission.

I am looking for a kind of POST REDIRECT GET pattern.

Thank you and sorry for my english :)

mhasan
  • 3,703
  • 1
  • 18
  • 37
Abass A
  • 713
  • 6
  • 14

3 Answers3

0

Just verify your springwebflow xml file configuration, it could be because of redirect flag set to false in the flow-execution-attributes.

    <webflow:flow-execution-attributes>
        <webflow:always-redirect-on-pause value="true"/>
        <webflow:redirect-in-same-state value="true"/>
    </webflow:flow-execution-attributes>
</webflow:flow-executor>
mhasan
  • 3,703
  • 1
  • 18
  • 37
0

To do the same

following is the code in Bean Level

@Bean
public FlowExecutor flowExecutor() {
    return getFlowExecutorBuilder(this.flowRegistry())
            .setRedirectInSameState(true)
            .setAlwaysRedirectOnPause(true)
            .build();
}

where the class extends AbstractFlowConfiguration

Parameshwar
  • 856
  • 8
  • 16
0

After lot of reading was finally able to change the default behaviour ( default behaviour was - Get request , post (302/303 - redirect as per location appended for each request ) , finally a get call.

So for one request we will send a Get Request then Service will return 302/303 with location attribute ( ie redirected with query param ) and as a response HTML with QueryString usually e1s1 is loaded. Sample proj is in this link and following is the change that is been implemented to avoid this default behaviour as following

To avoid 303/302 which has unpredictable behaviour i have stoped redirection with following addition to Config Class

@Configuration
public class WebFlowWithMvcConfig extends AbstractFlowConfiguration  {
    //implements WebMvcConfigurer
    @Autowired
    private LocalValidatorFactoryBean localValidatorFacotryBean;
    /*
    @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new LogInterceptor());
        }
     */
    
    @Bean
    public FlowDefinitionRegistry flowRegistry() {
        return getFlowDefinitionRegistryBuilder() //
                .setBasePath("classpath:flows") //
                .addFlowLocationPattern("/**/*-flow.xml") //
                .setFlowBuilderServices(this.flowBuilderServices()) //
                .build();
    }

    @Bean
    public FlowExecutor flowExecutor() {
        return getFlowExecutorBuilder(this.flowRegistry()) 
                .setAlwaysRedirectOnPause(false)
                .setRedirectInSameState(false) 
                .build();
    }

    @Bean
    public FlowBuilderServices flowBuilderServices() {
        return getFlowBuilderServicesBuilder() //
                .setViewFactoryCreator(this.mvcViewFactoryCreator()) // Important!
                .setValidator(this.localValidatorFacotryBean)
                .build();
    }
    // ----------------------------------------------------------

    @Bean
    public FlowHandlerMapping flowHandlerMapping() {
        FlowHandlerMapping handlerMapping = new FlowHandlerMapping();
        handlerMapping.setOrder(-1);
        handlerMapping.setFlowRegistry(this.flowRegistry());
        //handlerMapping.setInterceptors(new LogInterceptor());
        return handlerMapping;
    }

    @Bean
    public FlowHandlerAdapter flowHandlerAdapter() {
        FlowHandlerAdapter handlerAdapter = new FlowHandlerAdapter();
        handlerAdapter.setFlowExecutor(this.flowExecutor());
        handlerAdapter.setSaveOutputToFlashScopeOnRedirect(true);
        //handlerAdapter.setStatusCode(HttpStatus.SEE_OTHER);
        //handlerAdapter.setStatusCode(HttpStatus.TEMPORARY_REDIRECT);
        return handlerAdapter;
    }

    @Bean
    public ViewFactoryCreator mvcViewFactoryCreator() {
        MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator();
        factoryCreator.setViewResolvers(Collections.singletonList(this.thymeleafViewResolver()));
        factoryCreator.setUseSpringBeanBinding(true);
        return factoryCreator;
    }

    @Bean
    @Description("Thymeleaf AJAX view resolver for Spring WebFlow")
    public AjaxThymeleafViewResolver thymeleafViewResolver() {
        AjaxThymeleafViewResolver viewResolver = new AjaxThymeleafViewResolver();
        viewResolver.setViewClass(FlowAjaxThymeleafView.class);
        viewResolver.setTemplateEngine(this.templateEngine());
        viewResolver.setCharacterEncoding("UTF-8");
        return viewResolver;
    }

    @Bean
    @Description("Thymeleaf template resolver serving HTML 5")
    public ClassLoaderTemplateResolver templateResolver() {
        ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
        templateResolver.setPrefix("templates/");
        templateResolver.setCacheable(false);
        templateResolver.setSuffix(".html");
        templateResolver.setTemplateMode("HTML5");
        templateResolver.setCharacterEncoding("UTF-8");
        return templateResolver;
    }

    @Bean
    @Description("Thymeleaf template engine with Spring integration")
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(this.templateResolver());
        return templateEngine;
    }
}

So we have made following as false

            .setAlwaysRedirectOnPause(false)
            .setRedirectInSameState(false) 

Which will avoid location redirect now the similar change has to be implemented in the template html's too. So the change was to add an action url to html template wherever form is present as following

<form ..  th:action="${flowExecutionUrl}">

Which successfully does form submission and responds with 200 Ok http status and html page. Hence no more (GET - 200 to 302 redirect to 200) instead direct single request call with Get 200/Post 200 and response is binded to Html page.

Parameshwar
  • 856
  • 8
  • 16