grailsspring-webflowgrails3

Using spring webflow in grails 3 application


I have been trying to port some of my grails 2 code to grails 3. This specific code uses grails-webflow plugin (which was supported only till grails 2.x; it is broken right now because some overhauling in grails core).

So I decided to directly use spring webflow inside my app. I have been able to do the basic plumbing. That is I have setup * application context for webflow * created flow factories and all * wrote the flow xml. * created other necessary beans.

Now, when I hit the url that is mapped to my flow, I can see that my .gsp page is rendering. But problem is, its not resolving the layout. And page is coming without any styling/layout. What I am missing ?

This is my gsp page.

<html>
<head>
<title><g:brandedTitle/> - Repository Database: Administrator</title>
<meta content="main" name="layout"/>
<script type="text/javascript" src="${assetPath(src: 'da.js')}"></script>
.... 
....

This is how I have done the plumbing for webflow.

@Configuration
@ComponentScan
class InstallRepositoryWebflow extends AbstractFlowConfiguration {

    @Autowired
    GroovyPagesTemplateEngine groovyPagesTemplateEngine;
    @Autowired
    GroovyPageLocator groovyPageLocator;
    @Autowired
    GrailsLayoutViewResolver grailsLayoutViewResolver;

    @Bean
    public FlowDefinitionRegistry flowRegistry() {
        return getFlowDefinitionRegistryBuilder(flowBuilderServices())
        // type on browser localhost:<port>/<context-path>/hitMeToInvokeThisFlow to invoke this flow.
                .addFlowLocation("/WEB-INF/flows/install-repository.xml", "installrep/install")
                .build();
    }

    @Bean
    public FlowExecutor flowExecutor() {
        return getFlowExecutorBuilder(flowRegistry()).build();
    }

    @Bean
    public FlowBuilderServices flowBuilderServices() {
        return getFlowBuilderServicesBuilder()
                .setViewFactoryCreator(viewFactoryCreator())
                .build();
    }

    @Bean
    public ViewFactoryCreator viewFactoryCreator() {
        List<ViewResolver> resolvers = new ArrayList<>(1);
        resolvers.add(gspViewResolver());
        resolvers.add(grailsLayoutViewResolver);
        ViewFactoryCreator creator = new MvcViewFactoryCreator();
        creator.setViewResolvers(resolvers);
        return creator;
    }

    @Bean
    ViewResolver gspViewResolver() {
        GroovyPageViewResolver innerGspViewResolver = new GroovyPageViewResolver(groovyPagesTemplateEngine, groovyPageLocator);
        //innerGspViewResolver.setAllowGrailsViewCaching(!gspReloadingEnabled || viewCacheTimeout != 0);
        //innerGspViewResolver.setCacheTimeout(gspReloadingEnabled ? viewCacheTimeout : -1);
        return innerGspViewResolver;
    }
}

And this is the relevant section from resource.groovy

 flowHandlerAdapter(FlowHandlerAdapter) {
        flowExecutor = ref("flowExecutor");
    }

    flowHandlerMapping(FlowHandlerMapping) {
        flowRegistry = ref("flowRegistry");
    }

QUESTION IS Why is my layout not being rendered ? What Am I missing ?


Solution

  • Finally I found the answer to this question. If I use SitemeshLayoutViewResolver layoutViewResolver, instead of creating a custom resolver GroovyPageViewResolver innerGspViewResolver = new GroovyPageViewResolver(groovyPagesTemplateEngine, groovyPageLocator); then my problem is solved. So Basically it has to be like this.

    @Bean
    ViewResolver gspViewResolver() {
        return jspViewResolver;
    }
    @Autowired
    GrailsViewResolver jspViewResolver
    

    This is the sample project here, in case someone is looking for working example.

    Update

    Once I did all this, I encountered a very strange problem. The webflow part of the application works alright when I am running the app from intellij. But when I created a war using gradlew assemble task, I always got /error page on the app. In the logs, it says No mapping found for HTTP request with URI * in DispatcherServlet with name 'grailsDispatcherServlet'.

    Apparently, the beans that I am trying to create are not there. To solve this issue, I moved away from the annotation based configuration and did put resources.xml file in grails-app/conf/spring/ directory. That solve the issue for war. Here is my configuration file.

    <?xml version="1.0" encoding="UTF-8"?>
    <!--suppress SpringFacetInspection -->
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:webflow="http://www.springframework.org/schema/webflow-config"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans.xsd
               http://www.springframework.org/schema/webflow-config
               http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.4.xsd">
    
        <webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
            <webflow:flow-location path="/WEB-INF/flows/install-repository.xml" id="installrep/install"/>
        </webflow:flow-registry>
    
        <webflow:flow-executor id="flowExecutor" />
    
        <webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="mvcViewFactoryCreator"/>
    
        <bean id="mvcViewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
            <property name="viewResolvers" ref="resolvers"/>
        </bean>
    
        <bean id="resolvers" class="java.util.ArrayList">
            <constructor-arg>
                <list>
                    <ref bean="jspViewResolver" />
                </list>
            </constructor-arg>
        </bean>
    
        <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
            <property name="flowExecutor" ref="flowExecutor" />
        </bean>
    
        <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
            <property name="flowRegistry" ref="flowRegistry"/>
            <property name="order" value="0"/>
        </bean>
    
    </beans>