SpringMVC+Hibernate CRUD Application
I am going to create today a complete End-to-End SpringMVC 3, Hibernate 3 CRUD tutorial which uses MySQL as a database to store records. This will be a simple Bookstore application where user can Create, Update, View of Delete book records. We will use Hibernate 3 as an ORM tool with Spring MVC as a MVC Framework.
In this tutorial you will learn how we integrate SpringMVC with Hibernate using JPA annotations and I will also going to use Spring annotation configuration for Controller, Service and Repository annotations. The main advantage of using @Repository
or @Service
over @Component
is that it’s easy to write an AOP pointcut that targets, for instance, all classes annotated with @Repository
.
Upon completion of this tutorial the Application will look like following screenshot.
Lets Start
First of all, We need a SQL Table to save our Books details in RDBMS. You can create this table by the help of Hibernate also but its good to follow Bottom-Up approach to create an Application. Following SQL used to create a Books table in MySQL database.
CREATE TABLE IF NOT EXISTS books (
id int(10) NOT NULL auto_increment,
book_name varchar(100) NOT NULL,
author varchar(100) NOT NULL,
price int(10) NOT NULL,
qty int(10) NOT NULL,
PRIMARY KEY (id)
);
Hibernate Entity Class: Book
The @Entity
annotation is used to mark this class as an Entity bean. So the class should atleast have a package scope no-argument constructor.
The @Table
annotation is used to specify the table to persist the data. The name attribute refers to the table name. If @Table
annotation is not specified then Hibernate will by default use the class name as the table name.
The @Id
annotation is used to specify the identifier property of the entity bean. The placement of the @Id annotation determines the default access strategy that Hibernate will use for the mapping. If the@Id
annotation is placed over the field, then filed access will be used. Instead if it placed over the getter method of that field, then property access will be used. Here we use property access.
The @GeneratedValue
annotation is used to specify the primary key generation strategy to use. If the strategy is not specified by default AUTO will be used.
package com.mmc.bean;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="books",schema="test")
public class Book {
@Id
@Column(name="ID")
@GeneratedValue
private Integer id;
@Column(name="BOOK_NAME")
private String bookName;
@Column(name="AUTHOR")
private String author;
@Column(name="PRICE")
private int price;
@Column(name="QTY")
private int quantity;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
}
Data Access Layer
Data access layer of our application consist of one BookDoa Interface and its implementation BookDaoImpl class. The BookDaoImpl class has a @Repository
annotation which used to enable this class to eligible for persistence exception translation.
package com.mmc.dao;
import java.util.List;
import com.mmc.bean.Book;
public interface BookDao {
public void addBook(Book book);
public void updateBook(Book book);
public List<Book> listBooks();
public Book getBookById(Integer bookId);
public void removeBook(Integer id);
}
BookDaoImpl.java
package com.mmc.dao;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.mmc.bean.Book;
@Repository
public class BookDaoImpl implements BookDao {
@Autowired
private SessionFactory sessionFactory;
@Override
public void addBook(Book book) {
sessionFactory.getCurrentSession().save(book);
}
@Override
public void updateBook(Book book) {
sessionFactory.getCurrentSession().update(book);
}
@SuppressWarnings("unchecked")
@Override
public List<Book> listBooks() {
return sessionFactory.getCurrentSession().createQuery("from Book").list();
}
@Override
public Book getBookById(Integer bookId) {
Session session = sessionFactory.getCurrentSession();
Query query = session.createQuery("from Book b where b.id = :bookId");
query.setParameter("bookId", bookId);
List<Book> list = query.list();
return list.size() > 0 ? (Book)list.get(0) : null;
}
@Override
public void removeBook(Integer id) {
Book book = (Book)sessionFactory.getCurrentSession().load(Book.class, id);
if(book!=null){
sessionFactory.getCurrentSession().delete(book);
}
}
}<span style="color:#e04b39;">
</span>
Service Layer
Service layer also consist of one Service interface BookService and its implementation classBookServiceImpl.java
. We have annotated BookServiceImpl class with @Service
annotation.
package com.mmc.service;
package com.mmc.service;
import java.util.List;
import com.mmc.bean.Book;
public interface BookService {
public void addBook(Book book);
public void updateBook(Book book);
public Book getBookById(Integer bookId);
public List<Book> listBooks();
public void removeBook(Integer id);
}
BookServiceImpl.java
<span style="color:#333333;">package com.mmc.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.mmc.bean.Book;
import com.mmc.dao.BookDao;
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
@Transactional
@Override
public void addBook(Book book) {
bookDao.addBook(book);
}
@Transactional
@Override
public void updateBook(Book book) {
bookDao.updateBook(book);
}
@Transactional
@Override
public Book getBookById(Integer bookId) {
return bookDao.getBookById(bookId);
}
@Transactional
@Override
public List<Book> listBooks() {
return bookDao.listBooks();
}
@Transactional
@Override
public void removeBook(Integer id) {
bookDao.removeBook(id);
}
}</span><span style="color:#e04b39;">
</span>
Book Controller
Now create a BookController which will have all the method we need for our CRUD operations. We need to wire the bookService for this controller using @Autowired
annotation.
package com.mmc.controller;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.mmc.bean.Book;
import com.mmc.service.BookService;
@Controller
public class BookController {
@Autowired
private BookService bookService;
@RequestMapping("/index")
public String bookList(Map<String, Object> map){
map.put("book", new Book());
map.put("listBooks", bookService.listBooks());
return "book";
}
@RequestMapping(value="/book/add",method=RequestMethod.POST)
public String addBook(@ModelAttribute("book") Book book,BindingResult result){
if(null == book.getId()){
bookService.addBook(book);
} else{
bookService.updateBook(book);
}
return "redirect:/index";
}
@RequestMapping(value="/edit/{bookId}")
public String editBook(@PathVariable("bookId")Integer bookId,
Map<String, Object> map){
map.put("book", bookService.getBookById(bookId));
map.put("listBooks", bookService.listBooks());
return "book";
}
@RequestMapping(value="/delete/{bookId}")
public String deleteBook(@PathVariable("bookId") Integer bookId){
bookService.removeBook(bookId);
return "redirect:/index";
}
}
SpringMVC Configuration
Now we are all set with our java changes and we need to add spring relate configuration in xml files. First we add DispatcherServlet reference in web.xml file. Following xml tags will add a DispatcherServlet reference to web.xml file.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>spring01</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<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>
Now create a jdbc.properties
file which is used to set Database related properties into it. We can add those properties directly into spring xml file but it’s good to create a separate file and have all details of DB into it.
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.dialect=org.hibernate.dialect.MySQLDialect
jdbc.databaseurl=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=123456
Hibernate Configuration
We have created a Hinerbate Entity Book which is annotation base Entity. The benefit of creating an annotation based Entity class is We don’t need to create a .hbm.xml file for that entity but we need to create hibernate.cfg.xml file for Hibernate related configuration. Following XML shows the mininum Hibernate configuration File.
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<mapping class="com.mmc.bean.Book"/>
</session-factory>
</hibernate-configuration>
Spring Configuration
Now we need to add spring-servler.xml file which contain all beans and others MVC, Transaction related Tags. XML file is minimal and self-explanatory.
<?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:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<context:annotation-config></context:annotation-config>
<context:component-scan base-package="com.mmc"></context:component-scan>
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:annotation-driven/>
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="resources/messages" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="/WEB-INF/jdbc.properties" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.databaseurl}" p:username="${jdbc.username}"
p:password="${jdbc.password}" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>resources/hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
View creation
Now last but not the least, creating view to show our Book Add Form. I have also created a Table grid which show the List of all available Books after Book Entry form. You can click on Book Name and it will show the details for the Book. Further you can edit the details and Save it to Update the Changes.
book.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Spring 3 MVC Hibernate - Book CRUD</title>
<style type="text/css">
body {
font-family: verdana;
font-size: 12px;
margin: 40px;
}
.bookTable, .bookTable td {
border-collapse: collapse;
border: 1px solid #aaa;
margin: 2px;
padding: 2px 2px 2px 10px;
font-size: 12px;
}
.bookTable th {
font-weight: bold;
font-size: 12px;
background-color: #5C82FF;
color: white;
}
.bookLabel {
font-family: verdana;
font-size: 12px;
font-weight: bold;
}
a, a:AFTER {
color: blue;
}
</style>
<script type="text/javascript">
function deleteBook(bookId){
if(confirm('Do you want to delete this Book ?')){
var url = 'delete/' + bookId;
window.location.href = url;
}
}
</script>
</head>
<body>
<h2>Book Store - SpringMVC-Hibernate CRUD Application</h2>
<p style="color:green;font-weight:bold;">To add a New Book please click <a href="<c:url value='/index' />" >
<img src="<c:url value='/images/vcard_add.png' />" title="Add a New Book"/></a>
</p>
<c:url var="action" value="/book/add.html" ></c:url>
<form:form action="${action }" commandName="book" cssClass="bookForm" method="post">
<table>
<c:if test="${!empty book.bookName }">
<tr>
<td>
<form:label path="id" cssClass="bookLabel">
<spring:message code="label.bookId"></spring:message>
</form:label>
</td>
<td>
<form:input path="id" readonly="true" size="8" disabled="true" />
<form:hidden path="id" />
</td>
</tr>
</c:if>
<tr>
<td>
<form:label path="bookName" cssClass="bookLabel">
<spring:message code="label.bookName" />
</form:label>
</td>
<td>
<form:input path="bookName" />
</td>
</tr>
<tr>
<td>
<form:label path="author" cssClass="bookLabel">
<spring:message code="label.author" />
</form:label>
</td>
<td>
<form:input path="author" />
</td>
</tr>
<tr>
<td>
<form:label path="price" cssClass="bookLabel">
<spring:message code="label.price" />
</form:label>
</td>
<td>
<form:input path="price" />
</td>
</tr>
<tr>
<td>
<form:label path="quantity" cssClass="bookLabel">
<spring:message code="label.qty" />
</form:label>
</td>
<td>
<form:input path="quantity" />
</td>
</tr>
<tr>
<td colspan="2">
<c:if test="${!empty book.bookName}">
<input type="submit" value="<spring:message code="label.editbook"/>" />
</c:if>
<c:if test="${empty book.bookName}">
<input type="submit" value="<spring:message code="label.addbook"/>" />
</c:if>
</td>
</tr>
</table>
</form:form>
<h3>List of Books in Library</h3>
<c:if test="${!empty listBooks }">
<table class="bookTable">
<tr>
<th width="180">Book Name</th>
<th width="160">Author Name</th>
<th width="60">Price</th>
<th width="80">Quantity</th>
<th width="60">Action</th>
</tr>
<c:forEach items="${listBooks }" var="book">
<tr>
<td>${book.bookName }</td>
<td>${book.author }</td>
<td>${book.price }</td>
<td>${book.quantity }</td>
<td><img src="<c:url value='/images/vcard_delete.png' />" title="Delete Book" οnclick="javascript:deleteBook(${book.id})" />
<a href="<c:url value='/edit/${book.id}' />" >
<img src="<c:url value='/images/vcard_add.png' />" title="Edit Book"/>
</a>
</td>
</tr>
</c:forEach>
</table>
</c:if>
</body>
</html>
还没有评论,来说两句吧...