Visit my new website http://java4developers.com
In this post we are going to see a Spring Web Flow simple example. For that, we need to use the Java code we talked about in JPA basic example with EntityManager , Spring and Maven and Criteria JPA 2.0 and database metamodel auto generation with Maven. Spring Web Flow allow us to create our own web application in an easy and fast way using flows. Transitions happens from some pages to others depending on which actions are ocurring, as clicking a specified button for example.
Our project structure is as follows:
We can notice that the only difference we find with previous project is that there is a webapp folder where our configuration and jsps files are. Spring Web Flow will use services we created in previous posts, for example getCars() method will return a car list from our mySql database.
We are going to explain our file structure within Spring WebFlow. In the next diagram the arrows mean that a file use another file in our configuration (the one where the arrows end up).
The web.xml file is the main configuration file in any web application. In this file we are going to define two things.
Our application context. In our case we are going to define our context in the carMvc-service.xml file. In this file we have to add a bean service to access to our service layer.
A org.springframework.web.context.ContextLoaderListener listener that manages our application context.
In second place we need to define in the servlet elemen the servlet that deals with the web application requests. Our servlet will be named as carMvc (we are going to configure it in the carMvc-servlet.xml file) and will be a org.springframework.web.servlet.DispatcherServlet instance. We have to say this servlet which urls is responsible for. Our servlet will manage the ones that are requested to /flows/* url. Our web.xml :
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>aplicación de ejemplo</display-name> <!-- indicamos que nuestros beans de contexto serán los que se indiquen en el fichero carMvc-service.xml --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/carMvc-service.xml</param-value> </context-param> <!-- será la clase que se encargará de cargar nuestro contexto indicado en el context-param --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- nuestro servlet se llamará carMvc. Tendremos que crear un fichero carMvc-servlet donde tendremos que incluir el fichero donde definamos nuestros flows (carMvc-webflow.xml)--> <servlet> <servlet-name>carMvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <!-- nuestro servlet carMvc será el encargado de gestionar nuestros flows --> <servlet-mapping> <servlet-name>carMvc</servlet-name> <url-pattern>/flows/*</url-pattern> </servlet-mapping> </web-app>
Our carMvc-service.xml file where we define our application context is next.
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean name="carService" class="com.hopcroft.examples.service.CarService" /> <!-- The rest of the config is covered below --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost/test" p:username="root" p:password="" p:initialSize="5" p:maxActive="10"> </bean> <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory"> <property name="dataSource" ref="dataSource" /> </bean> <context:component-scan base-package="com.hopcroft.examples.dao"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" /> </context:component-scan> <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> </beans>
Our carMvc-servlet.xml only imports carMvc-webflow.xml file where we are going to manage our flow states.
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- se declaran los flows en otro fichero --> <import resource="carMvc-webflow.xml" /> </beans>
s
There are two different parts within the carMvc-webflow.xml file.
There is a web-flow:executor element to deal with our web flows through a specified controller bean that belong to org.springframework.webflow.mvc.servlet.FlowController class. Our flowController class is just a simple server that deals with our flows.
Besides that we have a webflow:flow-registry where we indicate that (bienvenido.xml) file will be the responsible of defining our application flows. carMvc-webflow.xml file is:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" 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-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd"> <bean name="/*" class="org.springframework.webflow.mvc.servlet.FlowController"> <property name="flowExecutor" ref="flowExecutor" /> </bean> <webflow:flow-executor id="flowExecutor"></webflow:flow-executor> <webflow:flow-registry id="flowRegistry"> <webflow:flow-location path="/WEB-INF/flows/welcome/bienvenido.xml"></webflow:flow-location> </webflow:flow-registry> </beans>
There is only one file left to explain. Within bienvenido.xml there are the two jsp files our project need. As we mentioned previously, our bienvenido.xml file defines our application flow diagram. Something important to say is that flow diagram files follow the Convention over configuration patter. What does it mean?. That means that if we say there will be a trasition from A view state to B view state, then there will be two jsp called A.jsp and B.jsp. Our bienvenido.xml content.
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <flow xmlns="http://www.springframework.org/schema/webflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"> <view-state id="bienvenido"> <transition on="next" to="list"></transition> </view-state> <view-state id="list"> <on-render> <evaluate expression="carService.getCars()" result="requestScope.cars"></evaluate> </on-render> </view-state> </flow>
There are two Spring Web Flowview states.
Bienvenido state will be our initial view state. Its visual aspect will be defined by the jsp named with the same name, i.e. , bienvenido.jsp. Bienvenido.jsp will be
<html> <head>Bienvenido</head> <body> <a href="${flowExecutionUrl}&_eventId=next">Next</a> </body> </html>
Take a look at bienvenido.xml and bienvenido.jsp files, we can find out how our application flow diagram is built. Bienvenido.jsp will have a link to a next event . When we click our link we will make a trasition to list view state.
List.jsp. will show our car list. If we take a look to bienvenido.xml we can see that carService.getCars() method is called before showing the car list. We add the response in a requestScope variable named cars. This cars variable will be used by our jsp to show our cars.
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> <html> <head> <title>Car list</title> </head> <body> <table> <tr> <th>Company</th> <th>Model</th> <th>Price</th> </tr> <h2>Car list</h2> <c:forEach items="${cars}" var="car"> <tr> <td><c:out value="${car.company}" /></td> <td><c:out value="${car.model}" /></td> <td><c:out value="${car.price}" /></td> </tr> </c:forEach> </table> </body> </html>
Here it is my pom.xml to define dependencies. We have to include the jetty plugin to use it directly from Maven.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.hopcroft.examples.spring</groupId> <artifactId>simpleWebFlowApp</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <build> <plugins> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>8.0.0.M3</version> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>javax.security</groupId> <artifactId>jacc</artifactId> <version>1.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.10</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.2.2</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>3.0.5.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>3.0.5.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>3.0.5.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>3.0.5.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>3.5.6-Final</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.ow2.easybeans</groupId> <artifactId>easybeans-uberjar-hibernate</artifactId> <version>1.2.1</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-jpamodelgen</artifactId> <version>1.0.0.Final</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.webflow</groupId> <artifactId>spring-webflow</artifactId> <version>2.3.0.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.1.2</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>3.0.5.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>3.0.5.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.webflow</groupId> <artifactId>spring-binding</artifactId> <version>2.3.0.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.webflow</groupId> <artifactId>spring-js</artifactId> <version>2.3.0.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> </dependencies> </project>
We can see our web application in our brower as follow (notice that you can see flow states in the url):
Our application is quite easy and it only needs Spring Web Flow view states. But Spring Web Flow has also state, decision, subflow and end states.
We use jsp pages in our application but in Spring Web Flow we can add different JSF frameworks such as IceFaces, RichFaces, or the one you prefer. Spring has its own JSF framework called Spring Faces. We can also use the Dojo toolkit through the Spring Javascript framework.
Web Development Company
18 julio, 2011 at 11:33 am
Thank you for sharing this post about the Web Development. This is very useful for Web Development Application Development. Thanks again 🙂
Emad Al-Bloushi
10 junio, 2012 at 9:20 am
Great Job 🙂
hop2croft
10 junio, 2012 at 4:41 pm
Thank you!!
0555111111
23 junio, 2012 at 3:47 pm
Great simple example, but how to just code and jsp in order to select one of the cars in the list using Spring Webflow? Thanks.
hop2croft
24 junio, 2012 at 11:08 am
Thank you for reading me!. Well, you can use the select spring tag to populate it and after that select one of them from it. Once you populate the select tag you can receive it once you submit the page within the specified controller.
Diana Munteanu
20 agosto, 2012 at 12:24 pm
I am getting the the following exception
java.lang.ClassCastException: org.springframework.web.servlet.DispatcherServlet cannot be cast to javax.servlet.Servlet
does anybody know why???
Diana Munteanu
20 agosto, 2012 at 12:41 pm
Sorry!!
My fault !, I wrote a wrong name in package-scan …
aironman2k
9 May, 2013 at 3:33 pm
hi, could you share the code on github? It will be useful for a lot of people.
Thanks in advance
alonso
hop2croft
15 agosto, 2013 at 8:58 pm
Hi Aironman,
apologies for answering you back so late. Unfortunately I already deleted these projects.
Thank you for reading my blog.
Alonso Isidoro Roman
15 agosto, 2013 at 11:06 pm
Hi hop2croft! you welcome.
By the way, i already made my own little project using web flow, you can check it out on my github.
https://github.com/alonsoir/spring-mvc_webflow_hibernate_security
thanks to you for sharing your knowledge
aironman2k
9 May, 2013 at 3:34 pm
http://java4developers.com returns a 403. check it!
thank you
hop2croft
15 agosto, 2013 at 8:59 pm
Thank yo Aironman.
I’ve already made it work.