- Details
- Written by Nam Ha Minh
- Last Updated on 21 June 2019   |   Print Email
In this second part of the Spring and Hibernate integration tutorial series, we demonstrate how to develop a Spring MVC - Hibernate application without using any XML configuration. The following configuration approaches are used for this tutorial’s demo application:
NOTE:- This is an update and expansion of Part 1, so that we don’t repeat the Project Setup (including database creation and Maven configuration).
- Using either XML or Java-based configuration is just a matter of choice. Using which is depending on your taste and situation. We never intend which is better or preferred.
The following technologies and pieces of software are used throughout this tutorial (of course you can use newer versions):
Let’s go!
1. Bootstrapping Spring Dispatcher Servlet
Instead of using XML in
web.xml to register the Spring Dispatcher Servlet, we can move the bootstrap code into a Java class that implements the
ServletContainerInitializerinterface which is introduced from Servlet 3.0. Spring framework provides an implementation - the
SpringServletContainerInitializer class which delegates a Servlet context to any implementations of the
WebApplicationInitializer interface.Thus, let’s create
SpringWebAppInitializer class to put our bootstrap code like the following:
package net.codejava.spring.config;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
public class SpringWebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
appContext.register(ApplicationContextConfig.class);
ServletRegistration.Dynamic dispatcher = servletContext.addServlet(
"SpringDispatcher", new DispatcherServlet(appContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
Here, code in the
onStartup() method is invoked when the Servlet container initializes the application. This method creates Spring Dispatcher Servlet dynamically to handle all requests coming through the application (denoted by the mapping “/”). The Spring Dispatcher Servlet takes an
AnnotationConfigWebApplicationContext which is responsible for Spring-related initializations using annotations. The actual class that does the configurations is
ApplicationContextConfig, which is covered in section 4 below.
NOTE: The
spring-web-VERSION.jar must present on the classpath for this bootstrap mechanism takes effect.
2. Mapping Model Class using JPA Annotations
Instead of using Hibernate XML mapping for model class like
Part 1, we embed JPA annotations directly into the model class as follows (
User.java):
package net.codejava.spring.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "USERS")
public class User {
private int id;
private String username;
private String password;
private String email;
@Id
@GeneratedValue
@Column(name = "USER_ID")
public int getId() {
return id;
}
// other getters and setters are hidden for brevity
}
Note that if the attribute names of the model class are identical to column names in database, we don’t need to specify column mapping explicitly.
3. Extending DAO Classes
In
Part 1, the
UserDAO interface declares only one
list() method. Now we extend it for full CRUD operations. Hence, update the
UserDAO interface as the following code:
package net.codejava.spring.dao;
import java.util.List;
import net.codejava.spring.model.User;
public interface UserDAO {
public List<User> list();
public User get(int id);
public void saveOrUpdate(User user);
public void delete(int id);
}
Its implementation -
UserDAOImpl class is then updated as the following code:
package net.codejava.spring.dao;
import java.util.List;
import net.codejava.spring.model.User;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
@Repository
public class UserDAOImpl implements UserDAO {
@Autowired
private SessionFactory sessionFactory;
public UserDAOImpl() {
}
public UserDAOImpl(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
@Transactional
public List<User> list() {
@SuppressWarnings("unchecked")
List<User> listUser = (List<User>) sessionFactory.getCurrentSession()
.createCriteria(User.class)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
return listUser;
}
@Override
@Transactional
public void saveOrUpdate(User user) {
sessionFactory.getCurrentSession().saveOrUpdate(user);
}
@Override
@Transactional
public void delete(int id) {
User userToDelete = new User();
userToDelete.setId(id);
sessionFactory.getCurrentSession().delete(userToDelete);
}
@Override
@Transactional
public User get(int id) {
String hql = "from User where id=" + id;
Query query = sessionFactory.getCurrentSession().createQuery(hql);
@SuppressWarnings("unchecked")
List<User> listUser = (List<User>) query.list();
if (listUser != null && !listUser.isEmpty()) {
return listUser.get(0);
}
return null;
}
}
We’ll see how the
SessionFactory and
TransationManager are configured in the next section below.
4. Configuring Spring Application Context using Java-based Configuration
Now, we come to the most important and interesting part of the application, which configures beans definitions using Java code instead of XML. Create
ApplicationContextConfig class with the following Spring annotations:
@Configuration
@ComponentScan("net.codejava.spring")
@EnableTransactionManagement
public class ApplicationContextConfig {
// @Bean configurations go here...
}
The
@Configuration annotation is required for any Java-based configuration in Spring. The
@ComponentScan annotation tells Spring to scan the specified package for annotated classes (the
HomeController class in case of this tutorial). The
@EnableTransactionManager annotation enables Spring’s annotation-driven transaction management capability. Let’s see how each component is configured using Java code.
Configuring Spring MVC View Resolvers
The following method configures a view resolver that converts logical view names to actual JSP pages:
@Bean(name = "viewResolver")
public InternalResourceViewResolver getViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
Configuring DataSource Bean
The following method configures a
DataSource to be used with Hibernate’s
SessionFactory:
@Bean(name = "dataSource")
public DataSource getDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/usersdb");
dataSource.setUsername("root");
dataSource.setPassword("secret");
return dataSource;
}
NOTE:- We create a DataSource from Apache Commons DBCP for standard database connection pooling capability.
- Remember to change attributes of the DataSource according to your environment.
This data source will be injected to a Hibernate’s
SessionFactory bean as below.
Configuring SessionFactory Bean
The following method configures a
SessionFactory bean:
@Autowired
@Bean(name = "sessionFactory")
public SessionFactory getSessionFactory(DataSource dataSource) {
LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(dataSource);
sessionBuilder.addAnnotatedClasses(User.class);
return sessionBuilder.buildSessionFactory();
}
NOTE: For Java-based configuration, Spring provides the
LocalSessionFactoryBuilder that facilitates the creation of Hibernate’s
SessionFactory. For XML configuration, a
LocalSessionFactoryBean is used instead. Notice this statement tells Hibernate to load the User class into its mapping definitions:
sessionBuilder.addAnnotatedClasses(User.class);
If you want to add more classes:
sessionBuilder.addAnnotatedClasses(User.class, Object.class);
Or scan packages for annotated classes:
sessionBuilder.scanPackages("net.codejava.model");
In case you want to specify a specific Hibernate property:
sessionBuilder.setProperty("hibernate.show_sql", "true");
Or specify a set of Hibernate properties:
sessionBuilder.addProperties(getHibernateProperties());
Whereas the
getHibernateProperties() method is implemented as followings:
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.show_sql", "true");
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
return properties;
}
This
SessionFactory bean will be wired into the
UserDAO bean below.
Configuring TransactionManager Bean
The following method configures a
HibernateTransactionManager for the
SessionFactory:
@Autowired
@Bean(name = "transactionManager")
public HibernateTransactionManager getTransactionManager(
SessionFactory sessionFactory) {
HibernateTransactionManager transactionManager = new HibernateTransactionManager(
sessionFactory);
return transactionManager;
}
By configuring a transaction manager, code in the DAO class doesn’t have to take care of transaction management explicitly. Instead, the
@Transactional annotation is used to tell Spring automatically inserts transaction management code into the bytecode.
Configuring DAO Bean
The following method configures a bean which is a
UserDAO implementation:
@Autowired
@Bean(name = "userDao")
public UserDAO getUserDao(SessionFactory sessionFactory) {
return new UserDAOImpl(sessionFactory);
}
This
UserDAO bean is injected into the controller class which is listed below.
5. Updating Spring Controller Class
In addition to the only one
list() method in
Part 1, the
HomeController class is now updated to handle CRUD operations of a list of users:
package net.codejava.spring.controller;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import net.codejava.spring.dao.UserDAO;
import net.codejava.spring.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
/**
* Handles requests for the application home page.
*/
@Controller
public class HomeController {
@Autowired
private UserDAO userDao;
@RequestMapping("/")
public ModelAndView handleRequest() throws Exception {
List<User> listUsers = userDao.list();
ModelAndView model = new ModelAndView("UserList");
model.addObject("userList", listUsers);
return model;
}
@RequestMapping(value = "/new", method = RequestMethod.GET)
public ModelAndView newUser() {
ModelAndView model = new ModelAndView("UserForm");
model.addObject("user", new User());
return model;
}
@RequestMapping(value = "/edit", method = RequestMethod.GET)
public ModelAndView editUser(HttpServletRequest request) {
int userId = Integer.parseInt(request.getParameter("id"));
User user = userDao.get(userId);
ModelAndView model = new ModelAndView("UserForm");
model.addObject("user", user);
return model;
}
@RequestMapping(value = "/delete", method = RequestMethod.GET)
public ModelAndView deleteUser(HttpServletRequest request) {
int userId = Integer.parseInt(request.getParameter("id"));
userDao.delete(userId);
return new ModelAndView("redirect:/");
}
@RequestMapping(value = "/save", method = RequestMethod.POST)
public ModelAndView saveUser(@ModelAttribute User user) {
userDao.saveOrUpdate(user);
return new ModelAndView("redirect:/");
}
}
This controller class is responsible for handling workflow of the application such as listing users, creating new, editing and deleting a user.
6. Updating User Listing Page
The
UserList.jsp uses
JSTL to enumerate the list of users passed from the controller:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Home</title>
</head>
<body>
<div align="center">
<h1>Users List</h1>
<h2><a href="/new">New User</a></h2>
<table border="1">
<th>No</th>
<th>Username</th>
<th>Email</th>
<th>Actions</th>
<c:forEach var="user" items="${userList}" varStatus="status">
<tr>
<td>${status.index + 1}</td>
<td>${user.username}</td>
<td>${user.email}</td>
<td>
<a href="/edit?id=${user.id}">Edit</a>
<a href="/delete?id=${user.id}">Delete</a>
</td>
</tr>
</c:forEach>
</table>
</div>
</body>
</html>
This page lists all users and provides corresponding actions like create new, edit and delete.
7. Coding User Form Page
The
UserForm.jsp uses Spring’s form tags to map between the
User object in the model and the HTML form:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>New or Edit User</title>
</head>
<body>
<div align="center">
<h1>New/Edit User</h1>
<table>
<form:form action="save" method="post" modelAttribute="user">
<form:hidden path="id"/>
<tr>
<td>Username:</td>
<td><form:input path="username"/></td>
</tr>
<tr>
<td>Email:</td>
<td><form:input path="email"/></td>
</tr>
<tr>
<td>Password:</td>
<td><form:password path="password"/></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="Save">
</td>
</tr>
</form:form>
</table>
</div>
</body>
</html>
This page is used when creating new user or editing an existing one.
Final Project StructureFor your reference, the following screenshot shows final project structure in Eclipse/STS:
8. Testing the Application
Application URL:
http://localhost:8080/springWe will see an empty list of users when accessing the application for the first time:
Click
New User link to add a new user. The
New/Edit User page appears:
Enter some dummy information then click
Save. The user is saved and we go back to the users list page:
Now we can click
Edit or
Delete link to update or remove a user.Congratulations! You have completed our second part of the Spring-Hibernate integration series. For your convenience, we provide downloads for the project and a deployable WAR file in the attachments section.
References: Related Spring-Hibernate Integration Tutorials:
Other Spring Tutorials:
About the Author:
Nam Ha Minh is certified Java programmer (SCJP and SCWCD). He started programming with Java in the time of Java 1.4 and has been falling in love with Java since then. Make friend with him on
Facebook and watch
his Java videos you YouTube.