2. Model 2 (MVC):
La richiesta del client viene sempre acquisita da una servlet che poi smista il flusso
verso l’opportuna pagina JSP.
La servlet quindi funge da processore di interfaccia con l’utente e gestisce
operazioni come l’autenticazione, il logging.
3. Modello MVC:
Il controller servlet incoraggia una maggiore estendibilità e riuso delle classi. Infatti
nel modello MVC si ha una netta separazione tra la business-logic, la presentazione
e la gestione delle richieste.
Il modello MVC può sembrare complesso, ma in realtà semplifica le applicazioni,
soprattutto per ciò che riguarda il loro mantenimento e la loro estendibilità.
Model
Si tratta di normali classi Java o Bean che sono in contatto diretto con una base di
dati. Nei casi delle applicazioni più complesse si avranno degli EJB.
View
Si tratta di pagine HTML, di JSP.
Control
Si tratta di una servlet con i compiti di unico punto d’ingresso dell’applicazione e di
supervisor.
4. Redirect e Forward
Il controller ha il compito, come detto, di smistare il flusso dell’applicazione a diversi
viewer (JSP). Esistono due modalità per effettuare questo:
response.sendRedirect(response.encodeRedirectURL(redirectStr));
in tal caso si ha una richiesta completamente nuova
verso la pagina di
destinazione e lo stato attuale memorizzato in request
viene perso.
Spesso tuttavia è necessario conservare il contenuto di
request, considerando soprattutto che nel caso del controller
il request contiene i parametri inviati dall’utente:
RequestDispatcher dispatcher =req.getRequestDispatcher(
redirectStr );
dispatcher.forward( req, resp );
5. Connection Pooling
Una delle operazioni più dispendiose di un’applicazione è l’apertura della connesione
con il database, soprattutto se si apre una connessione per eseguire solo poche
query. E’ quindi preferibile aprire un certo numero di connessioni all’avvio
dell’applicazione e porle in un ‘pool’ in modo che possano essere utilizzate
all’occorrenza.
In pratica la il pool di connessioni contiene un Vector di Connection da cui posso
recuperarne una in caso di necessità, segnandola come occupata, e restituendola al
pool quando non serve più.
Questo può essere fatto in modo manuale crendo delle classi opportune, oppure è
possibile utilizzare il package javax.sql.
6. PooledConnection
import java.sql.*;
public class PooledConnection {
private Connection connection = null;
private boolean inuse =false;
// Costruttore che memorizza la connessione JDBC
public PooledConnection(Connection value){ if(value != null){connection = value;} }
// Restituisce un riferimento alla connessione JDBC
public Connection getConnection() {return connection;}
// Imposta lo stato di PooledConnection.
public void setInUse(boolean value) {inuse = value;}
// Restituisce lo stato corrente di PooledConnection.
public boolean inUse() {return inuse;}
// Chiude la connessione JDBCreale
public void close ()
{ try { connection.close();
}
catch(SQLException sqle){System.err.println(sqle.getMessage()) ; }
}
}
7. Connection Pool – prima parte
import java.sql.*;
import java.util.*;
import java.io.Serializable;
public class ConnectionPool implements Serializable{
private String driver = null;
private String url = null;
private int size = 0; // Numero iniziale di connessioni.
private String username = new String("");
private String password = new String("");
private Vector pool = null; // Vettore di connessioni JDBC
public ConnectionPool(){}
public void setDriver(String value){if(value != null){driver = value;}}
public String getDriver(){return driver; }
public void setURL(String value){if(value != null){url = value;}}
public String getURL(){return url;}
public void setSize(int value){if(value > 1){size = value;}}
public int getSize(){return size;}
public void setUsername(String value){if(value != null){username= value;}}
public String getUserName(){return username;}
public void setPassword(String value){if(value != null){password = value;}}
public String getpassword(){return password;}
8. Connection Pool – seconda parte
// Crea e restituisce una connessione
private Connection createConnection() throws Exception{
Connection con = null;
con = DriverManager.getConnection(url,username,password);
return con;
}
// Aggiunge PooledConnectional pool
private void addConnection(PooledConnection value){
// Se il pool è null, crea un nuovo vettore
// con la dimensione iniziale "size"
if(pool == null){pool = new Vector(size);}
// Aggiunge l'oggetto PooledConnection al vettore
pool.addElement(value) ;
}
9. Connection Pool – terza parte
// Inizializza il pool
public synchronized void initializePool() throws Exception{
if(driver == null) throw new Exception("No Driver Name Specified!");
if(url == null) throw new Exception("No URL Specified!");
if(size < 1) throw new Exception("Pool size is less than 1!");
// Crea le connessioni
try{ Class.forName(driver);
for(int x = 0; x < size; x++){
Connection con = createConnection();
if(con != null)
{ PooledConnection pcon = new PooledConnection(con);
addConnection(pcon) ; }
}
}catch(Exception e){
System.err.println(e.getMessage());
throw new Exception(e.getMessage());}
}
10. Connection Pool – quarta parte
public synchronized void releaseConnection(Connection con){
// trova l'oggetto PooledConnection
for(int x = 0; x < pool.size(); x++){
PooledConnection pcon = (PooledConnection)pool.elementAt(x);
// Verifica se la connessione è corretta
if(pcon.getConnection() == con){
System.err.println("Releasing Connection " + x);
// Imposta l'attributo inuse a false, che
// rilascia per l'uso
pcon.setInUse(false);
break;
}
}
}
11. Connection Pool – quinta parte
// Trova una connessione disponibile
public synchronized Connection getConnection() throws Exception{
PooledConnection pcon = null;
for(int x = 0; x < pool.size(); x++){
pcon = (PooledConnection)pool.elementAt(x);
if(pcon.inUse() == false)
{pcon.setInUse(true);
return pcon.getConnection();}
}
// Non è riuscito a trovare una connessione libera, ne crea e aggiunge una
try{ Connection con = createConnection();
pcon = new PooledConnection(con);
pcon.setInUse(true);
pool.addElement(pcon);
}catch (Exception e){ System.err.println(e.getMessage());
throw new Exception(e.getMessage());}
return pcon.getConnection();
}
12. Connection Pool – sesta parte
// Quando si chiude il pool, occorre prima svuotarlo.
public synchronized void emptyPool(){
for(int x = 0; x < pool.size(); x++){
System.err.println("Chiusura connessione JDBC" + x);
PooledConnection pcon =(PooledConnection)pool.elementAt(x);
if(pcon.inUse() == false) pcon.close();
else{ // Se è in uso, attende 30 secondi e forza la chiusura.
try{ java.lang.Thread.sleep(30000);
pcon.close();
}catch(InterruptedException ie){
System.err.println(ie.getMessage());
}
}
}
}
}
13. Un sito di e-commerce
Un utente deve poter effettuare le seguenti operazioni:
•Ricerca di un prodotto per nome o descrizione
•Scorrere la lista dei prodotti scelta la categoria
•Vedere i dettagli dei prodotti
•Porre un prodotto in un carrello della spesa
•Vedere e modificare il contenuto del carrello
•Eseguire un ordine
20. Il controller (inizializzazione)
import java.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import com.brainysoftware.burnaby.DbBean;
public class ControllerServlet extends HttpServlet {
/**Initialize global variables*/
public void init(ServletConfig config) throws ServletException {
ServletContext context = config.getServletContext();
context.setAttribute("base", config.getInitParameter("base"));
context.setAttribute("imageUrl", config.getInitParameter("imageUrl"));
DbBean dbBean = new DbBean();
dbBean.setDbUrl(config.getInitParameter("dbUrl"));
dbBean.setDbUserName(config.getInitParameter("dbUserName"));
dbBean.setDbPassword(config.getInitParameter("dbPassword"));
context.setAttribute("dbBean", dbBean);
try { // loading the database JDBC driver
Class.forName(config.getInitParameter("jdbcDriver"));
} catch (ClassNotFoundException e)
{ System.out.println(e.toString()); }
super.init(config);
}
Si noti l’utilizzo so ServletContext per rendere disponibili le variabili per
tutta l’applicazione
21. Il controller doGet doPost
/**Process the HTTP Get request*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException
{ doPost(request, response); }
/**Process the HTTP Post request*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException
{ String base = "/jsp/";
String url = base + "Default.jsp";
String action = request.getParameter("action");
if (action!=null)
{ if (action.equals("search")) url = base + "SearchResults.jsp";
else if (action.equals("browseCatalog")) url = base + "BrowseCatalog.jsp";
else if (action.equals("productDetails")) url = base + "ProductDetails.jsp";
else if (action.equals("addShoppingItem") || action.equals("updateShoppingItem") ||
action.equals("deleteShoppingItem") || action.equals("displayShoppingCart"))
url = base + "ShoppingCart.jsp";
else if (action.equals("checkOut")) url = base + "CheckOut.jsp";
else if (action.equals("order")) url = base + "Order.jsp";
}
RequestDispatcher requestDispatcher = getServletContext().getRequestDispatcher(url);
requestDispatcher.forward(request, response);
}
}
22. Classi di supporto
Product.java
package com.brainysoftware.burnaby;
public class Product
{
public int id;
public String name;
public String description;
public double price;
}
ShoppingItem.java
package com.brainysoftware.burnaby;
public class ShoppingItem
{
public int productId;
public String name;
public String description;
public double price;
public int quantity;
}
23. File Inclusi: header.jsp
Si recuperano dal ServerContext i valor base e imageUrl:
<% String base = (String) application.getAttribute("base");
String imageUrl = (String) application.getAttribute("imageUrl"); %>
<TABLE WIDTH="740" CELLPADDING="0" HEIGHT="75" CELLSPACING="0" BORDER="0">
<TR>
<TD ALIGN="left" BGCOLOR="F6F6F6">
<FONT FACE="Verdana" SIZE="4">Burnaby e-Mall</FONT>
</TD>
<TD ALIGN="RIGHT" BGCOLOR="F6F6F6">
<A HREF="<%=base%>?action=displayShoppingCart">
<IMG BORDER="0" SRC="<%=(imageUrl + "cart.gif")%>">
</A>
</TD>
</TR>
</TABLE>