Questo post, ha l'obiettivo di introdurre Spring, attualmente il Framework più usato per lo sviluppo di applicazioni Java Enterprise.
Per fare questo integrerò Spring nello stesso esempio sviluppato nei primi post che trattavano il Framework Hibernate:
Hibernate relazione uno a uno
Hibernate relazione uno a molti
Hibernate relazione molti a molti
Cercherò di mantenere una struttura dell'applicazione simile e utilizzerò lo stesso database Apache Derby descritto negli esempi appena citati, in modo che sia chiara la differenza dello sviluppo con e senza l'utilizzo di Spring. La figura seguente descrive la struttura del DB:
Come prima cosa creo un nuovo progetto Maven utilizzando l'archetipo:
maven-archetype-quickstart
, Riporto di seguito le dipendenze del POM.xml
:
<dependency>
<groupid>org.hibernate</groupid>
<artifactid>hibernate-entitymanager</artifactid>
<version>4.2.0.Final</version>
</dependency>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-core</artifactid>
<version>3.2.2.RELEASE</version>
</dependency>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-context</artifactid>
<version>3.2.2.RELEASE</version>
</dependency>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-orm</artifactid>
<version>3.2.2.RELEASE</version>
</dependency>
<dependency>
<groupid>org.apache.derby</groupid>
<artifactid>derbyclient</artifactid>
<version>10.10.1.1</version>
</dependency>
<dependency>
<groupid>junit</groupid>
<artifactid>junit</artifactid>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<groupid>org.hibernate</groupid>
<artifactid>hibernate-entitymanager</artifactid>
<version>4.2.0.Final</version>
</dependency>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-core</artifactid>
<version>3.2.2.RELEASE</version>
</dependency>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-context</artifactid>
<version>3.2.2.RELEASE</version>
</dependency>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-orm</artifactid>
<version>3.2.2.RELEASE</version>
</dependency>
<dependency>
<groupid>org.apache.derby</groupid>
<artifactid>derbyclient</artifactid>
<version>10.10.1.1</version>
</dependency>
<dependency>
<groupid>junit</groupid>
<artifactid>junit</artifactid>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
Dato che il DB è lo stesso e l'applicazione usa Hibernate, le entità utilizzate rimangono le medesime degli esempi sopra citati, per questo motivo riporto solo i nomi delle classi, chi desidera può scaricarle da GitHub:
Utente.java
Dettaglioutente.java
Ufficio.java
Applicazione.java
Passo ora a definire le classi DAO (Data Access Object), ovvero le classi che eseguono l'accesso ai dati del database con operazioni di CRUD (Inserimento, cancellazione, aggiornamento).
Per implementare il DAO ho bisogno dell'
EntityManager
, che viene iniettato direttamente dall' IoC attraverso l'uso della annotation @PersistenceContext
. L’EntityManager
ha il compito di tradurre le entità in record nel database. Se richiediamo l’aggiornamento di un'entità, l'EntityManager
modifica i record corrispondenti del DB, se invece ne richiediamo la cancellazione provvede a rimuoverli. Viceversa quando richiamiamo un record presente nel database, l'EntityManager
crea un oggetto entity bean, lo popola con i dati relazionali e lo restituisce.Il
Persistence Context
gestisce l'insieme di tutte le modifiche e i cambiamenti di stato occorsi sugli oggetti entità invocate tramite EntityManager
in un dato intervallo di tempo. Le classi DAO usano l'annotazione JPA @Transactional
, in questo modo i metodi censiti all'interno di essa eseguiranno un commit
sul database se tutte le istruzioni vanno a buon fine, in caso contrario verrà eseguito un rollback
. Per attivare il comportamento transazionale è necessario inserire l’elemento
<tx:annotation-driven transaction-manager="transactionManager"/>
all'interno del file di applicationcontext.xml
che vedremo più avanti.Riporto i tre servizi per la gestione delle operazioni sulle entità.
package it.test.dao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.transaction.annotation.Transactional;
import it.test.entity.*;
/**
* Implementazione servizio DAO su Ufficio
*
* @author Mauro Cognolato
*/
@Transactional
public class UfficioDaoImpl {
@PersistenceContext
private EntityManager em;
public int save(Ufficio ufficio) {
em.persist(ufficio);
return ufficio.getUfficioId();
}
public void deleteUfficio(Integer id) {
em.remove(getUfficio(id));
}
public Ufficio getUfficio(Integer id) {
return em.find(Ufficio.class, id);
}
public void aggUffUte(Utente ute, Ufficio uff) {
uff.getUtenti().add(ute);
em.merge(uff);
}
public List<Ufficio>getAll() {
return em.createQuery("SELECT p FROM Ufficio p", Ufficio.class).getResultList();
}
}
package it.test.dao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.transaction.annotation.Transactional;
import it.test.entity.*;
* Implementazione servizio DAO su Utente
*
* @author Mauro Cognolato
*/
@Transactional
public class UtenteDaoImpl {
@PersistenceContext
private EntityManager em;
public int save(Utente utente) {
em.persist(utente);
return utente.getuserId();
}
public void deleteUtente(Integer id) {
em.remove(getUtente(id));
}
public Utente getUtente(Integer id) {
return em.find(Utente.class, id);
}
public void aggUte(Utente ute) {
em.merge(ute);
}
public List<Utente>getAll() {
return em.createQuery("SELECT p FROM Utente p", Utente.class).getResultList();
}
public void saveDetUte(Utente ute, Dettaglioutente dettUte) {
ute.setDettaglioutente(dettUte);
dettUte.setUtente(ute);
em.persist(ute);
em.flush();
// riallinea l'entitࡡi valori del DB
em.refresh(ute);
}
}
package it.test.dao; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import org.springframework.transaction.annotation.Transactional; import it.test.entity.Applicazione; /** * Implementazione servizio DAO su Applicazioni * * @author Mauro Cognolato */
@Transactional public class ApplicazioneDaoImpl { @PersistenceContext private EntityManager em; public int save(Applicazione applicazione) { em.persist(applicazione); em.flush(); em.refresh(applicazione); return applicazione.getAppid(); } public void deleteApplicazione(Integer id) { em.remove(getApplicazione(id)); } public void deleteApplicazioni() { List<Applicazione> appes = getAll(); for (Applicazione appe : appes) { em.remove(appe); } } public Applicazione getApplicazione(Integer id) { return em.find(Applicazione.class, id); } public List<Applicazione>getAll() { return em.createQuery("SELECT p FROM Applicazione p", Applicazione.class).getResultList(); } }
Passiamo ai file di configurazione di Spring. Il
persistence.xml
definisce le persistence-unit
, ovvero l'insieme di tutte le classi entità di un singolo Datasource che sono gestite dall'EntityManager
.<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="jpaData" />
</persistence>
ApplicationContext.xml
è il principale file di configurazione di Spring e contiene tutte le specifiche dell'applicazione, analizziamo i bean dichiarati:
come prima cosa notiamo la referenziazione delle classi DAO appena definite.Nell'elemento
DataSource
sono definiti i parametri di connessione al database Derby. In questo esempio sono in chiaro, ma solitamente i valori vengono gestiti in un file di properties
.L'
entityManagerFactory
è responsabile della creazione delle istanze dell'EntityManager
. Essa richiama la classe LocalContainerEntityManagerFactoryBean
che viene configurata per la gestione di JPA e Hibernate. Tra i parametri possiamo notare la definizione della persistent-unit del file persistence.xml
visto in precedenza. Tramite l'entityManagerFactory
appena creato viene definito anche il transactionManager
che coordina la transazionalità delle risorse.<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<tx:annotation-driven />
<context:annotation-config />
<bean id="utenteDao" class="it.test.dao.UtenteDaoImpl" />
<bean id="ufficioDao" class="it.test.dao.UfficioDaoImpl" />
<bean id="applicazioneDao" class="it.test.dao.ApplicazioneDaoImpl" />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>org.apache.derby.jdbc.ClientDriver</value>
<!-- value>org.apache.derby.jdbc.EmbeddedDriver</value -->
</property>
<property name="url">
<value>jdbc:derby://localhost:1527/derby/derbyDB</value>
</property>
<property name="username">
<value>tst</value>
</property>
<property name="password">
<value>test</value>
</property>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="jpaData" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.DerbyDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
</beans>
In conclusione creiamo la classe
app
che contiene il metodo main
per eseguire e testare l'applicazione. Come prima cosa istanzio i servizi Dao, procedo quindi con la definizione degli oggetti entità e la popolazione del database, quindi stampo a video alcuni campi per sincerarmi che le operazioni siano andate a buon fine.
L'utente Rossi Mario vive a Milano e lavora nell'ufficio Vendite
Abilitato all'applicazione: GIS - Sistema territoriale
Abilitato all'applicazione: SAP - Sistema gestionale
Come ultimo step ripulisco il database, da notare che eliminando l'oggetto ufficio di conseguenza vengono eliminati tutti gli utenti associati per i vincoli di constraint.package it.test;
import java.sql.Date;
import java.util.List;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import it.test.dao.UtenteDaoImpl;
import it.test.dao.UfficioDaoImpl;
import it.test.dao.ApplicazioneDaoImpl;
import it.test.entity.Ufficio;
import it.test.entity.Utente;
import it.test.entity.Applicazione;
import it.test.entity.Dettaglioutente;
/**
* Metodo per testare l'applicazione
*
* @author Mauro Cognolato
*/
public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new
ClassPathXmlApplicationContext("applicationContext.xml");
//Istanzio le classi DAO
UtenteDaoImpl daoUte = (UtenteDaoImpl) context.getBean("utenteDao");
UfficioDaoImpl daoUff = (UfficioDaoImpl) context.getBean("ufficioDao");
ApplicazioneDaoImpl daoApp = (ApplicazioneDaoImpl) context.getBean("applicazioneDao");
// Definisco un oggetto Ufficio e gli assegno il valore
Ufficio uff = new Ufficio();
uff.setNomeUfficio("Vendite");
daoUff.save(uff);
int idUff = uff.getUfficioId();
// Istanzio e salvo gli oggetti utente e dettaglioutente
Dettaglioutente dettUte = new Dettaglioutente( new Date(821212), "via Roma 11", "Milano", "0612345678");
Utente ute = new Utente("Mario", "Rossi", "Amministratore");
daoUte.saveDetUte(ute, dettUte);
// Creo gli oggetti Applicazione
Applicazione app1 = new Applicazione("SAP", "Sistema gestionale");
daoApp.save(app1);
Applicazione app2 = new Applicazione("GIS", "Sistema territoriale");
daoApp.save(app2);
// Creo un collegamento tra il nuovo utente e l'ufficio
daoUff.aggUffUte(ute, uff);
// Creo un collegamento tra il nuovo utente e la applicazioni create
ute.getApplicazioni().add(app1);
ute.getApplicazioni().add(app2);
// Aggiorno l'utente
daoUte.aggUte(ute);
// Recupero e stampo a video gli oggetti
List<Utente> utenti = daoUte.getAll();
String nomeUff = uff.getNomeUfficio();
for (Utente utente : utenti) {
System.out.println("L utente " + utente.getCognome() + " " + utente.getNome() + " vive a " + utente.getDettaglioutente().getCitta() + " e lavora nell'ufficio " + nomeUff);
for (Applicazione appx : utente.getApplicazioni()) {
System.out.println("Abilitato all'applicazione: " + appx.getNomeapp() + " - " + appx.getDescrizioneapp());
}
}
// Pulisco il Database
// Eliminando l'oggetto uff elimino anche tutti i dettagli associati
daoUff.deleteUfficio(idUff);
// Elimino le istanze delle applicazioni
daoApp.deleteApplicazioni();
}
}
In questo post ho introdotto l'utilizzo del framework Spring. Nel prossimo esempio inseriremo un framework di presentazione per la visualizzazione e manipolazione dei dati e di conseguenza trasformeremo l'applicazione in web application.
Potete consultare l'intero progetto su GitHub
Hai apprezzato questo post? Conferma le mie competenze o scrivi una segnalazione sul mio profilo Linkedin!
Nessun commento:
Posta un commento