Trasformare una Java (Console) Application in una Web Application

Pag. 1/12
Trasformare una Java (Console) Application in una Web Application (con utilizzo di un database MySQL)
Prendiamo in esame un qualsiasi progetto NetBeans tra quelli studiati che fa uso di un
database MySQL (nel nostro caso il database si chiama studenti_db e contiene le classiche
tabelle studenti_tbl e classi_tbl). Riporto di seguito lo schema ER che abbiamo usato in
classe in diverse occasioni.
Fig. 1: Diagramma ER con le entità Studente e ClasseScol
L'applicativo da cui partiamo per dimostrare la tesi contenuta nel titolo di questo articolo si
chiama StudentiJavaApp. Si tratta di un applicativo classico nel senso che l'output è la
“console”, quindi in effetti è poco utile nella pratica. L'applicativo è organizzato come si può
vedere nella figura.
La classe ClasseScol “mappa” la tabella classi_tbl e la classe Studente “mappa” la tabella
studenti_tbl.
Fig. 2: Struttura dell'applicazione, delle classi e
dei package
Pag. 2/12
L'interfaccia IDAO contiene tutti i metodi necessari al corretto funzionamento dell'applicativo e
soddisfa a diverse richieste (per esempio, esiste un metodo che individua l'elenco degli
studenti appartenenti a una certa classe, come pure esiste un metodo che conta le classi con
più di 3 studenti ecc) mentre la classe DAO è una implementazione concreta dei metodi
dell'interfaccia IDAO. Torno a ripetere che l'interfaccia IDAO non è strettamente necessaria ma
serve solo a impedire che lo studente alteri di sua iniziativa i nomi dei metodi dell'interfaccia.
La classe Main sostanzialmente ci serve per fare i test necessari.
Quello che dobbiamo fare, in sintesi, è trasformare la classe DAO in una Servlet in modo da
eseguirla direttamente sul server ottenendo dal server in una pagina web i risultati desiderati.
Procedo come segue: creo innanzitutto un'applicazione web
In NetBeans, scelgo File > New Project > Web Application
Fig. 3: Step 1: Java Web > Web Application
Pag. 3/12
Fig. 4: Step2: Nome dell'applicazione (consiglio di aggiungere il suffisso WebApp per ricordare
che si tratta questa volta di un'applicazione web)
Pag. 4/12
Fig. 5: Step 3: Scelta del server web (java) Tomcat che risponderà alle richieste del client. Vi
ricordo che Tomcat dispone di un JDK perchè è necessario che i file .java vengano compilati
(ottenendo dei file .class)
Nella schermata successiva (che qua non appare), salto la voce Framework e scelgo Finish.
A questo punto tutto quello che devo fare è copiare nel nuovo progetto tutti i package del
progetto StudentiJavaApp (con un banale copia-incolla dei file).
Seleziono tutti i package del progetto StudentiJavaApp col CTRL e faccio copia; poi vado nel
nuovo progetto StudentiWebApp e in Source Packages faccio incolla.
Pag. 5/12
La situazione quindi è la seguente:
Fig. 6: Ecco i package copiati (dentro ovviamente
ci sono le classi che ci interessano)
Ho copiato anche il package main (con all'interno la classe Main) per comodità, perchè poi
userò parte del codice di questa classe, nella Servlet che devo ancora creare.
Creo ora la Servlet (tasto destro del mouse sul progetto StudentiWebApp e scelgo New >
Servlet).
Mantenete le impostazioni della figura seguente:
Pag. 6/12
Fig. 7: Creazione della Servlet DAOServlet. Conviene inserire la Servlet in un package apposito
Pag. 7/12
Fig. 8: Registrazione della Servlet
La Servlet va registrata (cioè le va assegnato un nome interno) e poi occorre specificare un
URL con il quale richiamarla (la registrazione per fortuna è automatica: NetBeans memorizza
queste informazioni nel file web.xml, contenuto nella directory WEB-INF). Premo Finish e in
tal modo termina la procedura di creazione della Servlet.
NetBeans crea per me uno scheletro di Servlet che è il seguente (ho solo aggiunto in alto il
nome e decommentato gli output del metodo processRequest()):
/*
* DAOServlet.java
*/
package it.itiscastelli.servlet;
import
import
import
import
import
import
java.io.IOException;
java.io.PrintWriter;
javax.servlet.ServletException;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
/**
* @author maurizio
*/
public class DAOServlet extends HttpServlet {
/**
* Processes requests for both HTTP <code>GET</code> and <code>POST</code>
methods.
* @param request servlet request
Pag. 8/12
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse
response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet DAOServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Servlet DAOServlet at " + request.getContextPath () + "</h1>");
out.println("</body>");
out.println("</html>");
} finally {
out.close();
}
}
// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on
the left to edit the code.">
/**
* Handles the HTTP <code>GET</code> method.
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Handles the HTTP <code>POST</code> method.
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Returns a short description of the servlet.
* @return a String containing servlet description
*/
@Override
public String getServletInfo() {
Pag. 9/12
return "Short description";
}// </editor-fold>
}
Probabilmente mi verrebbe in mente di aggiungere alla Servlet il metodo init() per aprire la
connessione al database e il metodo destroy() per chiudere la connessione. Questo però
può causare dei problemi!
I motivi sono documentati all'indirizzo:
http://www.codestyle.org/java/servlets/faq-Lifecycle.shtml
FAQ: Q: Should I get my database connection in the init() method?
R. If you create a single database connection in the init(ServletConfig) method
and use it to all handle servlet requests, you must ensure all operations are
synchronized or you will get unpredictable results.
Cioè potrei ottenere risultati imprevedibili perchè dovrei assicurarmi che tutte le richieste dei
client siano tra loro sincronizzate (ogni richiesta proveniente da un client è un thread
distinto). Per agire in maniera corretta, occorrerebbe usare un pool di connessioni (i pool di
connessioni sono un argomento complesso per cui rimandiamo lo studio di questo argomento).
Quindi apriamo e chiudiamo la connessione nel momento in cui arriva la richiesta (cioè lo
faremo nel metodo processRequest()).
Vi ricordo che il solo attributo che devo usare è l'oggetto conn di tipo Connection.
Poi copio all'interno della Servlet tutti gli altri metodi previsti in origine dalla classe DAO.
Abbiamo quasi terminato. Ora nel metodo processRequest() aggiungo, copiandolo in parte
dal metodo main() della classe Main, il codice che risolve il mio problema (per esempio, voglio
l'elenco degli studenti di 5N).
out.println("Elenco studenti classe 5N");
// apro la connessione col db
this.apriConn();
Map<String, Studente> studenti5N = this.trovaStudentiPerClasse("5N");
for (Studente s : studenti5N.values())
out.println(s.toString());
chiudiConn();
Devo ricordarmi di togliere la parola System dal codice che ho copiato, perchè in questo
contesto non ha senso. Bisogna usare invece un oggetto di tipo PrintWriter (che in questo
contesto si chiama out) il quale provvede a inviare l'output nella pagina web.
Formattiamo meglio il codice precedente facendo in modo di avere un elenco puntato.
out.println("Elenco studenti classe 5N");
this.apriConn();
Map<String, Studente> studenti5N = this.trovaStudentiPerClasse("5N");
out.println("<ul>");
for (Studente s : studenti5N.values())
out.println("<li>"+s.toString()+"</li>");
out.println("</ul>");
this.chiudiConn();
Se l'applicativo non parte, potrebbe voler dire che avete dimenticato di aggiungere i driver del
database MySQL o che non avete lanciato il database server MySQL oppure che avete lanciato
il file sbagliato (index.jsp): occorre lanciare invece la Servlet (tasto destro del mouse sulla
Pag. 10/12
Servlet > Run).
Fig. 9: Risultato dell'esecuzione della Servet DAOServlet
L'URL (in questa figura poco visibile) è http://localhost:8084/StudentiWebApp/DAOServlet
Per vostra comodità, ho allegato al post sul mio sito, in un unico file zip, entrambi gli applicativi
(StudentiJavaApp e StudentiWebApp), oltre al file di generazione del database
(studenti.sql).
Un altro modo altrettando efficace consiste nell'immergere il codice Java direttamente nel
codice HTML della pagina web evidenziandolo con dei marcatori (<% e %>).
Ciò ci consente inoltre di selezionare da una casella a scorrimento una classe scolastica e di
avere in output l'elenco degli studenti relativi alla classe scelta.
Riportiamo di seguito il codice commentato della pagina web index.jsp e ricordiamo che
Tomcat provvederà a generare in automatico il sorgente di una Servlet (di solito si chiama
index_jsp.java), provvederà a compilarla e a generare il file .class che andrà in esecuzione sul
server.
Al codice della classe DAO è stato aggiunto un nuovo metodo, il metodo trovaClassi() che
restituisce la lista di tutte le classi scolastiche.
Pag. 11/12
File index.jsp
<%-Document : index
Created on : 4-mar-2010, 17.55.36
Author
: maurizio
--%>
<%@page
<%@page
<%@page
<%@page
contentType="text/html" pageEncoding="UTF-8"%>
import="it.itiscastelli.dao.DAO" %>
import="it.itiscastelli.classi.*" %>
import="java.util.*" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<h1>Hello World!</h1>
<%
// istanzio un oggetto di tipo DAO
DAO dao = new DAO();
// apro la connessione al database
dao.apriConn();
// carico le classi e successivamente creo una combo box
// con i dati delle classi
List<ClasseScol> classi = dao.trovaClassi();
%>
<form name="frmProva" action="${request.requestURI}" method="get">
<p>
<select name="mnuClassi">
<%
for (ClasseScol c : classi) {
%>
<!-- caricamento delle classi nella comboBox mnuClassi -->
<option><%=c.getSigla() %></option>
<%
} // fine for
%>
</select>
<input type="submit" name="btnInvia" value="Invia"/>
</p>
</form>
<%
// se l'utente ha premuto il tasto Invia
if (request.getParameter("btnInvia")!=null) {
// lettura della sigla della classe
String siglaC = request.getParameter("mnuClassi");
out.println("Elenco studenti "+siglaC);
Pag. 12/12
// il metodo restituisce una mappa degli studenti appartenenti alla classe
// selezionata precedentemente
Map<String, Studente> studentiPerClasse = dao.trovaStudentiPerClasse(siglaC);
// genero una lista non ordinata
out.println("<ul>");
for (Studente s : studentiPerClasse.values())
out.println("<li>"+s.toString()+"</li>");
out.println("</ul>");
}
// chiudo la connessione col db
dao.chiudiConn();
%>
</body>
</html>
Fig 1: Risultato dell'esecuzione dell'applicativo StudentiWebApp2