⬆️ ⬇️

Spring MVC 3, Hibernate Annotations, MySQL. Integration Tutorial

Not so long ago, I began to study the Spring framework and realized that the amount of material in Russian was literally limited to a couple of worthwhile articles. After a quick run, I wanted to do something more interesting, but I could not take it with a swoop. I had to google a few questions about the interaction between Spring and Hibernate. Suddenly, I stumbled upon a blog quite interesting developer Mark Serrano aka krams. Now, together with you, I would like to start a series of articles-translations, as well as my own training in the world of Spring.

Spring - Hibernate: One-to-Many Association

Let's start ...



In this tutorial, we will create a simple person management application using Spring MVC 3. We will build a simple CRUD (Create Read Update Delete) system to view, add, edit, and delete people. We will use Hibernate 3 and MySQL as the layer for working with the database, although you can use another database. This lesson assumes that you are familiar with MVC, ORM and SQL ( from the translator : do not be intimidated by these difficult words, feel free to read, everything will be quite simple)



What is Hibernate?



Hibernate is a library for the Java programming language, designed to solve object-relational mapping (object-relational mapping - ORM) tasks. This library provides an easy-to-use framework (framework) for mapping an object-oriented data model into traditional relational databases.



Hibernate solves the problem between storing an object in a database and its object-oriented representation at the language level.

')

What is MySQL?



MySQL database provides the most demanding networks, e-commerce and application transaction processing. It guarantees transaction security, ACID compatibility allows commits, rollbacks, recovery in case of failure, as well as row blocking capabilities. MySQL provides ease of use, scalability and performance, these qualities have made MySQL the most popular open source database in the world. Some of the most visited network resources use MySQL, such as Facebook, Google, Ticketmaster and Ebay.



At the beginning, let's look at the final structure of our project:



image



And let's see how our application will look like:



image



We begin by defining our domain object, Person (Person entities).



Person



package org.krams.tutorial.domain; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; /** * For a complete reference see * <a href="http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/"> * Hibernate Annotations Communit Documentations</a> */ @Entity @Table(name = "PERSON") public class Person implements Serializable { private static final long serialVersionUID = -5527566248002296042L; @Id @Column(name = "ID") @GeneratedValue private Integer id; @Column(name = "FIRST_NAME") private String firstName; @Column(name = "LAST_NAME") private String lastName; @Column(name = "MONEY") private Double money; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public Double getMoney() { return money; } public void setMoney(Double money) { this.money = money; } } 


Person is a simple POJO containing four private variables:



id

firstName

lastName

money



Addition from translator : POJO (English Plain Old Java Object) - “a simple old-style Java object”, a simple Java object not inherited from any specific object and not implementing any service interfaces beyond those needed for a business models (wiki)



Each of these variables with the annotation @Column corresponds to a column in the database:



ID

FIRST_NAME

LAST_NAME

MONEY



You do not need to deal with them, Hibernate will take it upon themselves. However, you must correctly declare these names (for example @Column (name = `` ID``)). You do not declare them in the database. Remember - your database does not exist yet.



POJO refers to the table of your database, pay attention to the Table annotation, where the name of the table corresponding to this object is indicated.



 @Entity @Table(name = "PERSON") public class Person implements Serializable 


Notice that the Entity annotation is in front of the annotation Table , this tells Hibernate that the POJO is a mapping of the database table.



We will manipulate the list of persons, so we will create a service for this:



Personservice



 package org.krams.tutorial.service; import java.util.List; import javax.annotation.Resource; import org.apache.log4j.Logger; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.krams.tutorial.domain.Person; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * Service for processing Persons * */ @Service("personService") @Transactional public class PersonService { protected static Logger logger = Logger.getLogger("service"); @Resource(name="sessionFactory") private SessionFactory sessionFactory; /** * Retrieves all persons * * @return a list of persons */ public List<person> getAll() { logger.debug("Retrieving all persons"); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession(); // Create a Hibernate query (HQL) Query query = session.createQuery("FROM Person"); // Retrieve all return query.list(); } /** * Retrieves a single person */ public Person get( Integer id ) { // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession(); // Retrieve existing person first Person person = (Person) session.get(Person.class, id); return person; } /** * Adds a new person */ public void add(Person person) { logger.debug("Adding new person"); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession(); // Save session.save(person); } /** * Deletes an existing person * @param id the id of the existing person */ public void delete(Integer id) { logger.debug("Deleting existing person"); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession(); // Retrieve existing person first Person person = (Person) session.get(Person.class, id); // Delete session.delete(person); } /** * Edits an existing person */ public void edit(Person person) { logger.debug("Editing existing person"); // Retrieve session from Hibernate Session session = sessionFactory.getCurrentSession(); // Retrieve existing person via id Person existingPerson = (Person) session.get(Person.class, person.getId()); // Assign updated values to this person existingPerson.setFirstName(person.getFirstName()); existingPerson.setLastName(existingPerson.getLastName()); existingPerson.setMoney(existingPerson.getMoney()); // Save updates session.save(existingPerson); } } 




We declared a simple CRUD system with the following methods:



getAll ()

add ()

delete ()

edit ()



In each method we get a session:



Session session = sessionFactory.getCurrentSession ();



This is like a database connection, so we can do our work. The Session object provides many methods for working as entity objects. For this lesson we use the following methods of the Session class:



session.createQuery ()

session.save ()

session.delete ()



We have created the domain and service layers, let's create a Spring controller.



MainController

 package org.krams.tutorial.controller; import java.util.List; import javax.annotation.Resource; import org.apache.log4j.Logger; import org.krams.tutorial.domain.Person; import org.krams.tutorial.service.PersonService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; 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.bind.annotation.RequestParam; /** * Handles and retrieves person request */ @Controller @RequestMapping("/main") public class MainController { protected static Logger logger = Logger.getLogger("controller"); @Resource(name="personService") private PersonService personService; /** * Handles and retrieves all persons and show it in a JSP page * * @return the name of the JSP page */ @RequestMapping(value = "/persons", method = RequestMethod.GET) public String getPersons(Model model) { logger.debug("Received request to show all persons"); // Retrieve all persons by delegating the call to PersonService List<person> persons = personService.getAll(); // Attach persons to the Model model.addAttribute("persons", persons); // This will resolve to /WEB-INF/jsp/personspage.jsp return "personspage"; } /** * Retrieves the add page * * @return the name of the JSP page */ @RequestMapping(value = "/persons/add", method = RequestMethod.GET) public String getAdd(Model model) { logger.debug("Received request to show add page"); // Create new Person and add to model // This is the formBackingOBject model.addAttribute("personAttribute", new Person()); // This will resolve to /WEB-INF/jsp/addpage.jsp return "addpage"; } /** * Adds a new person by delegating the processing to PersonService. * Displays a confirmation JSP page * * @return the name of the JSP page */ @RequestMapping(value = "/persons/add", method = RequestMethod.POST) public String add(@ModelAttribute("personAttribute") Person person) { logger.debug("Received request to add new person"); // The "personAttribute" model has been passed to the controller from the JSP // We use the name "personAttribute" because the JSP uses that name // Call PersonService to do the actual adding personService.add(person); // This will resolve to /WEB-INF/jsp/addedpage.jsp return "addedpage"; } /** * Deletes an existing person by delegating the processing to PersonService. * Displays a confirmation JSP page * * @return the name of the JSP page */ @RequestMapping(value = "/persons/delete", method = RequestMethod.GET) public String delete(@RequestParam(value="id", required=true) Integer id, Model model) { logger.debug("Received request to delete existing person"); // Call PersonService to do the actual deleting personService.delete(id); // Add id reference to Model model.addAttribute("id", id); // This will resolve to /WEB-INF/jsp/deletedpage.jsp return "deletedpage"; } /** * Retrieves the edit page * * @return the name of the JSP page */ @RequestMapping(value = "/persons/edit", method = RequestMethod.GET) public String getEdit(@RequestParam(value="id", required=true) Integer id, Model model) { logger.debug("Received request to show edit page"); // Retrieve existing Person and add to model // This is the formBackingOBject model.addAttribute("personAttribute", personService.get(id)); // This will resolve to /WEB-INF/jsp/editpage.jsp return "editpage"; } /** * Edits an existing person by delegating the processing to PersonService. * Displays a confirmation JSP page * * @return the name of the JSP page */ @RequestMapping(value = "/persons/edit", method = RequestMethod.POST) public String saveEdit(@ModelAttribute("personAttribute") Person person, @RequestParam(value="id", required=true) Integer id, Model model) { logger.debug("Received request to update person"); // The "personAttribute" model has been passed to the controller from the JSP // We use the name "personAttribute" because the JSP uses that name // We manually assign the id because we disabled it in the JSP page // When a field is disabled it will not be included in the ModelAttribute person.setId(id); // Delegate to PersonService for editing personService.edit(person); // Add id reference to Model model.addAttribute("id", id); // This will resolve to /WEB-INF/jsp/editedpage.jsp return "editedpage"; } } 


The controller announces the following views:



/ persons - for all persons

/ persons / add (GET) - show the Add form

/ persons / add (POST) - saves a new person.

/ persons / delete - deletes an existing person

/ persons / edit (GET) - shows the "Edit" form

/ persons / edit (POST) - saves the "corrected" person.



Each view calls a PersonService. When the PersonService completes processing, the controller sends the request to a JSP page, which shows a confirmation message. Here are the JSP pages:



personspage.jsp



 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ 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"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h1>Persons</h1> <c:url var="addUrl" value="/krams/main/persons/add" /> <table style="border: 1px solid; width: 500px; text-align:center"> <thead style="background:#fcf"> <tr> <th>First Name</th> <th>Last Name</th> <th>Money</th> <th colspan="3"></th> </tr> </thead> <tbody> <c:forEach items="${persons}" var="person"> <c:url var="editUrl" value="/krams/main/persons/edit?id=${person.id}" /> <c:url var="deleteUrl" value="/krams/main/persons/delete?id=${person.id}" /> <tr> <td><c:out value="${person.firstName}" /></td> <td><c:out value="${person.lastName}" /></td> <td><c:out value="${person.money}" /></td> <td><a href="${editUrl}">Edit</a></td> <td><a href="${deleteUrl}">Delete</a></td> <td><a href="${addUrl}">Add</a></td> </tr> </c:forEach> </tbody> </table> <c:if test="${empty persons}"> There are currently no persons in the list. <a href="${addUrl}">Add</a> a person. </c:if> </body> </html> 




editpage.jsp



 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://www.springframework.org/tags/form" prefix="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"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h1>Edit Person</h1> <c:url var="saveUrl" value="/krams/main/persons/edit?id=${personAttribute.id}" /> <form:form modelAttribute="personAttribute" method="POST" action="${saveUrl}"> <table> <tr> <td><form:label path="id">Id:</form:label></td> <td><form:input path="id" disabled="true"/></td> </tr> <tr> <td><form:label path="firstName">First Name:</form:label></td> <td><form:input path="firstName"/></td> </tr> <tr> <td><form:label path="lastName">Last Name</form:label></td> <td><form:input path="lastName"/></td> </tr> <tr> <td><form:label path="money">Money</form:label></td> <td><form:input path="money"/></td> </tr> </table> <input type="submit" value="Save" /> </form:form> </body> </html> 




addpage.jsp



 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://www.springframework.org/tags/form" prefix="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"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h1>Create New Person</h1> <c:url var="saveUrl" value="/krams/main/persons/add" /> <form:form modelAttribute="personAttribute" method="POST" action="${saveUrl}"> <table> <tr> <td><form:label path="firstName">First Name:</form:label></td> <td><form:input path="firstName"/></td> </tr> <tr> <td><form:label path="lastName">Last Name</form:label></td> <td><form:input path="lastName"/></td> </tr> <tr> <td><form:label path="money">Money</form:label></td> <td><form:input path="money"/></td> </tr> </table> <input type="submit" value="Save" /> </form:form> </body> </html> 




editedpage.jsp



 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ page import="java.util.Date" %> <%@ 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"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h1>Persons</h1> <p>You have edited a person with id ${id} at <%= new java.util.Date() %></p> <c:url var="mainUrl" value="/krams/main/persons" /> <p>Return to <a href="${mainUrl}">Main List</a></p> </body> </html> 


addedpage.jsp

 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ page import="java.util.Date" %> <%@ 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"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h1>Persons</h1> <p>You have added a new person at <%= new java.util.Date() %></p> <c:url var="mainUrl" value="/krams/main/persons" /> <p>Return to <a href="${mainUrl}">Main List</a></p> </body> </html> 


deletedpage.jsp

 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ page import="java.util.Date" %> <%@ 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"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h1>Persons</h1> <p>You have deleted a person with id ${id} at <%= new java.util.Date() %></p> <c:url var="mainUrl" value="/krams/main/persons" /> <p>Return to <a href="${mainUrl}">Main List</a></p> </body> </html> 


Let's configure our application.

For Spring MVC to work, add in the web.xml:



web.xml



 <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>/krams/*</url-pattern> </servlet-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> 


Notice the URL pattern. When accessing the pages of our application, the host name should be in the form of:



/ krams



In web.xml we specified spring as the name of the servlet. By convention, we also need to create the spring-servlet.xml file.



spring-servlet.xml



 <!-- Declare a view resolver --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" /> 


We also need to create an applicationContext.xml file.



applicationContext.xml



 <!-- Activates various annotations to be detected in bean classes --> <context:annotation-config /> <!-- Scans the classpath for annotated components that will be auto-registered as Spring beans. For example @Controller and @Service. Make sure to set the correct base-package--> <context:component-scan base-package="org.krams.tutorial" /> <!-- Configures the annotation-driven Spring MVC Controller programming model. Note that, with Spring 3.0, this tag works in Servlet MVC only! --> <mvc:annotation-driven /> <!-- Load Hibernate related configuration --> <import resource="hibernate-context.xml" /> 


Notice that in the applicationContext.xml file we declared the following import:



 <import resource="hibernate-context.xml" /> 


It contains the hibernate configuration files.



Hibernate-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:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd "> <context:property-placeholder location="/WEB-INF/spring.properties" /> <!-- Enable annotation style of managing transactions --> <tx:annotation-driven transaction-manager="transactionManager" /> <!-- Declare the Hibernate SessionFactory for retrieving Hibernate sessions --> <!-- See http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/orm/hibernate3/annotation/AnnotationSessionFactoryBean.html --> <!-- See http://docs.jboss.org/hibernate/stable/core/api/index.html?org/hibernate/SessionFactory.html --> <!-- See http://docs.jboss.org/hibernate/stable/core/api/index.html?org/hibernate/Session.html --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" p:dataSource-ref="dataSource" p:configLocation="${hibernate.config}" p:packagesToScan="org.krams.tutorial"/> <!-- Declare a datasource that has pooling capabilities--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" p:driverClass="${app.jdbc.driverClassName}" p:jdbcUrl="${app.jdbc.url}" p:user="${app.jdbc.username}" p:password="${app.jdbc.password}" p:acquireIncrement="5" p:idleConnectionTestPeriod="60" p:maxPoolSize="100" p:maxStatements="50" p:minPoolSize="10" /> <!-- Declare a transaction manager--> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" p:sessionFactory-ref="sessionFactory" /> </beans> 




In this file, we encapsulated all the associated Hibernate and Spring configurations.

Configuration Comments:



1. Turn on transaction support through the use of Spring annotations.



 <tx:annotation-driven transaction-manager="transactionManager" /> 


2. Declared SessionFactory for Hibernate.



 <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" p:dataSource-ref="dataSource" p:configLocation="${hibernate.config}" p:packagesToScan="org.krams.tutorial"/> 


SessionFactory is a factory that generates session objects for us. It’s like a car factory whose job it is to manufacture cars for people.



What is a session?



The main function of the Session is creating, reading, deleting objects of entity classes (classes marked with the Entity annotation).



SessionFactory requires a data source, which in this lesson is a database.

SessionFactory requires a file with a specific Hibernate configuration.



Hibernate.cfg.xml



 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- We're using MySQL database so the dialect needs to MySQL as well--> <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property> <!-- Enable this to see the SQL statements in the logs--> <property name="show_sql">false</property> <!-- This will drop our existing database and re-create a new one. Existing data will be deleted! --> <property name="hbm2ddl.auto">create</property> </session-factory> </hibernate-configuration> 


Here we have indicated the type of our database. We use MySQL dialect. We use a special dialect, MySQL5InnoDBDialect, because we use because we use the InnoDB memory management engine.



What is MySQL InnoDB?



InnoDB - MySQL engine that provides transaction security, allowing commits, rollback and recovery to protect user data.



So, back to the SessionFactory bean, it needs to know where our entity objects are located. Therefore, we indicate in this lesson that they are located in the org.krams.tutorial package.



3. We specify in the hibernate-context.xml file data sources.



 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" p:driverClass="${app.jdbc.driverClassName}" p:jdbcUrl="${app.jdbc.url}" p:user="${app.jdbc.username}" p:password="${app.jdbc.password}" p:acquireIncrement="5" p:idleConnectionTestPeriod="60" p:maxPoolSize="100" p:maxStatements="50" p:minPoolSize="10" /> 


For effective access to our database, we use the C3p0 pool. Why do we need to wrap our data in a pool?



JDBC connections are more often managed through a pool than directly through a driver. Examples of BoneCP, C3P0, and DBCP connection pools.



Why do you need a pool?



When developing a software connection pool, it is a cache for open connections. Pools are needed to improve performance. Opening and conducting a connection with the database, each user, requires a lot of resources. And when using pools, you only need to retrieve the desired connection from the cache, and not to establish the connection again.



We specify the database connection details in the spring.properties file.



spring.properties



 # database properties app.jdbc.driverClassName=com.mysql.jdbc.Driver app.jdbc.url=jdbc:mysql://localhost/mydatabase app.jdbc.username=root app.jdbc.password= #hibernate properties hibernate.config=/WEB-INF/hibernate.cfg.xml 


My database name is mydatabase.



As an alternative, we can specify these features directly in the hibernate-context.xml file.



The advantage of using separate configuration files is to encapsulate data related to the database connection.



We have completed our application. We managed to create a simple Spring MVC application using Hibernate to access MySQL.



To access the main page, enter the following URL: localhost : 8080 / spring-hibernate-mysql / krams / main / persons



The best way to learn is to try creating your own application.



To download the project, follow the link: spring-mvc-hibernate-annotations-integration-tutorial.googlecode.com/files/spring-hibernate-mysql.zip



UPD: As promised - link to github: github.com/sa4ek/spring-hibernate-mysql/tree/master

Source: https://habr.com/ru/post/248541/



All Articles