Creare una semplice web application con JAVA, Eclipse, Tomcat, Hibernate e PostgreSQL – Parte #5

Questo è il quinto di una serie di articoli, la parte precedente si trova qui: Creare una semplice web application con JAVA, Eclipse, Tomcat, Hibernate e PostgreSQL – Parte #4

Dopo aver analizzato nell’articolo precedente quali sono i principali errori che si potrebbero verificare in caso di errate di configurazioni o di problemi nel codice, torniamo alle funzionalità della nostra applicazione e proseguiamo nella loro implementazione.

AGGIUNGERE UN ATTRIBUTO ALLA REQUEST
Per prima cosa, avevamo lasciato in sospeso il discorso di passare un oggetto User (Model) dalla servlet (Controller) alla pagina JSP (View), senza che quest’ultima eseguisse nuovamente il getParameter dei parametri inviati tramite il form, ma ricevesse direttamente l’oggetto. In questo modo leggiamo i parametri in un solo punto, riducendo la probabilità di errore, ed evitiamo l’eventuale disallineamento delle informazioni dovuto alla doppia lettura qualora in uno dei due punti si sia commesso un errore (come abbiamo visto nell’articolo precedente in cui la pagina jsp leggeva correttamente i parametri ma la servlet no).
Per fare questo dobbiamo utilizzare il metodo setAttribute, definito sempre nell’interfaccia ServletRequest implementata dalla classe HttpServletRequest che rappresenta, come abbiamo visto, la richiesta che arriva alla servlet. Andando a consultare la documentazione (LINK!!!) vediamo che il metodo setAttribute è definito come segue:

void setAttribute(java.lang.String name, java.lang.Object o)

Parametri:

  • name: una stringa che definisce il nome dell’attributo
  • o: l’oggetto da salvare come attributo della richiesta

La documentazione aggiunge anche le seguenti informazioni:

  • Gli attributi sono relativi alla singola richiesta e sono disponibili finchè lo è la richiesta stessa
  • Il metodo è solitamente utilizzato in combinazione con un RequestDispatcher
  • Il nome degli attributi segue la stessa naming convention prevista per la definizione dei packages
  • Se l’oggetto passato al metodo è null l’attributo non viene inserito

Modifichiamo quindi la nostra Servlet inserendo la chiamata setAttribute prima del forward della richiesta alla JSP:

request.setAttribute("user", u);	// inseriamo l'oggetto User nella richiesta..
		
RequestDispatcher view = request.getRequestDispatcher("useradd.jsp");  // ..e lo inviamo alla JSP
view.forward(request, response);

L’immagine ci mostra come si presenta la nostra servlet “AddUser”:
Servlet to JSP setAttribute

Se nella nostra servlet settiamo l’attributo in modo tale da renderlo disponibile alla pagina JSP, in quest’ultima dobbiamo poi effettuarne la lettura. Per farlo, piuttosto intuitivamente, dobbiamo utilizzare il metodo getAttribute della request, passandogli il nome del parametro che vogliamo recuperare. Il metodo getAttribute restituisce un Object, per cui dobbiamo per forza fare un cast esplicito dell’oggetto al tipo User.
Per poter utilizzare la classe User dobbiamo farne l’import come segue:

<%@ page import="com.dede.app1st.model.User"%>

Il codice della nostra pagina JSP “useradd.jsp” diventa quindi il seguente:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"
    import="com.dede.app1st.model.User"%>
<!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=ISO-8859-1">
<title>1st Web App - New User Created</title>
</head>
<body>
	<h1>New User Created</h1>
	
	<p>
	<% User u = (User)request.getAttribute("user"); %>  // dobbiamo fare il cast esplicito
	First Name: <% out.print(u.getFirstname()); %> <br/>
	Last Name:  <% out.print(u.getLastname()); %> <br/>
	Country:    <% out.print(u.getCountry()); %>
	</p>
</body>
</html>

Servlet JSP getAttribute

Ora che abbiamo visto come perfezionare il meccanismo di comunicazione tra la servlet e la pagina JSP, possiamo tornare all’arricchimento della nostra applicazione. Il prossimo punto che affrontiamo è l’aggiunta di un controllo per garantire l’univocità degli utenti e verificare quindi che un utente che stia cercando di registrarsi non lo abbia già fatto in precedenza e risulti già presente nel database.

EVITARE LA DUPLICAZIONE DEGLI UTENTI
Per poter implementare un meccanismo che prevenga l’inserimento di utenti duplicati dobbiamo definire il criterio secondo cui riteniamo che l’utente che si sta registrando sia già presente nel nostro database. In genere un controllo di questo tipo viene effettuato su campi come lo username o l’indirizzo mail ma, vista la semplicità della struttura User che stiamo utilizzando, supponiamo che non ci possano essere nel nostro sistema due utenti con lo stesso nome e cognome. In fondo, al di la dei campi utilizzati, quello che ci interessa vedere è come definire un vincolo di unicità su una serie di campi della nostra struttura e quindi di colonne di una tabella del nostro database.
Allo stato attuale la nostra applicazione non effettua nessun controllo di questo tipo; proviamo ad esempio ad effettuare una nuova richiesta di creazione di un utente inserendo gli stessi dati che avevamo inserito in precedenza per creare il primo utente

Web Application input form

Una volta completata l’operazione andiamo a verificare nella tabella “users” del database e, come illustrato nella figura sottostante, possiamo vedere che è stato inserito un nuovo record con gli stessi valori delle colonne “firstname”, “lastname” e “country” del primo record inserito in precedenza.
Web Application database record duplicati

CREARE UNO UNIQUE CONSTRAINT NEL DATABASE
Per impedire che questo si verifichi e per garantire che la coppia di valori “firstname” e “lastname” sia univoca per tutte le righe della tabella “users” dobbiamo definire un constraint di unicità. Per farlo andiamo nella console pgAdmin3, in corrispondenza della tabella “users” del nostro database “firstapp” e clicchiamo con il tasto destro del mouse sulla voce “Constraints”, poi selezioniamo “New Object” e poi ancora “New Unique Constraints”. L’immagine seguente mostra questa operazione:
Web Application database new constraint

A questo punto si apre una nuova finestra per la creazione guidata del constraint, in cui iniziamo ad inserire il nome del constraint stesso ed eventualmente un commento che fornisce una descrizione di quale sia il suo scopo. Chiamiamo ad esempio il nostro constraint “UniqueName”, come illustrato in figura:
PostgreSQL new unique constraint

A questo punto dobbiamo selezionare quali sono le colonne che vogliamo includere nella definizione del constraint di unicità e che dovranno quindi, nel loro insieme, avere almeno un valore diverso in ciascun record della tabella. Per farlo ci spostiamo nel tab “Columns” della finestra di creazione e selezioniamo in questo caso le colonne “firstname” e “lastname”.

PostgreSQL create new unique constraint columns

Siamo quindi pronti per concludere la creazione del nostro constraint premendo su “OK”. Facendolo però, otteniamo il risultato della figura seguente, dove un avviso ci segnala che c’è stato un errore nella creazione del vincolo che avevamo configurato, dovuto al fatto che nella tabella esiste già una coppia di valori delle colonne “firstname” e “lastname” che si ripete. Nel messaggio di errore di viene anche segnalato quali sono questi valori ripetuti.
PostgreSQL create new unique constraint columns

Questo significa che, prima di poter creare il vincolo sulla nostra tabella, dobbiamo rimuovere i valori duplicati già presenti. Andiamo quindi sulla tabella “users”, selezioniamo l’ultimo record inserito, clicchiamo con il tasto destro del mouse e selezioniamo la voce “Delete” come illustrato nella figura sottostante.
PostgreSQL remove duplicate record
Ora che abbiamo eliminato il record duplicato, la creazione del vincolo unique va a buon fine e lo vediamo comparire sotto la voce “Constraints” della tabella “users” nella console di pgAdmin3.
PostgreSQL unique constraint created

SPECIFICARE IL CONSTRAINT UNIQUE IN JPA/HIBERNATE
Dopo aver definito il constraint di univocità sul database dobbiamo fornire l’informazione della sua esistenza ad Hibernate e trasferire questo concetto sulla nostra classe Entity “User” che mappa la tabella su cui abbiamo definito il vincolo.
La specifica Java Persistence API permette di specificare questa informazione tramite un attributo dell’annotation “@Table” chiamato appunto “uniqueConstraints”, che viene valorizzato tramite un’ulteriore annotation chiamata “@UniqueConstraint” che richiede un elemento obbligatorio columnNames definito come un array di String contenente la lista delle colonne che compongono la chiave univoca.
Dobbiamo quindi modificare l’annotation @Table nella classe User nel modo seguente:

@Table( name = "USERS",
	uniqueConstraints = {@UniqueConstraint(columnNames = {"firstname","lastname"})}
)

In figura è illustrata tale modifica:

JPA UniqueConstraint annotation
La cosa importante da ricordare è che le annotations JPA appena specificate non definiscono il vincolo di unicità di per se, ma forniscono solo l’informazione che tale vincolo è presente. Il vincolo deve sempre comunque essere definito nel database.

A questo punto effettuiamo un test, provando nuovamente a creare un utente inserendo ancora una volta le stesse informazioni del record già presente nel database.
Web Application input form

Mentre prima riuscivamo tranquillamente ad inserire nel database un record contenente informazioni identiche a quelle di un utente già presente, ora che abbiamo definito uno unique constraint sulla coppia di colonne “firstname” e “lastname” otteniamo una ConstraintViolationException:

Grave: Servlet.service() for servlet [com.dede.app1st.controller.AddUser] in context with path [/WebTest] threw exception
org.hibernate.exception.ConstraintViolationException: could not execute statement
. . .
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "UniqueName"
  Dettaglio: Key (firstname, lastname)=(Davis, Molinari) already exists.

Come possiamo vedere il tipo di errore è molto parlante e ci indica che stiamo cercando di inserire un record che viola il constraint di univocità chiamato “UniqueName”. Inoltre ci viene fornito il dettaglio di quali sono le colonne che compongono la chiave unica (“firstname” e “lastname”) e quali sono i valori che stiamo inserendo per cui esiste già una coppia nel database (“”Davis” e “Molinari”).
L’immagine seguente raffigura il risultato dell’operazione di insert del record esistente:
Unique Constraint violated

In questo modo la nostra applicazione impedisce si di inserire nel database due utenti uguali però, in una evenienza di questo tipo scatena un’eccezione. Nel prossimo articolo vediamo come gestire questa eccezione ed impedire che si generi l’errore, fornendo invece all’utente un messaggio relativo al problema verificatosi con un’altra pagina JSP opportuna.

Leggi anche:

This entry was posted in $1$s. Bookmark the permalink.

13 thoughts on “Creare una semplice web application con JAVA, Eclipse, Tomcat, Hibernate e PostgreSQL – Parte #5

  1. Pingback: Creare una semplice web application con JAVA, Eclipse, Tomcat, Hibernate e PostgreSQL – Parte #4 | Dede Blog

  2. ottimo tutorial Davis, difficile trovarne così chiari come il tuo (come tutti i tuoi articoli del resto).
    se la serie continua la leggerò con attenzione (e penso che non sarò l’unico)

    • Ciao Fabio,
      grazie mille, sono contento che hai trovato gli articoli utili e chiari. Avevo già in mente molte cose con cui andare avanti nella serie di articoli, spero di riuscire a riprenderle. L’argomento è vasto e si presterebbe facilmente ancora un sacco di cose interessanti. Spero di riuscire a riprendere la cosa.
      Grazie per aver lasciato un commento.
      Davis

  3. Ciao Fabio,
    ho iniziato da pochissimo ad approcciarmi al mondo di hibernate e devo dire con la tua guida a parte qualche rogna, sono riuscito a far funzionare la mia web application. Condivido quanto scritto da altri utenti, a trovarle in giro di questi tutorial fortemente dettagliati, sarebbe tutto più semplice per chi inizia e già mastica java :-) GRAZIE mille !!!!

    • Ciao,
      sono felice che la guida ti sia stata d’aiuto. Ho in cantiere altre “puntate” di questa serie sullo sviluppo di web application che riguardano nuovamente Hibernate, spero di riuscire a completarle e pubblicarle presto.
      Grazie per aver lasciato un commento, mi sono molto utili per capire se il taglio degli articoli va bene e cosa si può migliorare.

      Davis (non Fabio, Fabio era un altro utente a cui rispondevo :) )

      • hai ragione Davis :-) !!! Sorry… adesso sto riscontrando un problema nella lettura dei dati scritti su db. Cioe’ recupero una lista di Object contenente le informazione esatte ma non riesco a capire perché il casting esplicito non funziona. Su stackoverflow ho letto varie cose ma ancora nessun risultato…. :-(

  4. Eccellente tutorial: mi è stato utilissimo e …sono rimasta male quando l’ho trovato interrotto…

  5. Potresti continuare il tutorial?

    L’ho trovato molto utile, in giro – in termini di qualità – non ha eguali.

    • Ciao Marco,
      grazie mille per i complimenti. Purtroppo non ho più avuto tempo di proseguire con il tutorial; mi sono ripromesso più volte di riprenderlo ma per ora non ce l’ho fatta.
      Sei riuscito a risolvere il problema che avevi incontrato nella parte 3, per cui avevi lasciato il commento?

      Davis

      • Fortunatamente sì, sono riuscito a risolvere.

        Io sto usando Hibernate 5.1 e pare che in questa versione ci siano alcune differenze rispetto alle precedenti.

        Praticamente la Session Factory va creata così:

        SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();

        Anziché:

        Configuration config = new Configuration().configure();
        ServiceRegistry servReg = new StandardServiceRegistryBuilder().applySettings(config.getProperties()).build();
        SessionFactory factory = config.buildSessionFactory(servReg);

        Devo realizzare una “piccola” web application che interagisca con un DB in PostgreSQL e dopo tante ricerche sul Web mi sono finalmente imbattuto nel tuo sito, in particolare questo tutorial, che, oltre ad avere i suddetti contenuti di interesse, li espone in modo chiaro e conciso.

        Non immagini l’amarezza una volta resomi conto che fosse subito interrotto! Infatti sto cercando qualcosa di simile ma finora nessun esito… sono disperato perché purtroppo sono nuovo a queste tecnologie e non so dove andare a sbattere la testa!

        Del resto mi servirebbero giusto le competenze per realizzare qualche altra funzionalità basilare complementari a quelle da te mostrate… tipo mostrare i risultati della select su una o più tabelle… insomma, le classiche operazioni CRUD ma tramite JSP e servlet esattamente come avevi iniziato a fare tu in questa guida… . questo è ciò che il mio progettino prevede .

  6. Davis non mi hai più risposto… potresti almeno mostrarmi come sviluppare una funzione “mostra utenti” che faccia la select sulla tabella users e mostri i risultati? Sempre seguendo questo approccio MVC… io ho fatto un tentativo mettendo nella JSP il codice con la query ma a quanto pare non è corretto fare così

  7. Consiglio la lettura della nuova serie “Creare una web application con Spring Boot, MongoDB, Angular 4 e TypeScript e deployarla in cloud come Microsoft Azure Webapp“. La prima parte qui.

    Davis

Leave a Reply

Your email address will not be published. Required fields are marked *