Integrating Spring Web Flow with JSF

Spring Web Flow is a framework that provides abilities to developers to capture the workflow of a web application in the form of configurational constructs called Flows. JSF is a UI framework that provides support for developing complex user interface components along with simplified page navigation rules and event handling. In this article we will discuss about the integration techniques between Spring Web Flow and JSF with the assumption that the readers have a good understanding of these two technologies.

Test application

In this section, we will see the basic artifacts necessary for integrating Spring Web flow with JSF by developing a simple application. Because the idea is to illustrate the integration between Spring Web Flow and JSF, the application does nothing other than displaying a simple JSF invoked from Spring Web Flow. In the later sections of the article, we will see how to use services that makes use of database.

also read:

  1. Introduction to JSF
  2. JSF Interview Questions
  3. Request Processing Lifecycle phases in JSF

Web application deployment descriptor

We will start with defining the deployment descriptor of the application which is given below. Note that the following code snippet contains declarations specific to Spring Web Flow as well as JSF.

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app 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"
	version="2.4">

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			/WEB-INF/config/spring-fc-config.xml
		</param-value>
	</context-param>

	<context-param>
		<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
		<param-value>.xhtml</param-value>
	</context-param>

  	<context-param>
        <param-name>facelets.DEVELOPMENT</param-name>
   		<param-value>true</param-value>
  	</context-param>

  	<context-param>
  		<param-name>facelets.REFRESH_PERIOD</param-name>
  		<param-value>1</param-value>
  	</context-param>

    <filter>
        <filter-name>charEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>charEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<servlet>
		<servlet-name>Resources Servlet</servlet-name>
		<servlet-class>org.springframework.js.resource.ResourceServlet</servlet-class>
		<load-on-startup>0</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>Resources Servlet</servlet-name>
		<url-pattern>/resources/*</url-pattern>
	</servlet-mapping>

	<servlet>
		<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value></param-value>
		</init-param>
		<load-on-startup>2</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
		<url-pattern>/spring/*</url-pattern>
	</servlet-mapping>

	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.faces</url-pattern>
	</servlet-mapping>

	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
	</welcome-file-list>

</web-app>

The mapping for all the faces requests are handled by the Faces Servlet and the context path containing ‘spring’ is handled by Spring’s Dispatcher Servlet. A listener is configured which will load the application context which is found in the path ‘/WEB-INF/config/spring-fc.xml’.

Spring’s Configuration file

The content of Spring’s configuration file is given below. Note that this file contains a mixture of definitions related to Spring Web Flow and Spring MVC although it is possible to segregate them.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:webflow="http://www.springframework.org/schema/webflow-config"
       xmlns:faces="http://www.springframework.org/schema/faces"
       xsi:schemaLocation="

http://www.springframework.org/schema/beans


http://www.springframework.org/schema/beans/spring-beans-2.5.xsd


http://www.springframework.org/schema/webflow-config


http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd


http://www.springframework.org/schema/faces


http://www.springframework.org/schema/faces/spring-faces-2.0.xsd


http://www.springframework.org/schema/context


http://www.springframework.org/schema/context/spring-context-2.5.xsd">

	<webflow:flow-executor id="flowExecutor">
	</webflow:flow-executor>

	<webflow:flow-registry id="flowRegistry" flow-builder-services="facesFlowBuilderServices">
		<webflow:flow-location path="/WEB-INF/flows/test.xml" />
	</webflow:flow-registry>

	<faces:flow-builder-services id="facesFlowBuilderServices" />

	<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<value>
				/test=flowController
			</value>
		</property>
		<property name="defaultHandler">
			<bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
		</property>
	</bean>

	<bean id="flowController" class="org.springframework.webflow.mvc.servlet.FlowController">
		<property name="flowExecutor" ref="flowExecutor"/>
	</bean>

	<bean id="faceletsViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
		<property name="viewClass" value="org.springframework.faces.mvc.JsfView"/>
		<property name="prefix" value="/WEB-INF/" />
		<property name="suffix" value=".xhtml" />
	</bean>

</beans>

We have defined the Spring Web Flow’s flow Controller that is responsible for creating the flow definitions by loading the flows from the file ‘/WEB-INF/flows/test.xml’. We have defined URL based mapping of requests by defining ‘SimpleUrlHandlerMapping’. Note that for JSf integration, the declaration of ‘faces:flow-builder-services’ is necessary.

Faces Configuration file

<?xml version="1.0"?>
<!DOCTYPE faces-config PUBLIC
  "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
  "http://java.sun.com/dtd/web-facesconfig_1_0.dtd">

<faces-config>
	<application>
		<!-- Enables Facelets -->
		<view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
	</application>
</faces-config>

In the above faces configuration file, we have explicitly instructed to make use of Faceets as the view technology instead of JSF. Also note that the managed beans declarations and the navigation rules will simply go off and won’t be required at all as part of the integration since it will be taken care by Spring Web Flow itself.

Welcome file

The welcome file mentioned in the Web application’s deployment descriptor is ‘index.htm’ whose contents is given below.

<html>
<head>
  <meta http-equiv="Refresh" content="0; URL=spring/start">
</head>
</html>

Note that it re-directs the control to the url mapping which will be handled by Spring’s dispatcher servlet.

Flow Definition file

The code snippet for the flow definition file is given below. Remember that the below definitions will be loaded by Spring Web Flow’s Flow Controller as we have configured a context listener in the web.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<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="test">
	</view-state>

</flow>

There is only one state defined which is ‘test’. So, when the flow is invoked, the framework will look out for a file called ‘test.xhtml’ in the directory ‘/WEB-INF/flows’ as that is how we have configured the view resolver in the Spring’s application context file.

<bean id="faceletsViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
		<property name="viewClass" value="org.springframework.faces.mvc.JsfView"/>
		<property name="prefix" value="/WEB-INF/" />
		<property name="suffix" value=".xhtml" />
	</bean>

Sample Facelets file

The sample facelets file is given below. Note that it really does nothing other than displaying information message to the user. Also note that in the below file we are making use of templates and the name of the template file is ‘template.xhtml’.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html">
    <body>

        <ui:composition template="../template.xhtml">

            <ui:define name="heading">
            </ui:define>

            <ui:define name="body">
                Sample page which illustrates the integration between JSF and Spring Web Flow
            </ui:define>

        </ui:composition>

    </body>
</html>

Starting Page

Note that this is the page that will be invoked at startup and from here the control resumes back to Spring Web flow for displaying the page ‘test.xhtml’.

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
	    		xmlns:ui="http://java.sun.com/jsf/facelets"
	  			xmlns:h="http://java.sun.com/jsf/html"
	  			xmlns:f="http://java.sun.com/jsf/core"
                xmlns:sf="http://www.springframework.org/tags/faces"
				template="template.xhtml">

    <ui:define name="heading">
    </ui:define>

    <ui:define name="body">
        <div align="left">
            <p align="left">
                <a href="test">Click here to invoke the Facelets page</a>
            </p>
        </div>
    </ui:define>
</ui:composition>

Running the application

When the application is invoked, the welcome.html is invoked which redirects the control with the url pattern ‘spring/start’ which will ultimately invoke the file start.xhtml. From here, when the user clicks the link, the url ‘test’ will be mapped to test.xhtml file present in the directory ‘/WEB-INF/flows’. Running the above application will result in something like the following.

Sample application

That’s it. We have run the first sample application that integrates Spring Web Flow and JSF.

Making use of model

In this section, we will extend the knowledge that we gained in the last section by writing a simple search application that will perform search on a list of employees. When running the application, the interface will prompt the user to provide the name of the employee and will do the search accordingly. For brevity, we will omit the code snippets for the most commonly used files such as web.xml, faces-config.xml etc in this section.

Flow Definition file

The content of the flow definition file is given below. Note that the file also illustrates the usage of flow variables and flow transitions.

<?xml version="1.0" encoding="UTF-8"?>
<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">

    <var name="employeeSearchCriteria" class="net.javabeat.spring.webflow.jsf.search.employee.EmployeeCriteria" />

	<view-state id="showSearchPage">
        <transition on="searchEmployee" to="showSearchResults">
        </transition>
	</view-state>

	<view-state id="showSearchResults">
		<on-render>
			<evaluate expression="employeeSearchService.findEmployees(employeeSearchCriteria)"
                result="viewScope.allEmployees" result-type="dataModel" />
		</on-render>
	</view-state>

</flow>

We have declared a flow variable ‘employeeSearchCriteria’ of type ‘EmployeeCriteria’ and have used this in one of the state definitions. Initially the state ‘showSearchPage’ will be set which will display a simple facelets page for collecting the search parameter which is the ‘name of the employee’. When the user clicks the search button, then a transition occurs, which changes the state to ‘showSearchResults’. Note that the state ‘showSearchResults’ in turn will map to a facelets page that will display the results of the search. For finding out the matching employees, we have used the ‘findEmplyees’ service defined on the object ‘employeeSearchService’ and the results were stored in the variable ‘allEmployees’. We will look into the contents of both the facelets files in the next section.

Search Page

The content of the search page is given below. As you can see, it provides a simple form for collecting the name of the employee as the search criteria from the user.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:sf="http://www.springframework.org/tags/faces">
    <body>

        <ui:composition template="../template.xhtml">

            <ui:define name="heading">
                <p>Employee Search Page</p>
            </ui:define>

            <ui:define name="body">
                <h:form id="mainForm">
                    <h:outputLabel for="searchString">Search Employee:</h:outputLabel>
                    <sf:clientTextValidator promptMessage="Search employees by name">
                        <h:inputText id="empName" value="#{employeeSearchCriteria.empName}" />
                    </sf:clientTextValidator>
                    <br/><br/>
                    <sf:commandButton id="searchEmployees" value="Find Employees" processIds="*" action="searchEmployee" />
                </h:form>
            </ui:define>

        </ui:composition>

    </body>
</html>

Also note that the name of the action is ‘searchEmployee’ which happens to be the identifier for the state transition in the flow definition file. We have bound the user inputs to the model object ‘EmployeeSearchCriteria’ which we will be looking at shortly.

Search Results Page

This page will display the search results to the user. We are making use of the ‘dataTable’ element for displaying the results. Note that when the action is triggered, we use the search service for finding out the list of employees matching the criteria and the results of the search are stored in the flow variable ‘allEmployees’.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:sf="http://www.springframework.org/tags/faces">
    <body>

        <ui:composition template="../template.xhtml">

            <ui:define name="heading">
                <h2>Search Results</h2>
            </ui:define>

            <ui:define name="body">

            <h:dataTable id="allEmployees" var="employee" value="#{allEmployees}"  cellspacing="0" cellpadding="0" border="1">
                <h:column>
                    <f:facet name="header">Emp Id</f:facet>
                    <h:outputText value="#{employee.id}" align="left" />
                </h:column>
                <h:column>
                    <f:facet name="header">Name</f:facet>
                    <h:outputText value="#{employee.name}" align="left" />
                </h:column>
                <h:column>
                    <f:facet name="header">Date of Birth</f:facet>
                    <h:outputText value="#{employee.dob}" align="left" />
                </h:column>
                <h:column>
                    <f:facet name="header">Designation</f:facet>
                    <h:outputText value="#{employee.designation}" align="left" />
                </h:column>
            </h:dataTable>

            <p align="left">
                <a href="search">Search Again</a>
            </p>

            </ui:define>

        </ui:composition>

    </body>
</html>

Within the ‘dataTable’ element, we iterate over the search results for displaying the various properties of an employee such as id, name, date of birth. We still haven’t looked into the Employee model that we used in the above page which we will be discussing it shortly.

Employee Model object

The definition of the employee object is given below. The model comprises several properties such as id, name, date of birth and designation for an employee.

package net.javabeat.spring.webflow.jsf.search.employee;

import java.io.Serializable;
import java.util.Date;

public class Employee implements Serializable{

    private String id;
    private String name;
    private Date dob;
    private String designation;

    public String getDesignation() {
        return designation;
    }

    public void setDesignation(String designation) {
        this.designation = designation;
    }

    public Date getDob() {
        return dob;
    }

    public void setDob(Date dob) {
        this.dob = dob;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

Employee Search Criteria

If we could remember, in the employee search page, we use binding for collecting the user parameters in a model object which happens to be ‘EmployeeCriteria’, the definition of which is given below. Note that this is the object that will be passed to the Employee Service for finding out the matching employees.

package net.javabeat.spring.webflow.jsf.search.employee;

import java.io.Serializable;

public class EmployeeCriteria implements Serializable{

    private static final long serialVersionUID = 1L;
    private String empName;

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

}

Employee Search Service

The search service for employee object is given below. Note that we are not performing real-time search by hitting the database for finding out the matching employees, instead we create and load dummy employee objects and search against them.

package net.javabeat.spring.webflow.jsf.search.employee;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class EmployeeSearchService {

    private static List<Employee> allEmployees;

    public List<Employee> findEmployees(EmployeeCriteria criteria){

        List<Employee> searchedEmployees = new ArrayList<Employee>();
        if (criteria == null){
            return allEmployees;
        }

        String searchEmpName = criteria.getEmpName();
        if (searchEmpName != null && searchEmpName.trim().length() > 0){

            for (Employee anEmployee : allEmployees){

                if (anEmployee.getName().contains(searchEmpName)){
                    searchedEmployees.add(anEmployee);
                }
            }
            return searchedEmployees;
        }else{
            return allEmployees;
        }
    }

    static{

        allEmployees = new ArrayList<Employee>();
        allEmployees.add(employee("10000", "Steve Clark", new Date(1960, 6, 12), "Employee"));
        allEmployees.add(employee("10000", "Alfred Ray", new Date(1954, 4, 17), "Manager"));
        allEmployees.add(employee("10000", "Robert Woulsh", new Date(1944, 2, 16), "Director"));
    }

    static Employee employee(String id, String name, Date dob, String designation){

        Employee employee = new Employee();
        employee.setId(id);
        employee.setName(name);
        employee.setDob(dob);
        employee.setDesignation(designation);
        return employee;
    }
}

The above method findEmpoyees() was used in the expression definition for finding out the matched employees against the search criteria.

Running the application

Running the above application will display the following page for collecting the user input – i.e the name of the employee to be searched.

Employee search interface

After entering the name and clicking the ‘Find Employees’ button will taken to the search results page which is given below.

Employee search results

Interacting with the database

In this section, we will see how to integrate database in an application that runs on a Spring Web Flow and JSF framework. We will develop an application that provides an interface for adding book to a book store, since the purpose of the application is to demonstrate the integration of database; we will keep the functionality of this application as simple as possible.

Spring’s Configuration file

Other than the definitions that are related to Spring Web Flow and JSF, we have included lot many bean definitions which are related to persistence. For example, we have used the declarations ‘annotation-config’ that indicate that our persistent entities will be making use of annotations and all such entities which are present in the package ‘net.javabeat.spring.webflow.jsf.book’ has to be automatically scanned.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:webflow="http://www.springframework.org/schema/webflow-config"
       xmlns:faces="http://www.springframework.org/schema/faces"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="

http://www.springframework.org/schema/beans


http://www.springframework.org/schema/beans/spring-beans-2.5.xsd


http://www.springframework.org/schema/context


http://www.springframework.org/schema/context/spring-context-2.5.xsd


http://www.springframework.org/schema/webflow-config


http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd


http://www.springframework.org/schema/faces


http://www.springframework.org/schema/faces/spring-faces-2.0.xsd


http://www.springframework.org/schema/tx


http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

	<context:annotation-config />
	<context:component-scan base-package="net.javabeat.spring.webflow.jsf.book" />

	<webflow:flow-executor id="flowExecutor">
		<webflow:flow-execution-listeners>
			<webflow:listener ref="jpaFlowExecutionListener" />
		</webflow:flow-execution-listeners>
	</webflow:flow-executor>

	<webflow:flow-registry id="flowRegistry" flow-builder-services="facesFlowBuilderServices">
		<webflow:flow-location path="/WEB-INF/flows/bookMain.xml" />
	</webflow:flow-registry>

	<faces:flow-builder-services id="facesFlowBuilderServices" />

	<bean id="jpaFlowExecutionListener" class="org.springframework.webflow.persistence.JpaFlowExecutionListener">
		<constructor-arg ref="entityManagerFactory" />
		<constructor-arg ref="transactionManager" />
	</bean>

	<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<value>
                /bookMain=flowController
                /bookSearchPage=flowController
                /bookAdd=flowController
			</value>
		</property>
		<property name="defaultHandler">
			<bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
		</property>
	</bean>

	<bean id="flowController" class="org.springframework.webflow.mvc.servlet.FlowController">
		<property name="flowExecutor" ref="flowExecutor"/>
	</bean>

	<bean id="faceletsViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
		<property name="viewClass" value="org.springframework.faces.mvc.JsfView"/>
		<property name="prefix" value="/WEB-INF/" />
		<property name="suffix" value=".xhtml" />
	</bean>

	<tx:annotation-driven />

	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>

	<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
		</property>
	</bean>

	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
		<property name="url" value="jdbc:hsqldb:mem:book" />
		<property name="username" value="sa" />
		<property name="password" value="" />
	</bean>

</beans>

Integrating of database specific code happens through the declaration of the ‘jpaFlowExcutionListener’ that happens as part of flow execution. We have made use of HSQL in-memory database through the ‘dataSource’ definition and the same is referred in ‘entityManagerFactory’ which is again referred in Spring’s transaction manager. Note that JPA Flow Execution listener needs a reference to Entity Manager’s factory and a reference to the transaction manager.

Persistence Configuration file

The persistence configuration file has to be placed in ‘META-INF’ directory which in turn has to be in the application’s classpath.

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
             version="1.0">
   <persistence-unit name="bookDatabase">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
      <class>net.javabeat.spring.webflow.jsf.book.Book</class>
      <properties>
      	 <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
      	 <property name="hibernate.hbm2ddl.auto" value="create-drop" />
         <property name="hibernate.show_sql" value="true"/>
         <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider"/>
      </properties>
   </persistence-unit>
</persistence>

Book Entity

The declaration of the Book Entity is given below. Note that for indicating that the Book class is an Entity, we have annotated using @Entity.

package net.javabeat.spring.webflow.jsf.book;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Book implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;
    private String category;
    private String author;
    private double price;

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        if (!(object instanceof Book)) {
            return false;
        }
        Book other = (Book) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "net.javabeat.spring.webflow.jsf.book.Book[id=" + id + "]";
    }

}

We have also declared properties such as name of the book, book’s author, the categotry of book as well as its price.

Book Service interface

The book service interface that is used for creating and searching books is given here. Note that the method createBook() will be used when the user is attempting to create a new book. Similarly the methods findAllBooks() and findBooks() can be used for searching books.

package net.javabeat.spring.webflow.jsf.book;

import java.util.List;

public interface BookService {

    List<Book> findAllBooks();

    List<Book> findBooks(BookSearchCriteria criteria);

    void createBook(String name, String category, String author, double price);

}

Book Service Implementation

The service implementation for the book service interface is given below. Remember that we make use of JPA API for persisting entity information into the HSQL database. Also note the usage of the annotations @Service and @Repository. To indicate that the DAO class is a repository for Book objects, we have used the annotation @Repository.

package net.javabeat.spring.webflow.jsf.book;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service("bookService")
@Repository
public class BookServiceImpl implements BookService {

    private EntityManager em;

    @PersistenceContext
    public void setEntityManager(EntityManager em){
        this.em = em;
    }

    @Transactional(readOnly=true)
    public List<Book> findAllBooks() {
      Query query = em.createQuery("select book from Book book");
      List<Book> results = query.getResultList();

      if (results == null || results.size() == 0){
        createTestBooks();
        return query.getResultList();
      }else{
          return results;
      }
    }

    private void createTestBooks(){

        createBook("Java Programming", "Technical", "James", 1110.00);
        createBook("Life After Death", "Spiritual", "Unknown", 3140.00);
        createBook("All About Numerology", "Numerolgy", "Richard", 6130.00);
    }

    @Transactional(readOnly=true)
    public List<Book> findBooks(BookSearchCriteria criteria) {

        if (criteria == null){
            return findAllBooks();
        }

        String name = criteria.getName();
        String author = criteria.getAuthor();

        String query = "select book from Book";
        if (name != null && name.trim().length() > 0){
            query = query + " where upper(book.name) = :name ";
        }

        if (author != null && author.trim().length() > 0){
            if (query.contains("where")){
                query = query + " and ";
            }else{
                query = query + "where ";
            }
            query = query + " upper(book.author) = :author ";
        }

        Query queryObject = em.createQuery(query);
        queryObject.setParameter("name", name);
        queryObject.setParameter("author", author);

        List<Book> results = queryObject.getResultList();
        if (results == null || results.size() == 0){
            createTestBooks();
        }
        return queryObject.getResultList();
    }

    @Transactional(readOnly=true)
    public void createBook(String name, String category, String author, double price) {

        Book book = new Book();
        book.setName(name);
        book.setCategory(category);
        book.setAuthor(author);
        book.setPrice(price);
        em.persist(book);
    }
}

Flow Definition file

The flow definition file is given below and the flow is quite simple. The application will display a main page ‘bookPage’ that displays a form for creating a new book. In the same page, a separate section is available that displays the list of available books by fetching them from the database.

<?xml version="1.0" encoding="UTF-8"?>
<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">

    <var name="bookSearchCriteria" class="net.javabeat.spring.webflow.jsf.book.BookSearchCriteria" />

	<view-state id="bookMain">
		<on-render>
			<evaluate expression="bookService.findAllBooks()" result="viewScope.allBooks" result-type="dataModel" />
		</on-render>
        <transition on="addBooks" to="bookAdd">
        </transition>
    </view-state>

    <view-state id="bookAdd">
		<on-render>
			<evaluate expression="bookService.createBook(bookSearchCriteria.name, bookSearchCriteria.category,
            bookSearchCriteria.author, bookSearchCriteria.price)"/>
		</on-render>
    </view-state>

</flow>

When the user tries to create a book, then the state transition happens and the control gets transferred to the state definition ‘bookAdd’ and finally the service ‘createBook’ is called for creating a book. Also when the page gets loaded, we call the service findAllBooks() that fetches all book objects from the database for display. Running the application will display an interface similar to the following

Book Management Page

Conclusion

This article provided three sample applications that illustrated the techniques on making up an application that makes use of Spring Web Flow and JSF technologies. The first sample application provided a basic startup in illustrating the various pieces of artifacts required for supporting the integration. The second application illustrated the usage of flow variables, flow transitions by providing an employee search application. The final sample application explained the process of integration with the database by providing various configurations specific to JPA and Entities.

Comments

comments

About Krishna Srinivasan

He is Founder and Chief Editor of JavaBeat. He has more than 8+ years of experience on developing Web applications. He writes about Spring, DOJO, JSF, Hibernate and many other emerging technologies in this blog.

Comments

  1. Hi , hope you will be fine. i am passing parameter like this

    and i am trying to get it in manged bean like
    FacesContext fc = FacesContext.getCurrentInstance();
    String nameofFile1 =fc.getExternalContext().getRequestParameterMap().get(“photo_id”);
    ExternalContext externalContext = FlowFacesContext.getCurrentInstance().getExternalContext();
    String parameter =externalContext.getRequestParameterMap().get(“photo_id”);
    but in both cases it returns null.I have spring integration .this is very urgent for me . can you help me to “how to get parameter ” in manged bean .i will be thankfull to you. saqib mehmood

  2. I have one doubt when integrating Spring webflow with JSF, Can we call JSF actions like the below:

    JSF Action : (Sample.xhtml)

    It call the method login and returns message “success” (or) “failure”
    based on the controller return method i am writing transitions in webflow like below.

    Webflow:

    The above code is working fine, but is that feasible way?
    or any wrong?

    Please suggest…..

Speak Your Mind

*