5. Introduzione a Spring Data JPA
In questo capitolo, esamineremo la seguente architettura:
![]() |
Inseriamo un livello [JPA] (Java Persistence API) tra il livello [DAO] e il driver JDBC del DBMS. D'ora in poi, il livello JPA emette i comandi SQL destinati al DBMS. Il livello [DAO] non gestisce più i comandi SQL, ma solo oggetti chiamati entità JPA, che sono rappresentazioni delle varie tabelle nel database in uso. I campi di queste entità sono associati in modo univoco alle colonne delle tabelle tramite annotazioni Java. Questo è ciò che permette al livello JPA di tradurre in SQL le operazioni del livello [DAO] sulle entità JPA.
Spring Data è un ramo di Spring incentrato sull'accesso ai dati, indipendentemente dal fatto che questi siano memorizzati in un DBMS relazionale, in un database NoSQL o in altri tipi di archiviazione. In questa sede ci occupiamo esclusivamente di RDBMS e dell'accesso agli stessi tramite JPA. In seguito, a volte scriveremo [Spring JPA] per riferirci in realtà a [Spring Data JPA]. Nell'architettura sopra riportata, il livello [Spring Data] fornisce al livello [DAO] gli strumenti per gestire le entità JPA.
JPA è in realtà una specifica. Ne testeremo tre delle sue implementazioni:
- Hibernate (http://hibernate.org/);
- EclipseLink (http://www.eclipse.org/eclipselink/);
- OpenJpa (http://openjpa.apache.org/);
5.1. Esempio-01
Il sito web di Spring offre numerosi tutorial per iniziare a utilizzare Spring [http://spring.io/guides]. Ne useremo uno per introdurre Spring Data. A tal fine, utilizzeremo Spring Tool Suite (STS).
![]() |
- In [1], importiamo uno dei tutorial da [spring.io/guides];
![]() |
- In [2], selezioniamo il tutorial [Accessing Data Jpa], che mostra come accedere a un database utilizzando Spring Data;
- In [3], selezioniamo un progetto configurato da Maven;
- in [4], il tutorial è disponibile in due forme: [initial], che è una versione vuota da compilare seguendo il tutorial, oppure [complete], che è la versione finale del tutorial. Scegliamo quest'ultima;
- In [5], è possibile scegliere di visualizzare il tutorial in un browser;
- In [6], il progetto finale.
5.1.1. La configurazione Maven del progetto
Le dipendenze Maven del progetto sono configurate nel file [pom.xml]:
<groupId>org.springframework</groupId>
<artifactId>gs-accessing-data-jpa</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
</dependencies>
<properties>
<!-- use UTF-8 for everything -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<start-class>hello.Application</start-class>
</properties>
- righe 5–9: definiscono un progetto Maven padre. Questo progetto definisce la maggior parte delle dipendenze del progetto. Potrebbero essere sufficienti, nel qual caso non vengono aggiunte dipendenze aggiuntive, oppure potrebbero non esserlo, nel qual caso vengono aggiunte le dipendenze mancanti;
- righe 12–15: definiscono una dipendenza da [spring-boot-starter-data-jpa]. Questo artefatto contiene le classi Spring Data;
- Righe 16–19: definiscono una dipendenza dal DBMS H2, che consente di creare e gestire database in memoria.
Diamo un'occhiata alle classi fornite da queste dipendenze:
![]() | ![]() | ![]() |
Ce ne sono molte:
- alcune appartengono all'ecosistema Spring (quelle che iniziano con spring);
- altri appartengono all'ecosistema Hibernate (hibernate, jboss), di cui stiamo utilizzando l'implementazione JPA;
- altri sono librerie di test (junit, hamcrest);
- altri sono librerie di logging (log4j, logback, slf4j);
Le terremo tutte. Per un'applicazione di produzione, dovrebbero essere mantenute solo quelle necessarie.
Alla riga 26 del file [pom.xml], troviamo la riga:
<start-class>hello.Application</start-class>
Questa riga è collegata alle seguenti righe:
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Righe 6–9: Il [spring-boot-maven-plugin] consente di generare il JAR eseguibile dell'applicazione. La riga 26 del file [pom.xml] specifica quindi la classe eseguibile di questo JAR.
5.1.2. Il livello [JPA]
L'accesso al database viene gestito tramite un livello [JPA], la Java Persistence API:
![]() |
![]() |
L'applicazione è semplice e gestisce le entità [Cliente]. La classe [Cliente] fa parte del livello [JPA] ed è la seguente:
package hello;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String firstName;
private String lastName;
protected Customer() {
}
public Customer(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public String toString() {
return String.format("Customer[id=%d, firstName='%s', lastName='%s']", id, firstName, lastName);
}
}
Un cliente ha un ID [id], un nome [firstName] e un cognome [lastName]. Ogni istanza [Customer] rappresenta una riga in una tabella del database.
- riga 8: annotazione JPA che garantisce che la persistenza delle istanze [Customer] (Creazione, Lettura, Aggiornamento, Eliminazione) sarà gestita da un'implementazione JPA. In base alle dipendenze Maven, possiamo vedere che viene utilizzata l'implementazione JPA/Hibernate;
- Righe 11–12: annotazioni JPA che associano il campo [id] alla chiave primaria della tabella [Customer]. La riga 12 indica che l'implementazione JPA utilizzerà il metodo di generazione della chiave primaria specifico del DBMS in uso, in questo caso H2;
Non ci sono altre annotazioni JPA. Verranno quindi utilizzati i valori predefiniti:
- la tabella [Customer] prenderà il nome dalla classe, ovvero [Customer];
- le colonne di questa tabella prenderanno il nome dai campi della classe: [id, firstName, lastName], tenendo presente che nei nomi delle colonne della tabella non viene fatta distinzione tra maiuscole e minuscole;
Si noti che l'implementazione JPA utilizzata non viene mai denominata.
5.1.3. Il livello [Spring Data]
La classe [CustomerRepository] implementa il livello di accesso per la tabella [Customer]. Il suo codice è il seguente:
![]() |
![]() |
package hello;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
public interface CustomerRepository extends CrudRepository<Customer, Long> {
List<Customer> findByLastName(String lastName);
}
Si tratta quindi di un'interfaccia e non di una classe (riga 7). Essa estende l'interfaccia [CrudRepository], un'interfaccia Spring Data (riga 5). Questa interfaccia è parametrizzata da due tipi: il primo è il tipo degli elementi gestiti, in questo caso il tipo [Customer]; il secondo è il tipo della chiave primaria degli elementi gestiti, in questo caso un tipo [Long]. L'interfaccia [CrudRepository] è la seguente:
package org.springframework.data.repository;
import java.io.Serializable;
@NoRepositoryBean
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
<S extends T> S save(S entity);
<S extends T> Iterable<S> save(Iterable<S> entities);
T findOne(ID id);
boolean exists(ID id);
Iterable<T> findAll();
Iterable<T> findAll(Iterable<ID> ids);
long count();
void delete(ID id);
void delete(T entity);
void delete(Iterable<? extends T> entities);
void deleteAll();
}
Questa interfaccia definisce le operazioni CRUD (Create – Read – Update – Delete) che possono essere eseguite su un tipo JPA T:
- riga 8: il metodo save consente di salvare un'entità T nel database. Salva l'entità utilizzando la chiave primaria assegnatale dal DBMS. Consente inoltre di aggiornare un'entità T identificata dalla sua chiave primaria id. La scelta tra queste due azioni dipende dal valore della chiave primaria id: se è null, viene eseguita l'operazione di salvataggio; altrimenti, viene eseguita l'operazione di aggiornamento;
- riga 10: come sopra, ma per un elenco di entità;
- riga 12: il metodo findOne recupera un'entità T identificata dalla sua chiave primaria id;
- riga 22: il metodo delete consente di eliminare un'entità T identificata dal suo id di chiave primaria;
- righe 24–28: varianti del metodo [delete];
- riga 16: il metodo [findAll] recupera tutte le entità T persistenti;
- riga 18: come sopra, ma limitato alle entità per le quali è stato fornito un elenco di identificatori;
Torniamo all'interfaccia [CustomerRepository]:
package hello;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
public interface CustomerRepository extends CrudRepository<Customer, Long> {
List<Customer> findByLastName(String lastName);
}
- La riga 9 consente di recuperare un [Cliente] in base al suo [cognome];
E questo è tutto per il livello [DAO]. Non esiste una classe di implementazione per l'interfaccia precedente. Viene generata in fase di esecuzione da [Spring Data]. I metodi dell'interfaccia [CrudRepository] vengono implementati automaticamente. Per i metodi aggiunti all'interfaccia [CustomerRepository], dipende. Torniamo alla definizione di [Customer]:
private long id;
private String firstName;
private String lastName;
Il metodo alla riga 9 viene implementato automaticamente da [Spring Data] poiché fa riferimento al campo [lastName] (riga 3) di [Customer]. Quando incontra un metodo [findBySomething] nell'interfaccia da implementare, Spring Data lo implementa utilizzando la seguente query JPQL (Java Persistence Query Language):
Pertanto, il tipo T deve avere un campo denominato [something]. Di conseguenza, il metodo
sarà implementato con un codice simile al seguente:
return [em].createQuery("select c from Customer c where c.lastName=:value").setParameter("value",lastName).getResultList()
dove [em] si riferisce al contesto di persistenza JPA. Ciò è possibile solo se la classe [Customer] ha un campo denominato [lastName], come in questo caso.
In conclusione, in casi semplici, Spring Data ci permette di implementare il livello [DAO] con un'interfaccia semplice.
5.1.4. Il livello [console]
![]() |
![]() |
La classe [Application] è la seguente:
package hello;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application implements CommandLineRunner {
@Autowired
CustomerRepository repository;
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
@Override
public void run(String... strings) throws Exception {
// save a couple of customers
repository.save(new Customer("Jack", "Bauer"));
repository.save(new Customer("Chloe", "O'Brian"));
repository.save(new Customer("Kim", "Bauer"));
repository.save(new Customer("David", "Palmer"));
repository.save(new Customer("Michelle", "Dessler"));
// fetch all customers
System.out.println("Customers found with findAll():");
System.out.println("-------------------------------");
for (Customer customer : repository.findAll()) {
System.out.println(customer);
}
System.out.println();
// fetch an individual customer by ID
Customer customer = repository.findOne(1L);
System.out.println("Customer found with findOne(1L):");
System.out.println("--------------------------------");
System.out.println(customer);
System.out.println();
// fetch customers by last name
System.out.println("Customer found with findByLastName('Bauer'):");
System.out.println("--------------------------------------------");
for (Customer bauer : repository.findByLastName("Bauer")) {
System.out.println(bauer);
}
}
}
- riga 9: la classe implementa l'interfaccia [CommandLineRunner], che è un'interfaccia [Spring Boot] (riga 4). Questa interfaccia ha un solo metodo, quello alla riga 19;
- riga 8: @SpringBootApplication è un'annotazione che raggruppa diverse annotazioni [Spring Boot]:
- @Configuration: indica che la classe è una classe di configurazione;
- @EnableAutoConfiguration: indica a [Spring Boot] di creare automaticamente una serie di bean in base a varie proprietà, in particolare al contenuto del classpath del progetto. Poiché le librerie Hibernate si trovano nel Classpath, il bean [entityManagerFactory] verrà implementato utilizzando Hibernate. Poiché la libreria del DBMS H2 si trova nel Classpath, il bean [dataSource] verrà implementato utilizzando H2. Nel bean [dataSource], dobbiamo anche definire il nome utente e la password. Qui, Spring Boot utilizzerà l'amministratore H2 predefinito, che non ha password. Poiché la libreria [spring-tx] si trova nel Classpath, verrà utilizzato il gestore delle transazioni di Spring;
- @EnableWebMvc: se la libreria [spring-mvc] si trova nel Classpath. In questo caso, viene eseguita la configurazione automatica per l'applicazione web;
- @ComponentScan: indica a Spring dove cercare altri bean, configurazioni e servizi. Qui, vengono cercati per impostazione predefinita nel pacchetto contenente la classe annotata, ovvero il pacchetto [hello]. In questo modo, verranno trovate le classi [Customer] e [CustomerRepository]. Poiché la prima ha l'annotazione [@Entity], verrà catalogata come entità da gestire da Hibernate. Poiché la seconda estende l'interfaccia [CrudRepository], verrà registrata come bean Spring;
- righe 11–12: il bean [CustomerRepository] viene iniettato nel codice della classe principale;
- riga 15: viene eseguito il metodo statico [run] della classe [SpringApplication] del progetto Spring Boot. Il suo parametro è la classe che presenta un'annotazione [Configuration] o [EnableAutoConfiguration]. A questo punto avrà luogo tutto ciò che è stato spiegato in precedenza. Il risultato è un contesto applicativo Spring, ovvero un insieme di bean gestiti da Spring;
- righe 19–48: le operazioni seguenti utilizzano semplicemente i metodi del bean che implementa l'interfaccia [CustomerRepository];
L'output della console è il seguente:
- Righe 1-8: il logo del progetto Spring Boot;
- riga 9: viene eseguita la classe [hello.Application];
- riga 10: [AnnotationConfigApplicationContext] è una classe che implementa l'interfaccia [ApplicationContext] di Spring. Si tratta di un contenitore di bean;
- riga 11: il bean [entityManagerFactory] è implementato con la classe [LocalContainerEntityManagerFactory], una classe Spring. Gestisce il livello [JPA];
- riga 12: compare [Hibernate]. Questa è l'implementazione JPA scelta;
- riga 19: un dialetto Hibernate è la variante SQL da utilizzare con il DBMS. Qui, il dialetto [H2Dialect] indica che Hibernate funzionerà con il DBMS H2;
- righe 21–22: viene creato il database. Viene creata la tabella [CUSTOMER]. Ciò significa che Hibernate è stato configurato per generare tabelle dalle definizioni JPA, in questo caso la definizione JPA della classe [Customer];
- righe 26–30: risultato del metodo [findAll] dell'interfaccia;
- riga 34: risultato del metodo [findOne] dell'interfaccia;
- righe 38–39: risultati del metodo [findByLastName];
- righe 41 e seguenti: log dalla chiusura del contesto Spring.
5.1.5. Configurazione manuale del progetto Spring Data
Duplichiamo il progetto precedente nel progetto [gs-accessing-data-jpa-02]:
![]() |
In questo nuovo progetto, non ci affideremo alla configurazione automatica fornita da Spring Boot. Lo configureremo manualmente. Ciò può essere utile se le configurazioni predefinite non soddisfano le nostre esigenze.
Per prima cosa, specificheremo le dipendenze necessarie nel file [pom.xml]:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-accessing-data-jpa-02</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
</parent>
<dependencies>
<!-- Spring Data -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<!-- Hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
<!-- H2 Database -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<!-- Tomcat JDBC -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</dependency>
</dependencies>
<properties>
<!-- use UTF-8 for everything -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/libs-release</url>
</repository>
<repository>
<id>org.jboss.repository.releases</id>
<name>JBoss Maven Release Repository</name>
<url>https://repository.jboss.org/nexus/content/repositories/releases</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories>
</project>
- righe 10–14: il progetto Maven principale di cui useremo le librerie;
- righe 18–21: Spring Data utilizzato per accedere al database;
- righe 23–26: l'implementazione Hibernate della specifica JPA;
- righe 28–31: il DBMS H2;
- righe 33–36: i database vengono spesso utilizzati con pool di connessioni, che evitano di aprire e chiudere ripetutamente le connessioni. In questo caso, l'implementazione utilizzata è [tomcat-jdbc];
Nel nuovo progetto, l'entità [Customer] e l'interfaccia [CustomerRepository] rimangono invariate. Modificheremo la classe [Application], che verrà suddivisa in due classi:
- [Config], che sarà la classe di configurazione;
- [Main], che sarà la classe eseguibile;
![]() |
La classe eseguibile [Application] è ora la seguente:
package console;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import repositories.CustomerRepository;
import config.AppConfig;
import entities.Customer;
public class Application {
public static void main(String[] args) {
// instantiation Spring context
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
CustomerRepository repository = context.getBean(CustomerRepository.class);
// save a couple of customers
repository.save(new Customer("Jack", "Bauer"));
repository.save(new Customer("Chloe", "O'Brian"));
repository.save(new Customer("Kim", "Bauer"));
repository.save(new Customer("David", "Palmer"));
repository.save(new Customer("Michelle", "Dessler"));
...
// closing context
context.close();
}
}
- riga 9: la classe [Application] non presenta più alcuna annotazione di configurazione;
- righe 3–7: si noti che non sono più presenti importazioni del pacchetto [Spring Boot];
- riga 12: Istanziamo i bean Spring. Otteniamo il contesto Spring, che contiene i riferimenti ai bean creati;
- riga 13: richiediamo un riferimento al bean [CustomerRepository];
La classe [ Config] che configura il progetto è la seguente:
package config;
import javax.persistence.EntityManagerFactory;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = { "repositories" })
@Configuration
// @ComponentScan(basePackages={"package1","package2"})
public class AppConfig {
// h2 database
@Bean
public DataSource dataSource() {
// data source TomcatJdbc
DataSource dataSource = new DataSource();
// configuration access JDBC
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:./demo");
dataSource.setUsername("sa");
dataSource.setPassword("");
// an initially open connection
dataSource.setInitialSize(1);
// result
return dataSource;
}
// the provider JPA
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(false);
hibernateJpaVendorAdapter.setGenerateDdl(true);
hibernateJpaVendorAdapter.setDatabase(Database.H2);
return hibernateJpaVendorAdapter;
}
// EntityManagerFactory
@Bean
public EntityManagerFactory entityManagerFactory(JpaVendorAdapter jpaVendorAdapter, DataSource dataSource) {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(jpaVendorAdapter);
factory.setPackagesToScan("entities");
factory.setDataSource(dataSource);
factory.afterPropertiesSet();
return factory.getObject();
}
// Transaction manager
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
}
- riga 17: l'annotazione [@EnableTransactionManagement] indica che le annotazioni [@Transactional] devono essere interpretate. I metodi delle interfacce [CrudRepository] presentano queste annotazioni. Essi vengono quindi eseguiti all'interno di una transazione;
- riga 18: l'annotazione [@EnableJpaRepositories] specifica le directory in cui si trovano le interfacce [CrudRepository] di Spring Data. Queste interfacce diventeranno componenti Spring e saranno disponibili nel contesto Spring;
- riga 19: l'annotazione [@Configuration] rende la classe [Config] una classe di configurazione Spring;
- riga 20: l'annotazione [@ComponentScan] elenca le directory in cui devono essere cercati i componenti Spring. I componenti Spring sono classi annotate con annotazioni Spring come @Service, @Component, @Controller, ecc. Qui non ce ne sono altre oltre a quelle definite all'interno della classe [AppConfig], quindi l'annotazione è stata commentata;
- Righe 24–37: definiscono l'origine dati, il database H2. È l'annotazione @Bean alla riga 25 che rende l'oggetto creato da questo metodo un componente gestito da Spring. Il nome del metodo può essere qualsiasi cosa in questo caso. Tuttavia, deve essere denominato [dataSource] se l'EntityManagerFactory alla riga 51 è assente e viene definita tramite configurazione automatica;
- riga 30: il database si chiamerà [demo] e verrà generato nella cartella del progetto;
- Righe 40–47: definiscono l'implementazione JPA utilizzata, in questo caso un'implementazione Hibernate. Il nome del metodo può essere qualsiasi cosa qui;
- riga 43: nessun log SQL;
- riga 44: il database verrà creato se non esiste;
- righe 50–58: definiscono l'EntityManagerFactory che gestirà la persistenza JPA. Il metodo deve essere denominato [entityManagerFactory];
- riga 51: il metodo riceve due parametri dei tipi dei due bean definiti in precedenza. Questi saranno poi costruiti e iniettati da Spring come parametri del metodo;
- riga 53: imposta l'implementazione JPA da utilizzare;
- riga 54: specifica le directory in cui si trovano le entità JPA;
- riga 55: imposta l'origine dati da gestire;
- righe 61–66: il gestore delle transazioni. Il metodo deve essere denominato [transactionManager]. Riceve il bean delle righe 51–58 come parametro;
- riga 64: il gestore delle transazioni è associato all'EntityManagerFactory;
I metodi precedenti possono essere definiti in qualsiasi ordine.
L'esecuzione del progetto produce gli stessi risultati. Nella cartella del progetto compare un nuovo file, il file del database H2:
![]() |
5.1.6. Creazione di un archivio eseguibile
Per creare un archivio eseguibile del progetto, procedere come segue:
![]() |
- in [1]: creare una configurazione di runtime;
- in [2]: di tipo [Applicazione Java]
- in [3]: specificare il progetto da eseguire (utilizzare il pulsante Sfoglia);
- in [4]: specificare la classe da eseguire;
- in [5]: il nome della configurazione di esecuzione — può essere qualsiasi cosa;
![]() |
- in [6]: esporta il progetto;
- in [7]: come archivio JAR eseguibile;
- in [8]: specificare il percorso e il nome del file eseguibile da creare;
- in [9]: il nome della configurazione di esecuzione creata in [5];
10 ![]() |
- in [10], l'archivio creato;
Una volta fatto ciò, apri una console nella cartella contenente l'archivio eseguibile:
L'archivio viene eseguito come segue:
.....\dist>java -jar gs-accessing-data-jpa-02.jar
I risultati visualizzati nella console sono i seguenti:
5.1.7. Creazione di un progetto [Spring Data]
Per creare un modello di progetto Spring Data, segui questi passaggi:
![]() |
- In [1], creare un nuovo progetto;
- in [2]: seleziona [Spring Starter Project];
- Il progetto generato sarà un progetto Maven. In [3], specificare il nome del gruppo di progetto;
- In [4], specificare il nome dell'artefatto (in questo caso un JAR) che verrà creato al momento della compilazione del progetto;
- in [5]: il nome del progetto in Eclipse — può essere qualsiasi cosa (non deve necessariamente corrispondere a [4]);
- in [7]: specificare che si sta creando un progetto con un livello [JPA] utilizzando il DBMS MySQL. Le dipendenze richieste per un progetto di questo tipo saranno quindi incluse nel file [pom.xml];
![]() |
- in [8], inserisci il nome della cartella del progetto;
- in [9], completare la procedura guidata;
![]() |
- in [10]: il progetto creato;
Il file [pom.xml] include le dipendenze necessarie per un progetto JPA:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>istia.st.springdata</groupId>
<artifactId>intro-spring-data-01</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>intro-spring-data-01</name>
<description>démo spring data avec table de produits</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<start-class>demo.IntroSpringData01Application</start-class>
<java.version>1.7</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- righe 14–19: il progetto Maven principale;
- righe 28–31: la dipendenza richiesta per JPA – includerà [Spring Data];
- righe 32–36: la dipendenza dal driver JDBC di MySQL;
- righe 37–41: dipendenze richieste per i test JUnit integrati con Spring;
La classe eseguibile [Application] non fa nulla ma è preconfigurata:
package demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class IntroSpringData01Application {
public static void main(String[] args) {
SpringApplication.run(IntroSpringData01Application.class, args);
}
}
- L'annotazione [@SpringBootApplication] rende la classe una classe di configurazione automatica del progetto;
La classe di test [ApplicationTests] non fa nulla ma è preconfigurata:
package demo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = IntroSpringData01Application.class)
public class IntroSpringData01ApplicationTests {
@Test
public void contextLoads() {
}
}
- riga 9: l'annotazione [@SpringApplicationConfiguration] consente di utilizzare il file di configurazione [IntroSpringData01Application]. La classe di test potrà quindi beneficiare di tutti i bean definiti da questo file;
- riga 8: l'annotazione [@RunWith] consente l'integrazione di Spring con JUnit: la classe potrà essere eseguita come test JUnit. [@RunWith] è un'annotazione JUnit (riga 4), mentre la classe [SpringJUnit4ClassRunner] è una classe Spring (riga 6);
Ora che abbiamo uno scheletro di applicazione JPA, possiamo completarlo.




















