Malgré l’arrivée de nouveaux framework Web Java sur le marché (JSF, Spring MVC, Webwork, Tapestry…) et les critiques émises à son encontre, Struts 1 reste le framework Web de référence.
Struts 1
Cycle de vie standard:
- Dans un premier temps le framework capture la requête et peuple un contenant à partir de ces données. Le contenant peut être:
- ActionForm : classe étendant la classe org.apache.struts.action.ActionForm, en général une classe de ce type est créée par formulaire.
- DynaActionForm : le développement d’un ActionForm par page s’avère fastidieux et difficile à maintenir. Les DynaActionForm permettent de gérer dynamiquement des formulaires via de la configuration (plus besoin de créer une classe par formulaire).
- Ensuite le formulaire capturé est validé:
- via l’appel de la méthode validate de l’ActionForm.
- à l’aide de Struts validator (définition des règles de validation dans un fichier xml).
- Puis la méthode execute de l’action est appelée. Une action est une classe étendant la classe org.apache.struts.action.Action, elle implémente la logique de traitement de la requête.
- Enfin l’action délègue à la vue l’affichage. La vue est implémentée via une jsp, le plus souvent à l’aide des tags jstl et de ceux de Struts.
Les principales faiblesses de Struts 1 sont:
- fort couplage des actions avec le framework (les actions doivent hériter de la classe Action).
- fort couplage avec l’API servlet. En effet une action doit surcharger la méthode execute de la classe Action, donc introduire une dépendance vis à vis de l’API servlet (paramètres HttpServletRequest et HttpServletResponse). Ce couplage complexifie la mise en place de tests car il faut injecter la requête http (généralement StrutsTestCase est utilisé pour effectuer ces derniers).
- Obligation de re-décrire un javabean pour capturer un formulaire (via l’extension des ActionForm ou via un fichier xml pour les «DynaBean». La validation d’un ActionForm est réalisé en surchargeant la méthode validate, cela diminue donc la réutilisabilité de ces derniers. De plus, Struts 1 utilise l’api beanutils pour convertir les paramètres reçues, or cette api limite la conversion aux types primitifs et aux String (il est conseillé de n’utiliser que des String).
Struts 2
Face aux critiques émises, les équipes de Struts et de WebWork se sont alliées pour donner naissance à WebWork 2 (fusion de Struts et WebWork) rebaptisé par la suite Struts 2 (la compatibilité ascendante Struts 1 -> Struts 2 n’est pas assurée). Le première version stable (2.0.6) est disponible depuis fin février 2007.
Cycle de vie standard:
- une fois le «dispatcher filter» passé, la requête est soumise aux intercepteurs. Ces derniers ont pour rôle d’effectuer des pre/post traitements sur la requête (gestion des exceptions, upload de fichier, validation…).
- l’action est instanciée, peuplée puis le formulaire est validé.
- invocation de la méthode contenant la logique de l’action.
- délégation de l’affichage à la vue.
Les principaux avantages de Struts 2 sont:
- Pas de couplage du code avec l’api servlet.
- Checkbox stateful : au niveau de HTTP, le paramètre lié à la checkbox est envoyé si et seulement si sa valeur est true. Le framework remarque l’absence d’une checkbox dans la requête et injecte la valeur false à cette dernière.
- Support AJAX.
- Injection de dépendance au niveau des actions (via Plexus ou Spring)
- Capture d’un formulaire via un javabean ou une map. Struts 2 utilise OGNL pour la conversion de type. Le framework supporte nativement des convertisseurs pour les String, Boolean/boolean, Character/char, Integer/int, Float/float, Long/long, Double/double et les Date (utilisation de la Locale associée à la requête). Pour les autres types, il est possible d’implémenter des convertisseurs en étendant la classe StrutsTypeConverter.
- POJO action : n’importe quelle classe peut être utilisée comme une action (pas d’obligation d’étendre une classe ou d’implémenter une interface spécifique).
- Simplification du déploiement de plugin (il y a juste à déployer le jar de ce dernier, il n’y a plus besoin de configuration spécifique).
- «Customisation» du rendu des tags via l’utilisation de templates Freemarker.
- Utilisation d’intercepteurs en pré/post traitements sur la requête (possibilité d’intégrer ses propres intercepteurs).
- Plein d’autres choses !
Migration Struts 1 -> Struts 2
La migration peut être envisagée en 2 étapes (afin de diminuer les risques):
- La première étape consisterait à migrer l’application en restant le plus proche possible de celle développée avec Struts 1 (afin de minimiser le nombre de bugs):
- écriture de script de migration pour les fichiers de configuration (validateur, configuration struts …).
- migrer les actions en injectant les objets HttpServletRequest et HttpServletResponse
- Transformer les ActionForm en JavaBean (le formulaire peuplera ce javabean).
- ne pas injecter les services, conserver le code d’appel à ces derniers.
- la partie la plus lourde étant la migration des jsp (l’écriture d’un script de migration n’étant pas trivial, le gain dépendra de la taille de l’application).
- * …
- La seconde étape consisterait à «refactorer» l’application afin de rendre plus évolutive cette dernière et utiliser les nouvelles fonctionnalités offertes par Struts 2.
Conclusion
Malgré sa jeunesse, je conseille Struts 2 pour la mise en place de nouveaux projets (plus de flexibilité, de fonctionnalités…, le faible couplage n’est il pas un des objectifs à atteindre en POO) réalisé par une équipe maîtrisant Struts 1 (faible effort d’apprentissage).
L’intérêt d’une migration est de tirer profit des nouvelles fonctionnalités de Struts 2 en «refactorant» l’application. Une migration minimaliste présente très peu d’intérêts car la communauté Struts 1 reste très active (mise à disposition de Struts 1.3.8 en mars 2007 et de Struts 1.3.9 béta en août 2007). Cette migration n’étant pas triviale, il est important de connaître le ratio coût/intérêt avant d’envisager un tel chantier.