Java Bean, JSP e MVC

JavaBeans è un modello di programmazione a componenti per il linguaggio Java. L'obiettivo è quello di ottenere componenti software riusabili ed indipendenti dalla piattaforma (WORA: Write Once, Run Everywhere).
Inoltre tali componenti (beans) possono essere manipolati dai moderni tool di sviluppo visuali e composti insieme per produrre applicazioni.
Ogni classe Java che aderisce a precise convenzioni sulla gestione di proprietà ed eventi può essere un bean.
Una proprietà è un singolo attributo pubblico. Le proprietà possono essere in lettura/scrittura, sola lettura o sola scrittura, e possono essere di vari tipi: semplici, indicizzate, bound e constrained.
Una proprietà semplice rappresenta un singolo valore e può essere definita da una coppia di metodi set/get. Il nome della proprietà deriva dal nome di tali metodi. La sola presenza del metodo get indica che la proprietà è in sola lettura, la sola presenza del metodo set indica che la proprietà è in sola scrittura, mente la presenza di entrami i metodi indica una proprietà in letture e scrittura.
Ad esempio setX e getX indicano una proprietà X. La presenza di un metodo isX indica che X è una proprietà booleana
Esempio:

public class Prova1
{
  String myString="Hello";

//costruttore di default
  public Prova1(){
     }

  public void setMyString(String newString){
   myString = newString;
  }

  public String getMyString() {
   return myString;
  }
 
}


Prova1 ha una proprietà chiamata myString.


È possibile customizzare come un bean debba apparire e di comportarsi all'interno di un tool di composizione visuale attraverso le interfacce
Customizer consente di definire la propria versione della finestra proprietà all'interno del tool.
PropertyEditor consente di definire come impostare una determinata proprietà.
BeanInfo consente di definire come deve apparire il bean all'interno del tool (etichette, testo di aiuto, ecc.)
Per rendere persistenti i campi di un bean basta semplicemente dichiarare che il bean implementa java.io.Serializable.
Tutte le variabili eccetto le transient e le static verranno salvate.
I JavaBeans vengono distribuiti in archivi JAR. Questi archivi possono contenere classi, bean serializzati, file HTML di aiuto, file multi-mediali (audio, immagini) e quant'altro.
In genere contengono anche un file MANIFEST che descrive il contenuto dell'archivio, in particolare quali classi siano dei bean.
Riassumendo, possiamo dire che una classe è un bean quando:
1) ha un cotruttore senza parametri;
2) non ha variabili d'istanza pubbliche, ma solo metodi get e set  pubblici.

JSP e Java Bean

  Per usare un Bean in una JSP devo prima di tutto definirlo come nell'esempio seguente:
<jsp:useBean id="bean" class="MyBean" scope="session" />
L'id è il nome che assegno al bean, la class è la classe Java del bean, lo scope riguarda il campo di esistenza del bean. Altri scope possibili sono application, request, page. Significato degli scope:
application
l'esistenza del bean è legata alla durata dell'applicazione
session
l'esistenza del bean è legata alla durata della sessione
request
l'esistenza del bean è legata alla durata della richiesta
page
l'esistenza del bean è legata alla durata della pagina (this)

Leggere il valore di una proprietà:
<jsp:getProperty name="bean" property="costo" />
  Impostare il valore di una proprietà:
<jsp:setProperty name="bean" property="costo" value="3" />

In maniera analoga possiamo usare ad esempio setAttribute della classe HttpRequest per scambiare dei dati tra una Servlet e la pagina JSP.

Model View Controler

Abbiamo visto che conviene usare le pagine JSP per tutte quelle operazioni in cui la parte di "visualizzazione" è predominante rispetto a quella di "calcolo"
Le JSP possono essere impiegate per rendere più semplice lo sviluppo e la manutenzione della applicazione nei seguenti scenari:
Ma questi due semplici scenari non possono essere adottati in tutte le situazioni. Infatti:
 Per unire i benefici delle Servlet e JSP e separazione tra controllo (logica) e presentazione (aspetto)  si può utilizzare l'archietettura Model-View-Controller schematizzata nella seguente figura:
architettura Model View Controller
Integrare Servlet e JSP:
  1. La richiesta originale è processata dalla una servlet che esegue la validazione dei dati della richiesta e impartisce gli "ordini" ai bean;
  2. I bean conservano le informazioni per il successivo uso da parte della seguente pagina  JSP o dell'applicazione stessa;
  3. La richiesta è reindirizzata a una  pagina JSP per visualizzare il risultato. Inoltre possono essere usate  JSP differenti in risposta alla stessa servlet per ottenere presentazioni differenti.
Questo modello è chiamato "MVC (Model View Controller" o “Approccio JSP Model 2").
Dato che nella servlet non viene generato l'output, alla fine della fase di controllo della servlet stessa bisogna "inoltrare" la generazione della pagina HTML alla pagina JSP con le seguenti istruzioni:
ServletContext sc = getServletContext();
RequestDispatcher rd = sc.getRequestDispatcher(jsp);
rd.forward(req,res);
Le istruzioni di sopra  possiano essere racchiuse in un metodo della servlet come il seguente:
private void forward(HttpServletRequest request, HttpServletResponse response, String page)
{
ServletContext sc = getServletContext();
RequestDispatcher rd = sc.getRequestDispatcher(page);
rd.forward(request,response);
}

Esempio

Nell'esempio vediamo un possibile bean e come viene utilizzato da una servlet di controllo e dalle varie JSP responsabili della visualizzazione delle diverse risposte.
Esempio

Bean

package model;
public class Ordine
{
   static java.util.Map memory = new java.util.HashMap();
   int progressivo=-1;
   String descrizione=null;

   public int getProgressivo()
   {
      return progressivo;
   }

   public void setProgressivo(int progressivo)
   {
      this.progressivo=progressivo;
   }
  
   public String getDescrizione()
   {
      return descrizione;
   }

   public void setDescrizione(String descrizione)
   {
      this.descrizione=descrizione;
   }
   public void insert()
   {
     //... prossima lezione per accesso DB
     memory.put(new Integer(progressivo),this);
   }
   public void update()
   {
     //... prossima lezione per accesso DB
     memory.put(new Integer(progressivo),this);
   }
   static public Ordine load(int id)
   {
     //... prossima lezione per accesso DB
     return (Ordine) memory.get(new Integer(id));
   }
   static public java.util.Collection load()
   {
     //... prossima lezione per accesso DB
      return memory.values();
   }
}

file model/Ordine.java

package model;
public class Utente {
   
    /** Creates a new instance of Utente */
    public Utente() {
    }

    public Utente(String account)
    {
        setNome(account);
    }
    /**
     * Holds value of property nome.
     */
    private String nome;

    /**
     * Getter for property nome.
     * @return Value of property nome.
     */
    public String getNome() {
        return this.nome;
    }

    /**
     * Setter for property nome.
     * @param nome New value of property nome.
     */
    public void setNome(String nome) {
        this.nome = nome;
    }
   
    public boolean checkPassword(String password)
    {
        if ("pass".equals(password))
            return true;
        else
            return false;
    } 
}

file model/Utente.java


Servlet

 
public class ServletControllo extends HttpServlet{

public void init(...){
super.init(...);
// creazione e inizializzazione oggetti con scope application
}
public void doGet(request,response){
...


String op = request.getParameter("op");
HttpSession session = request.getSession(true);
Utente u = (Utente) session.getAttribute("user");
if ("login".equals(op) || op==null)
{
u = new Utente(request.getParameter("account"));
if (u==null || !u.checkPassword(request.getParameter("password")))
forward(request,response,"/login.jsp");
else
{
session.setAttribute("user",u);
forward(request,response,"/home.jsp");
}
return;
}
if ("inserimento".equals(op))
{
Ordine nuovo = new Ordine();
try
{
nuovo.setProgressivo(Integer.parseInt(request.getParameter("progressivo")));
}
catch (Exception e)
{
forward(request,response,"/inputError.jsp");
return;
}
nuovo.setDescrizione(request.getParameter("descrizione"));
nuovo.insert();
forward(request,response,"/home.jsp");
}
else if ("moduloInserimento".equals(op))
{
forward(request,response,"/moduloInserimento.jsp");
}
else if ("mostra".equals(op))
{
Ordine ordine=null;
try
{
ordine=Ordine.load(Integer.parseInt(request.getParameter("progressivo")));
}
catch (Exception e)
{
forward(request,response,"/inputError.jsp");
return;
}
request.setAttribute("ordine",ordine);
forward(request,response,"/mostra.jsp");
}
else if ("visualizza".equals(op))
{
forward(request,response,"/mostraOrdini.jsp");
}
//else da finire tutti i casi

}
private void forward(HttpServletRequest request, HttpServletResponse response, String page)
throws ServletException, IOException
{
ServletContext sc = getServletContext();
RequestDispatcher rd = sc.getRequestDispatcher(page);
rd.forward(request,response);
}
}

file ServletControllo.java
Questa classe servlet deve essere mappata all'url "/servlet" affinché sia collegata correttamente alle seguenti pagine jsp.

Pagine JSP


<head>
<title>Login</title>
</head>
<body>
<h2>Login</h2>
<form action="servlet" method="POST" name="dati">
<input type="hidden" name="op" value="login">
<table>
<tr><td>User:</td><td><input name="account" type="text"></td></tr>
<tr><td>Password:</td><td><input name="password" type="password"></td></tr>
<tr><td>&nbsp;</td><td><input type="submit" value="OK"></td></tr>
</table>
</form>
</body>
</html>
file login.jsp

<%@ page import="model.Utente" %>
<% Utente user = (Utente) session.getAttribute("user");
if (user==null){%>
<jsp:forward page="/login.jsp" />
<%return;}%>
<html>
<head>
<title>Home page</title>
</head>
<body>
<h2>Home</h2>
<ul>
<li><a href="servlet?op=moduloInserimento">Inserisci nuovo ordine</a>
<li><a href="servlet?op=visualizza">Visualizza Ordini</a>
<li>...
</ul>
</body>
</html>
file home.jsp

<%@ page import="model.Utente" %>
<% Utente user = (Utente) session.getAttribute("user");
if (user==null){%>
<jsp:forward page="/login.jsp" />
<%return;}%>
<html>
<head>
<title>Ordini</title>
</head>
<body>
<h2>Inserimento Ordine</h2>
<form action="servlet" method="POST" name="dati">
<input type=hidden name="op" value="inserimento">
<table>
<tr><td>Progressivo:</td><td><input name="progressivo" type="text"></td></tr>
<tr><td>Descrizione:</td><td><input name="descrizione" type="text"></td></tr>
<tr><td>&nbsp;</td><td><input type="submit" value="OK"></td></tr>
</table>
</form>
</body>
</html>
file moduloInserimento.jsp

<%@ page import="model.Ordine"%>
<%@ page import="model.Utente"%>
<% Utente user = (Utente) session.getAttribute("user");
if (user==null){%>
<jsp:forward page="/login.jsp" />
<%return;}%>
<% Ordine ordine = (Ordine) request.getAttribute("ordine");%>
<html>
<head>
<title>Ordini</title>
</head>
<body>
<h2>Visualizza Ordine</h2>
<table>
<tr><td>Progressivo:</td><td><%=""+ordine.getProgressivo()%></td></tr>
<tr><td>Descrizione:</td><td><%=ordine.getDescrizione()%></td></tr>
</table>
<a href="servlet?op=modifica&progressivo=<%=""+ordine.getProgressivo()
%>">Modifica questo ordine</a>
</body>
</html>
file mostra.jsp

<% Utente user = (Utente) session.getAttribute("user");%>
if (user==null){%>
<jsp:forward page="/login.jsp" />
<%return;}%>
<jsp:useBean id="ordine" class="package.Ordine" scope="request" />
<html>
<head>
<title>Ordini</title>
</head>
<body>
<h2>Visualizza Ordine</h2>
<table>
<tr><td>Progressivo:</td><td><jsp:getProperty name="ordine" property="progressivo" /></td></tr>
<tr><td>Descrizione:</td><td><jsp:getProperty name="ordine" property="descrizione" /></td></tr>
</table>
<a href="servlet?op=modifica&progressivo=<jsp:getProperty name="ordine" property="progressivo"/>">Modifica questo ordine</a>
</body>
</html>
file alternativo mostra.jsp



<%@ page import="model.Ordine"%>
<%@ page import="model.Utente"%>
<% Utente user = (Utente) session.getAttribute("user");
if (user==null){%>
<jsp:forward page="/login.jsp" />
<% return;}%>
<% java.util.Iterator iterator = Ordine.load().iterator();
Ordine ordine =null; %>
<html>
<head>
<title>Ordini</title>
</head>
<body>
<h2>Visualizza Ordini</h2>
<table>
<tr><td>Progressivo</td><td>Descrizione</td></tr>
<% while(iterator.hasNext())
{
ordine = (Ordine) iterator.next();%>
<tr><td><a href="servlet?op=mostra&progressivo=<%=""+ordine.getProgressivo()%>"><%=""+ordine.getProgressivo()%></a></td>
<td><%=ordine.getDescrizione()%></td></tr>
<%}%>
</table>
<a href="servlet?op=moduloInserimento">Inserisci ordine</a>
</body>
</html>
file mostraOrdini.jsp


Regole generali:

Vantaggi:

  1. JSP molto semplici, con le librerie di tag possono essere scritte senza codice Java (quindi da un esperto di codice HTML senza esperienza di programmazione);
  2. la possibilità che una stessa servlet o pagina JSP esegua il forward su differenti pagine JSP semplifica enormemente le JSP che in questo modo possono non contenere costrutti di controllo;
  3. il controllo è centralizzato nella servlet, posso riutilizzare il codice Java. Per la stessa ragione è preferibile ridurre al minimo il codice Java presente nella JSP o spostandolo nel controllo oppure definenfo un nuovo tag;
  4. riuso dei bean in contesti applicativi diversi. I Bean di per se stessi non sono legati ne al protocollo HTTP, ne al codice HTML. Quindi possono essere riusati in applicazioni differenti (ad esempio un applicazione non Web);
Esercizio
Completare gli esempi visti in questa lezione.