Esercitazioni di Spring Boot 3: gestiamo la logica di business
In questa esercitazione completiamo la struttura del nostro controller REST, analizzando più in dettaglio l'annotazione @RequestMapping
, e realizziamo un service per gestire la logica di business dell'applicazione.
Affinchè il controller sia di qualche effettiva utilità avremo bisogno di ulteriori endpoint per aggiungere un nuovo calciatore, aggiornarne i dati e cancellarlo dalla lista.
Prima di dedicarci alla stesura completa del controller facciamo un accenno al componente che annoteremo con @Service
.
E' buona norma non inserire direttamente nel REST controller il codice che "gestirà" di fatto le richieste dei client in modo da poter cambiare questa modalità con un minimo impatto.
In questo esempio utilizzeremo una lista di calciatori preimpostata giusto per fare qualche esperimento. In seguito ci appoggeremo ad un database come in uno scenario reale.
Utilizzando una classe Service
potremo passare da una soluzione all'altra semplicemente cambiando il bean che viene iniettato nel controller REST tramite @Autowired
senza toccarne il codice, ovviamente a patto che i metodi presenti nei due service abbiano la stessa firma.
Senza rubare ulteriore spazio vi rimando al codice su GitHub.
Abbiamo per l'appunto una lista di 3 calciatori e una serie di metodi che consentono di recuperare l'elenco, aggiungere, modificare e cancellare una voce dato il suo id.
Niente di più semplice. Dal punto di vista di Spring va rilevata solo la presenza dell'annotazione @Service
per denotare la tipologia della classe e consentire al framework di gestirne il lifecycle.
Ritorniamo al controller REST.
Abbiamo già visto che l'annotazione @RequestMapping
serve proprio a marcare gli endpoint del controller specificando il path di riferimento ma anche il tipo di richiesta (GET, POST, PUT, DELETE). In questo modo la DispatcherServlet
di Spring, che funziona come una sorta di centralino, saprà come smistare correttamente le richieste HTTP provenienti dai client.
Possiamo indicare, oltre al path, anche il tipo di richiesta ma per le GET e POST esistono specifiche annotazioni quali @GetMapping
e @PostMapping
.
Quindi
@GetMapping("/players")
equivale in una forma più compatta a
@RequestMapping(value = "/players", method = RequestMethod.GET)
Lo stesso dicasi per il metodo POST dove avremo
@PostMapping("/players")
in luogo di
@RequestMapping(value = "/players", method = RequestMethod.POST)
Si osservi che in entrambi i casi abbiamo lo stesso endpoint /players
ma, essendo differente la tipologia di richiesta (in un caso GET e nell'altro POST), non ci sarà alcun fraintendimento per il controller.
Il codice della classe è accessibile qui.
Come accennavo in precedenza andiamo ad iniettare il service con
@Autowired
private PlayerService playerService;
in modo da richiamarne i metodi direttamente nei vari endpoint.
Vediamo in dettaglio come gestire l'aggiunta di un nuovo calciatore.
PostMapping("/players")
public void addPlayer(@RequestBody Player player) {
playerService.addPlayer(player);
}
Possiamo notare che il metodo addPlayer(Player player)
richiede come parametro un oggetto di tipo Player
e che quest'ultimo è preceduto dall'annotazione @RequestBody
.
Poichè nelle richieste POST gli eventuali parametri sono passati all'interno del corpo delle stesse, tale annotazione permette di estrarne l'oggetto per passarlo al metodo. La cosa più straordinaria è che Spring si occupa di tutto in modo trasparente, in particolare gestendo la conversione da JSON a POJO.
L'aggiunta è effettuata dal metodo addPlayer()
della classe PlayerService
.
Commentiamo rapidamente gli altri due endpoint per l'aggiornamento e la cancellazione.
Nel primo caso si tratta di una richiesta PUT gestita dal metodo updatePlayer()
del service
@RequestMapping(value = "/players/{id}", method = RequestMethod.PUT)
public void updatePlayer(@PathVariable int id, @RequestBody Player player) {
playerService.updatePlayer(id, player);
}
Nell'altro di una DELETE affidata a deletePlayer()
.
@RequestMapping(value = "/players/{id}", method = RequestMethod.DELETE)
public void deletePlayer(@PathVariable int id) {
playerService.deletePlayer(id);
}
Mi preme osservare che in entrambe le situazioni l'annotazione @PathVariable
precede l'argomento passato all'endpoint ad indicare che quest'ultimo sarà estratto direttamente dall'URL.
Ad esempio volendo cancellare il calciatore con id = 3 dovremo inoltrare una richiesta di tipo DELETE all'URL http://localhost:8080/players/3, ipotizzando che l'applicazione giri localmente sulla porta 8080.
Non c'è altro da dire per ora. Trovate il codice completo su GitHub. Basterà eseguirlo all'interno del vostro IDE preferito o da riga di comando con
mvn spring-boot:run
ed utilizzare curl o Postman per fare i vostri esperimenti.
La prossima volta scenderà in campo il database MySQL.
[VIDEO]
[LINKS]