Spring MVC Controller (parte 1)

Come la Action di Struts o il Managed Bean di JSF, il Controller è il componente dell’architettura di Spring MVC che si occupa di gestire le request utente. I controller di Spring sono delle semplici classi java (POJO) che non necessitano di implementare alcuna interfaccia, come avveniva ad esempio in Struts 1.x, ma il framework adotta una strategia basata su annotazioni. Questo lascia al programmatore una enorme flessibilità nella definizione di un controller ed in particolare nella firma dei metodi che lo costituiscono.

Questo articolo vuole essere un breve vademecum delle principali possibilità offerte dal framework nella dichiarazione di un controller.

Definizione di un Controller

Le annotazioni principali per la definizione di un controller sono @Conttoller e @RequestMapping. La Dispatcher Servlet, opportunamente configurata, ricerca le classi annotate con @Controller e ne registra i metodi. Il mapping tra metodi del controller ed URL di invocazione è ottenuto attraverso l’annotazione @RequestMapping. Per un esempio di utilizzo si veda il LoginController.java presentato nell’articolo Primi Passi con Spring MVC (parte 2). I parametri accettati dall’annotazione @RequestMapping sono diversi:

path, value

Utilizzato per specificare la URI o le URI servite dal controller. Sono possibili diversi formati:

  1. formato semplice, es. /myURI.do;
  2. ant-style path, es. /myURI/*.do;
  3. placeholder, es. /myURI/{id}/*.do;
  4. regular expression, es. /{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}}.

Può essere utilizzato sia a livello di classe che di metodo. Il path definito a livello di classe è ereditato dai metodo e contribuisce a definire l’URI utilizzandolo com prefisso.

method Metodo o array di metodi HTTP serviti dal controller. Valori ammessi sono GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE, tutti definiti nella classe RequestMethod.
 headers Header ammessi nella richiesta HTTP servita dal metodo. Possono essere definiti attraverso una sequenza del tipo “Header1=Value1, …, HeaderN=ValueN”, eventualmente anche utilizzando espressioni negate “Header!=Value”.
consumes Consente di limitare la gestione alle sole request con una o più media type specifici, es. {“text/plain”, “application/*”}. L’espressione può essere negata utilizzando l’operatore “!”, es “!text/plain”.

Response Body

Principalmente utilizzata ai fini di test, ad esempio per verificare la raggiungibilità dei servizi, l’annotazione @ResponseBody indica che il valore restituito dal metodo del controller costituisce il body della response. Nessuna altra elaborazione è necessaria.

Fallback Method

Il fallback method è un metodo di un controller che viene utilizzato dal framework ogni volta che non esiste un metodo che gestisca la URI inserita.

Attributi di Sessione

Per la memorizzazione di parametri nella sessione HTTP in modo trasparente il framework mette a disposizione l’annotazione @SessionAttributes. E’ associata alla classe che implementa il controller ed elenca gli attributi che si intende inserire in sessione rendendoli quindi disponibili a request successive. Nell’esempio LoginController il nome dell’utente che esegue il login è un attributo che tipicamente è inserito in sessione.

Nel momento in cui il parametro name è inserito nell’oggetto ModelMap (operazione put()) viene automaticamente promosso a parametro di sessione ed inserito nella sessione HTTP. Il parametri rimangono in sessione fino a quando un altro controller non utilizza l’oggetto SessionStatus per chiudere la sessione:

Parametri di Input del Controller

Il framework non prevede vincoli specifici nella firma dei metodi del controller lasciando il programmatore libero di scegliere tra una varietà di argomenti e valori restituiti.

Path Variable

Nel caso di URI con placeholder (vedi sopra) è possibile recuperare i valori assunti dal segnaposto utilizzando l’annotazione @PathVariable. Estendiamo, ad esempio, il progetto dell’articolo Primi Passi con Spring MVC (parte 2) introducendo la lista dei todo assegnati ai vari utenti. Il dettaglio di uno specifico todo identificato da un id è ottenibile attraverso il seguente controller:

l’id nell’url è collegato al parametro id del metodo (il nome del parametro non deve necessariamente essere uguale) che poi lo utilizza per recuperare il todo e inserirlo nel model.

Parametri della Request

Per il recupero dei parametri nella request il framework introduce l’annotazione @RequestParam. Un esempio è il metodo handleUserLogin() che recupera nome utente e password inseriti nella form di login dall’utente.

I parametri in request possono essere inserite ad esempio utilizzando un form che viene sottomesso con metodo POST o GET, oppure più semplicemente inserendoli nell’URL come query string.

Spring provvede automaticamente ad eseguire la conversione del parametro nel tipo definito nella firma del metodo. In alternativa, se il parametro del metodo è di tipo Map<String,String>MultiValueMap<String,String>, tutti i parametri della request vengono inseriti nella mappa.

Di default il parametro è obbligatorio, ma è possibile renderlo opzionale attraverso l’attributo required dell’annotazione@RequestParam. I’attributo default consente invece, nel caso di parametro opzionale, di definire un valore di default.

Parametri nell’Header

Analogamente ai request parameter è possibile recuperare gli header parameter utilizzando l’annotazione @RequestHeader. Anche in questo caso è possibile ottenere il singolo parametro o la mappa di tutti i parametri presenti nell’header.

Accesso ai Cookie

Attraverso l’annotazione @CookieValue associata ad un argomento del metodo del controller è possibile consente ai cookie HTTP dell’utente. Nell’esempio seguente è recuperato il cookie JSESSIONID utilizzato dalle applicazioni web J2EE per il mantenimento della sessione utente.

La conversione di tipo del cookie è eseguita automaticamente dal framework nel caso in cui il parametro del metodo non sia di tipo String.

Request Body

L’uso della direttiva <mvc:annotation-driven/> nel file di configurazione di Spring abilita il supporto alla serializzazione degli oggetti java in formato XML e viceversa, utilizzando il framework JAXB. Questo consente ad un client di inviare un oggetto serializzato nel body della request ed al controller di recuperare direttamente l’oggetto deserializzato semplicemente utilizzando l’annotazione @RequestBody.

Nell’esempio seguente un oggetto Todo è passato in input al metodo del controller prelevandolo dalla request body e deserializzandolo con JAXB.

Naturalmente la classe le proprietà ed i metodo dell’oggetto  Todo dovranno essere opportunamente annotato con le annotazioni di JAXB secondo necessità. Sicuramente dovrà essere presente  l’annotazione @XmlRootElement a livello di classe.

Multipart Form Data

Il framework consente anche di gestire richieste con content-type uguale a multipart/form-data, generalmente utilizzata per allegare interi file alla request (upload). Per farlo è necessario abilitare un bean MultipartResolver, dichiarandolo nel file di configurazione di Spring, che viene utilizzato dalla DispatcherServelt per il parsing della request.

Ad esempio, l’annotazione @RequestPart associata da un argomento di tipo MultipartFile consente di eseguire l’upload di un file e di gestirlo nel controller prelevandolo dalla request.

Altro

Esiste una varietà di altre possibilità per gli argomenti dei metodi di un controller che non discuteremo nell’articolo. Per maggiori dettagli si rimanda alla documentazione ufficiale al paragrafo Method Arguments.

Parametri di Output del Controller

Si rimanda alla seconda parte di questo articolo: Spring MVC Controller (parte 2).

Codice Sorgente

Il codice sorgente completo degli esempi presentati è scaricabile qui login-sprmvc.