Applicazioni Web in Java 19-20
Applicazioni Web in Java 19-20
in Java
Tecnologie e progettazione di sistemi
informatici e di telecomunicazioni
Appendice.........................................................................................................................................................59
A1 – Memorizzazione di un’applicazione web in formato WAR................................................................59
A2 – Deployment di applicazioni web su server Ubuntu Linux 20.04 LTS................................................60
A2.1 – Installazione del software JDK 11..............................................................................................60
A2.2 – Installazione del software Tomcat 9............................................................................................60
A2.3 – Deployment dell’applicazione....................................................................................................60
Applicazioni proposte.......................................................................................................................................62
1. Servlet
Il client invia una richiesta HTTP con il metodo GET al seguente URL:
http://localhost:8080/info-piemonte/citta?sigla=vc
Inserendo nella query string il parametro sigla contenente la targa automobilistica della città desiderata.
Il server, dopo aver validato la richiesta, risponde inviando una pagina web in cui sono presenti alcune
informazioni sulla città. Nel caso in cui non sia possibile soddisfare la richiesta, il server segnala l’errore con
un apposito status code.
L’applicazione offre inoltre una pagina principale contenente un form con cui l’utente può selezionare,
tramite un apposito elenco, il capoluogo da visualizzare.
double superficie;
String[] frazioni;
String paramSigla = request.getParameter("sigla");
if (paramSigla == null) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
if (paramSigla.equals("no") == true) {
nome = "Novara";
abitanti = 104268;
superficie = 103.05;
frazioni = new String[] {"Agognate", "Lumellogno", "Veveri", "Vignale"};
} else if (paramSigla.equals("vc") == true) {
nome = "Vercelli";
abitanti = 46035;
superficie = 79.78;
frazioni = new String[]{"Bivio Sesia", "Carengo", "Larizzate",
"Montonero"};
}
else {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
response.setContentType("text/html");
out.format("</ul></li>%n");
out.println("</ul>");
out.println("</body>");
out.println("</html>");
}
}
<option value="no">Novara</option>
<option value="vc">Vercelli</option>
<option value="to">Torino</option>
</select>
</p>
<p>
<input type="submit" value="Invia" />
</p>
</form>
1) Inserimento/aggiornamento articoli: contiene un form HTML in cui sono inseriti tre dati: codice
(numero intero), descrizione (stringa), prezzo (numero reale). I dati sono inviati all’applicazione con
il metodo POST e sono processati secondo la seguente regola:
◦ Se il codice è già presente nel listino, i dati dell’articolo corrispondente (descrizione e prezzo)
sono aggiornati con le informazioni inviate dall’utente.
2) Visualizzazione listino: richiama il listino dei prezzi aggiornato all’ultima modifica. La richiesta è
inviata con il metodo GET.
L’applicazione restituisce:
main {
padding: 1rem 1.5rem;
text-align: center;
}
</style>
</head>
<body>
try {
boolean flagNuovo = listino.aggiorna(strCodice, strDescr, strPrezzo);
PrintWriter out = response.getWriter();
inizioRisposta(out);
out.println("<div class='alert alert-success' role='alert'>");
out.println(String.format("Articolo cod. %s %s con successo</div>",
strCodice, flagNuovo ? "Inserito" : "modificato"));
stampaListino(out);
fineRisposta(out);
}
catch (Exception e) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
}
pw.println("<head>");
pw.println("<meta charset='utf-8'>");
pw.println("<meta name='viewport' content='width=device-width, initial-scale=1, shrink-
to-fit=no'>");
pw.println("<link
href='https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css'
rel='stylesheet'");
pw.println("integrity='sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh'
crossorigin='anonymous'>");
pw.println("<title>Listino prezzi</title>");
pw.println("<style type='text/css'>");
pw.println("body {padding-top: 0rem;}");
pw.println("main {padding: 1rem 1.5rem; text-align: center;}");
pw.println("</style>");
pw.println("</head>");
pw.println("<body>");
pw.println("<main role='main' class='container'>");
Le operazioni da eseguire sono indicate dal client specificando nelle richieste HTTP il parametro
operazione. Le operazioni acquisto, carrello e pagamento sono inviate con il metodo GET, le altre con
POST.
A ogni utente è associato un carrello della spesa in cui sono memorizzati i prodotti acquistati. Il carrello è
gestito come attributo della sessione Java. Nella sessione è inoltre presente un atttributo msg utilizzato per
visualizzare di messaggi durante le varie operazioni.
Per evitare, durante un eventuale refresh della pagina web, che un articolo selezionato nel form HTML e
inviato al server con il metodo POST sia processato ripetutamente, causando la comparsa di articoli duplicati
nel carrello, si ricorre al pattern POST/REDIRECT/GET1: il server, ricevuta una richiesta POST, anziché
elaborare la pagina web di risposta, invia un codice di risposta della famiglia HTTP 3xx (Redirect) che porta
il client a formulare una nuova richiesta GET per ottenere il contenuto aggiornato del carrello.
Configurazione
File web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>VenditaServlet</servlet-name>
<servlet-class>VenditaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>VenditaServlet</servlet-name>
<url-pattern>/vendita</url-pattern>
</servlet-mapping>
</web-app>
1 https://en.wikipedia.org/wiki/Post/Redirect/Get
https://www.youtube.com/watch?v=DCC7ufuFD2w
out.println("</div>");
out.println("</div>");
out.println("</fieldset>");
out.println("<div class='form-group row'>");
out.println("<label for='qta' class='col-sm-2 col-form-label'>Quantità</label>");
out.println("<div class='col-sm-2'>");
out.println("<input type='number' class='form-control' id='qta' name='qta'
value='1' min='1' max='20' />");
out.println("</div>");
out.println("<div class='col-sm-8 text-left'>");
out.println("<button type='submit' class='btn btn-primary'>Acquista</button>");
out.println("<a class='btn btn-secondary' href='vendita?operazione=carrello'
role='button'>Carrello</a>");
out.println("</div>");
out.println("</div>");
fineRisposta(out);
}
out.println("<td>");
out.println("<form action='vendita' method='post'>");
out.println(String.format("<input type='hidden' name='operazione'
value='elimina'/>", riga));
out.println(String.format("<input type='hidden' name='riga' value='%d'/>", riga));
out.println("<button type='submit' class='btn btn-danger
btn-sm'>Elimina</button>");
out.println("</form>");
out.println("</td>");
out.println("</tr>");
riga++;
}
out.println("</tbody>");
out.println("<tfoot>");
out.println("<tr>");
out.println("<td colspan='5' class='text-right'>Totale:</td>");
out.println(String.format("<td><strong>€ %.2f</strong></td>", c.totale()));
out.println("<td> </td>");
out.println("</tr>");
out.println("</tfoot>");
out.println("</table>");
out.println("<div>");
out.println("<a class='btn btn-primary' href='vendita?operazione=acquisto'
role='button'>Nuovo acquisto</a>");
out.println("<a class='btn btn-success' href='vendita?operazione=pagamento'
role='button'>Paga e concludi</a>");
out.println("</div>");
fineRisposta(out);
}
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
inizioRisposta(out, null);
out.println("<h1>Pagamento eseguito</h1>");
out.println("<div class='row pt-4 pb-4'>");
out.println("<div class='col-sm-12 offset-md-2 col-md-8 text-center'>");
out.println("<p>L'acquisto degli articoli presenti nel carrello è stato
effettuato correttamente e il carrello è stato svuotato.");
out.println(String.format("L'importo pagato è pari a <strong>€
%.2f</strong>.</p>", pagato));
out.println("</div>");
out.println("</div>");
out.println("<a class='btn btn-primary' href='vendita?operazione=acquisto'
role='button'>Nuovo acquisto</a>");
fineRisposta(out);
}
pw.println("integrity='sha384-Vkoo8x4CGsO3+Hhxv8T/
Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh' crossorigin='anonymous'>");
// Per visualizzare i messaggi a scomparsa è richiesta la libreria JQuery
pw.println("<script src='https://code.jquery.com/jquery-3.4.1.js' ");
pw.println("integrity='sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU='
crossorigin='anonymous'></script>");
pw.println("<title>Vendita acqua minerale</title>");
pw.println("<style type='text/css'>");
pw.println("body {padding-top: 0rem;}");
pw.println("main {padding: 1rem 1.5rem; text-align: center;}");
pw.println("</style>");
pw.println("</head>");
pw.println("<body>");
pw.println("<nav style='height: 64px;' class='navbar navbar-expand-sm bg-light'>");
if (c != null) {
pw.println("<img width='50' src='img/carrello.png' />");
pw.println(String.format("<strong style='padding-left: 1em; font-size:
larger'>%d (€ %.2f)</strong>",
c.numeroArticoli(), c.totale()));
}
pw.println("</nav>");
pw.println("<main role='main' class='container'>");
pw.println("<h3>Vendita di acqua minerale on-line</h3>");
return sb.toString();
}
Classe Carrello
public class Carrello {
ArrayList<Articolo> articoli;
public Carrello() {
articoli = new ArrayList<>();
}
Classe Articolo
public class Articolo {
int codice;
String descrizione;
double costoUnitario;
int quantita;
this.codice = codice;
this.descrizione = descrizione;
this.costoUnitario = costoUnitario;
this.quantita = quantita;
}
USE dbanagrafica;
DROP TABLE IF EXISTS anagr_clienti;
CREATE TABLE anagr_clienti
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
cognome NVARCHAR(50) NOT NULL,
nome NVARCHAR(50) NOT NULL,
data_nascita DATE NOT NULL
);
Pagina index.jsp
<p>
<label for="nome" style="display: inline-block; width: 7em">Nome:</label>
<input type="text" name="nome" id="nome" size="30" maxlength="50"/>
</p>
<p>
<label for="nascita"style="display: inline-block; width: 7em">Data di
nascita:</label>
<input type="text" name="nascita" id="nascita" size="20" maxlength="20"/>
</p>
<p>
<input type="submit" value="Invia" />
<input type="reset" value="Reimposta" />
</p>
</form>
<h2>Ricerca cliente</h2>
<form action="anagrafica" method="get">
<p>
<label for="idcliente" >ID del cliente da cercare:</label>
<input type="number" name="idcliente" id="idcliente" value="1" />
</p>
<p>
<input type="submit" value="Cerca" />
<input type="reset" value="Reimposta" />
</p>
</form>
</body>
</html>
Classe AnagraficaServlet
package edu.fauser.netlab.anagraficasql;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
// In alternativa allo script SQL di inzializzazione da eseguire sul server di database, è possibile
// creare e popolare le tabelle tramite codice Java.
try(Connection cn = DriverManager.getConnection(dbu.getUrl(), dbu.getUser(), dbu.getPassword());
Statement st = cn.createStatement()) {
String sql = "CREATE TABLE IF NOT EXISTS anagr_clienti (" +
"id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, "+
"cognome NVARCHAR(50) NOT NULL, " +
"nome NVARCHAR(50) NOT NULL, " +
"data_nascita DATE NOT NULL);";
st.executeUpdate(sql);
st.executeUpdate(sql);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (request.getParameter("idcliente") == null)
// Esegue una query SQL standard
doElencoCompleto(request, response);
else
// Esegue una query SQL parametrica
doRicercaCliente(request, response);
}
String sql = "SELECT id, cognome, nome, data_nascita FROM anagr_clienti ORDER BY id";
try(Connection cn = DriverManager.getConnection(urlDb, userDb, passwordDb);
Statement ps = cn.createStatement();
ResultSet rs = ps.executeQuery(sql))
{
out.println("<h1>Anagrafica clienti</h1>");
if (!rs.next()) {
out.println("<p>Nessun cliente presente in archivio</p>");
}
else {
out.println("<table border='1' cellpadding='5'>");
out.println("<tr><th>ID</th><th>Cognome</th><th>Nome</th><th>Data di nascita</th></tr>");
do {
int id = rs.getInt("id");
String cognome = rs.getString("cognome");
String nome = rs.getString("nome");
out.println(String.format("<tr><td>%d</td><td>%s</td><td>%s</td><td>%s</td>",
id, cognome, nome, dataNascita));
}
while (rs.next());
out.println("</table>");
}
} catch (SQLException e) {
e.printStackTrace(out);
}
out.println("<p><a href='index.jsp'>Torna alla pagina principale</a></p>");
out.println("</body></html>");
}
String sqlParam = "SELECT id, cognome, nome, data_nascita FROM anagr_clienti WHERE id = ?";
@Override
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<h1>Inserimento nuovo cliente</h1>");
String sql = "INSERT INTO anagr_clienti(cognome, nome, data_nascita) VALUES (?, ?, ?)";
try(Connection cn = DriverManager.getConnection(urlDb, userDb, passwordDb);
PreparedStatement ps = cn.prepareStatement(sql))
{
ps.setString(1, cognome);
ps.setString(2, nome);
if (ps.executeUpdate() == 0) {
throw new SQLException("Errore di inserimento dati");
}
out.println("<p>Dati del nuovo cliente inseriti correttamente.</p>");
Sono inoltre disponibili alcuni video, in formato .webm, memorizzati in una cartella privata.
Application Server
Web application
DBUtility
DownloadServlet SQL
index.jsp
Utenti
AuthFilter
file video
• login.jsp: presenta un form HTML per l’inserimento delle credenziali e invia i dati raccolti alla
servlet LoginServlet.
Per evitare la riproduzione non autorizzata dei video, è necessario controllare l’accesso al servizio erogato da
DownloadServlet: nel caso di richiesta proveniente da un cliente non registrato, l’applicazione deve
reindirizzare l’utente alla pagina di login prima di inviare il contenuto.
Anteprime
USE dbvideo;
Pagina index.jsp
</div>
</nav>
<main class="container">
<div class="row">
<div class="col-lg-12 text-center">
<h1 class="mt-5">Mostra video</h1>
<% } %>
</div>
</div>
</main>
</body>
</html>
Pagina login.jsp
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no'>
<link href='https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css' rel='stylesheet'
integrity='sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh' crossorigin='anonymous'>
<title>Mostra video</title>
<link href="login.css" rel="stylesheet">
</head>
<body class="text-center">
<form class="form-signin" action="login" method="post">
<input type="hidden" name="redirect" value="<%= request.getParameter("redirect") != null ? request.getParameter("redirect") : "" %>" />
<img class="mb-4" src="img/logo.png" alt="" width="200" >
<% } %>
Classe LoginServlet
import edu.fauser.DbUtility;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.net.URLEncoder;
import java.sql.*;
sessione = request.getSession(true);
sessione.setAttribute("nomecompleto", nomeCompleto);
sessione.setMaxInactiveInterval(30*60); // 30 minuti
response.sendRedirect(redirect);
} else {
String url = String.format("%s/login.jsp?errore&redirect=%s",
request.getContextPath(),
URLEncoder.encode(redirect, "utf-8")
);
response.sendRedirect(url);
}
}
} catch (SQLException e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
e.printStackTrace();
}
Classe DownloadServlet
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Paths;
}
}
try {
FileInputStream fis = new FileInputStream(file);
ServletContext ctx = getServletContext();
String mimeType = ctx.getMimeType(file.getAbsolutePath());
ServletOutputStream os = null;
os = response.getOutputStream();
byte[] bufferData = new byte[4096];
int read;
while((read = fis.read(bufferData)) != -1){
os.write(bufferData, 0, read);
}
os.flush();
os.close();
fis.close();
} catch (FileNotFoundException e) {
response.setStatus(HttpServletResponse.SC_CONFLICT);
} catch (IOException e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
}
Classe AuthFilter
import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.net.URLEncoder;
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
HttpSession sessione = request.getSession(false);
boolean autenticato = sessione != null && sessione.getAttribute("nomecompleto") != null;
if (autenticato == false) {
String dest = request.getRequestURI();
if (request.getQueryString() != null)
dest += "?" + request.getQueryString();
String r = String.format("%s/login.jsp?redirect=%s",
request.getContextPath(),
URLEncoder.encode(dest, "utf-8")
);
response.sendRedirect(r);
} else {
chain.doFilter(req, resp);
}
}
Classe DbUtility 1.5.0 (classe esterna, disponibile sul sito del docente)
prodUser = user;
prodPassword = password;
}
• nuovadomanda.jsp: invia il testo di una domanda alla servlet specializzata nella creazione di nuove
domande.
• nuovarisp.jsp: consente di specificare la risposta a una domanda e alcuni dati sull’utente (nickname,
immagine del profilo). La form di inserimento supporta l’attributo enctype = "multipart/form-data"
per l’upload dell’immagine.
• DomandaServlet (mapping: domanda): inserisce una nuova domanda (priva di risposta) nella tabella
SQL a partire dal testo ricevuto con il metodo POST.
• RispostaServlet (mapping: risposta): riceve i dati della risposta con il metodo POST e aggiorna la
relativa domanda nella tabella SQL; il contenuto dell’immagine è memorizzato in un campo di tipo
“Blob” (Binary Large Object).
Anteprime
USE dbdomande;
Pagina index.jsp
ResultSet rs = s.executeQuery(
"SELECT codice, domanda, risposta, nickname FROM dr_domande");) {
%>
<!DOCTYPE HTML>
<html>
<%@include file="inc/head.jsp"%>
<body>
<%@include file="inc/header-index.jsp"%>
<div class="colorlib-blog" id="elenco">
<div class="container">
<div class="row">
<% int conta = 0;
while (rs.next()) {
conta++;
if (conta > 1 && (conta % 3) == 1) {
%>
</div><div class="row">
<% } %>
<div class="col-md-4 animate-box" >
<article>
<h2 style="height: 5em;"><%= AppUtility.escapeHTML(rs.getString("domanda")) %></h2>
<% if(rs.getString("risposta") == null) { %>
<p style="height: 5em;">
<a href="nuovarisp.jsp?codice=<%= rs.getInt("codice") %>">Rispondi</a>
</p>
<p style="height: 2.5em;" class="author-wrap"> </p>
<% } else { %>
<p style="height: 5em;"><%= AppUtility.escapeHTML(rs.getString("risposta")) %></p>
<p style="height: 2.5em;" class="author-wrap">
<span class="author-img" style="background-image: url(immagine?codice=<%= rs.getInt("codice")%>);"></span>
<span class="author">Autore: <%= AppUtility.escapeHTML(rs.getString("nickname")) %></span></p>
<% } %>
</article>
</div>
<% } // fine while %>
</div>
</div>
</div>
<%@include file="inc/footer.jsp"%>
</body>
</html>
<%
} catch (Exception e) {
e.printStackTrace(response.getWriter());
}
%>
Pagina nuovadomanda.jsp
<!DOCTYPE HTML>
<html>
<%@include file="inc/head.jsp"%>
<body>
<%@include file="inc/header.jsp"%>
<div id="colorlib-contact">
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2 animate-box">
<h2>Nuova domanda</h2>
<form action="domanda" method="post">
<div class="row form-group">
<div class="col-md-12">
<input type="text" maxlength="100" id="domanda" name="domanda" class="form-control"
placeholder="Testo della domanda" required>
</div>
</div>
<div class="form-group">
<input type="submit" value="Invia" class="btn btn-primary">
</div>
</form>
</div>
</div>
</div>
</div>
<%@include file="inc/footer.jsp"%>
</body>
Pagina nuovarisp.jsp
<%
String testo = null;
int codice = -1;
try {
codice = Integer.parseInt(request.getParameter("codice"));
}
catch (NumberFormatException e) {
e.printStackTrace(response.getWriter());
}
}
%>
<%@ page import="edu.fauser.DbUtility" %>
<%@ page import="java.sql.DriverManager" %>
<%@ page import="edu.fauser.netlab.AppUtility" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE HTML>
<html>
<%@include file="inc/head.jsp"%>
<body>
<%@include file="inc/header.jsp"%>
<div id="colorlib-contact">
<div class="container">
<div class="row">
<div class="col-md-10 col-md-offset-1 animate-box">
<h2>Nuova risposta</h2>
<form action="risposta" method="post" enctype = "multipart/form-data">
<input type="hidden" name="codice" value="<%= codice %>" />
<div class="row form-group">
<div class="col-md-12">
<div>Domanda: <strong><%= AppUtility.escapeHTML(testo) %></strong></div>
</div>
</div>
<div class="row form-group">
<div class="col-md-12">
<input type="text" maxlength="100" id="risposta" name="risposta" class="form-control"
placeholder="Testo della risposta" required>
</div>
</div>
<div class="row form-group">
<div class="col-md-4">
<input type="text" maxlength="100" id="nickname" name="nickname" class="form-control"
placeholder="Nickname" required>
</div>
<label for="img" class="col-md-3 col-form-label">Immagine (max. 10 kB)</label>
<div class="col-md-5">
<input type = "file" name = "img" id="img" size = "50" required />
</div>
</div>
<div class="form-group">
<input type="submit" value="Invia" class="btn btn-primary">
</div>
</form>
</div>
</div>
</div>
</div>
<%@include file="inc/footer.jsp"%>
<%
} catch (Exception e) {
e.printStackTrace(response.getWriter());
}
%>
Classe DomandaServlet
Classe RispostaServlet
import edu.fauser.DbUtility;
import edu.fauser.netlab.AppUtility;
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String strCod = request.getParameter("codice");
}
} catch (Exception e) {
e.printStackTrace(response.getWriter());
}
}
private static String estraiFileName(Part part) {
// Ricava il nome del file contenuto nella richiesta HTTP
for (String cd : part.getHeader("content-disposition").split(";")) {
if (cd.trim().startsWith("filename")) {
String fileName = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
return fileName.substring(fileName.lastIndexOf('/') + 1).substring(fileName.lastIndexOf('\\') + 1); // MSIE fix.
}
}
return null;
}
}
Classe ImmagineServlet
import edu.fauser.DbUtility;
ResultSet rs = ps.executeQuery();
if (rs.next() == false) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
// Stream collegato alla risposta HTTP
ServletOutputStream out = response.getOutputStream();
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Metodo POST non gestito da questa servlet
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
}
}
Classe AppListener
import edu.fauser.DbUtility;
@WebListener
public class AppListener implements ServletContextListener, HttpSessionListener, HttpSessionAttributeListener {
public AppListener() {
}
@Override
public void contextInitialized(ServletContextEvent sce) {
// Crea una nuova istanza della classe DbUtility e la condivide con
// le servlet e le pagine JSP sotto forma di attributi del contesto
Classe AppUtility
package edu.fauser.netlab;
import java.sql.SQLWarning;
}
return sb.toString();
}
}
}
Appendice
2. All’interno della sezione Project Settings selezionare la voce Artifacts, quindi premere il bottone + e
selezionare la voce Web Application: Archive → For <nomeapp>:war exploded
3. Allo scopo di facilitare la pubblicazione delle proprie applicazioni sulla piattaforma Netlab, si
consiglia di rinominare il file .war specificando il proprio cognome e l’application context.
4. Per generare l’applicazione in formato WAR, eseguire il comando Build → Build artifacts…,
quindi selezionare il nome dell’artifact e l’azione Build. IntelliJ Idea crea il file .war all’interno della
sottocartella out/artifacts.
<role rolename="manager-gui"/>
<role rolename="admin-gui"/>
<user username="tomcat" password="123456" roles="manager-gui,admin-gui"/>
Accedere all’applicazione di gestione di Tomcat: http://<indirizzo-ip>:8080/manager
Per avviare l’applicazione web, fare click sul relativo collegamento presente nell’elenco delle applicazioni
gestite da Tomcat.
Applicazioni proposte
I. [Applicazione Quadri] – Scrivere un'applicazione web basata su servlet che offra un servizio di
descrizione di quadri. L'applicazione presenta un elenco di quadri disponibili (ogni quadro è
caratterizzato da un codice univoco) da cui l'utente sceglie quello preferito. Successivamente è
inviata una richiesta HTTP per ottenere la pagina web contenente i seguenti dettagli del quadro:
titolo, artista, data di realizzazione, tecnica e materiali, dimensioni, ubicazione, descrizione
oggettiva, descrizione soggettiva. La pagina del quadro può contenere collegamenti a immagini
presenti su siti web esterni.
II. [Applicazione Museo] – All'interno di un museo sono presenti due aree: un'area "rossa" in cui sono
presenti alcuni quadri di pittori famosi; un'area "verde" in cui gli artisti locali espongono i propri
lavori. Il museo ammette solamente visite di gruppo e, a causa del numero elevato di opere d'arte da
ammirare, ogni visita a una qualunque area dura esattamente un giorno.
I costi per visitare il museo sono i seguenti: 12 Euro per ogni membro del gruppo nel caso di
l'accesso all'area rossa; 5 Euro nel caso di accesso all'area verde.
Scrivere un'applicazione web basata su servlet che permetta di prenotare una visita di gruppo a una
delle due aree del museo. L'applicazione, attraverso un'opportuna inrfaccia grafica, deve consentire
le seguenti operazioni:
(a) Inserimento di una nuova prenotazione: l'utente prenota una nuova visita specificando il proprio
nome, la data della visita, il tipo di area (rossa/verde) e il numero di partecipanti. L'applicazione
valuta la richiesta: se nella data indicata è già prevista un'altra visita in quella stessa area, rifiuta
la prenotazione informando l'utente con un opportuno messaggio; in caso contrario registra la
prenotazione e restituisce un messaggio di conferma contenente l'importo totale da pagare.
(b) Visualizzazione delle prenotazioni: l'utente può richiedere, specificando l'area del museo, l'elenco
delle prenotazioni registrate nel server per quell'area. Per ogni prenotazione sono riportati: data,
numero di partecipanti e nome della persona che ha effettuato la prenotazione.
III. [Applicazione Musica] – Scrivere un'applicazione web per la vendita di brani musicali in formato
MP3. I clienti accedono a un'area riservata inserendo opportune credenziali, quindi acquistano i brani
da un elenco proposto. Ogni brano dell'elenco è caratterizzato da: codice, titolo del brano, nome del
cantante, durata, prezzo, nome del file MP3. Prima di procedere all'acquisto, il cliente può
selezionare un apposito pulsante per riprodurre una breve anteprima del brano (max. 15 secondi). Al
termine di ogni acquisto, l'applicazione riassume i brani acquistati fino a quel momento e il costo
totale, permettendo al cliente di completare l'acquisto e procedere al pagamento.
Si supponga che le credenziali dei clienti e le informazioni sui brani acquistabili siano memorizzate
all'interno di tabelle SQL differenti di cui è richiesta la definizione della struttura. Le tabelle devono
inoltre essere popolate con almeno tre utenti e cinque brani.
Facoltativo 1: l'applicazione consente la modifica della password del cliente.
Facoltativo 2 (difficile, richiede un approfondimento2): l'applicazione, concluso il pagamento,
comprime i brani acquistati (in versione integrale) in un file .ZIP e invia il file compresso al cliente.
2 Per approfondire la tecnica di compressione di file nel formato .ZIP vedere:
https://www.codejava.net/java-se/file-io/how-to-compress-files-in-zip-format-in-java