Cours de base sur les fondamentaux du framework spring boot avec exemples

Spring Boot : encore de l’abstraction
Pour eviter les problémes de Spring MVC, Spring Boot propose :
Les demarreurs ( starter) : un demarreur est une dépendance, contenant un paquet de dependance, permettant de réealiser un type de projet (Web, Rest ). Ainsi, le developpeur n’a plus´ à gerer, lui méme le problème d’incompatibilité entre les versions.´
l’auto-configuration : c’est-a-dire laisser Spring Boot configurer le projet a partir de dépendances ajoutées par le développeur.éxemple, pour creer un projet web, il faut ajouter la dépendance´ Spring Boot suivante :
spring-boot-starter-web
Exemple, pour creer un projet web, il faut ajouter la dépendance´ Spring Boot suivante :
spring-boot-starter-web
Exemple, pour creer un projet web, il faut ajouter la dépendance´ Spring Boot suivante :
La dependance spring-boot-starter-web inclut les six dependances suivantes :
spring-boot-starter
spring-boot-starter-json
spring-boot-starter-tomcat
org.hibernate.validator
hibernate-validator
org.springframework
spring-web
org.springframework
spring-webmvc
Contenu de la section dependencies de
Pour la compatibilite d’´ Apache Tomcat avec les JSP, on ajoute la dependance suivante
org.apache.tomcat.embed
tomcat-embed-jasper
javax.servlet
jstl
Pour la compatibilite d’´ Apache Tomcat avec les JSP, on ajoute la dependance suivante´
org.apache.tomcat.embed
tomcat-embed-jasper
Pour utiliser la JSTL, on ajoute la dependance suivante´
Le point de demarrage de l’application
package;
import.SpringApplication;import.autoconfigure.SpringBootApplication;
@SpringBootApplicationpublic classFirstSpringBootApplication {
public static voidmain(String[] args) {
(FirstSpringBootApplication.class, args);
}
}
Explication
SpringApplication : la classe de demarrage d’une application Spring et qui va créer´ une instance de la classe ApplicationContext
ApplicationContext : l’interface centrale d’une application Spring permettant de fournir des informations de configuration a l’application.`
@SpringBootApplication : contient les 3 annotations suivantes
@Configuration : fait partie du noyau de Spring Framework et indique que la classe annote peut contenir des méhodes annotées´ par @Bean. Ainsi,Spring Container peut traiter la classe et gen´ erer des beans qui seront utilis´ es par l’application.´
@EnableAutoConfiguration : permet, au demarrage de´ Spring, de genérer automatiquement les configurations´ necessaires en fonction des d´ ependances ajoutées.´
@ComponentScan : demande de scanner ce package contenant de Beans de configuration
Allons donc à http://localhost:8080/Resultat : message d’erreur´
On a creé un projet web, mais on n’a aucune page HTML, JSP ou´ autre
Spring Boot, comme Spring MVC, implemente le patron de conception MVC, donc il nous faut au moins un controleur et une vue.ˆ
Le controleurˆ
un des composants du modele MVC` une classe Java annotee par´ Controller ou RestController
Il rec¸oit une requete du contrˆ oleur frontal et communique avec le modele pour pr` eparer et retourner une reponse a la vue`
Remplac¸ons le contenu du HomeController par le code suivant :
package.controller;
importorg.springframework.stereotype.Controller;import.annotation.RequestMapping;import.annotation.RequestMethod;
@Controllerpublic classHomeController {
@RequestMapping(value = "/hello", method = )public voidsayHello() {
.println("Hello World!");
}
}
Explication
La premiere ligne indique que notre contrôleur se trouve dans leˆ package .controller
Les trois imports concernent l’utilisation des annotations
L’annotation @Controller permet de declarer que la classe´ suivante est un controleur Springˆ
La valeur de l’annotation @RequestMapping indique la route
(/hello ici) et la methode permet d’indiquer la m´ ethode HTTP´
(get ici, c’est la methode par d´ efaut). On peut aussi utiliser le´
raccourci @GetMapping(value = "/url")
Remplac¸ons le contenu du HomeController par le code suivant :
package.controller; importorg.springframework.stereotype.Controller;import.annotation.GetMapping; @Controllerpublic classHomeController { @GetMapping(value = "/hello")public voidsayHello() { .println("Hello World!"); } } |
}
Ou ajouter la dependance Maven suivante´
Les vues sous Spring
Permettent d’afficher des donnees´
Communiquent avec le controleur pour rˆ ecupérer ces données´
Doivent etre crèées dans le répertoire views dans WEB-INF
Peuvent etre crˆ eées avec un simple code´ JSP, JSTL ou en utilisant un moteur de template comme Thymeleaf
Appelons a partir du contrôleurˆ package.controller; importorg.springframework.stereotype.Controller;import.annotation.GetMapping ; @Controllerpublic classHomeController { @GetMapping(value = "/hello")publicString sayHello() {return""; } } |
Dans le return, on precise le nom de la vue´ a afficher (ici c’est` )
Nouveau contenu d’application.properties
.prefix=/views/
Toutes les proprietés possibles de application.properties sont ici :
Nouveau contenu du controleurˆ
package.controller; importorg.springframework.stereotype.Controller;import.annotation.GetMapping ; @Controllerpublic classHomeController { @GetMapping(value = "/hello")publicString sayHello() {return"hello"; } } |
N’oublions pas de deplacer´ dans views qu’il faut le creer´ dans webapp
Comment le controleur envoie des donnˆ ees´ a la vue?`
package.controller; importorg.springframework.stereotype.Controller;import.Model;import.annotation.GetMapping ; @Controllerpublic classHomeController { @GetMapping(value = "/hello")publicString sayHello(Model model) { model.addAttribute("nom", "Wick");return"hello"; } } |
Dans la declaration de la m ethode, on injecte l’interface´ Model qui nous permettra d’envoyer des attributs a la vue`
Comment la vue recup´ ere les données envoy´ ees par le contr´ oleur?ˆ
<%@ page language="java" contentType="text/html; charset= UTF-8" pageEncoding="UTF-8"%> <html> <head> <metahttp-equiv="Content-Type"content="text/html; charset=UTF-8"> <title>first jsp called from controllertitle> head> <body> <h1>first jsp called from controllerh1> Je m’appelle ${ nom } body> html> |
Exactement comme dans la plateforme JEE
Comment la vue recup´ ere les données envoy´ ees par le contr´ oleur?ˆ
<%@ page language="java" contentType="text/html; charset= UTF-8" pageEncoding="UTF-8"%> <html> <head> <metahttp-equiv="Content-Type"content="text/html; charset=UTF-8"> <title>first jsp called from controllertitle> head> <body> <h1>first jsp called from controllerh1> Je m’appelle ${ nom } body> html> |
Exactement comme dans la plateforme JEE
Ajouter isELIgnored="false" s’il ne reconnait pas les Expressions de langage
Une deuxieme fac¸on en utilisant` ModelAndView
package.controller; importorg.springframework.stereotype.Controller;import.annotation.RequestMapping;import.annotation.RequestMethod;import.ModelMap; @Controllerpublic classHomeController { @RequestMapping(value = "/hello")publicString sayHello(ModelMap model) { model.addAttribute("nom", "Wick");return"hello"; } } |
Une troisieme fac¸on en utilisant` ModelAndView
package.controller; importorg.springframework.stereotype.Controller;import.annotation.RequestMapping;import.servlet.ModelAndView; @Controllerpublic classHomeController { @RequestMapping(value = "/hello")publicModelAndView sayHello(ModelAndView mv) { mv.setViewName("hello"); mv.addObject("nom", "wick");returnmv; } } |
Model vs ModelMap vs ModelAndView
Model : est une interface permettant d’ajouter des attributs et de les passer a la vue`
ModelMap : est une classe implementant l’interface Map et permettant d’ajouter des attributs sous forme de key - value et de les passer a la vue. On peut donc chercher unélément´ selon la valeur de la cle ou de la valeur´
ModelAndView : est un conteneur a la fois d’un` ModelMap pour les attributs et d’un View Object. Le controleur pourra ainsiˆ retourner une seule valeur.
Comment le controleur rˆ ecupére les param` etres de requéte?ˆ
package.controller; importorg.springframework.stereotype.Controller;import.Model;import.annotation.GetMapping;import.annotation.RequestParam; @Controllerpublic classHomeController { @GetMapping(value = "/hello")publicString sayHello(@RequestParam(value = "nom") String nom, Model model) { model.addAttribute("nom", nom);return"hello"; } } |
Pour tester, il faut aller sur l’URL
localhost:8080/hello?nom=wick
Explication
@RequestParam(value = "nom") String nom : permet de
recup´ erer la valeur du param etre de la requéte HTTP est deˆ l’affecter au parametre` nom de la methode.´
Il est possible aussi de preciser une valeur par d efaut´
@Controllerpublic classHomeController { @GetMapping(value = "/hello")publicString sayHello(@RequestParam(value = "nom", required =false, defaultValue = "wick") String nom, Model model) { model.addAttribute("nom", nom);return"hello"; } } |
Comment le controleur rˆ ecupére une variable de chemin?`
package.controller; import.annotation.PathVariable; @Controllerpublic classHomeController { @GetMapping(value = "/hello/{nom}")publicString sayHello(@PathVariable String nom, Model model) { model.addAttribute("nom", nom);return"hello"; } } |
Pour tester, il faut aller sur l’URL localhost:8080/hello/wick
Ou ajouter les dependances suivantes´
spring-boot-starter-data-jpa mysql mysql-connector-java runtime |
Dans application.properties, on ajoute les donnees concernant la connexion a là base de donnees et la configuration de Hibernate
= jdbc:mysql://localhost:3306/boot?useSSL=false& serverTimezone=UTC spring.datasource.username = root spring.datasource.password = root -auto = update -sql = true .properties.hibernate.dialect = org.hibernate.dialect.
MySQL5Dialect
L’ajout de la proprieté´ .hibernate.naming.physical-strategy = .model.naming.PhysicalNamingStrategyStandardImpl permet de forcer Hibernate a utiliser les m` emes noms pour les tables et les colonnes que lesèntites et les attributs.´
L’entite´ Personne
package.model; importjavax.persistence.Entity;importjavax.persistence.GeneratedValue;importjavax.persistence.GenerationType;import; @Entitypublic classPersonne { @Id @GeneratedValue(strategy = GenerationType.IDENTITY)privateLong num;privateString nom;privateString prenom;publicPersonne() { }publicPersonne(String nom, String prenom) {this.nom = nom;this.prenom = prenom; } // + getters / setters } |
Pour obtenir le DAO, il faut creer une interface qui´ etend´
soit CrudRepository : fournit les methodes principales pour´ faire le CRUD
soit PagingAndSortingRepository : herite de´
CrudRepository et fournit en plus des methodes de paginationét de tri sur les enregistrements
soit JpaRepository : herite de´
PagingAndSortingRepository en plus de certaines autres methodes JPA.´
Le repository
package ; import .repository. JpaRepository; import .model.Personne; public interface PersonneRepositoryextends JpaRepository <Personne, Long> { } |
Long est le type de la cle primaire ( Id) de la table (entite) personnes´
Preparons une vue
<%@ page language="java" contentType="text/html; charset= UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Index pagetitle> head> <body> <h2>Adding a new personh2> <form action="addPerson"method="post"><br> Nom : <input type="text"name="nom"><br> Prénom : <input type="text"name="prenom"> <button type="submit">Envoyerbutton> form> body> html> |
Preparons le contr´ oleurˆ
@Controllerpublic classPersonneController { @AutowiredprivatePersonneRepository personneRepository; @GetMapping(value = "/addPerson")publicString addPerson() {return"addPerson"; } @PostMapping(value = "/addPerson")publicModelAndView addPerson(@RequestParam(value = "nom") String nom, @RequestParam(value = "prenom") String prenom) { Personne p1 =newPersonne(nom,prenom); (p1); ModelAndView mv =newModelAndView(); mv.setViewName("confirm"); mv.addObject("nom", nom); mv.addObject("prenom", prenom);returnmv; } } |
La vue
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Confirm pagetitle> head> <body> <h1>Welcomeh1> Person named ${ nom } ${ prenom } has been successfully added. body> html> |
Pour recup´ erer la liste de toutes les personnes´
@GetMapping(value = "/showAll")public ModelAndView showAll() { ArrayList personnes =(ArrayList< Personne>) personneRepository.findAll(); ModelAndView mv =new ModelAndView(); mv.setViewName("result"); mv.addObject("personnes", personnes);return mv; } |
La vue
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="; prefix="c"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Result pagetitle> head> <body> <h1>List of personsh1> var="personne"> <div> <c:outvalue="${ personne.prenom } ${ }"/> div> body> html> |
@GetMapping(value = "/showAllByPage/{i}/{j}")publicModelAndView showAllByPage(@PathVariableinti, @PathVariableintj) { Page personnes = personneRepository.findAll( (i, j)); ModelAndView mv =newModelAndView(); mv.setViewName("result"); mv.addObject("personnes", personnes.getContent());returnmv; } |
Considerons le contenu suivant de la table Personne
Personne | ||
num | nom | prenom |
1 | Durand | Philippe |
2 | Leberre | Bernard |
3 | Benammar | Pierre |
4 | Hadad | Karim |
5 | Wick | John |
Personne | ||
num | nom | prenom |
3 | Benammar | Pierre |
4 | Hadad | Karim |
Considerons le contenu suivant de la table Personne
Personne | ||
num | nom | prenom |
1 | Durand | Philippe |
2 | Leberre | Bernard |
3 | Benammar | Pierre |
4 | Hadad | Karim |
5 | Wick | John |
En allant sur l’URL localhost:8080/firstspringmvc/showAllByPage/1/2, le resultat est´
On peut aussi recup´ erer une liste de personnes triée´
@GetMapping(value = "/showAllSorted")publicModelAndView showAllSorted() { List personnes = personneRepository.findAll( ("nom").descending()); ModelAndView mv =newModelAndView(); mv.setViewName("result"); mv.addObject("personnes", personnes);returnmv; } |
Les methodes personnalis´ ees du repository´
On peut aussi definir nos propres méthodes personnalis´ ees dans le´ repository et sans les implementer.´
Le repository
package ; import ;import .repository. JpaRepository; import org.eclipse.FirstSpringMvc.model.Personne; public interface PersonneRepositoryextends JpaRepository <Personne, Long> { List findByNomAndPrenom(String nom, String prenom); } |
nom et prenom : des attributs qui doivent exister dans l’entite´ Personne.
Il faut respecter le CamelCase
Le controleurˆ
@GetMapping(value = "/showSome")public ModelAndView showSome(@RequestParam(value = "nom") String nom, @RequestParam(value = "prenom" ) String prenom) { ArrayList personnes =(ArrayList< Personne>) personneRepository. findByNomAndPrenom(nom, prenom); ModelAndView mv =new ModelAndView(); mv.setViewName("result"); mv.addObject("personnes", personnes);return mv; } |
Pour plus de details :
/jpa/docs/current/reference/html/
On peut egalement ecrire des requ´ etes HQL (Hiberenate Query Language) avecˆ l’annotation Query
package; import.repository.JpaRepository;import.repository.Query; import; importorg.eclipse.firstspringmvc.model.Personne; public interfacePersonneRepositoryextendsJpaRepository< Personne, Long> { @Query("select p from Personne p where p.nom = ?1") List chercherSelonLeNom(String nom); List findByNomAndPrenom(String nom, String prenom); } |
Ou ajouter la dependance Maven suivante
Configurons application.properties
-names=jsp/* spring.thymeleaf.prefix=/views/ -names=thymeleaf/*
return "nomVue";
Dans les controleurs, remplacer chaque appel d’une page JSPˆ
return "nomVue";
Par
return "jsp/nomVue";
67 / 76
Dans les controleurs, remplacer chaque appel d’une page JSPˆ
return "nomVue";
Par
return "jsp/nomVue";
Pour appeler une page Thymeleaf
return "thymeleaf/nomVue";
Pour tester, creer un contr´ oleurˆ ThymeleafController
@Controllerpublic class ThymeleafController { @GetMapping(value = "/thymeleaf")public String displayMessage(Model model) { model.addAttribute("message", "Hello World!");return "thymeleaf/index"; } } |
La vue
<!DOCTYPE html> <html xmlns:th=""> <head> <meta charset="ISO-8859-1"> <title>First Thymeleaf Pagetitle> head> <body> <p th:text = "${ message }">p> body> html> |
La vue
<!DOCTYPE html> <html xmlns:th=""> <head> <meta charset="ISO-8859-1"> <title>First Thymeleaf Pagetitle> head> <body> <p th:text = "${ message }">p> body> html> |
En allant , Hello World! est affiche´
Preciser les sources et l’encodage de messages dans´ application.propertiesspring.messages.encoding=UTF-8 spring.messages.basename=messages
Preciser les sources et l’encodage de messages dans´ application.properties
spring.messages.encoding=UTF-8 spring.messages.basename=messages
Contenu de messages.properties (dans src/main/resources)
=Bonjour tout le monde
Preciser les sources et l’encodage de messages dans´ application.properties
spring.messages.encoding=UTF-8 spring.messages.basename=messages
Contenu de messages.properties (dans src/main/resources)
=Bonjour tout le monde
Contenu de messagesen.properties (dans src/main/resources)
=Hello world
Preciser les sources et l’encodage de messages dans´ application.properties
spring.messages.encoding=UTF-8 spring.messages.basename=messages
Contenu de messages.properties (dans src/main/resources)
=Bonjour tout le monde
Contenu de messagesen.properties (dans src/main/resources)
=Hello world
Dans une vue (Thymeleaf), ajouter
<h1 th:text= "#{ }">h1>
Creons la classe de configuration MvcConfig dans .configuration
@Configurationpublic classMvcConfigimplementsWebMvcConfigurer{ @Bean publicLocaleResolver localeResolver() { SessionLocaleResolver sessionLocaleResolver =new SessionLocaleResolver(); sessionLocaleResolver.setDefaultLocale(Locale.FRANCE);returnsessionLocaleResolver; } @Bean publicLocaleChangeInterceptor localeChangeInterceptor() { LocaleChangeInterceptor localeChangeInterceptor =new LocaleChangeInterceptor(); localeChangeInterceptor.setParamName("language");returnlocaleChangeInterceptor; } @Overridepublic voidaddInterceptors(InterceptorRegistry registry) { registry.addInterceptor(localeChangeInterceptor()); } } |
En allant sur http://localhost:8080/thymeleaf?language=en , le resultatést :
Hello world
En allant sur http://localhost:8080/thymeleaf?language=en , le resultatést :
Hello world
En allant sur http://localhost:8080/thymeleaf?language=fr , le resultatést :
Bonjour tout le monde
En allant sur http://localhost:8080/thymeleaf?language=en , le resultatést :
Hello world
En allant sur http://localhost:8080/thymeleaf?language=fr , le resultatést :
Bonjour tout le monde
En allant sur http://localhost:8080/thymeleaf?language=it , le resultatést toujours le meme :ˆ
Bonjour tout le monde
Considerons le contr´ oleurˆ PersonneRestController
@RestControllerpublic classPersonneRestController { @AutowiredprivatePersonneRepository personneRepository; @GetMapping("/personnes")publicList getPersonnes() {returnpersonneRepository.findAll(); } @GetMapping("/personnes/{id}")publicPersonne getPersonne(@PathVariable("id")longid) {returnpersonneRepository.findById(id).orElse(null); } @PostMapping("/personnes") publicPersonne addPersonne(@RequestBody Personne personne) { .println(personne);return(personne); } } |
Modifions le point d’entree (qui impl´ ementera l’interface´ ApplicationRunner) pour ajouter des tuples dans la base de donnees avant d’appeler nos services REST´
@SpringBootApplicationpublic classFirstSpringBootApplicationimplementsApplicationRunner { @AutowiredprivatePersonneRepository personneRepository; public static voidmain(String[] args) { (FirstSpringBootApplication.class, args); } @Overridepublic voidrun(ApplicationArguments args)throwsException { // TODO Auto-generated method stub Personne personne1 =newPersonne("wick", "john"); Personne personne2 =newPersonne("dalton", "jack"); (personne1); (personne2); } } |
On peut aussi modifier le chemin de contexte a partir de la classe de démarrage´
@SpringBootApplicationpublic classFirstSpringBootApplication { public static voidmain(String[] args) { System.setProperty("server.servlet.context-path", "/firstspringboot "); (FirstSpringBootApplication.class, args); } } |