I. Introduction▲
Suite à une conférence à Mix-IT 2014, j'hésite sur la manière de construire mon backend REST. Il m'arrive régulièrement d'avoir à écrire un backend REST pour une simple page web-app. En règle générale, je génère dans un premier temps mon application avec Express installé sur ma machine.
Cependant, ce n'est peut-être pas la méthode la plus efficace pour moi… Mon cœur de développeur balance entre un backend en NodeJS ou en Java grâce à Spring Boot. Sans trop de suspens, je vais mettre à l'épreuve la méthode avec Spring Boot.
Spring Boot nous apporte toute la puissance du framework Spring bien connu des développeurs Java, ainsi qu'un Tomcat embarqué et une documentation de référence expliquant clairement comment déployer une telle application dans le nuage, sur une plateforme telle que Heroku.
II. Installer Spring Boot▲
Spring Boot est très simple à utiliser. Tout ce que vous devez avoir est un JDK (au moins 7) et Maven ou Gradle. Une base de données peut être également utile pour stocker des données. Dans la suite de cet article, nous utiliserons Maven.
Ensuite, il suffit de créer un projet Maven comme vous le faites habituellement et d'ajouter cette configuration dans le fichier pom.xml.
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.
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd
<modelVersion>4.0.0</modelVersion>
<groupId>com.sqli</groupId>
<artifactId>boottutorial</artifactId>
<version>1.0-SNAPSHOT</version>
<parent> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.1.4.RELEASE</version>
</parent>
<dependencies>
<dependency> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Une fois que cela est fait, vous pouvez créer une classe principale qui sera appelée au démarrage, comme celle-ci :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
package
com.sqli;
import
org.springframework.boot.SpringApplication;
import
org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import
org.springframework.context.ApplicationContext;
import
org.springframework.context.annotation.ComponentScan;
import
org.springframework.context.annotation.Configuration;
@Configuration
@EnableAutoConfiguration
@ComponentScan
public
class
MainLauncher {
public
static
void
main
(
String[] args) throws
Exception {
SpringApplication.run
(
MainLauncher, args);
}
}
L'annotation @Configuration indique à Spring que cette classe peut contenir de la configuration, @EnableAutoConfiguration fait toute la magie de Spring Boot : vous n'avez pas à vous soucier de l'initialisation des beans, du déploiement sur un Tomcat, de la configuration de base, etc. Et l'annotation @ComponentScan initialise le component scanning que nous avions l'habitude de mettre dans le fichier de configuration Spring.
Votre application est désormais prête à être développée !
III. Créer son propre CONTROLLER▲
III-A. Les entités▲
Maintenant que la base de l'application est prête, vous pouvez développer votre application Java comme vous l'auriez fait avec un Spring classique.
Pour cet article, j'ai décidé de créer une API qui permet de stocker des emplacements sur une carte HTML avec un nom et un nom abrégé.
Pour commencer, nous construisons une classe entité comme suit :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
package
com.sqli.domain;
import
javax.persistence.*;
@Entity
public
class
Place {
@Id
@GeneratedValue
(
strategy =
GenerationType.AUTO) private
Long id;
@Column
(
unique =
true
, nullable =
false
) private
String name;
@Column
(
unique =
true
, nullable =
false
) private
String shortName;
private
String coordinates;
// Constructors, getters and setters are not shown here ...
}
Afin de stocker les données, nous utilisons PostGres. Mais vous pouvez choisir n'importe quelle base de votre choix (MySQL, Oracle, SQLServer, MongoDB, etc.). Afin de configurer la connexion à notre base de données, nous ajoutons les lignes suivantes dans le fichier pom.xml :
2.
3.
4.
5.
6.
7.
8.
9.
<!-- For the database connection -->
<dependency>
<groupId>
org.springframework.boot</groupId>
<artifactId>
spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>
postgresql</groupId>
<artifactId>
postgresql</artifactId>
<version>
9.1-901.jdbc4</version>
</dependency>
Et dans le dossier de ressources, nous ajoutons un fichier nommé application.yml. Ce fichier est automatiquement scanné par Spring Boot grâce à l'annotation @EnableAutoConfiguration.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
---
spring: profile: dev
jpa:
hibernate:
ddl-auto: create-drop
datasource:
platform: postgresql
url: jdbc:postgresql://localhost/springboot
username: postgres
password: postgres
driverClassName: org.postgresql.Driver
---
Comme vous pouvez le voir, vous pouvez déclarer plusieurs profils dans ce fichier. Vous pouvez regarder la documentation officielle pour plus de détails sur ce point.
III-B. La couche DAO▲
Nous avons décidé d'utiliser Spring Data pour récupérer des données depuis notre base. Une interface comme celle qui suit va nous permettre de récupérer les données voulues :
2.
3.
4.
5.
6.
7.
8.
9.
package
com.sqli.repositories;
import
com.sqli.domain.Place;
import
org.springframework.data.repository.CrudRepository;
public
interface
PlaceRepository extends
CrudRepository<
Place, Long>
{
Place findByShortName
(
String shortName);
}
L'avantage de Spring Data est que vous n'avez pas à écrire une quantité de méthodes pour seulement récupérer une donnée via son identifiant, son nom, ou supprimer ou mettre à jour cette donnée. Vous n'avez plus qu'à vous concentrer sur les cas plus complexes (ce qui n'est pas le cas dans l'exemple).
III-C. La couche SERVICE▲
Si vous voulez créer une application Spring avec toutes ses couches, vous devez créer une interface de service avec son implémentation. L'interface pourrait être la suivante :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
package
com.sqli.services;
import
com.sqli.domain.Place;
import
java.util.Collection;
public
interface
PlaceService {
Collection<
Place>
getAllPlaces
(
);
Place getPlaceById
(
Long id);
Place createPlace
(
Place place);
Place updatePlace
(
Place place); void
deletePlace
(
Long id);
Place getPlaceByShortName
(
String shortName);
}
et l'implémentation :
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.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
package
com.sqli.services.impl;
import
com.sqli.domain.Place;
import
com.sqli.repositories.PlaceRepository;
import
com.sqli.services.PlaceService;
import
org.apache.commons.collections4.IteratorUtils;
import
org.springframework.stereotype.Service;
import
javax.annotation.Resource;
import
java.util.Collection;
@Service
(
value =
"placeService"
)
public
class
PlaceServiceImpl implements
PlaceService {
@Resource
private
PlaceRepository placeRepository;
@Override
public
Collection<
Place>
getAllPlaces
(
) {
return
IteratorUtils.toList
(
this
.placeRepository.findAll
(
).iterator
(
));
}
@Override
public
Place getPlaceById
(
Long id) {
return
this
.placeRepository.findOne
(
id);
}
@Override
public
Place createPlace
(
Place place) {
return
this
.placeRepository.save
(
place);
}
@Override
public
Place updatePlace
(
Place place) {
return
this
.placeRepository.save
(
place);
}
@Override
public
void
deletePlace
(
Long id) {
this
.placeRepository.delete
(
id);
}
@Override
public
Place getPlaceByShortName
(
String shortName) {
return
this
.placeRepository.findByShortName
(
shortName);
}
public
PlaceRepository getPlaceRepository
(
) {
return
placeRepository;
}
public
void
setPlaceRepository
(
PlaceRepository placeRepository) {
this
.placeRepository =
placeRepository;
}
}
Vous pouvez remarquer que tout le binding se fait via annotations.
III-D. Le contrôleur▲
Il ne reste plus qu'une seule chose à faire : le contrôleur.
Il s'agit d'un contrôleur classique pour ceux qui connaissent Spring MVC. Et grâce à Spring 4, il n'y a plus besoin d'effectuer la conversion Objet vers JSON et inversement. Le marshaling et le unmarshaling sont effectués par Spring et grâce à l'annotation @RestController.
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.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
package
com.sqli.controllers;
import
com.sqli.domain.Event;
import
com.sqli.domain.Place;
import
com.sqli.services.EventService;
import
com.sqli.services.PlaceService;
import
org.springframework.web.bind.annotation.*;
import
javax.annotation.Resource;
import
java.util.Collection;
@RestController
@RequestMapping
(
value =
"/places"
)
public
class
PlaceController {
@Resource
private
PlaceService placeService;
@RequestMapping
(
method =
RequestMethod.POST)
public
Place createPlace
(
@RequestBody
Place place) {
return
this
.placeService.createPlace
(
place);
}
@RequestMapping
(
method =
RequestMethod.GET)
public
Collection<
Place>
getAllPlaces
(
) {
return
this
.placeService.getAllPlaces
(
);
}
@RequestMapping
(
value =
"/{shortName}"
, method =
RequestMethod.GET)
public
Place getPlaceForShortName
(
@PathVariable
(
value =
"shortName"
) String shortName) {
//find place by shortname
return
this
.placeService.getPlaceByShortName
(
shortName);
}
@RequestMapping
(
value =
"/{id}"
, method =
RequestMethod.DELETE)
public
void
deletePlace
(
@PathVariable
(
value =
"id"
) Long id) {
this
.placeService.deletePlace
(
id);
}
@RequestMapping
(
value =
"/{id}"
, method =
RequestMethod.PUT)
public
Place updatePlace
(
@PathVariable
(
value =
"id"
) Long id, @RequestBody
Place place) {
place.setId
(
id);
return
this
.placeService.updatePlace
(
place);
}
public
PlaceService getPlaceService
(
) {
return
placeService;
}
public
void
setPlaceService
(
PlaceService placeService) {
this
.placeService =
placeService;
}
}
IV. Filtre CORS▲
Si vous devez écrire une API publique, vous devez autoriser les requêtes Cross Domain. Pour cela, nous avons écrit une classe très simple qui autorise toutes les requêtes, quelle que soit la source :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
package
com.sqli.filters;
import
org.springframework.stereotype.Component;
import
org.springframework.web.filter.OncePerRequestFilter;
import
javax.servlet.FilterChain;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
java.io.IOException;
@Component
public
class
CorsFilter extends
OncePerRequestFilter {
@Override
protected
void
doFilterInternal
(
HttpServletRequest httpServletRequest, HttpServletResponse httpServlet) {
httpServletResponse.addHeader
(
"Access-Control-Allow-Origin"
, "*"
);
httpServletResponse.addHeader
(
"Access-Control-Allow-Methods"
, "GET, POST, PUT, DELETE, OPTIONS"
);
httpServletResponse.addHeader
(
"Access-Control-Allow-Headers"
, "origin, content-type, accept,
x-
req filterChain.doFilter
(
httpServletRequest, httpServletResponse);
}
}
Et parce que nous utilisons l'annotation @ComponentScan, notre filtre sera automatiquement chargé et utilisé à chaque requête.
V. Lancement de l'application▲
Maintenant que nous avons écrit tout le code, il ne nous reste plus qu'à lancer l'application. Pour cela, lancez la classe MainLauncher en tant qu'application Java.
Si vous vous rendez sur la page http://localhost:8080/places, vous aurez la liste de tous les lieux stockés dans votre base de données. Vous pouvez utiliser un client tel que Postman afin de requêter, ajouter, modifier ou supprimer des données en base.
VI. Conclusion▲
En tant que développeur Java, je trouve que Spring Boot permet de créer rapidement et simplement une application sans avoir à écrire de nombreux fichiers XML complexes, sans avoir de serveur Java sur soi, etc. Spring Boot peut donc être utilisé pour prototyper votre backend REST sans trop de difficultés, mais peut également être utilisé afin de concevoir des applications Spring plus complexes.
VII. Remerciements▲
Cet article a été publié avec l'aimable autorisation de SQLI qui est le partenaire de référence des entreprises dans la définition, la mise en œuvre et le pilotage de leur transformation digitale.
Nous tenons à remercier Claude Leloup pour la relecture orthographique et milkoseck pour la mise au gabarit.