Skip to content

1. Informazioni generali

Il PDF del documento è disponibile |QUI|.

1.1. Obiettivi

In questo articolo esploreremo un framework di sviluppo chiamato Struts. Jakarta Struts è un progetto della Apache Software Foundation (www.apache.org) progettato per fornire un framework standard per lo sviluppo di applicazioni web Java basate sull'architettura MVC (Model-View-Controller).

1.2. Il modello MVC

Il modello MVC mira a separare i livelli di presentazione, elaborazione e accesso ai dati. Un'applicazione web che aderisce a questo modello sarà strutturata come segue:

Questa architettura è denominata architettura a 3 livelli:

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

L'interfaccia utente è spesso un browser web, ma può anche essere un'applicazione autonoma che invia richieste HTTP al servizio web attraverso la rete e formatta i risultati ricevuti. La logica applicativa consiste in script che elaborano le richieste degli utenti. La fonte di dati è spesso un database, ma può anche essere un semplice file di testo, una directory LDAP, un servizio web remoto, ecc. È nell'interesse dello sviluppatore mantenere un alto grado di indipendenza tra queste tre entità in modo che, se una di esse cambia, le altre due non debbano cambiare, o solo in misura minima.

Quando si applica questo modello con i servlet e le pagine JSP, si ottiene la seguente architettura:

Nel blocco [Logica dell'applicazione], distinguiamo

  • il servlet, che è il punto di ingresso dell’applicazione ed è anche chiamato controller
  • il blocco [Classi di business], che contiene le classi Java necessarie per la logica dell’applicazione
  • il blocco [Classi di accesso ai dati], che contiene le classi Java necessarie per recuperare i dati richiesti dal servlet, spesso dati persistenti (database, file, servizi web, ecc.)
  • il blocco delle pagine JSP, che costituisce 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 segue il modello MVC sopra descritto. Lo esamineremo qui.

  1. Inizieremo definendo tutte le viste dell'applicazione. Si tratta delle pagine web presentate all'utente. Adotteremo quindi la prospettiva dell'utente nella progettazione delle viste. Esistono tre tipi di viste:
    • il modulo di input, utilizzato per ottenere informazioni dall'utente. Questo modulo include in genere un pulsante per inviare le informazioni inserite al server.
    • la pagina di risposta, che serve solo a fornire informazioni all'utente. Spesso include un link che permette all'utente di continuare a utilizzare l'applicazione su un'altra pagina.
    • la pagina mista: il servlet ha inviato al client una pagina contenente le informazioni che ha generato. Questa stessa pagina verrà utilizzata dal client per fornire al servlet ulteriori informazioni.
  1. Ogni vista genererà una pagina JSP. Per ciascuna di queste:
    • progetteremo il layout della pagina
    • determineremo quali parti di essa sono dinamiche:
      • le informazioni destinate all'utente, che devono essere fornite dal servlet come parametri alla vista JSP
      • i dati di input che devono essere trasmessi al servlet per l'elaborazione. Questi dati devono far parte di un modulo HTML.
  1. Possiamo rappresentare graficamente l'I/O per ciascuna vista
    • Gli input sono i dati che il servlet deve fornire alla pagina JSP, sia nella richiesta che nella sessione.
    • Gli output sono i dati che la pagina JSP deve fornire al servlet. Fanno parte di un modulo HTML e il servlet li recupererà utilizzando un'operazione come request.getParameter(...).
  1. Scriveremo il codice Java/JSP per ogni vista. Il più delle volte assumerà la seguente forma:
<%@ page ... %>    // importations de classes le plus souvent
<%!
    // variables d'instance de la page JSP (=globales)
    // nécessaire que si la page JSP a des méthodes partageant des variables (rare)    
    ...    
%>
<%
    // récupération des données envoyées par la servlet
    // soit dans la requête (request) soit dans la session (session)
    ...
%>

<html>
...
        // on cherchera ici à minimiser le code java
</html>
  1. Possiamo quindi passare ai test iniziali. Il metodo di distribuzione spiegato di seguito è specifico per il server Tomcat:
    • Il contesto dell'applicazione deve essere creato nel file server.xml di Tomcat. Possiamo iniziare testando questo contesto. Indichiamo con C questo contesto e con DC la cartella ad esso associata. Creeremo un file statico denominato test.html e lo inseriremo nella cartella DC. Dopo aver avviato Tomcat, richiederemo l'URL http://localhost:8080/DC/test.html in un browser.
    • Ogni pagina JSP può essere testata. Se una pagina JSP si chiama formulaire.jsp, richiederemo l'URL http://localhost:8080/DC/formulaire.jsp in un browser. La pagina JSP si aspetta valori dal servlet che la chiama. In questo caso, la stiamo chiamando direttamente, quindi non riceverà i parametri previsti. Per garantire che il test sia comunque possibile, inizializzeremo manualmente i parametri previsti nella pagina JSP utilizzando delle costanti. Questi test iniziali verificano che le pagine JSP siano sintatticamente corrette.
  1. Successivamente, scriviamo il codice del servlet. Esso presenta due metodi distinti:
    • il metodo init, che viene utilizzato per:
      • recuperare i parametri di configurazione dell'applicazione dal file web.xml
      • creare eventualmente istanze delle classi di business che saranno necessarie in seguito
      • gestire eventuali errori di inizializzazione che verranno segnalati ai futuri utenti dell'applicazione. Questa gestione degli errori può includere anche l'invio di un'e-mail all'amministratore dell'applicazione per avvisarlo di un malfunzionamento
    • il metodo doGet o doPost, a seconda di come il servlet riceve i parametri dai propri client. Se il servlet gestisce più moduli, è buona norma che ogni modulo invii informazioni che lo identifichino in modo univoco. Ciò può essere fatto utilizzando un attributo nascosto nel modulo del tipo <input type="hidden" name="action" value="...">. Il servlet può iniziare leggendo il valore di questo parametro e quindi delegare l'elaborazione della richiesta a un metodo interno privato responsabile della gestione di questo tipo di richiesta.
    • Si dovrebbe evitare il più possibile di inserire la logica di business nel servlet. Non è per questo che è stato progettato. Il servlet agisce come una sorta di caposquadra (controller) che riceve le richieste dai propri clienti (client web) e le fa eseguire dalle entità più appropriate (le classi di business). Durante la scrittura del servlet, si definirà l'interfaccia delle classi di business da creare (costruttori, metodi). Ciò vale se queste classi di business devono essere create. Se esistono già, allora il servlet deve adattarsi all'interfaccia esistente.
    • Il codice del servlet verrà compilato.
  1. Scriveremo lo scheletro delle classi di business richieste dal servlet. Ad esempio, se il servlet utilizza un oggetto di tipo proxyArticles e questa classe deve avere un metodo getCodes che restituisce un elenco (ArrayList) di stringhe di caratteri, inizialmente possiamo semplicemente 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. Ora possiamo procedere al 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, impostiamo l'URL attraverso il quale si accederà al servlet principale (<servlet-mapping>).
    • Tutte le classi necessarie (servlet, classi di business) sono collocate in WEB-INF/classes.
    • Tutte le librerie di classi necessarie (.jar) sono collocate in WEB-INF/lib. Queste librerie possono contenere classi di business, driver JDBC, ecc.
    • Le viste JSP vengono collocate nella radice dell'applicazione o in una cartella dedicata. Lo stesso vale per le altre risorse (HTML, immagini, audio, video, ecc.).
    • Una volta fatto ciò, l'applicazione viene testata e gli errori iniziali vengono corretti. Al termine di questa fase, l'architettura dell'applicazione è operativa. Questa fase di test può essere complessa poiché non è disponibile uno strumento di debug con Tomcat. Per questo, Tomcat dovrebbe essere integrato in uno strumento di sviluppo (JBuilder Developer, Sun One Studio, ecc.). È possibile utilizzare le istruzioni System.out.println("...."), che scrivono sulla console di Tomcat. La prima cosa da verificare è che il metodo init recuperi correttamente tutti i dati dal file web.xml. Per farlo, possiamo scrivere i valori di questi parametri nella finestra di Tomcat. Verificheremo allo stesso modo che i metodi doGet e doPost recuperino correttamente i parametri dai vari moduli HTML dell'applicazione.

Scriviamo le classi di business richieste dal servlet. Ciò comporta generalmente lo sviluppo standard di una classe Java, che di solito è indipendente da qualsiasi applicazione web. Verrà prima testata al di fuori di questo ambiente, ad esempio con un'applicazione console. Una volta scritta una classe di business, possiamo integrarla nell'architettura di distribuzione dell'applicazione web e testarne la corretta integrazione al suo interno. Questo processo viene ripetuto per ogni classe di business.

1.4. L'approccio di sviluppo STRUTS

I creatori della metodologia STRUTS hanno cercato di definire un metodo di sviluppo standard che aderisse all'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 permettono di applicare questo metodo di sviluppo. Si tratta di librerie di classi Java disponibili sul sito web della Apache Foundation (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 estenderlo. Per i casi semplici, ciò non è necessario. Questo servlet generico recupera le informazioni di cui ha bisogno da un file chiamato, nella maggior parte dei casi, struts-config.xml.
  • Se la richiesta del client contiene parametri di modulo, questi vengono inseriti in un oggetto Bean. Si dice che una classe sia di tipo Bean se segue le regole di costruzione di cui parleremo più avanti. Gli oggetti Bean creati nel tempo vengono memorizzati nella sessione o nella richiesta del client. Questa impostazione è configurabile. Non è necessario ricrearli se sono già stati creati.
  • Nel file di configurazione struts-config.html, ogni URL che deve essere elaborato dal programma (e quindi non corrispondente a una vista JSP che potrebbe essere richiesta direttamente) è associato a determinate informazioni:
    • il nome della classe di tipo Action responsabile dell'elaborazione della richiesta. Anche in questo caso, l'oggetto Action istanziato può essere memorizzato nella sessione o nella richiesta.
    • Se l'URL richiesto è parametrizzato (come quando un modulo viene inviato al controller), viene specificato il nome del bean responsabile della memorizzazione dei dati del modulo.
  • Grazie a queste informazioni fornite dal file di configurazione, al ricevimento di una richiesta URL da un client, il controller è in grado di determinare se è necessario creare un bean 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 chiamato `validate` viene chiamato automaticamente dal controller. Il bean è creato dallo sviluppatore. Lo sviluppatore inserisce quindi il codice che verifica la validità dei dati del modulo all'interno del metodo validate. Se i dati risultano non validi, il controller non procederà oltre. Passerà il controllo a una vista il cui nome trova nel proprio file di configurazione. L'interazione è quindi completata. Si noti che lo sviluppatore può scegliere di non far verificare la validità del modulo. Anche questo viene fatto nel file struts-config.html. In questo caso, il controller non chiama il metodo validate del bean.
  • Se i dati del bean sono corretti, o se non è prevista alcuna convalida, o se non c'è alcun bean, il controller passa il controllo all'oggetto Action associato all'URL. Lo fa chiamando il metodo execute di quell'oggetto, passando ad esso il riferimento al bean che potrebbe aver costruito. È qui che lo sviluppatore fa ciò che deve essere fatto: potrebbe dover chiamare classi di business o 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. L'interazione con il client è completata.

La metodologia di sviluppo STRUTS inizia a prendere forma:

  • Definizione delle viste. Si distingue tra le viste che sono moduli e le altre viste.
    • Ogni vista modulo genera una definizione nel file struts-config.xml. In esso sono definite le seguenti informazioni:
      • il nome della classe Bean che conterrà i dati del modulo, nonché un'indicazione relativa alla necessità o meno di convalidare i dati. Se la convalida è richiesta e i dati risultano non validi, in questo caso deve essere specificata la vista da rinviare al client.
      • Il nome della classe Action responsabile dell'elaborazione del modulo.
      • i nomi di tutte le viste che possono essere inviate al client una volta elaborata la richiesta. La classe Action ne selezionerà una in base al risultato dell'elaborazione.
    • Ogni vista corrisponde a una pagina JSP. Vedremo che nelle viste, in particolare nelle viste dei moduli, a volte utilizziamo una libreria di tag specifici di Struts.
  • Scrittura delle classi JavaBean corrispondenti alle viste dei moduli
  • Scrittura delle classi Action responsabili dell’elaborazione dei moduli
  • Scrivere eventuali classi di logica di business o di accesso ai dati

1.4.2. Strumenti di sviluppo STRUTS

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

Image

Si consiglia di leggere questa pagina. Molti dei progetti sono di interesse per gli sviluppatori Java. Se seguiamo il link Struts sopra riportato, arriviamo alla home page del progetto:

Image

Anche in questo caso, si consiglia di leggere la home page. Per scaricare le librerie Java di Struts, seguire il link "Binaries" sopra:

Image

Per gli utenti Windows, utilizzare il link 1.1.zip; per gli utenti Unix, utilizzare il link 1.1.tar.gz (novembre 2003). Una volta decompresso il file 1.1.zip, si vedrà la seguente struttura di directory:

Image

Questa struttura di directory contiene le librerie di classi Java necessarie per lo sviluppo con Struts. Queste sono memorizzate in file .jar o .war, simili ai file .zip. Possono essere aperte utilizzando 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 regole di validazione per i file XML. Un file XML può fare riferimento a un file DTD di questo tipo nel proprio contenuto. Il programma (chiamato parser) che analizza il contenuto del file XML utilizzerà le regole di validazione presenti nel file DTD di riferimento per determinare se il file XML è sintatticamente corretto. Ad esempio, il file struts-config_1_1.dtd definisce le regole per la creazione del file di configurazione struts-config.xml per Struts versione 1.1.

Vediamo ora dove collocare i vari elementi della struttura di directory di Struts per distribuire un'applicazione Struts sul server Tomcat.

1.5. Distribuzione di un'applicazione Struts

Un'applicazione Struts è un'applicazione web come qualsiasi altra. 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. La procedura di distribuzione per Tomcat versione 5.x è inclusa nell'appendice. Qui seguiremo le regole di distribuzione per 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" />

Una volta fatto ciò, riavviamo Tomcat se necessario affinché tenga conto del nuovo contesto. Possiamo verificare la validità del contesto richiedendo l'URL http://localhost:8080/strutspersonne:

Image

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

  1. Creiamo la sottocartella WEB-INF nella cartella fisica associata al contesto strutspersonne.
  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 Struts predefinita chiamata ActionServlet. Si trova nel file struts.jar. Per garantire che Tomcat possa trovare questa classe, inseriremo struts.jar nella cartella <tomcat>\common\lib, che è una delle cartelle in cui Tomcat effettua la ricerca delle classi. Infatti, inseriremo lì tutti i file .jar presenti nella cartella <struts>\lib, dove <struts> è la cartella principale dell'albero di directory di Struts.

Image

  • Inseriremo anche i file struts-el.jar e jstl.jar che si trovano in <struts>\contrib\struts-el\lib:

Image

  • Qui abbiamo accesso al server web. Non è sempre così. Se distribuisci un'applicazione web/Java in un contenitore web che non amministri tu stesso, è meglio che l'applicazione includa tutte le librerie di cui ha bisogno. Queste devono quindi essere collocate nella cartella WEB-INF/lib, che devi creare.
  • Abbiamo notato che il controller richiede determinate informazioni, che normalmente trova in un file struts-config.xml situato nella stessa cartella di web.xml. In realtà, il nome di questo file è configurabile. È il parametro config, menzionato sopra, che imposta questo nome.
  • Il tag <servlet-mapping> indica che si accederà al controller tramite tutti gli URL che terminano con il suffisso .do. Questa mappatura è richiesta da Struts. Questi URL saranno poi filtrati dal controller, che accetterà solo gli URL dichiarati nel suo file di configurazione struts-config.xml

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

  1. Richiederemo l'URL /main.do dall'applicazione strutspersonne. In base al precedente file web.xml, questo URL verrà quindi passato al servlet org.apache.struts.action. Verrà istanziata la classe ActionServlet e verrà chiamato il suo metodo init. Questo metodo tenta di leggere il file di configurazione definito dal parametro config. Questo 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 per struts-config.xml non è lo stesso di quello per 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 tag viene utilizzato per indicare al controller cosa fare quando riceve una richiesta per quell'URL. Qui, si specificano 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 gestire la richiesta. Qui utilizziamo una classe Action predefinita in Struts. Non esegue alcuna operazione autonomamente e inoltra la richiesta del client all'URL specificato nell'attributo parameter.
  3. parameter="/main.html": il nome dell'URL a cui la richiesta deve essere inoltrata. In questo caso, si tratta di un file HTML statico.

In sintesi, quando l'utente richiede l'URL /main.do, verrà indirizzato all'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/views:

Image

È possibile accedervi direttamente tramite l'URL http://localhost:8080/strutspersonne/main.html:

Image

In questo caso, il controller Struts dell'applicazione non è intervenuto, poiché interviene solo quando viene richiesto un URL del tipo *.do. Tuttavia, in questo caso, abbiamo richiesto l'URL /vues/main.html.

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

Image

  1. Verificheremo ora che il controller dell'applicazione strutspersonne funzioni correttamente richiedendo l'URL /main.do dopo aver riavviato Tomcat, se necessario.

Image

In questo caso, il controller Struts è intervenuto poiché abbiamo richiesto un URL del tipo *.do. Abbiamo ottenuto con successo la pagina prevista (main.html). Ora disponiamo dei componenti di base necessari al funzionamento della nostra applicazione: il contesto strutspersonne, i file di configurazione web.xml e struts-config.xml e le librerie Struts.

Cosa sarebbe successo se avessimo richiesto un URL come /toto.do? Secondo il file web.xml dell'applicazione strutspersonne, viene chiamato il controller Struts per gestirlo. Esso controlla quindi il proprio file di configurazione struts-config.html e non trova alcuna configurazione per l'URL /toto. Cosa fa allora? Proviamo:

Image

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