Spring: I Controller

Questo articolo è parte di una serie di articoli dedicati alla programmazione di Web App. Si tratta di un articolo divulgativo ed è pensato per essere di supporto e ripasso alle lezioni che tengo nel mondo reale. Buona lettura.

In qualsiasi modo sia stata generata la vostra Request, la risposta ad essa sarà sempre generata da un Controller, almeno in una Web Application creata con Spring.

I Controller sono un pezzo fondamentale del paradigma MVC ed hanno appunto il compito di rispondere alle Request, generando una Response.

Il Controller è un po’ il “punto di ingresso” di un’applicazione web. Ogni controller è una classe Java che ha uno o più metodi, ognuno dei quali è associato ad un diverso indirizzo URL. Quando arriva una request verso quell’indirizzo verrà eseguito il metodo corrispondente.

Vediamo un esempio:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/home")
public class HomeController {

    @GetMapping("/hello")
    public ResponseEntity<String> result(@RequestParam int limit) {
        return new ResponseEntity<>("Hello World!", HttpStatus.OK);
    }
}

Questo controller definisce una route (un “percorso”) all’indirizzo /home/hello in modalità GET, accetta un parametro chiamato limit e restituisce una response, con “Hello World” come contenuto, come body.

La mappatura di un URL avviene attraverso le annotations @GetMapping e @RequestMapping, che vanno lette insieme. Annotando l’intero controller si fornisce una “base” per tutti gli URL che sono definiti sui singoli metodi. E’ una pratica comune ma non obbligatoria. Quello che conta di più sono le annotazioni sul singolo metodo, poiché è così che (ovviamente) si indica al sistema quale “pezzo di codice” eseguire a fronte di una Request su quell’indirizzo.

Come si può facilmente immaginare l’annotation @GetMapping indica una mappatura per una richiesta con metodo GET, mentre l’annotation @PostMapping indicherà una richiesta con metodo POST. L’annotation @RequestMapping è invece più generica e può essere usata per mappare richieste con metodi diversi. Le annotation (tutte, in generale) possono avere degli attributi ed anche queste non fanno eccezione. Per esempio:

@RequestMapping(value="/entity/save", method="POST")

mapperà l’indirizzo “/entity/save” con metodo POST.

Per “produrre” una response, invece, il controller nell’esempio restituisce un apposito oggetto (ResponseEntity) ma esistono anche altri modi con cui un Controller può restituire la response. Vediamoli in breve:

  1. Restituire un oggetto ResponseEntity<T>, dove T è normalmente una Stringa.
  2. Manipolando in modo diretto l’oggetto HttpServletResponse, richiesto appositamente come parametro nel metodo.
  3. Restituendo il nome di un template Thymeleaf, dopo che Thymeleaf sarà stato configurato come template engine.
  4. Restituendo un oggetto con l’annotation @ResponseBody, che converte automaticamente l’oggetto restituito in una stringa JSON.

Si noti poi che l’intera classe è stata etichettata con l’annotation @Controller. Questa annotation permette a Spring di capire che la classe in questione è un componente di sistema, nello specifico (appunto) un controller e che quindi bisognerà annotare tutti gli URL mappati con i loro relativi metodi.

I parametri

Veniamo ora ad un aspetto particolarmente importante dei metodi di un controller: parametri. I parametri del metodo scelto per rappresentare un determinato URL rappresentano i parametri della request, ma non solo. E’ possibile chiedere a Spring determinate risorse, semplicemente inerendole come parametri. Per esempio, il metodo:

public void hello(HttpServletResponse response) throws IOException

chiede a Spring di avere a disposizione la Response da restituire all’utente, in modo da poterla manipolare in modo diretto. Allo stesso modo il metodo:

public String hello(Model model)

chiede a Spring di avere un oggetto Model in ingresso, che verrà usato per passare parametri dal controller al template. E così via.

Se invece siamo interessati a farci dare dal sistema i parametri della request, dobbiamo usare l’annotation @RequestParam come nell’esempio all’inizio di questo articolo. un altra possibilità è usare l’annotation @PathVariable, ma in questo caso i parametri saranno espressi all’interno dell’URL e saranno riconosciuti in base alla posizione e al tipo. Per esempio:

@PostMapping("/entity/{id}/save")
public ResponseEntity<String> update(@PathVariable int id)

definisce un parametro intero id, che si troverà fra le stringhe /entity/ e /save nella request.

Ancora, è possibile mappare interi oggetti grazie all’oggetto BindingResult. Si consideri il seguente esempio:

@RequestMapping(value = "/simple/save", method=RequestMethod.POST)    public String save(Company company, BindingResult bindingResult) 

L’oggetto BindingResult cercherà una corrispondenza nominale fra i parametri presenti nella Request ed i metodi setter dell’oggetto Company, cercando appunto di ricostruire un oggetto di questo tipo. Se tutto va a buon fine (ovvero se i nomi dei parametri della request corrispondono in pieno con i nomi degli attributi dell’oggetto Company) allora un’istanza dell’oggetto Company sarà passata come parametro di questo metodo e tale istanza conterrà i valori dei corrispondenti parametri della Request. Altrimenti verranno generati degli errori di matching, che saranno comunque recuperaibili all’intrno dell’oggetto BindingResult.

Esiste poi un ultimo metodo, ancora più semplice, ma valido solo per le chiamate REST e per ricevere oggetti in formato JSON. Si tratta di anteporre al tipo del parametr che vogliamo ricevere l’annotation @RequestBody, in modo da indicare che tale oggetto sarà presente nel body della Request come JSON, appunto. Per esempio, così:

@PostMapping("/company/save")    
public String save(@RequestBody Company company)

Vi consiglio di esecitarvi molto con i parametri della request e di cercare online anche altri esempi più completi e più specifici dei presenti.

I Controller ed i loro parametri sono una parte molto importante della programmazione di Web App ed è bene conoscerli a fondo prima di continuare nell’apprendimento. Per oggi è tutto. Grazie per l’attenzione e buon lavoro!

Comments are closed.