Spring Data JPA es parte de la familia Spring Data. Spring Data facilita la creación de aplicaciones impulsadas por Spring que utilizan nuevas formas de acceder a los datos, como bases de datos no relacionales, marcos de reducción de mapas, servicios en la nube, así como un sólido soporte para bases de datos relacionales avanzadas. Este artículo tratará sobre Spring Data JPA. También exploraremos un ejemplo de aplicación utilizando Spring Data JPA.
Spring Data JPA
Algunas de las características interesantes proporcionadas por Spring Data JPA son:
- Crear y respaldar repositorios creados con Spring y JPA
- Soporte para QueryDSL y consultas JPA
- Auditoría de clases de dominio
- Soporte para carga por lotes, ordenación, consultas dinámicas
- Admite el mapeo XML para entidades
- Reducir el tamaño del código para operaciones CRUD genéricas utilizando CrudRepository
¿Cuándo usar Spring Data JPA?
I would say that if you need to quickly create a JPA-based repository layer that is mainly for CRUD operations, and you do not want to create abstract DAO, implementing interfaces, Spring Data JPA is a good choice.
Ejemplo de Spring Data JPA
Para nuestro ejemplo de Spring Data JPA, crearemos un servicio web RESTful que se conectará a la base de datos Postgresql. Implementaremos operaciones CRUD básicas y trabajaremos con datos de muestra que ya hemos creado.
Datos de muestra del ejemplo Spring JPA
Utiliza la siguiente consulta para crear la tabla en la base de datos Postgresql y agregar algunos datos de prueba.
create table people (
id serial not null primary key,
first_name varchar(20) not null,
last_name varchar(20) not null,
age integer not null
);
insert into people (id, first_name, last_name, age) values
(1, 'Vlad', 'Boyarskiy', 21),
(2,'Oksi', ' Bahatskaya', 30),
(3,'Vadim', ' Vadimich', 32);
Estructura del Proyecto Maven de Spring Data JPA
La imagen siguiente muestra la estructura final del proyecto Spring JPA. Más adelante, analizaremos en detalle cada uno de los componentes.
Dependencias Maven de Spring Data JPA
Necesitamos agregar las siguientes dependencias para nuestro proyecto de ejemplo de Spring Data JPA.
postgresql
: Controlador Java de Postgresql.spring-core
,spring-context
: Dependencias principales de Spring Framework Core.spring-webmvc
,jackson-databind
: Para aplicaciones REST de Spring.spring-data-jpa
,hibernate-entitymanager
: para el soporte de Spring Data JPA y Hibernate.
A continuación se muestra el contenido del archivo de construcción pom.xml final.
<project xmlns="https://maven.apache.org/POM/4.0.0" 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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.journaldev</groupId>
<artifactId>springData</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>Spring Data JPA Maven Webapp</name>
<url>https://maven.apache.org</url>
<properties>
<spring.framework>4.3.0.RELEASE</spring.framework>
<postgres.version>42.1.4</postgres.version>
<serializer.version>2.8.1</serializer.version>
<spring.data>1.3.4.RELEASE</spring.data>
<hibernate.manager>4.2.5.Final</hibernate.manager>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.framework}</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${postgres.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.framework}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.framework}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${spring.data}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.manager}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${serializer.version}</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
</build>
</project>
Clases de Configuración de Spring
package com.journaldev.spring.config;
import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.ejb.HibernatePersistence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories("com.journaldev.spring.repository")
@PropertySource("classpath:database.properties")
public class DataConfig {
private final String PROPERTY_DRIVER = "driver";
private final String PROPERTY_URL = "url";
private final String PROPERTY_USERNAME = "user";
private final String PROPERTY_PASSWORD = "password";
private final String PROPERTY_SHOW_SQL = "hibernate.show_sql";
private final String PROPERTY_DIALECT = "hibernate.dialect";
@Autowired
Environment environment;
@Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean lfb = new LocalContainerEntityManagerFactoryBean();
lfb.setDataSource(dataSource());
lfb.setPersistenceProviderClass(HibernatePersistence.class);
lfb.setPackagesToScan("com.journaldev.spring.model");
lfb.setJpaProperties(hibernateProps());
return lfb;
}
@Bean
DataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setUrl(environment.getProperty(PROPERTY_URL));
ds.setUsername(environment.getProperty(PROPERTY_USERNAME));
ds.setPassword(environment.getProperty(PROPERTY_PASSWORD));
ds.setDriverClassName(environment.getProperty(PROPERTY_DRIVER));
return ds;
}
Properties hibernateProps() {
Properties properties = new Properties();
properties.setProperty(PROPERTY_DIALECT, environment.getProperty(PROPERTY_DIALECT));
properties.setProperty(PROPERTY_SHOW_SQL, environment.getProperty(PROPERTY_SHOW_SQL));
return properties;
}
@Bean
JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
}
-
@Configuration
: esta anotación de Spring indica que es una clase de configuración. -
@EnableTransactionManagement
: esta anotación permite a los usuarios utilizar la gestión de transacciones en la aplicación. -
@EnableJpaRepositories("com.journaldev.spring.repository")
: indica dónde están presentes las clases de repositorio. -
@PropertySource("classpath:database.properties")
: indica que tenemos un archivo de propiedades en nuestro classpath. Los valores de este archivo se inyectarán en la variable de entorno. El contenido del archivo database.properties se muestra a continuación.driver=org.postgresql.Driver url=jdbc:postgresql://127.0.0.1:5432/postgres user=postgres password=postgres hibernate.dialect=org.hibernate.dialect.PostgreSQL82Dialect hibernate.show_sql=true
-
Para usar Spring Data, primero debemos configurar el bean
DataSource
. Luego, necesitamos configurar el beanLocalContainerEntityManagerFactoryBean
. Necesitamos este bean para controlar las entidades. En este bean, debes especificar el proveedor de persistencia, es decir,HibernatePersistence
en nuestro caso. -
El siguiente paso es configurar el bean para la gestión de transacciones. En nuestro ejemplo, es
JpaTransactionManager
. Ten en cuenta que sin configurar el gestor de transacciones no podemos usar la@Transactional
anotación.
Las clases AppInitializer
y WebConfig
son para configurar nuestra aplicación como una aplicación web sin utilizar el archivo web.xml.
Clase Modelo
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
@Table(name = "people")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "age")
private Integer age;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
public Person() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
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;
}
@Override
public String toString() {
return "Person{" + "id=" + id + ", age=" + age + ", firstName='" + firstName + '\'' + ", lastName='" + lastName
+ '\'' + '}';
}
}
Aquí tenemos algunas nuevas anotaciones. Hablemos de ellas con más detalle.
- @Entity: Esta anotación permite que el gestor de entidades use esta clase y la sitúa en contexto.
- @Table(name = “people”): asocia una clase con una tabla en la base de datos.
@Id
: indica que este campo es la clave primaria.@GeneratedValue(strategy = GenerationType.IDENTITY)
: Define la estrategia para generar la clave primaria.@Column(name = "age")
: denota una columna en la base de datos con la que este campo estará asociado.
Repositorio de Spring Data JPA
El siguiente paso es crear el repositorio JPA.
package com.journaldev.spring.repository;
import org.springframework.data.repository.CrudRepository;
import com.journaldev.spring.model.Person;
import java.util.List;
public interface PersonRepository<P> extends CrudRepository<Person, Long> {
List<Person> findByFirstName(String firstName);
}
Al heredar de CrudRepository
, podemos llamar a muchos métodos sin necesidad de implementarlos nosotros mismos. Algunos de estos métodos son:
- save
- findOne
- exists
- findAll
- count
- delete
- deleteAll
También podemos definir nuestros propios métodos. Estos nombres de método deben usar palabras clave especiales como “find”, “order” con el nombre de las variables. Los desarrolladores de Spring Data JPA han tratado de tener en cuenta la mayoría de las opciones posibles que puedas necesitar. En nuestro ejemplo, el método findByFirstName(String firstName)
devuelve todas las entradas de la tabla donde el campo first_name
es igual a firstName
. Esta es una de las características más importantes de Spring Data JPA porque reduce una gran cantidad de código repetitivo. Además, las posibilidades de errores son menores porque estos métodos de Spring están bien probados por muchos proyectos que ya los utilizan.
Clase de Servicio de Spring
Ahora que nuestro código de Spring Data JPA está listo, el siguiente paso es crear una clase de servicio y definir los métodos con los que trabajaremos con la tabla de la base de datos.
package com.journaldev.spring.services;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.journaldev.spring.model.Person;
import com.journaldev.spring.repository.PersonRepository;
@Service
public class PersonService {
@Autowired
PersonRepository<Person> personRepository;
@Transactional
public List<Person> getAllPersons() {
return (List<Person>) personRepository.findAll();
}
@Transactional
public List<Person> findByName(String name) {
return personRepository.findByFirstName(name);
}
@Transactional
public Person getById(Long id) {
return personRepository.findOne(id);
}
@Transactional
public void deletePerson(Long personId) {
personRepository.delete(personId);
}
@Transactional
public boolean addPerson(Person person) {
return personRepository.save(person) != null;
}
@Transactional
public boolean updatePerson(Person person) {
return personRepository.save(person) != null;
}
}
@Transactional
indica que el método se ejecutará en la transacción. Spring se encargará de la gestión de transacciones.
Clase Controladora de Spring
El paso final es crear la clase controladora para exponer nuestras API al mundo exterior.
package com.journaldev.spring.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.journaldev.spring.model.Person;
import com.journaldev.spring.services.PersonService;
@RestController
public class PersonController {
@Autowired
PersonService personService;
@RequestMapping(value = "/person/{id}", method = RequestMethod.GET)
public @ResponseBody Person getAllUsers(@PathVariable Long id) {
return personService.getById(id);
}
@RequestMapping(value = "/personByName/{name}", method = RequestMethod.GET)
public List<Person> getPersoneByName(@PathVariable String name) {
return personService.findByName(name);
}
@RequestMapping(value = "/person", method = RequestMethod.GET)
public List<Person> getAll() {
return personService.getAllPersons();
}
@RequestMapping(value = "/person/{id}", method = RequestMethod.DELETE)
public HttpStatus deletePersnone(@PathVariable Long id) {
personService.deletePerson(id);
return HttpStatus.NO_CONTENT;
}
@RequestMapping(value = "/person", method = RequestMethod.POST)
public HttpStatus insertPersone(@RequestBody Person person) {
return personService.addPerson(person) ? HttpStatus.CREATED : HttpStatus.BAD_REQUEST;
}
@RequestMapping(value = "/person", method = RequestMethod.PUT)
public HttpStatus updatePerson(@RequestBody Person person) {
return personService.updatePerson(person) ? HttpStatus.ACCEPTED : HttpStatus.BAD_REQUEST;
}
}
Pruebas de Spring Data JPA
Simplemente construya e implemente el proyecto en su contenedor de servlet favorito, como Tomcat. Las imágenes a continuación muestran la respuesta para algunas de las llamadas a la API.
Spring Data JPA Leer Todo
Spring Data JPA Obtener Por Nombre
Spring Data JPA Crear
Spring Data JPA Actualizar
Spring Data JPA Eliminar
Eso es todo para el tutorial de ejemplo de Spring Data JPA. Puedes descargar el proyecto final desde el siguiente enlace.
Descargar Proyecto de Ejemplo de Spring Data JPA
Referencia: Sitio web oficial
Source:
https://www.digitalocean.com/community/tutorials/spring-data-jpa