You are on page 1of 19

A tutorial for Spring,Hibernate,JSF,Richfaces v1.

MOTIVATION

In this basic tutorial, I tried to show how spring, hibernate, jsf, richfaces can be used together
as a working example. Sources can be downloaded at the end of page.
I am working about 3 days to configure Spring, Hibernate, JSF, Facelets, Richfaces all in one
as a maven project with maven jetty plugin. Now it is time to share this configuration as a
working example. First, lets look at root pom.xml.

ROOT

• pom.xml

<?xml version="1.0" encoding="UTF-8"?>


<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/maven-
v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>blogspot.sezera.exampleproject</groupId>
<artifactId>exampleproject</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>exampleproject</name>
<url>http://maven.apache.org</url>
<dependencies/>
<modules>
<module>exampleproject.core</module>
<module>exampleproject.web</module>
</modules>
</project>

We have 2 project. One of them is core and the other is web. Nothing is interesting here.

Core Project

• pom.xml

<?xml version="1.0" encoding="UTF-8"?>


<project>
<parent>
<artifactId>exampleproject</artifactId>
<groupId>blogspot.sezera.exampleproject</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>blogspot.sezera.exampleproject.core</groupId>
<artifactId>exampleproject.core</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>Exampleproject Core</name>
<url>http://maven.apache.org</url>
<build>
<resources>
<resource>
<directory>target/generated-resources</directory>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.4</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.2.6.ga</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.3.1.GA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-tools</artifactId>
<version>3.2.0.ga</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.0.5</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.4</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>maven2-repository.dev.java.net</id>
<name>Java.net Repository for Maven</name>
<url>http://download.java.net/maven/2</url>
<layout>default</layout>
</repository>
</repositories>
</project>
java.net repository needed for maven to download Richfaces jars. Other jars will be
downloaded from maven.org maven 2 repository.

• dao-context.xml

<?xml version="1.0" encoding="UTF-8"?>


<!-- DATASOURCE DEFINITON-->
<beans xmlns="http://www.springframework.org/schema/beans"
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-2.0.xsd">
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/exampleproject" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<!-- HIBERNATE CONFIGURATION -->
<bean id="sessionFactory"

class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>blogspot.sezera.exampleproject.domain.User</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.use_outer_join">true</prop>
<prop key="hibernate.max_fetch_depth">1</prop>
<prop key="hibernate.jdbc.batch_size">0</prop>
<prop
key="hibernate.default_schema">exampleproject</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
</beans>

blogspot.sezera.exampleproject.domain.User class is entity class and it will be persisted to


mysql database with hibernate. Because User class using EJB3 annotation , instead of xml
mapping files, Spring's AnnotationSessionFactoryBean is used for building Session Factory
bean. A datasource is defined as a property to sessionFactory bean.
User class is given as a parameter to annotatedClass list property. Here you must add your
annotated classes which will be persisted to database.
And another property is hibernateProperties which is actually arguments to hibernate. Here
"default schema" is defined as "exampleproject" and hibernate.hbm2ddl.auto set to "update".
It means hibernate will update database schema reading EJB3 annotated entity classes like
"User" class. There is no hbm.xml map files but its name stays same, actually everything done
with annotation. So at first, you need to create an empty database schema (create database
exampleproject) in mysql database and hibernate will take care of rest.

• User.java

package blogspot.sezera.exampleproject.domain;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="User")
public class User implements Serializable{

private Long id;

private String username;


private String password;

@Id
@GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}

public String getUsername() {


return username;
}

public void setUsername(String username) {


this.username = username;
}

public String getPassword() {


return password;
}

public void setPassword(String password) {


this.password = password;
}

User class is a basic entity with email, password fields and accessor methods. id attribute is
defined as unique identifier for User entity by @Id annotation. Here ids are generating and
managing by hibernate. Accessor for id is getId() method. @GeneratedValue annotation can
be used for defining id generation strategy but we leave it default here.

• main-context.xml

<?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:aop="http://www.springframework.org/schema/aop"
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.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<import resource="dao-Context.xml"/>

<!--SERVICE BEAN DEFINITIONS-->


<bean id="userService"
class="blogspot.sezera.exampleproject.service.impl.UserServiceImpl">
<constructor-arg ref="sessionFactory"></constructor-arg>
</bean>

<!--TRANSACTIAN MANAGEMENT-->
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:advice id="txAdvice" transaction-manager="txManager">


<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true" />
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*" />
</tx:attributes>
</tx:advice>

<!-- ensure that the above transactional advice runs for any execution
of an operation defined by the userManagementService interface -->
<aop:config>
<aop:pointcut id="managementServiceOperation"
expression="execution(*
blogspot.sezera.exampleproject.service.*.*(..))" />
<aop:advisor advice-ref="txAdvice"
pointcut-ref="managementServiceOperation" />
</aop:config>

</beans>

main-Context.xml corresponds to Spring's applications classic application-context.xml but we


moved entity definition, database and hibernate configurations to dao-Context.xml so we start
with importing it.
Every class in service layer has its own interface so UserService interface defined with single
createUser method. userService bean is defined with concrete UserServiceImpl class and
sessionFactory which is defined in dao-Context.xml before is injected with constructor
injection.
Hibernate needs transactions. Without transactions you can't write anything to database.
Thanks to aspects transaction behaviour of exampleproject defined easily. A transaction
manager bean is defined and sessionFactory instance is given via setter injection. Secondly an
advice is defined which says all methods starts with get(like getUserName ...) in a transaction
is readonly and other metods are in default transaction behaviour. Critical point is defining
where to apply advice in short pointcuts. With aspect expression we define pointcuts for every
class under blogspot.sezera.exampleproject.core.service package which is actually service
layer.

• UserService.java

package blogspot.sezera.exampleproject.service;
public interface UserService {
void createUser(String username,String password);
}

• UserServiceImpl.java

package blogspot.sezera.exampleproject.service.impl;

import org.hibernate.SessionFactory;

import blogspot.sezera.exampleproject.dao.GenericDaoImpl;
import blogspot.sezera.exampleproject.domain.User;
import blogspot.sezera.exampleproject.service.UserService;

public class UserServiceImpl implements UserService{

private SessionFactory m_sessionFactory;


private GenericDaoImpl<User,Long> userDao;

public UserServiceImpl(SessionFactory sessionFactory) {


m_sessionFactory = sessionFactory;
userDao = new GenericDaoImpl<User, Long>(m_sessionFactory){};
}

public void createUser(String username, String password) {


User user = null;
if(username!=null){
user = new User();
user.setUsername(username);
user.setPassword(password);
userDao.makePersistent(user);
}
}
}

Here Dao pattern is used with generics support. A GenericDaoImpl instance is created for
User entity and persisted with makePersistent method which is actually a single line:
getSession().saveOrUpdate(entity).

• GenericDao.java

package blogspot.sezera.exampleproject.dao;

import java.io.Serializable;

public interface GenericDao<T extends Serializable,ID extends Serializable>{


T makePersistent(T entity);
}

• GenericDaoImpl.java

package blogspot.sezera.exampleproject.dao;

import java.io.Serializable;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

public abstract class GenericDaoImpl<T extends Serializable,ID extends Serializable> implements


GenericDao<T,ID>{

private SessionFactory sessionFactory;

public GenericDaoImpl(SessionFactory sessionFactory) {


this.sessionFactory = sessionFactory;
}

public T makePersistent(T entity) {


getSession().saveOrUpdate(entity);
return entity;
}
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
}

Now we have everything in core side to create a User. So moving to web project.

Web project

• pom.xml

<?xml version="1.0"?>
<project>
<parent>
<artifactId>exampleproject</artifactId>
<groupId>blogspot.sezera.exampleproject</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>blogspot.sezera.exampleproject.web</groupId>
<artifactId>exampleproject.web</artifactId>
<packaging>war</packaging>
<name>exampleproject.web Maven Webapp</name>
<version>1.0-SNAPSHOT</version>
<url>http://maven.apache.org</url>
<build>
<finalName>exampleproject.web</finalName>
<!--MAVEN JETTY PLUGIN-->
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.10</version>
<configuration>
<scanIntervalSeconds>3</scanIntervalSeconds>
</configuration>

</plugin>
</plugins>

</build>
<dependencies>
<dependency>
<groupId>blogspot.sezera.exampleproject.core</groupId>
<artifactId>exampleproject.core</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>1.2_02</version>
</dependency>
<dependency>
<groupId>com.sun.facelets</groupId>
<artifactId>jsf-facelets</artifactId>
<version>1.1.11</version>
</dependency>
<dependency>
<groupId>javax.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>1.2-b19</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.richfaces.ui</groupId>
<artifactId>richfaces-ui</artifactId>
<version>3.1.0</version>
</dependency>

</dependencies>
<repositories>
<repository>
<id>repository.jboss.com</id>
<name>Jboss Repository for Maven</name>
<url>http://repository.jboss.com/maven2/</url>
<layout>default</layout>
</repository>
</repositories>
</project>

• UserController.java

package blogspot.sezera.exampleproject.controller;

import blogspot.sezera.exampleproject.service.UserService;

public class UserController {

private UserService service;


private String username;
private String password;

public UserController(){

}
public String getUsername() {
return username;
}

public void setUsername(String username) {


this.username = username;
}

public String getPassword() {


return password;
}
public void setPassword(String password) {
this.password = password;
}

public void setService(UserService service) {


this.service = service;
}

public void createUser(){


service.createUser(username, password);
}
public UserService getService() {
return service;
}
}

• EmailValidator.java

package blogspot.sezera.exampleproject.validator;

import java.util.ResourceBundle;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;

public class EmailValidator implements Validator{

public void validate(FacesContext arg0, UIComponent arg1, Object arg2)


throws ValidatorException {

String email = arg2.toString();


if(email.contains("@")==false){
//error message
ResourceBundle bundle =
ResourceBundle.getBundle("messages",arg0.getCurrentInstance().getViewRoot().getLocale());
FacesMessage msg = new FacesMessage(bundle.getString("emailNotValid"));
throw new ValidatorException(msg);
}

}
}

To validate user email address when creating user I have created a basic EmailValidator. It
validates if user email address contains "@". If not a ValidatorException is thrown.

• messages_en_US.properties

emailNotValid=E-mail is not valid

• newUser.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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<head>
<title>New User</title>
</head>
<body>
<f:view>
<h:form>
<table>
<tr>
<td><h:outputLabel value="UserName "></h:outputLabel></td>
<td><h:inputText id="email" value="#{userController.username}">
<f:validator validatorId="emailValidator" />
<a4j:support event="onkeyup" requestDelay="300"
reRender="output"/>
</h:inputText>
</td>
<td>
<h:outputLabel id="output">
<h:message for="email"/>
</h:outputLabel>
</td>
</tr>
<tr>
<td><h:outputLabel value="Password"></h:outputLabel></td>
<td><h:inputSecret
value="#{userController.password}"></h:inputSecret><br/></td>
</tr>
</table>
<h:commandButton value="Create User"
action="#{userController.createUser}"></h:commandButton>
</h:form>
</f:view>
</body>
</html>

When user started to write his email address, page send an AJAX request to server in every
300 second and EmailValidator executes. If there is an error in user email, page renders an
error message right of user email input text area.

• web.xml

<?xml version="1.0"?>
<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>ExampleProject Web</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/main-Context.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>org.richfaces.SKIN</param-name>
<param-value>classic</param-value>
</context-param>
<context-param>
<param-name>org.ajax4jsf.VIEW_HANDLERS</param-name>
<param-value>com.sun.facelets.FaceletViewHandler</param-value>
</context-param>
<filter>
<display-name>RichFaces Filter</display-name>
<filter-name>richfaces</filter-name>
<filter-class>org.ajax4jsf.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>richfaces</filter-name>
<servlet-name>Faces Servlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.web.util.IntrospectorCleanupListener
</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
<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>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
</web-app>

• faces-config.xml

<?xml version="1.0" encoding="UTF-8"?>

<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
version="1.2">

<application>

<resource-bundle>
<base-name>messages</base-name>
<var>msgs</var>
</resource-bundle>

<locale-config>
<default-locale>en_US</default-locale>
</locale-config>

<variable-resolver>
org.springframework.web.jsf.DelegatingVariableResolver
</variable-resolver>

</application>

<validator>
<validator-id>emailValidator</validator-id>
<validator-class>
blogspot.sezera.exampleproject.validator.EmailValidator
</validator-class>
</validator>
<managed-bean>
<managed-bean-name>userController</managed-bean-name>
<managed-bean-class>
blogspot.sezera.exampleproject.controller.UserController
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>service</property-name>
<value>#{userService}</value>
</managed-property>
</managed-bean>

</faces-config>

HOW TO RUN EXAMPLEPROJECT

• download source codes without jars.


• mvn clean install under root directory
• create an empty database named "exampleproject" in mysql
• Under exampleproject.web execute: mvn jetty:run
• Go to <http://localhost:8080/exampleproject.web/newUser.faces>

NOTE:Attention to url extension is .faces NOT .xhtml. It must be same as url-pattern of Faces
Servlet Mapping in web.xml.
SCREENSHOT
DOWNLOAD

Source code <http://rapidshare.com/files/129333598/exampleproject.rar>

REFERENCES

• Spring - JSF integration


<http://static.springframework.org/spring/docs/2.5.x/reference/web-integration.html#jsf-
delegatingvariableresolver>
• Hibernate Reference
<http://www.hibernate.org/hib_docs/annotations/reference/en/html_single/#d0e2123>
• a4j:support
<http://www.jboss.org/file-
access/default/members/jbossrichfaces/freezone/docs/devguide/en/html/support.html>

AUTHOR

Sezer Akar
Blog <http://sezera.blogspot.com>