Skip to content

1. Informazioni generali

Il PDF del documento è disponibile |QUI|.

1.1. Obiettivi

In questa sede ci proponiamo di scoprire un metodo di sviluppo denominato STRUTS. Jakarta Struts è un progetto dell’Apache Software Foundation (www.apache.org) che ha lo scopo di fornire un framework standard per lo sviluppo di applicazioni web in Java che rispetti l’architettura denominata MVC (Modello-Vista-Controllore).

1.2. Il modello MVC

Il modello MVC mira a separare i livelli di presentazione, elaborazione e accesso ai dati. Un’applicazione web che rispetta questo modello sarà strutturata nel modo seguente:

Tale architettura è denominata a 3 livelli o a 3 strati:

  • l’interfaccia utente è il V (la vista)
  • la logica applicativa è la C (il controller)
  • le fonti di dati sono la M (Modello)

L'interfaccia utente è spesso un browser web, ma può anche essere un'applicazione autonoma che, tramite la rete, invia richieste HTTP al servizio web e formatta i risultati che quest'ultimo le restituisce. La logica applicativa è costituita dagli script che elaborano le richieste dell'utente. La fonte dei dati è spesso un database, ma può trattarsi anche di semplici file di testo, una directory LDAP, un servizio web remoto, ecc. È nell’interesse dello sviluppatore mantenere un’ampia indipendenza tra queste tre entità, in modo che, qualora una di esse cambi, le altre due non debbano subire modifiche o ne subiscano solo in misura minima.

Quando si cerca di applicare questo modello con servlet e pagine JSP, si ottiene la seguente architettura:

Nel blocco [Logique Applicative] si distinguono

  • il servlet, che funge da punto di ingresso dell’applicazione e viene anche chiamato controller
  • il blocco [Classes métier], che raggruppa le classi Java necessarie alla logica dell’applicazione;
  • il blocco [Classes d'accès aux données], che raggruppa le classi Java necessarie per ottenere i dati richiesti dal servlet, spesso dati persistenti (BD, file, servizio WEB, ...)
  • il blocco delle pagine JSP che costituiscono le viste dell'applicazione.

1.3. Un approccio di sviluppo MVC che utilizza servlet e pagine JSP

Abbiamo definito un approccio per lo sviluppo di applicazioni web Java che rispetta il modello MVC sopra descritto. Lo riportiamo qui di seguito.

  1. Si inizierà definendo tutte le viste dell’applicazione. Queste sono le pagine web presentate all’utente. Ci si porrà quindi dal punto di vista dell’utente per progettare le viste. Si distinguono tre tipi di viste:
    • il modulo di inserimento dati, che serve a ottenere informazioni dall’utente. Di solito è dotato di un pulsante per inviare le informazioni inserite al server.
    • la pagina di risposta, che serve esclusivamente a fornire informazioni all’utente. Spesso dispone di un link che consente all’utente di proseguire l’applicazione con un’altra pagina.
    • la pagina mista: il servlet ha inviato al client una pagina contenente informazioni da esso generate. Questa stessa pagina servirà al client per fornire al servlet ulteriori informazioni.
  1. Ogni vista darà origine a una pagina JSP. Per ciascuna di esse:
    • si definirà l’aspetto della pagina
    • si determineranno quali sono le parti dinamiche della stessa:
      • le informazioni destinate all’utente che dovranno essere fornite dalla servlet come parametri alla vista JSP
      • i dati inseriti che dovranno essere trasmessi al servlet per l’elaborazione. Questi dovranno far parte di un modulo HTML.
  1. È possibile schematizzare gli input e gli output di ciascuna vista
    • gli ingressi sono i dati che il servlet dovrà fornire alla pagina JSP, sia nella richiesta (request) che nella sessione (session).
    • Le uscite sono i dati che la pagina JSP dovrà fornire al servlet. Fanno parte di un modulo HTML e il servlet li recupererà tramite un’operazione del tipo request.getparameter(...).
  1. Scriveremo il codice Java/JSP di ciascuna vista. Nella maggior parte dei casi avrà la seguente forma:
<%@ page ... %>    // importazioni di classi più frequenti
<%!
     // variabili di istanza della pagina JSP (=globali)
     // necessario solo se la pagina JSP ha metodi che condividono variabili (raro)     
    ...    
%>
<%
     // recupero dei dati inviati dal servlet
     // sia nella richiesta (request) che nella sessione (session)
    ...
%>

<html>
...
         // qui si cercherà di ridurre al minimo il codice Java
</html>
  1. A questo punto è possibile procedere con i primi test. Il metodo di distribuzione illustrato di seguito è specifico per il server Tomcat:
    • il contesto dell’applicazione deve essere creato nel file server.xml di Tomcat. Si potrà iniziare testando questo contesto. Indichiamo con C questo contesto e con DC la cartella ad esso associata. Creeremo un file statico test.html che inseriremo nella cartella DC. Dopo aver avviato Tomcat, si richiederà tramite un browser l’indirizzo http://localhost:8080/DC/test.html.
    • È possibile testare ogni pagina JSP. Se una pagina JSP si chiama formulaire.jsp, si richiederà tramite un browser l'indirizzo http://localhost:8080/DC/formulaire.jsp. La pagina JSP si aspetta dei valori dal servlet che la chiama. In questo caso la si chiama direttamente, quindi non riceverà i parametri previsti. Affinché i test siano comunque possibili, inizializzeremo noi stessi nella pagina JSP i parametri previsti utilizzando delle costanti. Questi primi test consentono di verificare che le pagine JSP siano sintatticamente corrette.
  1. Si scrive quindi il codice del servlet. Questo presenta due metodi ben distinti:
    • il metodo init, che serve a:
      • recuperare i parametri di configurazione dell’applicazione dal file web.xml della stessa
      • creare eventualmente istanze delle classi di business che dovrà utilizzare in seguito
      • gestire un eventuale elenco di errori di inizializzazione che verrà restituito ai futuri utenti dell’applicazione. Tale gestione degli errori può arrivare fino all’invio di un’e-mail all’amministratore dell’applicazione per avvisarlo di un malfunzionamento
    • il metodo doGet o doPost a seconda del modo in cui il servlet riceve i parametri dai propri clienti. Se il servlet gestisce più moduli, è opportuno che ciascuno di essi invii un’informazione che lo identifichi in modo univoco. Ciò può avvenire tramite un attributo nascosto nel modulo del tipo <input type="hidden" name="action" value="...">. La servlet può iniziare leggendo il valore di questo parametro e poi delegare l'elaborazione della richiesta a un metodo privato interno incaricato di gestire questo tipo di richiesta.
    • Si eviterà il più possibile di inserire codice di business nel servlet. Non è stato progettato per questo. Il servlet è una sorta di caposquadra (controller) che riceve le richieste dai propri clienti (clienti web) e le fa eseguire dalle persone più adatte (le classi di business). Durante la scrittura del servlet, si definirà l’interfaccia delle classi di business da implementare (costruttori, metodi). Ciò vale nel caso in cui tali classi di business debbano essere create. Se invece esistono già, il servlet dovrà adattarsi all’interfaccia esistente.
    • Il codice del servlet verrà compilato.
  1. Si scriverà lo scheletro delle classi di business necessarie alla servlet. Ad esempio, se la servlet utilizza un oggetto di tipo proxyArticles e tale classe deve disporre di un metodo getCodes che restituisce un elenco (ArrayList) di stringhe di caratteri, in una prima fase ci si può limitare a scrivere:
public ArrayList getCodes(){
    String[] codes= {"code1","code2","code3"};
    ArrayList aCodes=new ArrayList();
    for(int i=0;i<codes.length;i++){
        aCodes.add(codes[i]);
    }
        return aCodes;
}
  1. A questo punto è possibile procedere con i test del servlet.
    • È necessario creare il file di configurazione web.xml dell'applicazione. Deve contenere tutte le informazioni richieste dal metodo init del servlet (<init-param>). Inoltre, si imposta il URL attraverso il quale verrà raggiunto il servlet principale (<servlet-mapping>).
    • Tutte le classi necessarie (servlet, classi di business) vengono collocate in WEB-INF/classes.
    • Tutte le librerie di classi (.jar) necessarie sono collocate in WEB-INF/lib. Queste librerie possono contenere classi di business, driver JDBC, ...
    • Le viste JSP sono collocate nella directory principale dell’applicazione o in una cartella dedicata. Lo stesso vale per le altre risorse (html, immagini, audio, video, ...)
    • Una volta fatto ciò, l'applicazione viene testata e vengono corretti i primi errori. Al termine di questa fase, l'architettura dell'applicazione è operativa. Questa fase di test può risultare complessa, dato che con Tomcat non si dispone di strumenti di debug. A tal fine, Tomcat dovrebbe essere integrato in uno strumento di sviluppo (JBuilder Developer, Sun One Studio, ...). Si potrà ricorrere alle istruzioni System.out.println("....") che scrivono nella finestra di Tomcat. La prima cosa da verificare è che il metodo init recuperi correttamente tutti i dati provenienti dal file web.xml. A tal fine, si può scrivere il valore di tali dati nella finestra di Tomcat. Allo stesso modo, si verificherà che i metodi doGet e doPost recuperino correttamente i parametri dei diversi moduli HTML dell’applicazione.

Si scrivono le classi di business necessarie al servlet. Si tratta in genere dello sviluppo classico di una classe Java, il più delle volte indipendente da qualsiasi applicazione web. Essa verrà innanzitutto testata al di fuori di questo ambiente, ad esempio con un’applicazione da console. Una volta scritta una classe di business, è possibile integrarla nell’architettura di distribuzione dell’applicazione web e verificarne la corretta integrazione al suo interno. Si procederà in questo modo per ogni classe di business.

1.4. Il processo di sviluppo STRUTS

Gli ideatori della metodologia STRUTS hanno cercato di definire un metodo di sviluppo standard che rispetti l’architettura MVC per le applicazioni web scritte in Java. Il progetto STRUTS presenta due aspetti:

  • il metodo di sviluppo. Vedremo che è abbastanza simile a quello descritto sopra per i servlet e le pagine JSP
  • gli strumenti che ci consentono di applicare questo metodo di sviluppo. Si tratta di librerie di classi Java disponibili sul sito della Fondazione Apache (www.apache.org).

1.4.1. Il metodo di sviluppo

L’architettura MVC utilizzata da STRUTS è la seguente:

  • il controller è il cuore dell’applicazione. Tutte le richieste del client passano attraverso di esso. Si tratta di un servlet generico fornito da STRUTS. In alcuni casi potrebbe essere necessario derivarla. Per i casi semplici, ciò non è necessario. Questa servlet generica preleva le informazioni di cui ha bisogno da un file solitamente denominato struts-config.xml.
  • Se la richiesta del client contiene parametri di modulo, questi vengono inseriti in un oggetto Bean. Una classe è detta di tipo bean se rispetta le regole di costruzione che vedremo più avanti. Gli oggetti bean così creati nel corso del tempo vengono memorizzati nella sessione o nella richiesta del client. Questo aspetto è configurabile. Non è necessario ricrearli se sono già stati creati.
  • Nel file di configurazione struts-config.html, a ogni URL che deve essere elaborata dal programma (e che quindi non corrisponde a una vista JSP che si potrebbe richiedere direttamente) vengono associate alcune informazioni:
    • il nome della classe di tipo Action incaricata di elaborare la richiesta. Anche in questo caso, l’oggetto Action istanziato può essere conservato nella sessione o nella richiesta.
    • se la URL richiesta è parametrizzata (nel caso dell’invio di un modulo al controller), viene indicato il nome del bean incaricato di memorizzare le informazioni del modulo.
  • Grazie a queste informazioni fornite dal proprio file di configurazione, alla ricezione di una richiesta di URL da parte di un client, il controller è in grado di determinare se esiste un bean da creare e quale. Una volta istanziato, il bean può verificare se i dati che ha memorizzato, provenienti dal modulo, sono validi o meno. Un metodo del bean denominato `validate` viene chiamato automaticamente dal controller. Il bean viene implementato dallo sviluppatore, il quale inserisce nel metodo `validate` il codice che verifica la validità dei dati del modulo. Se i dati risultano non validi, il controller non proseguirà oltre, ma passerà il controllo a una vista il cui nome troverà nel proprio file di configurazione. A questo punto lo scambio è terminato. Si noti che lo sviluppatore può richiedere che la validità del modulo non venga verificata. Lo fa anche nel file struts-config.html. In questo caso, il controller non chiama il metodo `validate` del bean.
  • Se i dati del bean sono corretti, se non è prevista alcuna verifica o se non è presente alcun bean, il controller passa il controllo all’oggetto di tipo Action associato al file URL. Lo fa richiedendo l’esecuzione del metodo `execute` di tale oggetto, al quale trasmette il riferimento al bean che ha eventualmente costruito. È qui che lo sviluppatore esegue le operazioni necessarie: dovrà eventualmente ricorrere a classi di business o a classi di accesso ai dati. Al termine dell’elaborazione, l’oggetto `Action` restituisce al controller il nome della vista che deve inviare in risposta al client.
  • Il controller invia questa risposta. Lo scambio con il client è terminato.

Comincia a delinearsi la metodologia di sviluppo STRUTS:

  • la definizione delle viste. Si distingue tra le viste che sono moduli e le altre.
    • Ogni vista modulo dà origine a una definizione nel file struts-config.xml. In esso si definiscono le seguenti informazioni:
      • il nome della classe Bean che conterrà i dati del modulo, nonché l’indicazione relativa alla necessità o meno di verificare i dati. Se devono essere verificati e risultano non validi, è necessario indicare la vista da inviare in risposta al client in tale caso.
      • il nome della classe Action incaricata di elaborare il modulo.
      • il nome di tutte le viste che potrebbero essere inviate in risposta al client una volta elaborata la richiesta. La classe Action ne sceglierà una in base al risultato dell’elaborazione.
    • Ogni vista è oggetto di una pagina JSP. Vedremo che nelle viste, in particolare in quelle dei moduli, talvolta si utilizza una libreria di tag specifica di Struts.
  • la scrittura delle classi JavaBean corrispondenti alle viste dei moduli
  • la scrittura delle classi Action incaricate di elaborare i moduli
  • la scrittura di eventuali classi di business o di accesso ai dati

1.4.2. Gli strumenti di sviluppo STRUTS

Il progetto STRUTS è uno dei progetti dell'Apache Software Foundation. Molti di questi progetti sono raggruppati sotto il nome di Jakarta e sono disponibili su http://jakarta.apache.org:

Image

Si consiglia di leggere questa pagina. Numerosi progetti sono di interesse per gli sviluppatori Java. Seguendo il link Struts riportato sopra, si arriva alla pagina iniziale del progetto:

Image

Anche in questo caso, si consiglia di leggere la pagina iniziale. Per scaricare le librerie Java di Struts, seguiamo il link «Binaries» riportato sopra:

Image

Per l’ambiente Windows, si utilizzerà il link 1.1.zip e 1.1.tar.gz per l’ambiente Unix (novembre 2003). Una volta decompresso il file 1.1.zip, si ottiene la seguente struttura di directory:

Image

In questa struttura si trovano le librerie delle classi Java necessarie per lo sviluppo STRUTS. Queste sono contenute in file .jar o .war, simili ai file .zip. È possibile aprirli con le stesse utilità. La maggior parte delle librerie necessarie si trova nella cartella lib sopra indicata:

Image

Oltre alle librerie di classi .jar, sono presenti file .dtd (Document Type Definition) che contengono le regole di validità dei file XML. Un file XML può, nel proprio contenuto, fare riferimento a un file di questo tipo, ad esempio DTD. Il programma (chiamato parser) che analizza il contenuto del file XML utilizzerà le regole di validità presenti nel file DTD a cui si fa riferimento per determinare se il file XML è sintatticamente corretto. Ad esempio, il file struts-config_1_1.dtd definisce le regole di costruzione del file di configurazione struts-config.xml per la versione 1.1 di Struts.

Vediamo ora dove collocare i diversi elementi dell’albero di Struts per distribuire un’applicazione Struts all’interno del server Tomcat.

1.5. Distribuzione di un'applicazione Struts

Un’applicazione Struts è un’applicazione web come le altre. Segue quindi le regole di distribuzione del contenitore in cui viene eseguita. In questo caso, un’applicazione, che chiameremo strutspersonne, verrà eseguita da un server Tomcat versione 4.x. In allegato è riportata la procedura di distribuzione per Tomcat versione 5.x. Qui seguiamo le regole di distribuzione di Tomcat 4.x:

  1. Definiamo il contesto «strutspersonne» nel file di configurazione server.xml di Tomcat:
                <Context path="/strutspersonne" docBase="e:/data/serge/web/struts/personne" />

Fatto ciò, se necessario, riavviamo Tomcat affinché riconosca il nuovo contesto. Possiamo verificare la validità del contesto richiedendo l’URL http://localhost:8080/strutspersonne:

Image

Se non viene visualizzata una pagina di errore, significa che il contesto è corretto.

  1. Creiamo, nella cartella fisica associata al contesto strutspersonne, la sottocartella WEB-INF.
  2. Nella cartella WEB-INF dell’applicazione, definiamo il file di configurazione web.xml dell’applicazione:

Image

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
    <servlet>
      <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    <init-param>
        <param-name>config</param-name>
      <param-value>/WEB-INF/struts-config.xml</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
      <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

</web-app>
  • La classe del controller (servlet) dell'applicazione è una classe predefinita di Struts, denominata ActionServlet. Si trova nel file struts.jar. Affinché Tomcat possa trovare questa classe, inseriremo struts.jar nella cartella <tomcat>\common\lib, che è una delle cartelle esplorate da Tomcat durante la ricerca delle classi. In realtà, vi inseriremo tutti i file .jar presenti nella cartella <struts>\lib, dove <struts> è la cartella radice dell’albero di Struts.

Image

  • Si inseriranno inoltre i file struts-el.jar e jstl.jar presenti in <struts>\contrib\struts-el\lib:

Image

  • In questo caso abbiamo accesso al server web. Non è sempre così. Se si distribuisce un'applicazione web/Java in un contenitore web che non si amministra direttamente, è preferibile che l'applicazione includa tutte le librerie di cui ha bisogno. Queste devono quindi essere collocate nella cartella WEB-INF/lib, che va creata.
  • Abbiamo indicato che il controller necessitava di alcune informazioni che normalmente trovava in un file struts-config.xml situato nella stessa cartella di web.xml. In realtà, il nome di questo file è configurabile. È il parametro config, sopra indicato, che ne definisce il nome.
  • Il tag <servlet-mapping> indica che il controller sarà raggiungibile tramite tutti i file URL che terminano con il suffisso .do. Questa associazione è richiesta da Struts. Questi URL saranno poi filtrati dal controller, che accetterà solo i URL dichiarati nel proprio file di configurazione struts-config.xml

Per il momento, il nostro file web.xml è sufficiente.

  1. Richiederemo l’URL /main.do all’applicazione strutspersonne. In base al precedente file web.xml, questa URL verrà quindi trasmessa alla servlet org.apache.struts.action. Verrà istanziata la classe ActionServlet e verrà chiamato il suo metodo init. Quest’ultimo tenterà di leggere il file di configurazione definito dal parametro config. Il file deve quindi esistere. Creiamo il seguente file struts-config.xml:
<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

<struts-config>
    <action-mappings>
      <action
          path="/main"
          parameter="/main.html"
          type="org.apache.struts.actions.ForwardAction"
      />
    </action-mappings>
</struts-config>

Si noti che il file DTD di struts-config.xml non è lo stesso di quello del file web.xml, il che indica che non hanno la stessa struttura. Per ogni URL che il controller deve gestire, è necessario definire un tag <action>. Questo serve a indicare al controller cosa deve fare quando gli viene richiesto quel URL. In questo caso, specifichiamo i seguenti elementi:

  1. path="/main": definisce il nome dell’URL configurato dal tag <action>. Il suffisso .do è implicito.
  2. type="org.apache.struts.actions.ForwardAction": definisce il nome della classe Action che deve elaborare la richiesta. In questo caso, si utilizza una classe Action predefinita in Struts. Essa non esegue alcuna operazione autonomamente, ma inoltra la richiesta del client all'URL specificata nell'attributo parameter.
  3. parameter="/main.html": il nome dell'URL a cui deve essere inoltrata la richiesta. In questo caso si tratta di un file HTML statico.

In sintesi, quando l'utente richiederà il file URL /main.do, otterrà il file URL /main.html.

  1. Il file main.html sarà il seguente:
<html>
    <head>
      <title>Application strutspersonne</title>
  </head>
  <body>
      Application strutspersonne active ....
  </body>
</html>

Questo file si trova nella cartella dell'applicazione strutspersonne/vues:

Image

È possibile richiederlo direttamente tramite il codice URL http://localhost:8080/strutspersonne/main.html:

Image

In questo caso, il controller Struts dell'applicazione non è intervenuto poiché interviene solo se si richiede l'URL di tipo *.do. In questo caso, invece, è stato richiesto l'URL /vues/main.html.

  1. Il file struts-config.xml creato in precedenza deve essere inserito nella stessa cartella WEB-INF del file web.xml:

Image

  1. Ora verificheremo il corretto funzionamento del controller dell’applicazione strutspersonne richiedendo i file URL /main.do dopo aver, se necessario, riavviato Tomcat.

Image

In questo caso il controller Struts è intervenuto poiché abbiamo richiesto una URL di tipo *.do. Abbiamo ottenuto la pagina prevista (main.html). Abbiamo quindi gli elementi di base del funzionamento della nostra applicazione: il contesto strutspersonne, i file di configurazione web.xml e struts-config.xml, le librerie Struts.

Cosa sarebbe successo se avessimo richiesto un URL di tipo /toto.do? Secondo il file web.xml dell’applicazione strutspersonne, in tal caso verrebbe chiamato il controller Struts per elaborarlo. Quest’ultimo consulta quindi il proprio file di configurazione struts-config.html e non trova alcuna configurazione per il URL /toto. Cosa fa allora? Proviamo:

Image

Otteniamo una pagina di errore, il che sembra normale. Ora possiamo passare alla scrittura di un'applicazione.