Spring Mvc And Hibernate Tutorial Without Xml Configuration
In this tutorial, we will learn how to create a web application using Spring MVC and Hibernate ORM framework without xml configuration. To integrate Hibernate with Spring MVC application. We can use the LocalSessionFactoryBean
class, which set up a shared SessionFactory
object within a Spring application context. This SessionFactory
object can be passed to DAO classes via dependencies injection.
We will use in this tutorial these technologies and tools:
- Spring 4.3.7.RELEASE
- Hibernate Validator 5.4.1.Final
- Hibernate ORM 5.2.10.Final
- C3P0 0.9.5.2
- JavaSE 1.8
- Eclipse Neon.3
- Maven 3.3.9
- MySQL Server 5.7.12
- Apache Tomcat 7.0.47
Project structure
This is the web project structure build using Maven.
Maven dependencies:
In pom.xml
file of your maven project, add the dependencies below.
<?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 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.elgarnaoui</groupId>
<artifactId>tutorial</artifactId>
<name>SpringTuto</name>
<version>1.0.0-BUILD-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<java-version>1.8</java-version>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<dependencies>
<!-- Spring MVC Dependency -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- Spring ORM -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- Mysql Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
<!-- Hibernate ORM -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.10.Final</version>
</dependency>
<!-- Hibernate-C3P0 Integration -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>5.2.10.Final</version>
</dependency>
<!-- c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!-- Hibernate Validator -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.1.Final</version>
</dependency>
<!-- JSTL Dependency -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>javax.servlet.jsp.jstl-api</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<!-- Servlet Dependency -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- JSP Dependency -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!-- Embedded Apache Tomcat required for testing war -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
Spring configuration:
Create a web @Configuration
class annotated with @EnableWebMvc
and @ComponentScan
as follows.
Then, We will override the getValidator()
method of WebMvcConfigurerAdapter
to set the custom error messages for User
form.
WebConfig.java
package com.elgarnaoui.tutorial;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
/**
* @author elgarnaoui.com
*/
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.elgarnaoui"})
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setViewClass(JstlView.class);
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource source = new ResourceBundleMessageSource();
source.setBasename("messages");
return source;
}
@Override
public Validator getValidator() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setValidationMessageSource(messageSource());
return validator;
}
}
Create another @Configuration
class to configure Hibernate in Spring MVC application.
Then, annotate this class with @EnableTransactionManagement
annotation to enable the transaction management.
AppConfig.java
package com.elgarnaoui.tutorial;
import java.util.Properties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.elgarnaoui.tutorial.model.User;
import static org.hibernate.cfg.Environment.*;
/**
* @author elgarnaoui.com
*/
@Configuration
@PropertySource("classpath:database.properties")
@EnableTransactionManagement
@ComponentScans(value = @ComponentScan("com.elgarnaoui"))
public class AppConfig {
@Autowired
private Environment env;
@Bean
public LocalSessionFactoryBean getSessionFactory() {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
Properties props = new Properties();
// Setting JDBC properties
props.put(DRIVER, env.getProperty("mysql.driver"));
props.put(URL, env.getProperty("mysql.url"));
props.put(USER, env.getProperty("mysql.user"));
props.put(PASS, env.getProperty("mysql.password"));
//Hibernate properties
props.put(SHOW_SQL, env.getProperty("hibernate.show_sql"));
props.put(HBM2DDL_AUTO, env.getProperty("hibernate.hbm2ddl.auto"));
// Setting C3P0 properties
props.put(C3P0_MIN_SIZE,
env.getProperty("hibernate.c3p0.min_size"));
props.put(C3P0_MAX_SIZE,
env.getProperty("hibernate.c3p0.max_size"));
props.put(C3P0_ACQUIRE_INCREMENT,
env.getProperty("hibernate.c3p0.acquire_increment"));
props.put(C3P0_TIMEOUT,
env.getProperty("hibernate.c3p0.timeout"));
props.put(C3P0_MAX_STATEMENTS,
env.getProperty("hibernate.c3p0.max_statements"));
factoryBean.setHibernateProperties(props);
factoryBean.setAnnotatedClasses(User.class);
return factoryBean;
}
@Bean
public HibernateTransactionManager getTransactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(getSessionFactory().getObject());
return transactionManager;
}
}
As you can see, we are using the @PropertySource
annotation to read the JDBC, Hibernate and C3P0 properties. So we need to create a database.properties
file under src/main/resources
folder as follows.
database.properties
# MySQL properties
mysql.driver=com.mysql.cj.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/elgarnaoui
mysql.user=root
mysql.password=admin
# Hibernate properties
hibernate.show_sql=true
hibernate.hbm2ddl.auto=update
#C3P0 properties
hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.acquire_increment=1
hibernate.c3p0.timeout=1800
hibernate.c3p0.max_statements=150
Servlet container initialization:
Create a container initializer class by extending the AbstractAnnotationConfigDispatcherServletInitializer
class as follows.
MyWebAppInitializer.java
package com.elgarnaoui.tutorial;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
* @author elgarnaoui.com
*/
public class MyWebAppInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
The AbstractAnnotationConfigDispatcherServletInitializer
class, implements the WebApplicationInitializer
, is implemented in Servlet 3.0+ environments in order to configure the ServletContext
programmatically.
Entities class:
Create a @Entity
class, Then we will annotate those fields names with Hibernate Validator constraint and JPA annotations.
Also, we will use this entity class for mapping the database table with User
. And we will use it for binding from data to the model using @ModelAttribute
annotation in controller’s handler method.
User.java
package com.elgarnaoui.tutorial.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.Email;
@Entity
@Table(name = "USER")
public class User {
@Id
@GeneratedValue
@Column(name = "UID")
private Long id;
@Column(name = "NAME")
@Size(max = 20, min = 3, message = "{user.name.invalid}")
private String name;
@Column(name = "EMAIL", unique = true)
@Email(message = "{user.email.invalid}")
private String email;
public User() {
super();
// TODO Auto-generated constructor stub
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
In this example, we are using the Hibernate Validator constraints annotations for validation of User
form.
To override the default error messages, provided by Hibernate Validator framework, create messages.properties
file under src/main/resources
folder.
messages.properties
user.name.invalid=Name entered is invalid. It must be between {2} and {1} characters.
user.email.invalid=Invalid email! Please enter valid email.
Data Access Object (DAO) class
Create @Repository
classes under com.elgarnaoui.tutorial.dao
package as follows.
UserDao.java
package com.elgarnaoui.tutorial.dao;
import java.util.List;
import com.elgarnaoui.tutorial.model.User;
public interface UserDao {
void save(User user);
List<User> list();
}
UserDaoImpl.java
package com.elgarnaoui.tutorial.dao;
import java.util.List;
import javax.persistence.TypedQuery;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.elgarnaoui.tutorial.model.User;
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
private SessionFactory sessionFactory;
@Override
public void save(User user) {
sessionFactory.getCurrentSession().save(user);
}
@Override
public List<User> list() {
@SuppressWarnings("unchecked")
TypedQuery<User> query = sessionFactory.getCurrentSession().createQuery("from User");
return query.getResultList();
}
}
Service class
Create @Service
classes under com.elgarnaoui.tutorial.service
package as follows.
UserService.java
package com.elgarnaoui.tutorial.service;
import java.util.List;
import com.elgarnaoui.tutorial.model.User;
public interface UserService {
void save(User user);
List<User> list();
}
UserServiceImpl.java
package com.elgarnaoui.tutorial.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.elgarnaoui.tutorial.dao.UserDao;
import com.elgarnaoui.tutorial.model.User;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Transactional
public void save(User user) {
userDao.save(user);
}
@Transactional(readOnly = true)
public List<User> list() {
return userDao.list();
}
}
Controller class:
Create a controller class to handle the user form data as follows.
UserController.java
package com.elgarnaoui.tutorial.controller;
import java.util.Locale;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import com.elgarnaoui.tutorial.model.User;
import com.elgarnaoui.tutorial.service.UserService;
/**
* @author elgarnaoui.com
*/
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/")
public String userForm(Locale locale, Model model) {
model.addAttribute("user", new User());
model.addAttribute("users", userService.list());
return "user/";
}
@PostMapping("/saveUser")
public String saveUser(@ModelAttribute("user") @Valid User user,
BindingResult result, Model model) {
if (result.hasErrors()) {
model.addAttribute("users", userService.list());
return "user/";
}
userService.save(user);
return "redirect://";
}
}
JSP View
Create user.jsp
file under src\main\webapp\WEB-INF\views
folder to take input and display the user details.
user.jsp
<%@ page language="java" contentType="text/html;
charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>ELGARNAOUI.COM</title>
<style type="text/css">
fieldset {
border: 1px solid #dedede;
}
legend {
font-size: 20px;
text-transform: uppercase;
}
.error {
color: red;
}
.resltTable {
width: 98%;
border-collapse: collapse;
border-spacing: 0px;
}
.resltTable td, .resltTable th {
border: 1px solid #565454;
}
</style>
</head>
<body>
<fieldset style="width: 40%">
<legend>User From</legend>
<form:form action="saveUser" method="post" modelAttribute="user">
<table>
<tr>
<th>Name :</th>
<td><form:input path="name" /> <form:errors path="name"
cssClass="error" /></td>
</tr>
<tr>
<th>Email :</th>
<td><form:input path="email" /> <form:errors path="email"
cssClass="error" /></td>
</tr>
<tr>
<td colspan="2"><button type="submit">Submit</button></td>
</tr>
</table>
</form:form>
</fieldset>
<br>
<br>
<fieldset style="width: 40%">
<legend>Users List</legend>
<table class="resltTable">
<tr>
<th>Name</th>
<th>Email</th>
</tr>
<c:forEach items="${users}" var="user">
<tr>
<td>${user.name}</td>
<td>${user.email}</td>
</tr>
</c:forEach>
</table>
</fieldset>
</body>
</html>
The <form:errors>
is used to display the error messages and the path
attribute show the field name of model class for which display the error message.
Build + Deploy + Run application:
Use this maven commands to build, deploy and run Tomcat server.
mvn clean install (This command triggers war packaging)
mvn tomcat7:run (This command run embedded tomcat and deploy war file automatically)
open the browser and type this URLs in the browser’s address bar to open the user input from.
http://localhost:8080/tutorial/
You will see the user details on successful submission of form data as follows.
Make contact with us if you have any requests or issues. To support us share this post with your friends on social media below đŸ™‚