Il progetto Spring Boot consente di semplificare enormemente la realizzazione di applicazioni stand-alone basate sul framework Spring. In questo articolo vediamo come creare una applicazione Spring Boot per l’esposizione di servizi REST. Tali servizi sono stati affrontati nei post Primi Passi con JAX-RS, Iniezione dei Parametri in JAX-RS e Gestione Tipi non Primitivi in JAX-RS.
Creazione del Progetto
Per creare il progetto utilizzeremo Maven ed in particolare l’archetype maven-archetype-quickstart
. Apriamo quindi una shell, posizioniamoci sulla cartella di lavoro e eseguiamo il seguente goal maven di generazione:
1 2 3 4 5 |
mvn archetype:generate -DarchetypeArtifactId=maven-archetype-quickstart -DgroupId=it.javaboss -DartifactId=javaboss-boot -DinteractiveMode=false |
Apriamo quindi Eclipse ed importiamo un progetto maven esistente nel workspace. Eliminiamo la classe AppTest.java
di cui non abbiamo bisogno.
Procediamo quindi modificando il POM file del progetto inseriamo il tag <parent>
verso spring-boot-starter-parent
, in modo da ereditare alcune dipendenze e configurazioni di default come meglio specificato nella documentazione ufficiale.
Inoltre inseriamo la starter dependency spring-boot-starter-web
che include le principali dipendenze per le web application in Spring (RESTful, Spring MVC, etc) e che utilizza Tomcat come container.
Infine inseriamo il plug-in spring-boot-maven-plugin
che introduce specifico goal maven per la gestione di Spring boot.
Il POM quindi avrà il seguente aspetto:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>it.javaboss</groupId> <artifactId>javaboss-boot</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>javaboss-boot</name> <url>http://www.javaboss.it</url> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.1.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> |
La Classe Main
Rinominiamo la classe App.java
generata da maven in Application.java
, per conformità alle best practice di Spring Boot, ed annotiamola con l’annotazione @SpringBootApplication
, che è equivalente all’utilizzo delle annotazioni @Configuration
, @EnableAutoConfiguration
e @ComponentScan
che in progetti Spring Boot sono generalmente utilizzate insieme. In particolare:
@Configuration
permette alla classe di definire dei metodi per la creazione di bean gestiti da container Spring utilizzando l’annotazione@Bean
;@ComponentScan istruisce
Spring per cercare tutte le classi annotate con@Component
,@Service, @Controller
,@Repository
ecc.;@EnableAutoConfiguration
abilita il meccanismo di autoconfigurazione alla base di Spring Boot che fa sì che in base alle librerie presenti nel classpath Spring Boot inserisca automaticamente nel proprio container un insieme di bean.
Infine modifichiamo il metodo main()
in modo da avviare Spring Boot indicando la classe Application.java
come entry point. La classe avrà il seguente aspetto:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * Spring Boot main Application * */ @SpringBootApplication // same as @Configuration @EnableAutoConfiguration @ComponentScan public class Application { public static void main( String[] args ) throws Exception { SpringApplication.run(Application.class, args); } } |
Esecuzione dell’Applicazione
Torniamo alla shell e posizioniamoci nella cartella di root del nostro progetto, dove è collocato il file pom.xml
, quindi utilizziamo il plug-in spring-boot-maven-plugin
per eseguire il progetto utilizzando il goal run
:
1 |
mvn spring-boot:run |
Dopo una prima fase di compilazione noterete che viene avviato il server Tomcat, che è quindi enbedded nell’applicazione, e che rimane in ascolto sulla porta 8080. Se proviamo ad inserire in un browser l’url http://localhost:8080 verrà visualizzata una pagina di errore che ci conferma il corretto avvio dell’applicazione, ma ci dice anche che l’applicazione è “vuota”.
L’alternativa all’utilizzo del plug-in è quella di pacchettizzare l’applicazione in un jar utilizzando l’istruzione:
1 |
mvn clean package |
target
del progetto, ed eseguire quindi il jar con l’istruzione:
1 |
java -jar target/javaboss-boot-1.0-SNAPSHOT.jar |
Questo consente di avviare l’applicazione anche in un ambiente in cui maven non è presente, come generalmente avviene in esercizio.
In ambiente Eclipse un modo rapido di avvio è semplicemente quello di collocarsi sulla classe Application
e, dal menù contestuale, selezionare Run As -> Java Application
.
I Servizi REST
Implementiamo ora un servizio REST di esempio (molto banale) che l’applicazione deve esporre. Per farlo creiamo nel progetto una nuova classe MessageController
ed annotiamola con @RestController
. Si tratta di una annotazione che estende @Controller
e che indica a Spring di convertire gli oggetti restituiti di metodi della classe in JSON o XML.
1 2 3 4 |
@RestController public class MessageController { .... } |
Successivamente inseriamo nella classe il primo controller method getMessages()
che dovrà servire una richiesta HTTP su uno specifico endpoint. Il model Message
non è riportato per semplicità.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@RequestMapping( value="/api/messages", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<List<Message>> getMessages() { // Dummy collection List<Message> messages = new ArrayList<Message>(){ { add( new Message(1, "Hello World") ); add( new Message(2, "I'm Java Boss") ); }}; // Return messages and status code 200 return new ResponseEntity<List<Message>> ( messages, HttpStatus.OK ); } |
Il metodo è annotato con @RequestMapping
che informa Spring che il metodo è in grado di rispondere alle richieste http. I parametri dell’annotazione configurano ulteriormente il controller method indicando:
- l’endpoint cui il metodo e collegato (context path);
- il tipo di metodo http a cui risponde (GET, POST, etc.)
- il tipo di conversione da effettuare sull’oggetto restituito dal metodo.
La classe ResponseEntity
è un wrapper che Spring converte in una response http, mentre il tipo generico con cui è qualificato indica il tipo degli oggetti che saranno inseriti nel body della response. Nel nostro caso una collezione di messaggi.
Procediamo avviando nuovamente l’applicazione e questa volta inserendo nel browser l’url http://localhost:8080/api/messages compariranno i nostri messaggi in formato JSON:
1 2 3 4 5 6 7 8 |
[{ "id":1, "text":"Hello World" }, { "id":2, "text":"I'm Java Boss" }] |
Per completezza implementiamo un secondo metodo per il recupero di un messaggio specifico, dal quale impariamo come utilizzare l’annotazione @PathVariable
per estrarre parametri dall’end-point del servizio e come restituire status differenti dal solito OK corrispondente allo status code 200.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@RequestMapping( value="/api/messages/{id}", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<Message> getMessage( @PathVariable("id") Integer id) { if ( id < 0 || id > 2 ) { return new ResponseEntity<Message> ( HttpStatus.NOT_FOUND ); } if ( id == 1 ) { return new ResponseEntity<Message> ( new Message(1, "Hello World"), HttpStatus.OK ); } else { return new ResponseEntity<Message> ( new Message(2, "I'm Java Boss"), HttpStatus.OK ); } } |
Tornate al browser ed inserite l’url http://localhost:8080/api/messages/1 per visualizzare il JSON del primo messaggio.
Codice Sorgente
Il codice sorgente dell’esempio è scaricabile qui javaboss-boot.