Spring Hibernate JPA Configuration Example

In this example, we will learn to configure Spring MVC and Hibernate with JPA along with few other things e.g. validation and custom property editors. I have been asked quite enough times to write this tutorial in past, so here it is. Feel free to post your doubts, comments and suggestions. If you want to learn about using hibernate’s session factory then you may want to read Spring and hibernate integration tutorial.

Table of Contents

1) Application Overview
2) Spring's application context configuration
3) DAO classes
4) Maven dependencies
5) Other application files

1) Application Overview

This demo application is an employee management screen which lists down all employee records in database, and a form which you can use to add more employees. There is validation functionality added to form, so if you try to add empty form then you will get validation errors. To store the record in database, Hibernate JPA implementation is used. Front end is implemented using Spring MVC.

application-screen-shot-hibernate-jpa

The all files involved in this application are as below:

application-folder-structure-hibernate-jpa

2) Spring’s application context configuration

This file is center piece of application and require your most attention.

spring-servlet.xml

<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:tx="http://www.springframework.org/schema/tx"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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/tx/ http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
	http://www.springframework.org/schema/mvc/ http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
 
 	<!-- It register the beans in context and scan the annotations inside beans and activate them -->
    <context:component-scan base-package="com.howtodoinjava.demo" />
    
    <!-- This allow for dispatching requests to Controllers -->
    <mvc:annotation-driven />
     
    <!-- This helps in mapping the logical view names to directly view files under a certain pre-configured directory -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>
     
    <!-- This resolves messages from resource bundles for different locales --> 
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename" value="messages" />
    </bean>
    
    <!-- To validate the posted add employee form -->
    <bean id="employeeValidator" class="com.howtodoinjava.demo.validator.EmployeeValidator" />
    
    <!-- This produces a container-managed EntityManagerFactory; 
    	 rather than application-managed EntityManagerFactory as in case of LocalEntityManagerFactoryBean-->
    <bean id="entityManagerFactoryBean" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
      <property name="dataSource" ref="dataSource" />
      <!-- This makes /META-INF/persistence.xml is no longer necessary -->
      <property name="packagesToScan" value="com.howtodoinjava.demo.model" />
      <!-- JpaVendorAdapter implementation for Hibernate EntityManager.
      	   Exposes Hibernate's persistence provider and EntityManager extension interface -->
      <property name="jpaVendorAdapter">
         <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
      </property>
      <property name="jpaProperties">
         <props>
            <prop key="hibernate.hbm2ddl.auto">validate</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
         </props>
      </property>
   </bean>
 
   <!-- Simple implementation of the standard JDBC DataSource interface, 
   		configuring the plain old JDBC DriverManager via bean properties -->
   <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <property name="driverClassName" value="com.mysql.jdbc.Driver" />
      <property name="url" value="jdbc:mysql://localhost:3306/test" />
      <property name="username" value="root" />
      <property name="password" value="password" />
   </bean>
    
    <!-- This transaction manager is appropriate for applications that use a single JPA EntityManagerFactory for transactional data access. 
    	JTA (usually through JtaTransactionManager) is necessary for accessing multiple transactional resources within the same transaction. -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
      <property name="entityManagerFactory" ref="entityManagerFactoryBean" />
   </bean>
   
   <!-- responsible for registering the necessary Spring components that power annotation-driven transaction management; 
        such as when @Transactional methods are invoked -->
   <tx:annotation-driven />
   
</beans>

Let’s note down few important points.

  • context:component-scan : register the beans in context; and it also scans the annotations inside beans and activate them. So context:component-scan does what context:annotation-config does, but additionally it scan the packages and register the beans in application context.

    Read More : context:annotation-config vs context:component-scan

  • mvc:annotation-driven : tag essentially sets you your Spring context to allow for dispatching requests with annotated controller methods using annotations such as @RequestMapping, @ExceptionHandler, and others.

    Read More : Spring MVC Config

  • InternalResourceViewResolver : view template decides that which view should be rendered based on returned logical view name by mapping the logical view names to directly view files under a certain pre-configured directory.

    Read More : InternalResourceViewResolver Configuration Example

  • entityManagerFactoryBean : LocalEntityManagerFactoryBean produces an application-managed EntityManagerFactory whereas LocalContainerEntityManagerFactoryBean produces a container-managed EntityManagerFactory. It supports links to an existing JDBC DataSource, supports both local and global transactions.
  • JpaTransactionManager : This transaction manager is appropriate for applications that use a single JPA EntityManagerFactory for transactional data access. JTA (usually through JtaTransactionManager) is necessary for accessing multiple transactional resources within the same transaction. Note that you need to configure your JPA provider accordingly in order to make it participate in JTA transactions. Of course, JtaTransactionManager does require a full JTA-supporting application server, rather than a vanilla servlet engine like Tomcat.
  • tx:annotation-driven : enable the configuration of transactional behavior based on annotations e.g. @Transactional. The @EnableTransactionManagement annotation provides equivalent support if you are using Java based configuration. To do this. simply add the annotation to a @Configuration class.

3) DAO classes

Next important classes are DAO classes which use the entity manager to perform CRUD operations using hibernate entities, and specifying methods which support transactions through @Transactional annotation. In our case, we have applied @Transactional annotation at class level, making all public methods transactional.

EmployeeDAO.java

public interface EmployeeDAO 
{
	public List<EmployeeEntity> getAllEmployees();
	public List<DepartmentEntity> getAllDepartments();
	public void addEmployee(EmployeeEntity employee);
}

EmployeeDAOImpl.java

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.howtodoinjava.demo.model.DepartmentEntity;
import com.howtodoinjava.demo.model.EmployeeEntity;

@Repository
@Transactional
public class EmployeeDAOImpl implements EmployeeDAO 
{
	@PersistenceContext
	private EntityManager manager;
	
	public List<EmployeeEntity> getAllEmployees() 
	{
		List<EmployeeEntity> employees = manager.createQuery("Select a From EmployeeEntity a", EmployeeEntity.class).getResultList();
        return employees;
	}
	
	public List<DepartmentEntity> getAllDepartments() 
	{
		List<DepartmentEntity> depts = manager.createQuery("Select a From DepartmentEntity a", DepartmentEntity.class).getResultList();
        return depts;
	}
	
	public DepartmentEntity getDepartmentById(Integer id) 
	{
        return manager.find(DepartmentEntity.class, id);
	}
	
	public void addEmployee(EmployeeEntity employee) 
	{
		//Use null checks and handle them
		employee.setDepartment(getDepartmentById(employee.getDepartment().getId()));
		manager.persist(employee);
	}
}
When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ if you need to annotate non-public methods.

@PersistenceContext expresses a dependency on a container-managed EntityManager and its associated persistence context. @Repository is usually applied on DAO layer.

Read More : @Component, @Repository, @Service and @Controller Annotations

4) Maven dependencies

The last thing, you should be interested in this example is maven dependencies for spring, hibernate and JPA extension. Here are all dependencies for this example.

<dependencies>
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.12</version>
		<scope>test</scope>
	</dependency>

	<!-- Spring MVC support -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-webmvc</artifactId>
		<version>4.1.4.RELEASE</version>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-web</artifactId>
		<version>4.1.4.RELEASE</version>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-orm</artifactId>
		<version>4.1.4.RELEASE</version>
	</dependency>

	<!-- Tag libs support for view layer -->
	<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>jstl</artifactId>
		<version>1.2</version>
		<scope>runtime</scope>
	</dependency>
	<dependency>
		<groupId>taglibs</groupId>
		<artifactId>standard</artifactId>
		<version>1.1.2</version>
		<scope>runtime</scope>
	</dependency>
	
	<dependency>
		<groupId>javax.validation</groupId>
		<artifactId>validation-api</artifactId>
		<version>1.0.0.GA</version>
	</dependency>
	
	<dependency>
		<groupId>org.hibernate</groupId>
		<artifactId>hibernate-core</artifactId>
		<version>4.0.1.Final</version>
	</dependency>
	<dependency>
		<groupId>org.hibernate</groupId>
		<artifactId>hibernate-validator</artifactId>
		<version>4.2.0.Final</version>
	</dependency>
	<dependency>
		<groupId>org.hibernate.common</groupId>
		<artifactId>hibernate-commons-annotations</artifactId>
		<version>4.0.1.Final</version>
		<classifier>tests</classifier>
	</dependency>
	
	<dependency>
		<groupId>org.hibernate.javax.persistence</groupId>
		<artifactId>hibernate-jpa-2.0-api</artifactId>
		<version>1.0.1.Final</version>
	</dependency>
	<dependency>
		<groupId>org.hibernate</groupId>
		<artifactId>hibernate-entitymanager</artifactId>
		<version>4.0.1.Final</version>
	</dependency>
	<dependency>
		<groupId>javax.validation</groupId>
		<artifactId>validation-api</artifactId>
		<version>1.0.0.GA</version>
	</dependency>
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-api</artifactId>
		<version>1.6.4</version>
	</dependency>
	<dependency>
		<groupId>org.jboss.logging</groupId>
		<artifactId>jboss-logging</artifactId>
		<version>3.1.0.CR2</version>
	</dependency>
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-log4j12</artifactId>
		<version>1.6.4</version>
	</dependency>
	
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>5.1.10</version>
	</dependency>

</dependencies>

5) Other application files

Now list down, other files also which are used in this example.

web.xml

<web-app id="WebApp_ID" 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 
	https://www.oracle.com/java/technologies/;
	
	<display-name>Spring Hibernate JPA Hello World Application</display-name>
	
	<!-- Configuration file for the root application context -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring-servlet.xml
        </param-value>
    </context-param>
	
	<!-- Configuration for the DispatcherServlet -->
	<servlet>
		<servlet-name>spring</servlet-name>
			<servlet-class>
				org.springframework.web.servlet.DispatcherServlet
			</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>spring</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

</web-app>

listEmployeeView.jsp

<%@ page contentType="text/html;charset=UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<html>
<head>
	<title>Employee Management</title>
	<style>
	.error 
	{
		color: #ff0000;
		font-weight: bold;
	}
	#listOfEmployees tr:first-child{
		font-weight: bold;
	}
	</style>
</head>

<body>
	
	<h2><spring:message code="lbl.page.list" text="lbl.page.list" /></h2>
	<br/>
	
	<table id="listOfEmployees" border="1">
	<tr>
	    <td>ID</td>
	    <td>First Name</td>
	    <td>Last Name</td>
	    <td>Email</td>
	    <td>Department</td>
	  </tr>
	<c:forEach items="${allEmployees}" var="employee">    
	  <tr>
	    <td>${employee.id}</td>
	    <td>${employee.firstName}</td>
	    <td>${employee.lastName}</td>
	    <td>${employee.email}</td>
	    <td>${employee.department.name}</td>
	  </tr>
	</c:forEach>
	</table>

	<h2><spring:message code="lbl.page" text="Add New Employee" /></h2>
	<br/>
	<form:form method="post" modelAttribute="employee">
		<table>
			<tr>
				<td><spring:message code="lbl.firstName" text="First Name" /></td>
				<td><form:input path="firstName" /></td>
				<td><form:errors path="firstName" cssClass="error" /></td>
			</tr>
			<tr>
				<td><spring:message code="lbl.lastName" text="Last Name" /></td>
				<td><form:input path="lastName" /></td>
				<td><form:errors path="lastName" cssClass="error" /></td>
			</tr>
			<tr>
				<td><spring:message code="lbl.email" text="Email Id" /></td>
				<td><form:input path="email" /></td>
				<td><form:errors path="email" cssClass="error" /></td>
			</tr>
			<tr>
				<td><spring:message code="lbl.department" text="Department" /></td>
				<td><form:select path="department" items="${allDepartments}" itemValue="id" itemLabel="name" /></td>
				<td><form:errors path="department" cssClass="error" /></td>
			</tr>
			<tr>
				<td colspan="3"><input type="submit" value="Add Employee"/></td>
			</tr>
		</table>
	</form:form>
</body>
</html>


messages.properties

lbl.page=Add New Employee
lbl.page.list=List of Employees
lbl.firstName=First Name
lbl.lastName=Last Name
lbl.email=Email Id

error.firstName=First Name can not be blank
error.lastName=Last Name can not be blank
error.email=Email Id can not be blank

EmployeeValidator.java

@Component
public class EmployeeValidator implements Validator {

	public boolean supports(Class clazz) {
		return EmployeeEntity.class.isAssignableFrom(clazz);
	}

	public void validate(Object target, Errors errors) 
	{
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "error.firstName", "First name is required.");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "lastName", "error.lastName", "Last name is required.");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "email", "error.email", "Email is required.");
	}
}

EmployeeManager.java

public interface EmployeeManager 
{
	public List<EmployeeEntity> getAllEmployees();
	public List<DepartmentEntity> getAllDepartments();
	public void addEmployee(EmployeeEntity employee);
}

EmployeeManagerImpl.java

@Service
public class EmployeeManagerImpl implements EmployeeManager {

	@Autowired
	EmployeeDAO dao;
	
	public List<EmployeeEntity> getAllEmployees() {
		return dao.getAllEmployees();
	}

	public List<DepartmentEntity> getAllDepartments() {
		return dao.getAllDepartments();
	}

	public void addEmployee(EmployeeEntity employee) {
		dao.addEmployee(employee);
	}
}


EmployeeEntity.java

@Entity
@Table (name="employee")
public class EmployeeEntity implements Serializable 
{
	private static final long serialVersionUID = 1L;

	@Id
    @GeneratedValue
	private Integer id;
	
	@NotEmpty
	private String firstName;
	private String lastName;
	private String email;
	
	@NotNull
	@ManyToOne
	private DepartmentEntity department;
	
	public EmployeeEntity() {}
	 
    public EmployeeEntity(String name, DepartmentEntity department) {
        this.firstName = name;
        this.department = department;
    }
     
    public EmployeeEntity(String name) {
        this.firstName = name;
    }

	//Setters and Getters

	@Override
	public String toString() {
		return "EmployeeVO [id=" + id + ", firstName=" + firstName
				+ ", lastName=" + lastName + ", email=" + email
				+ ", department=" + department + "]";
	}
}

DepartmentEntity.java

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

	private static final long serialVersionUID = 1L;
	
	@Id
	@GeneratedValue
	private Integer id;
	private String name;
	
	public DepartmentEntity(){
	}

	public DepartmentEntity(Integer id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	
	@OneToMany(mappedBy="department",cascade=CascadeType.PERSIST)
    private List<EmployeeEntity> employees = new ArrayList<EmployeeEntity>();
	
	//Setters and Getters
	
	@Override
	public String toString() {
		return "DepartmentVO [id=" + id + ", name=" + name + "]";
	}
}

EmployeeController.java

@Controller
@RequestMapping("/employee-module")
@SessionAttributes("employee")
public class EmployeeController
{
	@Autowired
	EmployeeManager manager;

	private Validator validator;

	//Bind custom validator for submitted form
	public EmployeeController()
	{
		ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
		validator = validatorFactory.getValidator();
	}
	
	/**
	 * Bind DepartmentEditor to DepartmentEntity; Look at JSP file for clearer picture
	 * */
	@InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(DepartmentEntity.class, new DepartmentEditor());
    }
	/**
	 * Bind all departments
	 * */
	@ModelAttribute("allDepartments")
    public List<DepartmentEntity> populateDepartments() 
    {
        List<DepartmentEntity> departments = manager.getAllDepartments();
        return departments;
    }
	
	/**
	 * Bind all employees list
	 * */
	@ModelAttribute("allEmployees")
    public List<EmployeeEntity> populateEmployees() 
    {
        List<EmployeeEntity> employees = manager.getAllEmployees();
        return employees;
    }
	
	/**
	 * Method will be called in initial page load at GET /employee-module
	 * */
	@RequestMapping(method = RequestMethod.GET)
	public String setupForm(Model model) 
	{
		EmployeeEntity employeeVO = new EmployeeEntity();
		model.addAttribute("employee", employeeVO);
		return "listEmployeeView";
	}

	/**
	 * Method will be called on submitting add employee form POST /employee-module
	 * */
	@RequestMapping(method = RequestMethod.POST)
	public String submitForm(@ModelAttribute("employee") EmployeeEntity employeeVO,
			BindingResult result, SessionStatus status) {

		Set<ConstraintViolation<EmployeeEntity>> violations = validator.validate(employeeVO);
		
		for (ConstraintViolation<EmployeeEntity> violation : violations) 
		{
            String propertyPath = violation.getPropertyPath().toString();
            String message = violation.getMessage();
            // Add JSR-303 errors to BindingResult
            // This allows Spring to display them in view via a FieldError
            result.addError(new FieldError("employee", propertyPath, "Invalid "+ propertyPath + "(" + message + ")"));
        }

		if (result.hasErrors()) {
			return "listEmployeeView";
		}
		// Store the employee information in database
		manager.addEmployee(employeeVO);
		
		// Mark Session Complete and redirect to URL so that page refresh do not re-submit the form
		status.setComplete();
		return "redirect:employee-module";
	}
}

Please feel free to comment with your questions and suggestions.

Happy Learning !!

Comments

Subscribe
Notify of
guest
39 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode