Spring Data JPA fa parte della famiglia Spring Data. Spring Data facilita la creazione di applicazioni basate su Spring che utilizzano nuovi metodi per accedere ai dati, come database non relazionali, framework di map-reduction, servizi cloud, nonché un supporto avanzato per database relazionali. Questo articolo tratterà di Spring Data JPA. Guarderemo anche un esempio di applicazione Spring Data JPA.
Spring Data JPA
Alcune delle caratteristiche interessanti fornite da Spring Data JPA sono:
- Creazione e supporto di repository creati con Spring e JPA
- Supporto per QueryDSL e query JPA
- Auditing delle classi di dominio
- Supporto per il caricamento batch, ordinamento, query dinamiche
- Supporto per il mapping XML per le entità
- Riduzione delle dimensioni del codice per le operazioni generiche CRUD utilizzando CrudRepository
Quando utilizzare 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.
Esempio di Spring Data JPA
Per il nostro esempio di Spring Data JPA, creeremo un servizio web RESTful che si collegherà al database Postgresql. Implementeremo le operazioni CRUD di base e lavoreremo su dati di esempio che abbiamo già creato.
Esempio di dati di esempio di Spring JAP
Utilizza la query seguente per creare la tabella nel database Postgresql e aggiungere alcuni dati di test.
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);
Struttura del progetto Maven Spring Data JPA
La seguente immagine mostra la struttura finale del progetto Spring JPA. Esamineremo ogni componente in dettaglio in seguito.
Dependency Maven di Spring Data JPA
Dobbiamo aggiungere le seguenti dipendenze per il nostro progetto di esempio Spring Data JPA.
postgresql
: driver Java Postgresql.spring-core
,spring-context
: Dipendenze di base di Spring Framework.spring-webmvc
,jackson-databind
: Per l’applicazione Spring REST.spring-data-jpa
,hibernate-entitymanager
: Per il supporto di Spring Data JPA e Hibernate.
Di seguito è riportato il contenuto del file di build pom.xml finale.
<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>
Classi di configurazione di 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
: Questa annotazione di Spring indica che questa è una classe di configurazione. -
@EnableTransactionManagement
: Questa annotazione permette agli utenti di utilizzare il controllo delle transazioni nell’applicazione. -
@EnableJpaRepositories("com.journaldev.spring.repository")
: Indica dove sono presenti le classi dei repository. -
@PropertySource("classpath:database.properties")
: indica che abbiamo un file di proprietà nel nostro classpath. I valori da questo file saranno iniettati nelle variabili di ambiente. Il contenuto del file database.properties è mostrato di seguito.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
-
Per utilizzare Spring Data, prima di tutto dobbiamo configurare il bean
DataSource
. Quindi dobbiamo configurare il beanLocalContainerEntityManagerFactoryBean
. Abbiamo bisogno di questo bean per controllare le entità. In questi bean, è necessario specificare il provider di persistenza, ovveroHibernatePersistence
nel nostro caso. -
Il passo successivo è configurare il bean per la gestione delle transazioni. Nel nostro esempio è
JpaTransactionManager
. Nota che senza configurare il gestore delle transazioni non possiamo utilizzare l’annotazione@Transactional
.
Le classi AppInitializer
e WebConfig
servono per configurare la nostra applicazione come applicazione web senza utilizzare il file web.xml.
Classe Modello
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
+ '\'' + '}';
}
}
Qui abbiamo alcune nuove annotazioni. Parliamone più dettagliatamente.
- @Entity: Questa annotazione consente all’entity manager di utilizzare questa classe e la inserisce nel contesto.
- @Table(name = “people”): associa una classe a una tabella nel database.
@Id
: indica che questo campo è la chiave primaria.@GeneratedValue(strategy = GenerationType.IDENTITY)
: Definisce la strategia per generare la chiave primaria.@Column(name = "age")
: indica una colonna nel database con cui questo campo sarà associato.
Spring Data JPA Repository
Il prossimo passo è creare il repository 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);
}
Ereditando da CrudRepository
, possiamo chiamare molti metodi senza la necessità di implementarli noi stessi. Alcuni di questi metodi sono:
- save
- findOne
- exists
- findAll
- count
- delete
- deleteAll
Possiamo anche definire i nostri metodi personalizzati. Questi nomi dei metodi dovrebbero utilizzare parole chiave speciali come “trova”, “ordina” con il nome delle variabili. Gli sviluppatori di Spring Data JPA hanno cercato di tenere conto della maggior parte delle opzioni possibili di cui potresti avere bisogno. Nel nostro esempio, il metodo findByFirstName(String firstName)
restituisce tutte le voci dalla tabella dove il campo first_name
è uguale a firstName
. Questa è una delle caratteristiche più importanti di Spring Data JPA perché riduce molto il codice ripetitivo. Inoltre, le possibilità di errori sono minori perché questi metodi Spring sono stati già testati da molti progetti che li utilizzano.
Classe di Servizio Spring
Ora che il nostro codice Spring Data JPA è pronto, il prossimo passo è creare una classe di servizio e definire i metodi con cui dovremo lavorare sulla tabella del database.
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
l’annotazione indica che il metodo verrà eseguito nella transazione. Spring si occuperà della gestione della transazione.
Classe Controller Spring
Il passo finale è creare la classe controller per esporre le nostre API al mondo esterno.
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;
}
}
Test Spring Data JPA
Basta compilare e distribuire il progetto nel tuo container servlet preferito, come Tomcat. Di seguito sono mostrate le risposte per alcune delle chiamate API.
Lettura di tutti i dati di Spring Data JPA
Ottieni per nome di Spring Data JPA
Crea di Spring Data JPA
Aggiorna di Spring Data JPA
Elimina di Spring Data JPA
Questo è tutto per il tutorial di esempio di Spring Data JPA. Puoi scaricare il progetto finale dal link sottostante.
Scarica il Progetto di Esempio di Spring Data JPA
Riferimento: Sito Ufficiale
Source:
https://www.digitalocean.com/community/tutorials/spring-data-jpa