Spring
Maitriser les bases
Créé par Tony MEMBOT via l'API de présentation Reveal.js
Se présenter.
Leur domaine / niveau struts/spring/MVC/...
Pas formation expert. Il faut fouiller/adapter.
Spring
C'est quoi spring ?
Spring Core
Spring MVC
Spring Security
Spring Batch
Aller plus loin avec Spring
Un conteneur léger
Framework reposant sur 3 grands principes
Inversion de contrôle
Programmation orientée aspect
Couche d'abstraction (pour d'autres API)
2003 : première version
2016 : 4.2.3
Libre
Conteneur léger : brique de base pour instancier des objets et les mettre en relation.
Pour faire plus, on rajoute des briques.
Tomcat = conteneur léger, jboss conteneur lourd
Inversion de contrôle = Injection de dépendance. (exemple par la suite)
Définir programmation orienté aspect => transversale.
Couche d'abstraction : Hibernate / quartz / velocity / jdbc / ...
Entre chaque version il y a eu de nombreuses et importantes évolution.
Attention aux versions !
Une version majeure = grand ménage de printemps
La formation se base sur les versions suivantes :
Spring Framework : 4.3.2.RELEASE
Spring Security : 4.1.3.RELEASE
Spring Batch : 3.0.7.RELEASE
évoluer est nécessaire. C'est une force de spring
IoC : Inversion of Control
Aujourd'hui renommé injection de dépendance
Déresponsabilisation / Déspécialisation des classes
On injecte dynamiquement les dépendances plutôt que de les écrire explicitement dans le code
public class Parking {
private Voiture voiture;
/** Constructeur qui crée une voiture spécifique: pas d'IoC */
public Parking() {
voiture = new Clio();
}
/** Constructeur avec voiture: compatible IoC */
public Parking(Voiture voiture) {
this.voiture = voiture;
}
}
Parking a ici la responsabilité de l'instanciation de la Clio. Ca ne peut être que ça.
Si l'application évolue, ou on souhaite l'étendre, ou on souhaite mocker pour test => on doit modifier le
code.
Exemple XML
Dépendances maven sur spring-context
Un fichier xml de configuration principal
Déclaration de bean et d'injection de dépendance via l'xml
Chargement du context spring pour utilisation
Explorons le projet Spring 1 ...
Projet exemple : springFormation_1 .
Dépendance de context : https://mvnrepository.com/artifact/org.springframework/spring-context/4.3.2.RELEASE
app / beans / core / expression.
Il est possible de découper le fichier XML en réalisant des imports (Mais un seul point d'entrée).
Exemple Annotation
Dépendances identiques
Une classe de configuration principale
Déclaration des beans et injection de dépendance via les annotations
Chargement du context spring dans le main légèrement différent
Explorons le projet Spring 2 ...
Annotation ou XML ?
Pas de best solution
On peut quasi tout faire dans les deux solutions
Utiliser le meilleur des deux : un mix, exemple
Annotation pour tout ce qui est static
XML pour tout ce qui est plus dynamique
Mais attention, la communauté tend vers le full annotation, notamment avec Spring boot.
@Component
Sur la classe VoitureDeCourse, va créer un bean nommé "voitureDeCourse"
On peut préciser ce nom @Component(value = "voiture2course")
@Service, @Controller, @Repository sont des spécialisations
On laisse spring gérer l'instanciation
@Service, ... sont des spécialisations dans le but d'utiliser l'AOP.
@Bean
Disponible uniquement si on utilise @Configuration
Sur la méthode myVoitureDeCourse, va créer un bean nommé "myVoitureDeCourse"
On peut préciser ce nom @Bean(name={"voiture2course"})
C'est le développeur qui gère l'instanciation
Attention, on ne peut plus utiliser l'AOP sur des instanciations de type @Bean.
=> http://zezutom.blogspot.fr/2014/02/spring-series-part-5-component-vs-bean.html
@Autowired peut injecter un @Bean
@Bean factory
@Bean
@Scope("prototype")
public SomeService someService() {
switch (state) {
case 1:
return new Impl1();
case 2:
return new Impl2();
case 3:
return new Impl3();
default:
return new Impl();
}
}
Ce cas peut être utile pour du mock par exemple, ou pour instancier des classes différentes selon un
environnement ...
La différence entre les deux est ténue. On préfera garder @Component généralement.
Les injections de dépendances
Ou injecter ?
Via le fichier xml, dans la déclaration du bean
Par annotation, il est possible d'injecter au niveau
De la propriété
Du constructeur
Du setter
@Autowired
Attention, @Qualifier est une annotation java
Démonstration :
1. Créer une classe MessageServiceAutreImpl qui implémente MessageService
2. Lancer l'appli. => plante.
pas obligatoire = ne plante pas.
@Resource
Injection par Name > Type > Qualifier
Pour injecter par nom : @Resource(name = "name")
On peut lui joindre un @Qualifier("name")
Même souci sur la double implémentation que @Autowired
Annotation Java
@Inject
Fournit depuis JEE 6 par la spécification CDI.
Utilisé avec l'implémentation Spring, c'est l'équivalent de @autowired..
Injection par Type > Qualifier > Name
.. sauf pour la propriété required
Peut se compléter avec @Qualifier pour la recherche par qualifier
Peut se compléter avec @Named pour la recherche par nom
Introduction à CDI
Context and Dependency Injection
Google ou
Ne pas oublier d'inclure la dépendance maven
javax.inject
javax.inject
1
@Resource ou @Autowired ou @Inject ?
Bin ça dépend en fait ..
Référence 1
Référence 2
Setter ou constructeur ?
On peut mixer les deux. La logique veut qu'on mette en setter les dépendances facultatives et en constructeur les obligatoires.
@inject : si on veut sortir de spring
@autowired : si on veut rester dans spring
@ressource : si surcharge nombreuses et complexe (by name first)
Le scope d'injection
Modifions un peu le projet Spring2 ...
Par défaut, tout est singleton !
Scopes :
Singleton
Prototype
Request *
Session *
GlobalSession *
Faire un test sur formationSpring_2 en ajoutant un 2ème service dans MessagePrinter.
Puis ajouter dans l'appel d'affichage
System.out.println(service2.getMessage());
service2.setMessage("message modifié");
System.out.println(service.getMessage());
System.out.println(service2.getMessage());
* = que dans spring web.
Ajouter => @Scope("prototype")
Injection de collections
Types disponibles :
Tout est string dans un fichier xml ...
... mais il existe des converters automatiques
Explorons le projet 3
Et l'injection d'une valeur null ?
Exemple avec le projet spring 3.
L'utilité de tout ça ? notamment pour injecter des listes de beans / référence.
Injecter null ? "" représentant une chaîne vide ?
init-method
Modifier le projet 1 pour ajouter une init method à messageserviceimpl qui changerait le message par exemple.
L'héritage / Surcharge des beans
On peut rendre un bean abstract="true" sans définir de class (sera pas instancié par Spring)
http://www.tutorialspoint.com/spring/spring_bean_definition_inheritance.htm
Testons !
Instancier via un new (projet 1)
Compléter le projet Exo 1 ...
Créer les beans des voitures clio / ferrari / lotus
Créer deux parkings
Concession : avec deux clio, une ferrari, deux lotus
Occasion : avec deux clio, une lotus
Les parking initialisent les niveaux d'essence via initEssence()
Créer le bean garage référençant les deux parkings et le commercial
GarageApplication doit tourner !
1. L'objet est hors contexte, pas d'initialisation de variable etc. erreur courante au début !
2. voiture ne doit pas être instancié, les voitures = prototype
Montrer exemple spEL
Spring properties
Externaliser les données "changeantes" / techniques
Chargement de properties dans le context spring
Récupération des valeurs directement dans l'initialisation d'un bean ou via un @value
Possibilité de mettre en place un système de surcharge
Possibilité de mettre des valeurs par défaut
exemple du projet 4.
pour utiliser la variable, déclarer dans les arguments vm : -Dproject.home=c:/
rajouter une valeur par défaut : :c:/conf/
MVC : un petit rappel
découpage de responsabilité ...
Spring & le web
spring mvc est une spécialisation de spring qui donne des outils pour gérer des pages web.
Le dispatcher
Spring web tourne autour du servletdispatcher (remplace notre main)
Chef d'orchestre des appels HTTP et de leurs traitements
Request HTTP basique
Récupération du bon controller
Aiguillage (POST/GET) & préparatop, les datas
Récupération de la bonne view (JSP, ...)
Fusion des datas dans la view
1. Après l'avoir reçu, DispatcherServlet consulte HandlerMapping pour appelerle bon Controller.
2. Le Controller gère la request et appel la bonne méthode (GET / POST) et prépare les objets qui vont alimentés le model ainsi que le nom du modèle.
3. Le DispatcherServlet utilise le ViewResolver pour récupérer la bonne view.
4. Le DispatcherServlet fusione les datas avec la view et retourne le résultat.
Explorons le projet spring 5 ...
lancer l'appli et accéder à http://localhost:8080/hello (si lancer depuis intellij)
web.xml => dispatcher servlet
hellocontroller => @controller @requestmapping
hello-servlet
=> spring recherche automatiquement le fichier {{nomservlet}}-servlet.xml
=> on peut lui préciser d'autres noms dans le web.xml
=> contient la ligne de scan pour les controller
=> contient un résolver permettant de rediriger vers nos ressources jsp.
=> le resolver peut implémenter des framework de view comme tiles / velocity / ...v
Spring EL
EL = Expression Language
Spring EL = EL au niveau injection / context spring
Explorons le projet spring 6 ...
localhost:8080/hello & localhost:8080/hello/toto
spring-el est déjà en dépendance de webmvc
dépendance : ne pas oublier d'ajouter javax.servlet
attention à la vieille erreur que les paramètres ne s'affichent pas sur les jsp
https://www.mkyong.com/spring-mvc/modelandviews-model-value-is-not-displayed-in-jsp-via-el/
(web.xml) el ne marche pas :
(web.xml) el marche :
Les ressources statiques
Si tout est résolu par le resolver .. tout est jsp ?
Et les js, css ?
Spring peut définir un context de ressources statiques
Exemple dans le projet spring 6 ..
Exemple de spring 6 : localhost:8080/index
On a ajouté dans le servlet.xml
mvc:resources ...
mvc:annotation-driven ...
Et dans hello.jsp ajout des références et utilisation de taglib.
Redirect & Forward
Toujours utile pour le pattern POST/Redirect/GET pour gérer les submit multiples
Redirect = retour vers le navigateur avec une réponse http 302 (redirection) vers la nouvelle url => on perd la request
Forward = redirection interne au serveur, transparente pour le navigateur et l'utilisateur => on conserve la request
Depuis la 3.1, Spring intègre les RedirectAttributes ...
http://www.tikalk.com/redirectattributes-new-feature-spring-mvc-31/
Exemple dans le projet spring 7 ..
exemple du projet 7 : localhost:8080/index
RedirectAttributes = flash attribute = marche pour 1 seul redirect.
F5 et tout disparaît => http://www.tikalk.com/redirectattributes-new-feature-spring-mvc-31/
Controller - signature dynamique
Comment récupérer la request ? la response ? via l'injection spring
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-arguments
Exemple projet 7
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-arguments
HttpServletResponse response
TimeZone timezone
Formulaire de saisie
Utilisation d'une taglib pour le form
Passage des data par un bean nommé "command" par défaut (paramétrable)
Le submit popule ce bean que l'on récupère dans le controller
Exemple dans le projet spring 8 ..
exemple du projet formationspring_8 :
objet "command" = bean (attention aux setter / getter)
nom du bean paramétrable
Gestion des autres input
Spring gère également les select, textarea, checbox, ...
Norme HTML => un checkbox décoché n'est pas envoyé dans le post
Exemple dans le projet spring 8b ..
Des valeurs par défaut ont été mises en place.
Gestion d'un appel Ajax
Mapping object / data simplifié par Spring
Gestion de l'XML, du JSon, ...
Ajout des dépendances correspondantes
Exemple dans le projet spring 8c ..
Ajouts dépendances jackson
Appel JQuery Ajax. Mapping automatique.
Attention de bien produire du JSON (on peut renseigner le produce dans le requestmapping)
Upload de fichier
Spring gère églament l'upload des fichiers
Quelques dépendances supplémentaires sont nécessaires
Exemple dans le projet spring 8d ..
Ajout dépendances commons-fileupload & commons-io
AJout enctype="multipart/form-data" dans le formulaire
Remarque, ce n'est pas un champ form:file
Spring message / internationalisation
Utilisation d'un message resource : ReloadableResourceBundleMessageSource
Injection du bean dans les classes Java
Utilisation de la taglib spring:message pour les JSP
Internationalisation :
Gérer par défaut par la locale http (navigateur)
Gestion de priorité de la locale : application_fr_fr / application_fr / application
Exemple dans le projet spring 9 ..
exemple du projet formationspring_9
on a ajouté un resolver ainsi qu'un interceptor, via l'url on peut changer la locale.
http://localhost:8080/student
http://localhost:8080/student?locale=en
De manière native c'est géré par le accept language de la requête http.
Fichiers externe à l'application ? file:/usr/local/conf/app/messages/messages
Valider un formulaire
Pré version spring 4.X
C'est classique et bien détaillé, voyons plutôt la solution spring.
Valider les informations d'un formulaire
Post version 4.X
Spring réalise son implémentation avec @validated
Création de classe implémentant l'interface Validator
Utilisation de form:error pour remonter les erreurs
Exemple dans le projet Spring 10 ..
http://www.mkyong.com/spring-mvc/spring-mvc-form-handling-example/
Projet Spring 10 = Spring 8 + validation.
on rajoute l'email pour montrer les dépendances de validator.
Ajout de deux validator
Ajout du tag form:error dans la jsp du formulaire
Modification du controller pour déclencher le validator
détail sur le messageressource => on a plusieurs fichiers de messageresource maintenant.
note : il y a un ordre d'application. le dernier prend le pas sur les suivant.
permet de faire du fallback. on charge d'abord le fichier dans l'appli puis un externe par exemple.
Attention ! dans le controller, l'attribut bindingresult result doit obligatoirement être placé juste après le modelattribute à valider.
sinon erreur 400 ! c'est le seul paramètre qui a une place conditionné au niveau des controlleurs spring.
=> http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-methods
Filter encoding
Filtre au niveau spring
Permet de traiter les données HTTP dans l'encoding cible
Ne dispense pas de setter correctement l'encoding sur les vues
Exemple dans le projet 10
Init
Gestion d'authentifications et d'autorisations
Brique à part entière (ne suis pas les versions)
Fichier de configuration à part
Configuration minimale pour une utilisation directe
Exemple dans le projet spring 11...
web.xml
on ajoute le filtre de spring security dans le web.xml
on crée le fichier de configuration de spring security
test d'accès :
localhost:8080/welcome
localhost:8080/admin
la login page est par défaut
spring 4 demande de gérer des tokens crslf
Personnalisation
Personnalisation de la page de login
Personnalisation des redirection logout
...
Exemple dans le projet spring 12
ajout d'une page de login
déclaration controller login
ajout page login
le logout est géré par login?logout automatiquement
l'erreur de log est géré par login?error automatiquement
username et password doivent être présent
Testons Spring Web !
Compléter le projet Exo 2 ...
GarageController doit mapper / pour renvoyer la page index.jsp
Afficher le nom du commercial dans le message d'accueil
Afficher les parkings
Afficher les voitures dans chaque parking
Mettre en place un bouton permettant d'ajouter de l'essence pour tout le parking
Mettre en place un formulaire au niveau parking pour ajouter une voiture via un input
Modifier ce formulaire pour prendre une liste de nom de voitures à la place de l'input
Spring Batch
Gère des opérations récurrentes et/ou de gros volumes de données
Brique à part entière (ne suis pas les versions)
Gestion des transactions, des logs
Console d'administration web (start/stop/restart/skip/retry)
Difficile d'accès / complexe
Exemple dans le projet spring 13..
Spring batch donne des notions communes à tous les jobs : job step itemwriter ...
http://projects.spring.io/spring-batch/
http://www.mkyong.com/tutorials/spring-batch-tutorial/
http://blog.netapsys.fr/spring-batch-par-lexemple-2/
Spring & le test unitaire
Intégration avec JUnit
Spring, container léger, s'occupe d'instancier à la place de java
JUnit doit connaître le contexte Spring
Nécessite a déclaration d'un runner particulier
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {[...].class})
@ContextConfiguration(locations = {"classpath:[...].xml"})
Exemple dans les projets spring 14 et 15..
Spring boot
Permet la création d'une application stand alone (JAR)
Embarque Tomcat (default), Jetty ou Undertow
Configuration automatique de spring quand c'est possible
Aucune génération de code, aucun XML
Fournit des metrics par défaut
Exemple dans le projet spring 16..
Nouvelles dépendances. On a ajouté web et test.
Dans les tests, nouvelles annotations
Dans APP : @SpringBootApplication
Méthode main avec un runner.
On a un controller classique.
java -jar ... ==> Test du health ==> localhost:8080/health
Actuator se lance pas automatiquement sous intellIJ
Spring actuator
Ensemble de metrics par défaut
/health
/info
/metrics
/loggers
...
Possibilité d'ajouter / surcharger
Attention, non accessible sans auth par défaut
Exemple dans le projet spring 17..
Il faut autoriser http ou être authentifié pour accéder aux endpoints.
Si on a un env JPA, automatiquement le health sera ajouté.
Spring boot Undertow
Il est possible de choisir son serveur d'application
Exemple dans le projet spring 17..
ne pas oublier l'exclusion dans starter web
On regarde dans la console, on voit undertow
Customisation
Grande possibilité de customisation
Fichier de paramétrage yaml possible
Exemple dans le projet spring 17..
Un petit projet Todo ?
@PostMapping
Possibilité de scheduler
Référence : https://spring.io/guides/gs/scheduling-tasks/
Exemple dans le projet Spring 18..
start.spring.io
Génération de projet spring boot : https://start.spring.io/
De nombreux exemple
Spring boot est très fournit en documentation
https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples
Alors Spring boot ça déchire non ?
Bien ...
Se déploie partout juste en déponsant le jar
Parfait pour les micro services
Stack / dépendance simplifié
Démarrage rapide d'un nouveau projet
Pas de configuration xml
... mais pas parfait
Très compliqué à ajouter dans un projet legacy
Customisation parfois "lourde"
Pas de configuration via xml
Effet black box
On a pas forcément toute la main sur le serveur d'appli
Documentation fournit mais parfois brouillone
Aller plus loin avec Spring
Spring c'est aussi du ...
Cache (ehcache)
JDBC / JPA (Hibernate)
Mail
JMS
REST
AOP
Templating (thymeleaf)
...
Spring 5
Release prévu en Mars 2017
Niveau de compatibilité drastiquement augmenté
Java 8+
Hibernate 5+
JPA 2.1+
Inclusion de spring reactive
Compatible kotlin
spring reactive => Programmation réactive = programmation avec des flux de données asynchrones
http://home.heeere.com/tech-intro-programmation-reactive.html
Spring 5
Abandon du support de nombreuses librairies :
PortletMVC
JDO
Guava caching
JasperReports
OpenJPA
Tiles 2
XMLBeans
Velocity
Ressources supplémentaires
injection list : https://www.mkyong.com/spring/spring-listfactorybean-example/
La bible : http://www.mkyong.com/