Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Spring MVC: la gestione dei Form

Link copiato negli appunti

Spring MVC: la gestione dei Form

Dopo aver introdotto le prime due componenti del modello MVC ovvero i Controller e le View è ora di parlare di Model. Rispetto agli altri, il concetto di Model è un po' più ampio e privo di confini precisi.

Con Model infatti si intende qualsiasi oggetto che rappresenta la realtà descritta dall'applicazione Web che funge da connettore tra gli altri componenti. Nell'articolo precedente abbiamo imparato ad usare l'oggetto Model che serve a passare informazioni reali dal Controller alla Vista.

In questo articolo parleremo di una seconda tipologia di Model: gli oggetti Form. Nonostante questa dicitura possa sembrare impropria, tale tipologia di oggetti svolge la medesima funzione ma in senso opposto, ovvero permette di raccogliere dati dalle View e di renderli disponibili nei Controller.

Il primo form

Il miglior modo per realizzare un form Web è quello di partire dalla tipologia di contenuto che esso rappresenta e creare una classe ad hoc per i suoi attributi. Come primo esempio prendiamo in considerazione un semplice form di anagrafica dove è possibile registrare persone. Creiamo quindi la nostra classe PersonForm:

public class PersonForm {
	private String name;
	private String surname;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSurname() {
		return surname;
	}
	public void setSurname(String surname) {
		this.surname = surname;
	}
}

Una volta definita la classe possiamo occuparci del Controller che, grazie a Spring MVC non dovrà preoccuparsi di Request e parametri vari, ma potrà gestire direttamente un model istanziato dalla classe PersonForm. Dato che per gestire un form web sono necessari due step: visualizzazione del form e raccolta dati, il miglior modo è quello di mantenere una URL unica per le azioni, differenziandone i metodi HTTP e ovviamente i metodi Java.

@RequestMapping(value="/person", method=RequestMethod.GET)
public String savePerson(@ModelAttribute PersonForm personForm, Model model) {
	model.addAttribute("personForm", personForm);
	return "person";
}
@RequestMapping(value="/person", method=RequestMethod.POST)
public String savePersonPost(@ModelAttribute PersonForm personForm) {
	System.out.println(personForm.getName() + " " + personForm.getSurname());
	return "redirect:/person";
}

Entrambi i metodi fanno affidamento alla annotation @ModelAttribute che permette di associare, se presenti, i parametri ricevuti da un oggetto. Nel caso del metodo savePerson esso sarà istanziato senza nessuna proprietà mentre, nel caso del metodo savePersonPost, i parametri verranno iniettati dentro l'oggetto grazie ad un'operazione di binding.

Il termine binding può essere tradotto come legame o attacco e rappresenta l'operazione, svolta da Spring MVC, di conversione da parametri HTTP (che principalmente sono stringhe) in oggetti
composti e definiti dall'utente. Per la maggior parte dei casi le operazioni di binding già presenti in Spring MVC sono più che sufficienti, ma in caso contrario sarà possibile definirne dei propri.

L'ultimo step per completare il ciclo è la scrittura della pagina person.jsp; anche in questo caso Spring MVC ci viene in aiuto con un insieme di tag adatto al nostro scopo:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<c:url var="url" value="/person" />
<form:form action="${url}" method="post" modelAttribute="personForm">
<label>Nome:</label>
<form:input path="name" />
<label>Cognome:</label>
<form:input path="surname" />
<input type="submit" />
</form:form>

I tag di Spring utilizzano i valori inseriti negli attributi modelAttribute (di form:form) e di path (di form:input) per fare il binding dei valori inseriti dall'utente. Ovviamente lo stesso approccio può essere utilizzato anche in caso di form prepopolati, utili in caso di modifica di un'entità:

@RequestMapping(value="/updatePerson", method=RequestMethod.GET)
public String updatePerson(@ModelAttribute PersonForm personForm, Model model) {
	personForm.setName("Nome di default");
	personForm.setSurname("Cognome di default");
	model.addAttribute("personForm", personForm);
	return "person";
}

La validazione dei form

Non esiste form che non si rispetti che non abbia una validazione dei dati inseriti dall'utente. Spring MVC utilizza l'API di javax.validation (jsr-303 bean validation) per gestire la validazione degli oggetti form. Dopo aver inserito le dipendenze dell'API e di una sua implementazione nel pom.xml, possiamo annotare la nostra classe form in questo modo:

public class PersonForm {
   @NotNull
   @Size(min=1)
   private String name;
   @NotNull
   @Size(min=3)
   private String surname;
   // [...]
}

Con queste annotation abbiamo comunicato al framework che entrambi i campi sono obbligatori e che il cognome deve essere lungo almeno 3 caratteri. Riguardo alle annotations è necessario un
approfondimento: le specifiche JSR-303 non presentano una valida annotation per gestire le stringhe di lunghezza zero, l'unico meccanismo valido per il controllo è quello di inserire la doppia
annotation @NotNull e @Size(min=1). Nel provider di validazione più utilizzato (hibernate-annotations) questa mancanza viene coperta con una nuova annotation specifica per questo caso fortemente legato al Web: @NotBlank. La scelta di quale sia la miglior strategia dipende dalla volontà di far riferimento allo standard o di legarsi ad una particolare libreria.

Passiamo ora al controller che riceverà l'oggetto form:

@RequestMapping(value="/person", method=RequestMethod.POST)
public String savePersonPost(@Valid @ModelAttribute PersonForm personForm, BindingResult result, Model model) {
   if(result.hasErrors()) {
       model.addAttribute("personForm", personForm);
       return "person";
   }
   System.out.println(personForm.getName() + " " + personForm.getSurname());
   return "redirect:/person";
}

In questo caso abbiamo aggiunto l'annotation @Valid al nostro oggetto form per forzarne la validazione automatica e un nuovo parametro di tipo BindingResult alla firma del metodo. Quest'ultimo oggetto, disponibile solamente per i form, contiene eventuali incongruenze di binding tra il form e l'oggetto Java e, tramite il metodo .hasErrors(), informazioni su errori di validazione.

In caso di errori ritorniamo alla vista person impostando nel model l'oggetto ricevuto per offrire all'utente i campi già prepopolati con i valori precedenti.

All'interno delle nostre JSP possiamo mostrare l'errore utilizzando il tag <form:errors>:

<form:errors path="*" />
<label>Nome:</label>
<form:input path="name" />
<form:errors path="name" />

Grazie all'attributo path del tag possiamo scegliere per quale campo visualizzare l'errore; utilizzando l'asterisco ("*") possiamo dire a Spring MVC di mostrarci tutti gli errori.

Per internazionalizzare il testo degli errori si possono utilizzare un MessageSource utilizzando una chiave costruita secondo la regola nomeValidazione.nomeModelAttribute.nomeProprieta. Nel caso in cui il cognome sia più lungo di tre caratteri: Size.personForm.surname.

Ti consigliamo anche