Spring
Formation au Framework couteau suisse
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 ...
Projet exemple : springFormation_2.
On peut retrouver l'annotation @Bean aussi
Ainsi, si dans messageServiceImpl on supprime le @Component, on peut déclarer dans la classe Application:
@Bean
public MessageServiceImpl messageService(){
return new MessageServiceImpl();
}
Il est à noter que l'on peut avoir plusieurs @Configuration si on souhaite découper notre application.
On peut réaliser des héritages / dépendances avec @Import(nomClass.class)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
@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
@Autowired
- Injection par type
- Et si on a deux implémentations de la même interface ? => Démonstration
- Avec @Qualifier("name") : injection par nom
- Peut préciser qu'il n'est pas obligatoire @Autowired(required = false)
- Annotation Spring
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 type
- Même souci sur la double implémentation que @Component
- Pour injecter par nom :
@Resource(name = "name")
- Annotation Java
@Resource(name = "toto")
private Toto toto;
==
@Autowired
@Qualifier("toto")
private Toto toto;
@Resource ou @Autowired ?
Sur des injections de propriétés, il est préférable d'utiliser @Resource qui est un standard Java et qui est fait pour ça.
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.
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:fileSpring 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 crslfPersonnalisation
- 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ésentTestons 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/
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
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
Plus de Spring EL
- "#{ T(java.lang.Math).random() * 100.0 }"
- "#{ systemProperties['user.region'] }"
- http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html#expressions-beandef
- http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html#expressions-ref-functions
- https://www.mkyong.com/spring3/spring-el-hello-world-example/
- https://www.mkyong.com/spring3/spring-el-lists-maps-example/
Converter date : https://www.mkyong.com/spring/spring-how-to-pass-a-date-into-bean-property-customdateeditor/
Converter bean & mvc : https://www.javacodegeeks.com/2013/11/type-conversion-in-spring-2.html
Ressources
- inject, resource, autowired : http://blogs.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/
- injection list : https://www.mkyong.com/spring/spring-listfactorybean-example/
- La bible : http://www.mkyong.com/
-
Spring
Formation au Framework couteau suisse
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.