Tutorial de ejemplo de CRUD de integración de MySQL con Hibernate y Spring MVC

Aprendimos a integrar Spring e Hibernate en nuestro último tutorial. Hoy avanzaremos e integraremos los frameworks Spring MVC e Hibernate en un ejemplo de CRUD de aplicación web. La estructura final de nuestro proyecto se parece a la imagen de abajo, veremos cada uno de los componentes uno por uno. Tenga en cuenta que estoy usando versiones de Spring 4.0.3.Releasee Hibernate 4.3.5.Finalpara nuestro ejemplo, el mismo programa también es compatible con Spring 4 e Hibernate 3, sin embargo, debe realizar pequeños cambios en el archivo de configuración del bean Spring que se analizó en el último tutorial.

Dependencias de Maven

Veamos todas las dependencias de Maven que son necesarias para la integración del marco Hibernate y Spring MVC.

?xml version="1.0" encoding="UTF-8"?project  xmlns_xsi="https://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd"modelVersion4.0.0/modelVersiongroupIdcom.journaldev.spring/groupIdartifactIdSpringMVCHibernate/artifactIdnameSpringMVCHibernate/namepackagingwar/packagingversion1.0.0-BUILD-SNAPSHOT/versionpropertiesjava-version1.6/java-versionorg.springframework-version4.0.3.RELEASE/org.springframework-versionorg.aspectj-version1.7.4/org.aspectj-versionorg.slf4j-version1.7.5/org.slf4j-versionhibernate.version4.3.5.Final/hibernate.version/propertiesdependencies!-- Spring --dependencygroupIdorg.springframework/groupIdartifactIdspring-context/artifactIdversion${org.springframework-version}/versionexclusions!-- Exclude Commons Logging in favor of SLF4j --exclusiongroupIdcommons-logging/groupIdartifactIdcommons-logging/artifactId /exclusion/exclusions/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-webmvc/artifactIdversion${org.springframework-version}/version/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-tx/artifactIdversion${org.springframework-version}/version/dependency!-- Hibernate --dependencygroupIdorg.hibernate/groupIdartifactIdhibernate-core/artifactIdversion${hibernate.version}/version/dependencydependencygroupIdorg.hibernate/groupIdartifactIdhibernate-entitymanager/artifactIdversion${hibernate.version}/version/dependency!-- Apache Commons DBCP --dependencygroupIdcommons-dbcp/groupIdartifactIdcommons-dbcp/artifactIdversion1.4/version/dependency!-- Spring ORM --dependencygroupIdorg.springframework/groupIdartifactIdspring-orm/artifactIdversion${org.springframework-version}/version/dependency!-- AspectJ --dependencygroupIdorg.aspectj/groupIdartifactIdaspectjrt/artifactIdversion${org.aspectj-version}/version/dependency!-- Logging --dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-api/artifactIdversion${org.slf4j-version}/version/dependencydependencygroupIdorg.slf4j/groupIdartifactIdjcl-over-slf4j/artifactIdversion${org.slf4j-version}/versionscoperuntime/scope/dependencydependencygroupIdorg.slf4j/groupIdartifactIdslf4j-log4j12/artifactIdversion${org.slf4j-version}/versionscoperuntime/scope/dependencydependencygroupIdlog4j/groupIdartifactIdlog4j/artifactIdversion1.2.15/versionexclusionsexclusiongroupIdjavax.mail/groupIdartifactIdmail/artifactId/exclusionexclusiongroupIdjavax.jms/groupIdartifactIdjms/artifactId/exclusionexclusiongroupIdcom.sun.jdmk/groupIdartifactIdjmxtools/artifactId/exclusionexclusiongroupIdcom.sun.jmx/groupIdartifactIdjmxri/artifactId/exclusion/exclusionsscoperuntime/scope/dependency!-- @Inject --dependencygroupIdjavax.inject/groupIdartifactIdjavax.inject/artifactIdversion1/version/dependency!-- Servlet --dependencygroupIdjavax.servlet/groupIdartifactIdservlet-api/artifactIdversion2.5/versionscopeprovided/scope/dependencydependencygroupIdjavax.servlet.jsp/groupIdartifactIdjsp-api/artifactIdversion2.1/versionscopeprovided/scope/dependencydependencygroupIdjavax.servlet/groupIdartifactIdjstl/artifactIdversion1.2/version/dependency!-- Test --dependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion4.7/versionscopetest/scope/dependency/dependencies    build        plugins            plugin                artifactIdmaven-eclipse-plugin/artifactId                version2.9/version                configuration                    additionalProjectnatures                        projectnatureorg.springframework.ide.eclipse.core.springnature/projectnature                    /additionalProjectnatures                    additionalBuildcommands                        buildcommandorg.springframework.ide.eclipse.core.springbuilder/buildcommand                    /additionalBuildcommands                    downloadSourcestrue/downloadSources                    downloadJavadocstrue/downloadJavadocs                /configuration            /plugin            plugin                groupIdorg.apache.maven.plugins/groupId                artifactIdmaven-compiler-plugin/artifactId                version2.5.1/version                configuration                    source1.6/source                    target1.6/target                    compilerArgument-Xlint:all/compilerArgument                    showWarningstrue/showWarnings                    showDeprecationtrue/showDeprecation                /configuration            /plugin            plugin                groupIdorg.codehaus.mojo/groupId                artifactIdexec-maven-plugin/artifactId                version1.2.1/version                configuration                    mainClassorg.test.int1.Main/mainClass                /configuration            /plugin        /plugins        finalName${project.artifactId}/finalName    /build/project

Algunas de las dependencias anteriores están incluidas por STS (Spring Tool Suite) cuando creo un proyecto Spring MVC. Las dependencias importantes anteriores son spring-context , spring-webmvc , spring-tx , hibernate-core , hibernate-entitymanager y spring-orm . Estoy usando Apache Commons DBCP para la agrupación de conexiones, pero en situaciones de la vida real, lo más probable es que la agrupación de conexiones la realice el contenedor y todo lo que necesitamos es proporcionar los detalles de referencia JNDI para usar. NOTA : Noté que algunos de los lectores tienen problemas de conexión a la base de datos. Observe que en mi pom.xml, no hay ningún controlador de base de datos. Eso funciona para mí porque tengo el controlador MySQL en el directorio lib de tomcat y algunas conexiones DataSource configuradas con él. Para cualquier problema relacionado con la conexión a la base de datos, coloque el controlador de la base de datos en la biblioteca del contenedor o inclúyalo en las dependencias pom.xml.

Descriptor de implementación

Necesitamos conectar el marco Spring a nuestra aplicación web, lo que se hace configurando el marco Spring DispatcherServletcomo el controlador frontal. Nuestro archivo web.xml se ve como se muestra a continuación.

?xml version="1.0" encoding="UTF-8"?web-app version="2.5" xmlns_xsi="https://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"!-- The definition of the Root Spring Container shared by all Servlets and Filters --context-paramparam-namecontextConfigLocation/param-nameparam-value/WEB-INF/spring/root-context.xml/param-value/context-param!-- Creates the Spring Container shared by all Servlets and Filters --listenerlistener-classorg.springframework.web.context.ContextLoaderListener/listener-class/listener!-- Processes application requests --servletservlet-nameappServlet/servlet-nameservlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-classinit-paramparam-namecontextConfigLocation/param-nameparam-value/WEB-INF/spring/appServlet/servlet-context.xml/param-value/init-paramload-on-startup1/load-on-startup/servletservlet-mappingservlet-nameappServlet/servlet-nameurl-pattern//url-pattern/servlet-mapping/web-app

La mayor parte de la parte es código repetitivo, la parte más importante es la ubicación del archivo de contexto de Spring donde configuraremos nuestros servicios y beans de Spring. Si lo desea, puede cambiarlos según los requisitos de su proyecto.

Bean de entidad de hibernación

Usamos anotaciones JPA en nuestra clase de bean de entidad, sin embargo, también podemos tener un bean Java simple y detalles de mapeo en el archivo XML. En ese caso, necesitamos proporcionar detalles del archivo de mapeo al configurar Hibernate SessionFactory en las configuraciones de bean Spring.

package com.journaldev.spring.model;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.Table;/** * Entity bean with JPA annotations * Hibernate provides JPA implementation * @author pankaj * */@Entity@Table(name="PERSON")public class Person {@Id@Column(name="id")@GeneratedValue(strategy=GenerationType.IDENTITY)private int id;private String name;private String country;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getCountry() {return country;}public void setCountry(String country) {this.country = country;}@Overridepublic String toString(){return "id="+id+", name="+name+", country="+country;}}

Nuestro bean de entidad se asigna a la tabla PERSONA en la base de datos MySQL. Observe que no he anotado los campos “nombre” y “país” @Columnporque tienen el mismo nombre. El siguiente script SQL muestra los detalles de la tabla.

CREATE TABLE `Person` (  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,  `name` varchar(20) NOT NULL DEFAULT '',  `country` varchar(20) DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

Implementación de Hibernate DAO

Crearemos PersonDAOuna interfaz para declarar los métodos que utilizaremos en nuestro proyecto. A continuación, proporcionaremos una implementación específica de Hibernate para ello.

package com.journaldev.spring.dao;import java.util.List;import com.journaldev.spring.model.Person;public interface PersonDAO {public void addPerson(Person p);public void updatePerson(Person p);public ListPerson listPersons();public Person getPersonById(int id);public void removePerson(int id);}

La implementación de DAO específica de Hibernate se ve a continuación.

package com.journaldev.spring.dao;import java.util.List;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Repository;import com.journaldev.spring.model.Person;@Repositorypublic class PersonDAOImpl implements PersonDAO {private static final Logger logger = LoggerFactory.getLogger(PersonDAOImpl.class);private SessionFactory sessionFactory;public void setSessionFactory(SessionFactory sf){this.sessionFactory = sf;}@Overridepublic void addPerson(Person p) {Session session = this.sessionFactory.getCurrentSession();session.persist(p);logger.info("Person saved successfully, Person Details="+p);}@Overridepublic void updatePerson(Person p) {Session session = this.sessionFactory.getCurrentSession();session.update(p);logger.info("Person updated successfully, Person Details="+p);}@SuppressWarnings("unchecked")@Overridepublic ListPerson listPersons() {Session session = this.sessionFactory.getCurrentSession();ListPerson personsList = session.createQuery("from Person").list();for(Person p : personsList){logger.info("Person List::"+p);}return personsList;}@Overridepublic Person getPersonById(int id) {Session session = this.sessionFactory.getCurrentSession();Person p = (Person) session.load(Person.class, new Integer(id));logger.info("Person loaded successfully, Person details="+p);return p;}@Overridepublic void removePerson(int id) {Session session = this.sessionFactory.getCurrentSession();Person p = (Person) session.load(Person.class, new Integer(id));if(null != p){session.delete(p);}logger.info("Person deleted successfully, person details="+p);}}

Tenga en cuenta que no estoy usando Hibernate Transaction, esto se debe a que el marco Spring se encargará de ello.

Clases de servicio de primavera

Aquí están nuestras clases de servicio que utilizan clases DAO de Hibernate para trabajar con objetos Persona.

package com.journaldev.spring.service;import java.util.List;import com.journaldev.spring.model.Person;public interface PersonService {public void addPerson(Person p);public void updatePerson(Person p);public ListPerson listPersons();public Person getPersonById(int id);public void removePerson(int id);}
package com.journaldev.spring.service;import java.util.List;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import com.journaldev.spring.dao.PersonDAO;import com.journaldev.spring.model.Person;@Servicepublic class PersonServiceImpl implements PersonService {private PersonDAO personDAO;public void setPersonDAO(PersonDAO personDAO) {this.personDAO = personDAO;}@Override@Transactionalpublic void addPerson(Person p) {this.personDAO.addPerson(p);}@Override@Transactionalpublic void updatePerson(Person p) {this.personDAO.updatePerson(p);}@Override@Transactionalpublic ListPerson listPersons() {return this.personDAO.listPersons();}@Override@Transactionalpublic Person getPersonById(int id) {return this.personDAO.getPersonById(id);}@Override@Transactionalpublic void removePerson(int id) {this.personDAO.removePerson(id);}}

Tenga en cuenta que la gestión de transacciones declarativas de Spring se aplica mediante el uso @Transactionalde anotaciones.

Clase controladora de resorte

Nuestras clases DAO y de servicio están listas, es hora de escribir nuestra clase controladora que se encargará de las solicitudes de los clientes y utilizará las clases de servicio para realizar operaciones específicas de la base de datos y luego devolverá las páginas de vista.

package com.journaldev.spring;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;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.journaldev.spring.model.Person;import com.journaldev.spring.service.PersonService;@Controllerpublic class PersonController {private PersonService personService;@Autowired(required=true)@Qualifier(value="personService")public void setPersonService(PersonService ps){this.personService = ps;}@RequestMapping(value = "/persons", method = RequestMethod.GET)public String listPersons(Model model) {model.addAttribute("person", new Person());model.addAttribute("listPersons", this.personService.listPersons());return "person";}//For add and update person both@RequestMapping(value= "/person/add", method = RequestMethod.POST)public String addPerson(@ModelAttribute("person") Person p){if(p.getId() == 0){//new person, add itthis.personService.addPerson(p);}else{//existing person, call updatethis.personService.updatePerson(p);}return "redirect:/persons";}@RequestMapping("/remove/{id}")    public String removePerson(@PathVariable("id") int id){        this.personService.removePerson(id);        return "redirect:/persons";    }     @RequestMapping("/edit/{id}")    public String editPerson(@PathVariable("id") int id, Model model){        model.addAttribute("person", this.personService.getPersonById(id));        model.addAttribute("listPersons", this.personService.listPersons());        return "person";    }}

Tenga en cuenta que estoy usando @Controlleranotaciones, de modo que Spring Framework lo tratará como una clase de controlador para manejar las solicitudes del cliente. También estoy usando @Autowiredanotaciones @Qualifierpara inyectar PersonService, podríamos haberlo hecho también en el archivo xml de contexto de Spring. Lectura recomendada: Conexión automática de Spring Bean

Configuración de Spring Bean

Nuestros servicios están listos, todo lo que necesitamos es conectarlos a través de las configuraciones de los beans de Spring. Nuestro archivo root-context.xml está vacío, por lo que solo buscaremos en el archivo servlet-context.xml.

?xml version="1.0" encoding="UTF-8"?beans:beans xmlns_xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns_beans="https://www.springframework.org/schema/beans"xmlns:context="https://www.springframework.org/schema/context" xmlns_tx="https://www.springframework.org/schema/tx"xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsdhttps://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsdhttps://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsdhttps://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-4.0.xsd"!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure --!-- Enables the Spring MVC @Controller programming model --annotation-driven /!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory --resources mapping="/resources/**" location="/resources/" /!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory --beans:beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"beans:property name="prefix" value="/WEB-INF/views/" /beans:property name="suffix" value=".jsp" //beans:beanbeans:beandestroy-method="close"beans:property name="driverClassName" value="com.mysql.jdbc.Driver" /beans:property name="url"value="jdbc:mysql://localhost:3306/TestDB" /beans:property name="username" value="pankaj" /beans:property name="password" value="pankaj123" //beans:bean!-- Hibernate 4 SessionFactory Bean definition --beans:beanclass="org.springframework.orm.hibernate4.LocalSessionFactoryBean"beans:property name="dataSource" ref="dataSource" /beans:property name="annotatedClasses"beans:listbeans:valuecom.journaldev.spring.model.Person/beans:value/beans:list/beans:propertybeans:property name="hibernateProperties"beans:propsbeans:prop key="hibernate.dialect"org.hibernate.dialect.MySQLDialect/beans:propbeans:prop key="hibernate.show_sql"true/beans:prop/beans:props/beans:property/beans:beanbeans:beanbeans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" //beans:beanbeans:beanbeans:property name="personDAO" ref="personDAO"/beans:property/beans:beancontext:component-scan base-package="com.journaldev.spring" /tx:annotation-driven transaction-manager="transactionManager"/beans:beanbeans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" //beans:bean/beans:beans

El bean dataSource se define para org.apache.commons.dbcp.BasicDataSourcela clase de agrupación de conexiones básica. org.springframework.orm.hibernate4.LocalSessionFactoryBeanEl bean se utiliza para SessionFactory de Hibernate 4. Para Hibernate 3, encontrará clases similares a org.springframework.orm.hibernate3.LocalSessionFactoryBeany org.springframework.orm.hibernate3.AnnotationSessionFactoryBean. Un punto importante es que cuando dependemos del marco Spring para la gestión de sesiones de Hibernate, no deberíamos definir hibernate.current_session_context_class, de lo contrario, obtendrá muchos problemas relacionados con las transacciones de sesión. Los beans personDAO y personService se entienden por sí mismos. La definición del bean transactionManager para org.springframework.orm.hibernate4.HibernateTransactionManageres necesaria para que Spring ORM admita la gestión de transacciones de sesiones de Hibernate. Para Hibernate 3, encontrará una clase similar a org.springframework.orm.hibernate3.HibernateTransactionManager. Spring utiliza AOP para la gestión de transacciones, ahora puede relacionarlo con @Transactionalla anotación. Lectura recomendada : Spring AOP y Spring Transaction Management

Ver página

Nuestra última parte de la aplicación es la página de vista. Observe los atributos agregados al Modelo en los métodos del controlador del Controlador. Los usaremos para crear nuestra página de vista. También usaremos etiquetas JSTL , etiquetas Spring Core y Spring Form.

%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c" %%@ taglib uri="https://www.springframework.org/tags" prefix="spring" %%@ taglib uri="https://www.springframework.org/tags/form" prefix="form" %%@ page session="false" %htmlheadtitlePerson Page/titlestyle type="text/css".tg  {border-collapse:collapse;border-spacing:0;border-color:#ccc;}.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:#ccc;color:#333;background-color:#fff;}.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:#ccc;color:#333;background-color:#f0f0f0;}.tg .tg-4eph{background-color:#f9f9f9}/style/headbodyh1Add a Person/h1c:url var="addAction" value="/person/add" /c:urlform:form action="${addAction}" commandName="person"tablec:if test="${!empty person.name}"trtdform:label path="id"spring:message text="ID"//form:label/tdtdform:input path="id" readonly="true" size="8"  disabled="true" /form:hidden path="id" //td /tr/c:iftrtdform:label path="name"spring:message text="Name"//form:label/tdtdform:input path="name" //td /trtrtdform:label path="country"spring:message text="Country"//form:label/tdtdform:input path="country" //td/trtrtd colspan="2"c:if test="${!empty person.name}"input type="submit"value="spring:message text="Edit Person"/" //c:ifc:if test="${empty person.name}"input type="submit"value="spring:message text="Add Person"/" //c:if/td/tr/table/form:formbrh3Persons List/h3c:if test="${!empty listPersons}"tabletrthPerson ID/ththPerson Name/ththPerson Country/ththEdit/ththDelete/th/trc:forEach items="${listPersons}" var="person"trtd${person.id}/tdtd${person.name}/tdtd${person.country}/tdtda href="c:url value='/edit/${person.id}' /" Edit/a/tdtda href="c:url value='/remove/${person.id}' /" Delete/a/td/tr/c:forEach/table/c:if/body/html

Pruebas de aplicaciones Spring MVC Hibernate

Simplemente cree e implemente el proyecto en cualquier contenedor de servlets de su elección, por ejemplo, Tomcat. Las capturas de pantalla a continuación muestran las páginas de visualización de nuestra aplicación. También encontrará registros similares en el archivo de registro del servidor.

Hibernate: insert into PERSON (country, name) values (?, ?)INFO : com.journaldev.spring.dao.PersonDAOImpl - Person saved successfully, Person Details=id=15, name=Pankaj, country=USAHibernate: select person0_.id as id1_0_, person0_.country as country2_0_, person0_.name as name3_0_ from PERSON person0_INFO : com.journaldev.spring.dao.PersonDAOImpl - Person List::id=10, name=Raman, country=UK2INFO : com.journaldev.spring.dao.PersonDAOImpl - Person List::id=11, name=Lisa, country=FranceINFO : com.journaldev.spring.dao.PersonDAOImpl - Person List::id=15, name=Pankaj, country=USA

Resumen

Este tutorial tiene como objetivo brindarte detalles suficientes para comenzar a trabajar con la integración de Spring MVC e Hibernate. Espero que te resulte útil. Puedes descargar el proyecto final desde el siguiente enlace y experimentar con él.

Descargar el proyecto de integración de Hibernate con Spring MVC

You can also checkout the project from our GitHub Repository.

SUSCRÍBETE A NUESTRO BOLETÍN 
No te pierdas de nuestro contenido ni de ninguna de nuestras guías para que puedas avanzar en los juegos que más te gustan.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio