Skip to content

16. Applicazione Web MVC in un'architettura a 3 livelli – Esempio 2

16.1. Introduzione

Abbiamo scritto l'applicazione [people-01] con la seguente struttura:

Il livello [dao] ha implementato l'elenco delle persone gestite utilizzando un oggetto [ArrayList]. Questo ci ha permesso di evitare di complicare eccessivamente i livelli [dao] e [service], in modo da poterci concentrare sul livello [web]. Vogliamo far evolvere l'applicazione verso un ambiente più realistico in cui l'elenco delle persone venga memorizzato in una tabella del database. Ciò richiederà una modifica del livello [dao], con ripercussioni sugli altri due livelli. Per sfruttare l'indipendenza dei livelli offerta da Spring IoC, prenderemo l'applicazione [people-01] e la configureremo con Spring IoC:

La nuova applicazione si chiamerà [people-02]. Una volta scritta, sappiamo che saremo in grado di modificare i livelli [DAO] e [service] senza cambiare il codice nel livello [web]. Questo è esattamente ciò a cui miriamo.

Creiamo un nuovo progetto Eclipse [people-02] copiando e incollando il progetto [people-01], come spiegato nella sezione 6.2:

In [1] vediamo apparire il file di configurazione, nel quale definiremo i bean per i livelli [dao] e [service]. Il suo contenuto è il seguente:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <!-- the dao class -->
    <bean id="dao" class="istia.st.mvc.personnes.dao.DaoImpl" init-method="init"/>
    <!-- service class -->
    <bean id="service" class="istia.st.mvc.personnes.service.ServiceImpl">
        <property name="dao">
            <ref local="dao" />
        </property>
    </bean>
</beans>
  • Riga 5: definisce il bean denominato [dao] come istanza della classe [DaoImpl]. Dopo l'istanziazione, viene eseguito il metodo [init] dell'istanza.
  • Righe 7–10: definiscono il bean denominato [service] come istanza della classe [ServiceImpl].
  • Righe 8–10: la proprietà [dao] dell'istanza [DaoImpl] viene inizializzata con il riferimento al livello [dao] creato alla riga 5. Ricordiamo che la classe [ServiceImpl] possiede effettivamente la proprietà [dao] e il corrispondente setter:
public class ServiceImpl implements IService {

    // the [dao] layer
    private IDao dao;

    public IDao getDao() {
        return dao;
    }

    public void setDao(IDao dao) {
        this.dao = dao;
    }
...

Ovviamente, questo file da solo non fa nulla. Il controller [Application] lo utilizzerà nel suo metodo [init] per istanziare il livello [service]. Ricordiamo la versione precedente del metodo [init] del controller:

@SuppressWarnings("serial")
public class Application extends HttpServlet {
...
    // service
    ServiceImpl service = null;

    // init
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
...
        // dao] layer instantiation
        DaoImpl dao = new DaoImpl();
        dao.init();
        // instantiation of the [service] layer
        service = new ServiceImpl();
        service.setDao(dao);
    }

Alla riga 5, abbiamo dovuto specificare esplicitamente il nome della classe di implementazione del livello [service], mentre alla riga 12 quello del livello [dao]. Con Spring IoC, il metodo [init] diventa il seguente:

@SuppressWarnings("serial")
public class Application extends HttpServlet {
    // instance parameters
    ...

    // service
    private IService service = null;

    // init
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
    ...
        // instantiation of the [service] layer
        service = (IService) new XmlBeanFactory(new ClassPathResource("spring-config.xml")).getBean("service");
    }
  • riga 7: il campo privato [service] non è più di tipo [ServiceImpl] ma di tipo [IService], ovvero del tipo dell'interfaccia del livello [service]. Il livello [web] non è quindi più legato a una specifica implementazione di questa interfaccia.
  • riga 14: inizializzazione del campo [service] dal file di configurazione [spring-config.xml].

Queste sono le uniche modifiche da apportare. Integriamo questa nuova applicazione in Tomcat, avviamola e poi richiediamo l'URL [http://localhost:8080/personnes-02]:

Image

16.2. Archiviazione dell'applicazione web

Abbiamo sviluppato un progetto Eclipse/Tomcat per un'applicazione a tre livelli:

In una versione futura, il gruppo di persone verrà memorizzato in una tabella del database.

  • Ciò richiederà una riscrittura del livello [DAO]. È facile da capire.
  • Anche il livello [service] verrà modificato. Attualmente, il suo unico ruolo è garantire l’accesso sincronizzato ai dati gestiti dal livello [dao]. A tal fine, abbiamo sincronizzato tutti i metodi nel livello [service]. Abbiamo spiegato perché questa sincronizzazione è stata collocata in questo livello piuttosto che nel livello [DAO]. Nella nuova versione, il livello [service] avrà ancora il solo ruolo di sincronizzare l'accesso, ma ciò sarà gestito dalle transazioni del database piuttosto che dalla sincronizzazione dei metodi Java.
  • Il livello [web] rimarrà invariato.

Per facilitare il passaggio da una versione all'altra, stiamo creando un nuovo progetto Eclipse [mvc-personnes-02B], una copia del progetto precedente [mvc-personnes-02] ma in cui i livelli [web, service, dao, entities] sono stati inseriti in archivi .jar:

La cartella [src] ora contiene solo il file di configurazione Spring [spring-config.xml]. In precedenza conteneva anche il codice sorgente delle classi Java. Questi elementi sono stati rimossi e sostituiti dalle loro versioni compilate inserite negli archivi [people-*.jar] mostrati in [1]:

Il progetto [mvc-personnes-02B] è stato configurato per includere gli archivi [personnes-*.jar] nel proprio ClassPath.

Distribuiamo il progetto web [mvc-personnes-02B] all'interno di Tomcat:

Per testare il progetto, avviamo Tomcat e quindi richiediamo l'URL [http://localhost:8080/personnes02B]:

Image

Il lettore è invitato a eseguire ulteriori test.

Nella versione con database, modificheremo i livelli [service] e [dao]. Vogliamo dimostrare che sarà quindi sufficiente sostituire gli archivi [personnes-dao.jar] e [personnes-service.jar] del progetto precedente con i nuovi archivi affinché la nostra applicazione funzioni ora con un database. Non sarà necessario modificare gli archivi del livello [web] e del livello [entities].