domenica 7 novembre 2010

JPA con Spring, Hibernate su JBoss

In questo post voglio illustrare il modo più semplice per utilizzare JPA tramite Spring in una web-application che usa come framework MVC Struts2.

Ovviamente nel mio caso estenderò Struts2Tutorial il quale, se avete letto i mie precedenti tutorial su queste tecnologie, dovreste conoscere e che metto in allegato al post con le nuove implementazioni...

Aggiungeremo un nuovo servizio di gestione dei contatti cioè che prevede le classiche funzioni di inserimento, ricerca, modifica e eliminazione (dette anche operazioni CRUD) di una Persona e dei suoi relativi Recapiti.

Non voglio scendere nel tecnico ma vedere i passi per configurare e utilizzare JPA con Spring su JBOSS darò per scontato alcune nozioni su tali framework.

Prima di procedere dovete configurare l'ambiente di sviluppo.

Dato l'utilizzo di JPA e delle transazioni mi era necessario utilizzare un application server che supportasse la transazionalità senza nessuna configurazione particolare. Ho scelto JBOSS 4.2.2 GA quindi il mio tutorial si basa su quest'ultimo ma potete sceglierne un'altro qualsiasi.

Benissimo ora fate in modo di configurare il vostro progetto affinchè possa essere compilato con le librerie di jboss del profilo default.

Nella cartella web-inf/lib del progetto web devono essere presenti le seguenti librerie:

  • aopalliance.jar
  • commons-beanutils-1.7.0.jar
  • commons-digester-2.0.jar
  • commons-fileupload-1.2.1.jar
  • commons-logging-1.0.4.jar
  • dom4j-1.6.1.jar
  • freemarker-2.3.15.jar
  • log4j-1.2.15.jar
  • mysql-connector-java-5.1.12-bin.jar
  • ognl-2.7.3.jar
  • slf4j-api-1.5.8.jar
  • slf4j-log4j12-1.5.0.jar
  • spring-aop.jar
  • spring-beans-2.5.6.jar
  • spring-context-2.5.6.jar
  • spring-core-2.5.6.jar
  • spring-jdbc.jar
  • spring-orm.jar
  • spring-tx.jar
  • spring-web-2.5.6.jar
  • struts2-core-2.1.8.1.jar
  • struts2-spring-plugin-2.1.8.1.jar
  • struts2-tiles-plugin-2.1.8.1.jar
  • tiles-api-2.0.6.jar
  • tiles-core-2.0.6.jar
  • tiles-jsp-2.0.6.jar
  • xwork-core-2.1.6-modified.jar
Se notate l'ultima libreria ci stà un modified perche ho dovuto modificarla per una sua incompatibilità con jboss. Comunque trovate il motivo e la modifica in questo mio precedente post:

JBoss, Hibernate, JPA, Spring, Struts2: Javassist Enhancement failed



Configurato l'ambiente di lavoro passiamo allo sviluppo.

La prima cosa da fare è configurare tale integrazione...

Come sapete JPA utilizza un suo file di configurazione XML chiamato persistence.xml quindi create una cartella META-INF nella root dei sorgenti (src/META-INF) e create al suo interno il file persistence.xml con il seguente contenuto:



come vedete nel nostro caso lo lasciamo vuoto senza nessuna configurazione diamo solo il nome al persistence-unit. Faremo in modo che sia spring a configurare JPA con il suo file di configurazione.

Configuriamo ora spring ecco l'applicationContext.xml necessario:



Allora nel XML di Spring abbiamo configurato un bean con il nome dataSource il quale si occuperà della connessione e comunicazione con il db instanziando la classe di Spring DriverManagerDataSource e fornendogli i parametri necessari.

Abbiamo defnito un'altro bean di nome entityManagerFactory che instanzia una classe di tipo LocalContainerEntityManagerFactoryBean. Tale tipo è la più semplice da utilizzare ma Spring ne mette a disposizione altre a secondo dell'architettura del vostro software e della gestione delle transazioni che avete scelto.
A tale bean gli abbiamo settato il datasource precedentemente definito.
Gli abbiamo detto quale jpaVendorAdapter utilizzare nel nostro caso uno di tipo HibernateJpaVendorAdapter dato che useremo come ORM Hibernate.
Nei parametri del jpaVendorAdapter gli abbiamo detto il tipo di database (MySql) , di generare automaticamente il ddl e di visualizzare l'sql nei log.
Come ultima proprietà del entityManagerFactory gli abbiamo settato jpaProperties definendo il dialetto da utilizzare e di generare ed eliminare le tabelle necessarie su db ad ogni esecuzione e stop dell'application server. Ovviamente io ho usato questa per comodità in modo da non dover rigenerare tt il db ad ogni modifica ;) , ma se non volete ciò basta mettere come valore del parametro update .

Con abbiamo detto a Spring che la transazionalità sarà definita tramite annotation nelle classi.

In fine abbiamo definito il bean transactionManager di tipo JpaTransactionManager che si occupa di gestire la transazione dicendogli quale è l'entityManagerFactory ossia quello creato precedentemente.

Come vedete tt la configurazione di JPA sta nel file d configurazione di Spring. Il resto che vedete nel file non centra con JPA, ma se volete sapere a che servono guardate i miei precedenti post.

Infine per completare la configurazione dobbiamo inserire il filtro OpenEntityManagerInViewFilter nel web.xml

Il filtro serve a mappare su quali richieste Spring deve instanziare l'entityManager. Di seguito il contenuto del web.xml aggiornato:




Ora passiamo al modello dati e da ora in poi, dato che lo scopo era mostrare come integrare JPA con Spring, sarò meno descrittivo tranne che per alcune accortezze.
I dati che andremo a gestire sono Persona e Recapito. Dove una persona può avere più recapiti. Ecco le classi:

Persona.java


Come vedete è un semplice Pojo che ha come attributi id,nome, cognome, e una lista di recapiti. Per mappare l'oggetto abbiamo usato le annotation di JPA, ne farò un ripasso generale per approfondire andate sulla documentazione ufficiale:
  • @Entity gli abbiamo detto che è un entità su db ed in questo caso (non spqcificando la tabella) sarà creata o comunque mappata su una tabella col nome Persona.
  • @Id abbiamo detto che l'attributo è la chiave primaria.
  • @GeneratedValue serve per definire la strategia di generazione degli id nel nostro caso auto, cioè sara il db a generarli.
  • @Column indichiamo che l'attributo è un campo della tabella
  • @OneToMany abbiamo definito una associazione uno a molti.
  • @JoinTable serve per dire che nell'associazione sarà utilizzata una tabella di join
Recapito.java


Ci sono le stesse annotation tranno @ManyToOne che indica una associazione una a molti e joinTable che punte alla stessa tabella di join di pima.

Il risultato del modello dati su db sarà il seguente:


Definito il modello passiamo alla classe PersonaDao. Ecco l'interfaccia:


quindi l'interfaccia prevede i seguenti metodi:
  • salvataggio o modifica di una persona
  • rimozione di una persona
  • ricerca di una persona
  • recupero di tutte le persone
  • aggiunta di un recapito ad una perona
  • remozione di un recapito
Data la semplicità del modello ho creato un unico dao sia per Persona che per Recapito.
Ed ecco la sua implementazione PersonaDaoImpl:


Prima di descrivere altro guardate le righe dalla 29 all 34 abbiamo definito l'entityManager e il suo metodo set il quale sarà utilizzato da Spring per settare l'entityManager presente nel file di configurazione. Tale settaggio sarà eseguito da Spring poichè abbiamo messo sul metodo l'annotation @PersistenceContext.

Fate attenzione poi alla riga 25 è presente l'annotation @Transactional. Mettendola come in questo caso come annotazione di classe abbiamo detto a Spring che ogni metodo in essa definito è di tipo transazionale. Cioè ogni transazione si avvia e si chiude rispetivamente all'invocazione e uscita del metodo. Ma possiamo anche definire una transazione a livello di metodo usando l'annotazione come annotazione di metodo.
In ogni caso non è detto che la transazionalità sia definita nel dao, ma può essere anche definita in una classe che richiama il dao (quidi a livello ancora superiore) in una classe che fa da business-logic o domain del servizio.

Come vedete l'entity manager offre metodi per l'accesso in lettura e in scrittura su db come persist (nuovo oggetto), merge(aggiornamento di un oggetto), find(lettura di un oggetto), createQuery per select particolari ecc... ma ce ne stanno altri.

Per ultima cosa fate attenzione all'implementazione dei metodi che accedono in scrittura. Fanno bene attenzione che prima di persistere o modificare un oggetto questo sia ben consistente con tutti gli altri oggetti che esso ha come attributi.

Ora ecco la ContattiBl ossia la classe che fa da domain o business logic del servizio contatti e che urilizza al suo interno PersonaDao:


Nel progetto l'ho utilizzata richiamandola nelle action di Struts2 ma questa parte ve la ometto ormai dovreste essere padroni di struts2 grazie ai miei tutorial :P Potete scaricare il progetto qui senza librerie.

Nessun commento:

Posta un commento