
guide
Tutti i linguaggi per diventare uno sviluppatore di app per Android.
Prosegue la serie per realizzare una app completa con AppFuse. Questa volta implementiamo i servizi (DAO, Service, …)
Nel primo e secondo articolo di questa serie sul framework AppFuse abbiamo svolto diversi compiti importanti per il nostro progetto JobBoard:
Chi ha seguito tutti i passi precedenti avrà già verificato con soddisfazione che molte delle user story in realtà sono già pre-impostate da AppFuse, quindi non ci dilungheremo troppo su questi aspetti, ma ci occuperemo della realizzazione del cuore dell’applicazione, ovvero:
La suddivisione logica che andremo a operare in Model, DAO e Service non è casuale, di fatto è l’architettura utilizzata da tutte le applicazioni enterprise, nessuna esclusa, ovviamente con le variazioni e peculiarità del caso.
In alcuni casi infatti non abbiamo una separazione netta fra due strati adiacenti, ad esempio lo strato DAO a volte va a coincidere con il Model (come nei framework Rails-like), altre volte invece è implicito nel Service.
Questi accorpamenti sono spesso dettati dall’esigenza di risparmiare (meno codice = meno test = risparmio di tempo e denaro), tuttavia siamo convinti che limitino le possibilità di evoluzione del progetto.
Avere strati applicativi distinti e indipendenti infatti consente di “cambiare idea” quando il progetto è già in uno stadio avanzato, senza costringere a dover ripensare tutta l’applicazione da capo!
AppFuse adotta in pieno questa filosofia, è infatti organizzato secondo l’architettura classica che abbiamo esposto.
AppFuse fornisce in partenza due classi del modello, entrambe nel package org.appfuse.model
: User e Role. Il loro sorgente però non è nella directory del progetto, ovvero in src/main/java
, perché sono contenute in una libreria. Nel caso abbiate intenzione di modificare queste o altre classi del progetto è possibile eseguire il comando full-source, come spiegato sulla documentazione ufficiale.
Creiamo ora le nostre prime entity nel package it.html.jobboard.model
. Ecco il sorgente della classe Company:
package it.html.jobboard.model;
import javax.persistence.*;
@Entity
@Table(name = "companies")
public class Company {
private Long id;
private String name;
public Company() {}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
@Basic(optional = false)
public String getName() {
return name;
}
// TODO: altri getter/setter ...
}
La classe JobOffer sarà invece simile allo snippet seguente:
@Entity
@Table(name = "job_offers")
public class JobOffer {
public enum ContractType {
PERMANENT,
TEMPORARY_CONTRACT
}
public JobOffer() {}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
@ManyToOne(optional = false)
public Company getCompany() {
return company;
}
@Basic(optional = false)
public String getTitle() {
return title;
}
@Enumerated(EnumType.STRING)
@Basic(optional = false)
public ContractType getContractType() {
return contractType;
}
// TODO: altri getter/setter ...
}
Vediamo a questo punto alcune delle loro caratteristiche principali:
@Entity
, @Table
, eccetera;@GeneratedValue(strategy = GenerationType.AUTO)
;@ManyToOne
) da JobOffer a Company;ContractType
va configurata con @Enumerated(EnumType.STRING)
per salvarla sotto forma di stringa, in caso contrario verrebbe salvato il suo ordinale;@Basic(optional = false)
indica che la proprietà (e quindi la colonna sul database) non può avere valore NULL.Le possibilità di mapping offerte da JPA e le estensioni di Hibernate sono davvero molte e sofisticate, ma già con questi elementi basilari siamo in grado di creare uno schema di database non banale, con foreign key e vincoli di non-nullità.
Fortunatamente grazie a Maven e ad un plugin di Hibernate è sufficiente eseguire un comando Maven per creare tutte le tabelle e le relazioni
mvn hibernate3:hbm2ddl
In ogni caso, questa fase è inserite nel processo di build generale e viene eseguita ogni volta, in modo da ricreare da zero il database e ri-testare tutto in un ambiente pulito e soprattutto prevedibile. Dopo ogni build quindi, avremo lo schema job_board aggiornato sul database MySql. Controllate!
Ecco uno schema delle tabelle create, con tanto di relazioni:
Nella prossima parte implementeremo anche gli oggetti DAo e finalmente i servizi veri e propri
A questo punto possiamo creare gli oggetti DAO, che si occuperanno di eseguire le query vere e proprie sul database: ricerca, lettura, salvataggio.
In un certo senso sono lo strato applicativo che si “sporca le mani” più degli altri, perché deve nascondere tutta la complessità di Hibernate e JDBC e mostrare allo strato superiore (il Service layer) solamente dei semplici metodi Java.
Questo approccio facilità senza dubbio la manutenibilità del codice nei vari layer, che non devono conoscere esattamente cosa succede nello strato sottostante e possono così occuparsi solamente delle proprie responsabilità.
Per rafforzare questo aspetto si usa creare almeno due sorgenti per ogni oggetto, sia nel DAO che nel Service layer: l’interfaccia e una (o più) implementazioni.
Ecco quindi l’interfaccia it.html.jobboard.dao.JobBoardDao
:
public interface JobBoardDao {
/**
* Ricerca offerte di lavoro, mostra prima le più recenti.
* @return lista di {@link JobOffer}
*/
List<JobOffer> findAllJobOffer();
}
In pieno stile Agile svilupperemo i test prima delle implementazioni, come dettato dalle regole del Test-driven development. Quello che a prima vista può sembrare un controsenso è in realtà un ottimo modo per:
Ecco quindi il test per JobBoardDao, da salvare in una sotto-directory di src/test/java
:
public class JobBoardDaoTest extends BaseDaoTestCase {
JobBoardDao jobBoardDao;
@Autowired
public void setJobBoardDao(JobBoardDao jobBoardDao) {
this.jobBoardDao = jobBoardDao;
}
@Test
public void test_findAllJobOffer() {
List<JobOffer> result = jobBoardDao.findAllJobOffer();
assertEquals(4, result.size());
// controlla l'ordine dei risultati
assertEquals(4L, result.get(0).getId().longValue());
// ...
}
}
Notiamo subito alcuni particolari:
org.appfuse.dao.BaseDaoTestCase
ci permette di sfruttare l’auto-wiring di Spring, replicando ciò che succede a runtime. In questo modo i test vengono eseguiti in un ambiente del tutto simile a quello “vero”;@Autowired
per l’appunto indica a Spring che desideriamo ricevere l’istanza di JobBoardDao
già configurata;import static org.junit.Assert.*
ci permette di utilizzare i vari metodi di asserzione di questa classe, come assertEquals()
, assertTrue()
, eccetera.Inoltre il test sembra dare per scontato che ci siano dei dati di prova, già inseriti da qualche parte nel database: questi sono nel file src/test/resources/sample-data.xml
, utilizzato dal plugin DbUnit durante il build per popolare le tabelle. Aggiungiamo quindi le sezioni <table name="companies">
e <table name="job_offers">
a questo file, che purtroppo comincerà ad essere davvero molto verboso e un po’ difficile da seguire:
[...]
<table name="companies">
<column>id</column>
<column>name</column>
<row>
<value description="id">1</value>
<value description="name">Company A</value>
</row>
<row>
<value description="id">2</value>
<value description="name">Company B</value>
</row>
</table>
<table name="job_offers">
<column>id</column>
<column>creationDate</column>
<column>company_id</column>
<column>contractType</column>
<column>country</column>
<column>title</column>
<column>description</column>
<row>
<value description="id">1</value>
<value description="creationDate">2012-02-01 11:36:55.0</value>
<value description="company_id">1</value>
<value description="contractType">PERMANENT</value>
<value description="country">Italia</value>
<value description="title">Job Offer 1</value>
<value description="description">Descrizione Job Offer 1</value>
</row>
[...]
</table>
Ecco infine l’implementazione del DAO, it.html.jobboard.dao.hibernate.JobBoardDaoImpl
:
package it.html.jobboard.dao.hibernate;
@Repository
public class JobBoardDaoImpl extends HibernateDaoSupport implements JobBoardDao {
@Autowired
public void init(SessionFactory factory) {
setSessionFactory(factory);
}
public List<JobOffer> findAllJobOffer() {
return getHibernateTemplate().find("from JobOffer o order by o.creationDate desc");
}
}
Da notare che abbiamo inserito questa classe in un sotto-package hibernate; in questo modo la suddivisione fra le varie (eventuali) altre implementazioni come jdbc, EJB, eccetera, è ancora più esplicita.
Alcune osservazioni:
@Repository
istruisce Spring sul fatto che questo componente sia un DAO, e che va inizializzato con un’opportuna SessionFactory
;init()
;getHibernateTemplate()
per ottenere un HibernateTemplate
, classe di Spring che fa da tramite con le API di Hibernate;HibernateTemplate è una classe di utilità di Spring che facilita l’utilizzo di Hibernate, nascondendone a sua volta la complessità e permettendoci di scrivere solo il codice strettamente necessario, come la query dell’esempio.
Siamo giunti allo strato Service, che nel nostro caso sarà solamente un passacarte, vista la semplicità quasi banale dei metodi realizzati finora. Avremo quindi l’interfaccia JobBoardService:
package it.html.jobboard.service;
public interface JobBoardService {
/**
* Ricerca offerte di lavoro, mostra prima le più recenti.
* @return lista di {@link JobOffer}
*/
List<JobOffer> findAllJobOffer();
}
Il test JobBoardServiceTest:
package it.html.jobboard.service;
public class JobBoardServiceTest extends BaseManagerTestCase {
JobBoardService jobBoardService;
@Autowired
public void setJobBoardService(JobBoardService jobBoardService) {
this.jobBoardService = jobBoardService;
}
@Test
public void test_findAllJobOffer() {
List<JobOffer> result = jobBoardService.findAllJobOffer();
assertTrue(result.size() >= 0);
}
}
L’implementazione JobBoardServiceImpl:
package it.html.jobboard.service.spring;
@Service
@Transactional
public class JobBoardServiceImpl implements JobBoardService {
private JobBoardDao jobBoardDao;
@Autowired
public void setJobBoardDao(JobBoardDao jobBoardDao) {
this.jobBoardDao = jobBoardDao;
}
public List<JobOffer> findAllJobOffer() {
return jobBoardDao.findAllJobOffer();
}
}
Ora è sufficiente eseguire un build per verificare che tutto sia perfettamente funzionante:
mvn package
Come stiamo verificando, sviluppare i vari servizi applicativi in maniera indipendente ci permette di concentrarci sul buon funzionamento dei singoli componenti, facendo addirittura risparmiare tempo perché non vi è la necessità di mettere in piedi tutta la filiera per avere l’applicazione completa sul browser (database, servizi, controller web, pagine jsp, javascript, ecc.). Nei prossimi appuntamenti vedremo come, arrivati a questo punto, sia molto facile realizzare la parte web e aggiungere altre funzionalità.
Se vuoi aggiornamenti su AppFuse: realizzare un'applicazione completa inserisci la tua email nel box qui sotto:
Compilando il presente form acconsento a ricevere le informazioni relative ai servizi di cui alla presente pagina ai sensi dell'informativa sulla privacy.
La tua iscrizione è andata a buon fine. Se vuoi ricevere informazioni personalizzate compila anche i seguenti campi opzionali:
Compilando il presente form acconsento a ricevere le informazioni relative ai servizi di cui alla presente pagina ai sensi dell'informativa sulla privacy.
Cos’è una “cloud app” e cosa significa avere una infrastruttura capace di scalare all’infinito e crescere o decrescere in base […]
Tutti i linguaggi per diventare uno sviluppatore di app per Android.
Come creare applicazioni per il Web con PHP e MySQL per il DBMS.
Tutte le principali tecnologie per diventare uno sviluppatore mobile per iOS.
I fondamentali per lo sviluppo di applicazioni multi piattaforma con Java.
Diventare degli esperti in tema di sicurezza delle applicazioni Java.
Usare Raspberry Pi e Arduino per avvicinarsi al mondo dei Maker e dell’IoT.
Le principali guide di HTML.it per diventare un esperto dei database NoSQL.
Ecco come i professionisti creano applicazioni per il Cloud con PHP.
Lo sviluppo professionale di applicazioni in PHP alla portata di tutti.
Come sviluppare applicazioni Web dinamiche con PHP e JavaScript.
Fare gli e-commerce developer con Magento, Prestashop e WooCommerce.
Realizzare applicazioni per il Web utilizzando i framework PHP.
Creare applicazioni PHP e gestire l’ambiente di sviluppo come un pro.
Percorso base per avvicinarsi al web design con un occhio al mobile.
Realizzare siti Web e Web application con WordPress a livello professionale.
Impariamo ad utilizzare Takamaka, una blockchain Java Full Stack, per scrivere codice Java installabile ed eseguibile su una blockchain
In questo articolo impareremo a gestire gli URL (Uniform Resource Locator) attraverso le API messe a disposizione dal linguaggio di programmazione Java.
Java 13: In questo articolo andiamo a presentare le nuove caratteristiche introdotte dalla release elencandole in base al codice JEP che le identifica.
Impariamo a sviluppare applicazioni Java per i sistemi Embedded, piattaforme che a differenza delle tradizionali soluzioni general purpose vengono progettate per svolgere compiti specifici. Nel corso delle guida verranno fornite le nozioni necessarie per installare Oracle Java SE Embedded, scegliere il profilo e la JVM da utilizzare, configurare una JRE personalizzata, creare una prima App ed effettuarne il deploy