Integrating Spring Web Flow with JSF

November 11, 2010

Java Server Faces (JSF)

«»

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.

Download Source Code

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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<?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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?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.

email

«»

Comments

comments

,