Guide De Démarrage Rapide

Introduction

Le but de ce guide est de vous initier et de vous rendre autonome dans Stripes le plus vite possible. Il contient une section sur la configuration d'une application web utilisant Stripes, et une autre sur le développement de votre première application Stripes.

Pré-requis

Stripes utilise différentes caractéristiques de Java 1.5 comme les Annotations et les Génériques. Il s'appuie aussi beaucoup sur les technologies des spécifications Servlet 2.4/JSP 2.0. C'est la raison pour laquelle vous aurez besoin du JDK v1.5 (disponible maintenant pour presque toutes les plateformes principales), et d'un Conteneur de Servlet avec qui adhère à la spécification Servlet 2.4 (par exemple Tomcat 5.x, qui est gratuit, et les plus récentes versions de l'excellent Caucho Resin, gratuit seulement pour des usages non-commerciaux).

Un minimum d'expérience du développement JSP est nécessaire, ainsi que les rudiments du Langage d'Expressions (EL), sans toutefois le maîtriser totalement.

Configuration de Stripes

Stripes est conçu de façon à requérir le minimum de configuration possible. Avant de pouvoir l'utiliser il suffit juste de configurer le Stripes Filter ainsi que le Stripes Dispatcher Servlet dans le fichier web.xml de votre application web. Une configuration normale ressemblerait à ceci :

web.xml
 
<?xml version="1.0" encoding="UTF-8"?> 

<web-app xmlns="http://java.sun.com/xml/ns/j2ee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" 
version="2.4"> 

<filter> 
<display-name>Stripes Filter</display-name> 
<filter-name>StripesFilter</filter-name> 
<filter-class>net.sourceforge.stripes.controller.StripesFilter</filter-class> 
<init-param> 
<param-name>ActionResolver.Packages</param-name> 
<param-value>net.sourceforge.stripes.examples</param-value> 
</init-param> 
</filter> 

<filter-mapping> 
<filter-name>StripesFilter</filter-name> 
<url-pattern>*.jsp</url-pattern> 
<dispatcher>REQUEST</dispatcher> 
</filter-mapping> 

<filter-mapping> 
<filter-name>StripesFilter</filter-name> 
<servlet-name>StripesDispatcher</servlet-name> 
<dispatcher>REQUEST</dispatcher> 
</filter-mapping> 

<servlet> 
<servlet-name>StripesDispatcher</servlet-name> 
<servlet-class>net.sourceforge.stripes.controller.DispatcherServlet</servlet-class> 
<load-on-startup>1</load-on-startup> 
</servlet> 

<servlet-mapping> 
<servlet-name>StripesDispatcher</servlet-name> 
<url-pattern>*.action</url-pattern> 
</servlet-mapping> 
</web-app> 

Le paramètre ActionResolver.Packages

Stripes découvre automatiquement vos ActionBeans au démarrage en parcourant le classpath de votre application web. Ceci vous évite de lister tous vos ActionBeans dans un fichier quelque par, mais il faut donner des piste à Stripes. Pour cela, utiliser l'init-param ActionResolver.Packages du Filtre Stripes (StripesFilter) pour indiquer un ou plusieurs répertoires racine. N'utiliser pas .* à la fin d'un répertoire car des sous-répertoires sont automatiquement inclus. Utiliser des virgules pour séparer plusieurs répertoires racine.

l'init-param ActionResolver.Packages est le seul paramètre requis par le Filtre Stripes.

Puis il faudra que vous placiez stripes.jar dans votre classpath (normalement WEB-INF/lib). Ceci est la seule dépendance au moment de la compilation pour développer avec Stripes. Pour développer et utiliser Stripes vous aurez besoin de copier les fichers libraires ci-dessous fournis avec Stripes dans votre classpath :

  • commons-logging.jar (1.1) - Apache Commons Logging est utilisé afin de fournir une interface de logging avec une implémentation agnostique.
  • cos.jar - le package libraire com.oreilly.servlets, grâce à Jason Hunter, est utilisé pour gérer les uploads de fichiers multi-part à partir de formulaires d'envoi

Les fichiers libraires ci-dessus sont fournis avec la distribution de Stripes, et ont été testés avec Stripes. Des versions plus récentes peuvent fonctionner, mais vous serez en territoire inconnu.

De plus, les messages de journalisation (logging) de Stripes peuvent vous aider. Pour cela, vous aurez besoin de fournir soit votre propre configuration Log4J, soit une autre configuration compatible avec Commons Logging. Le jar Log4J, log4j-1.2.9.jar, est distribué avec Stripes. Quelques exemples de configurations suivent ci-dessous :

commons-logging.properties
 
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
log4j.properties
 
### direct log messages to stdout ### 
log4j.appender.stdout=org.apache.log4j.ConsoleAppender 
log4j.appender.stdout.Target=System.out 
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n 

### direct messages to file ### 
log4j.appender.file=org.apache.log4j.FileAppender 
log4j.appender.file.File=/tmp/stripes.log 
log4j.appender.file.layout=org.apache.log4j.PatternLayout 
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n 

### set log levels - for more verbose logging change 'info' to 'debug' ### 
log4j.rootLogger=INFO, stdout, file 
log4j.logger.net.sourceforge.stripes=DEBUG 

Les fichiers de configuration logging doivent être placés dans votre classpath, ex. /WEB-INF/classes.

La dernière partie à être plaçée est le fichier StripesResources.properties; il faudra tout simplement le copier dans /WEB-INF/classes. StripesResources.properties est utilisé (par défaut) pour contenir des messages d'erreurs qui sont utilisés pour la validation incluse par défaut dans Stripes et la validation faite dans les ActionBeans, et il doit pouvoir être retrouvé dans le classpath. Voici un fragment exemple du fichier :

Extrait du StripesResources.properties
 
# Validation error messages used by Stripes' built in type converters 
converter.number.invalidNumber=The value ({1}) entered in field {0} must be a valid number 
converter.byte.outOfRange=The value ({1}) entered in field {0} was out of the range {2} to {3} 
converter.short.outOfRange=The value ({1}) entered in field {0} was out of the range {2} to {3} 
converter.integer.outOfRange=The value ({1}) entered in field {0} was out of the range {2} to {3} 
converter.float.outOfRange=The value ({1}) entered in field {0} was out of the range {2} to {3} 
converter.enum.notAnEnumeratedValue=The value "{1}" is not a valid value for field {0} 
converter.date.invalidDate=The value ({1}) entered in field {0} must be a valid date 
converter.email.invalidEmail=The value ({1}) entered is not a valid email address 
... 

Mon premier Stripe

Pour la première application nous allons développer une calculatrice simple d'une page qui contient deux chiffres et en fait l'addition, puis peut-être d'autres opérations plus tard. Tout d'abord, concevons la JSP. L'exemple qui suit est le minimum dont nous avons besoin pour notre JSP. Il vous faut le placer dans un dossier qui s'appelle 'quickstart' au-dessous la racine de votre application web.

La JSP

"index.jsp"
 
<%@ page contentType="text/html;charset=UTF-8" language="java" %> 
<%@ taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes.tld"%> 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html> 
<head><title>Mon Premier Stripe</title></head> 
<body> 
<h1>Calculatrice Stripes</h1> 

Bonjour, Je suis le Calculatrice Stripes. Je peux seulement faire une addition. 
Peut-être un jour un gentil développeur m'apprendra comment faire d'autres choses ? 

<stripes:form beanclass="net.sourceforge.stripes.examples.quickstart.CalculatorActionBean" focus=""> 
<table> 
<tr> 
<td>Numéro 1 :</td> 
<td><stripes:text name="numberOne"/></td> 
</tr> 
<tr> 
<td>Numéro 2 :</td> 
<td><stripes:text name="numberTwo"/></td> 
</tr> 
<tr> 
<td colspan="2"> 
<stripes:submit name="addition" value="Add"/> 
</td> 
</tr> 
<tr> 
<td>Resultat :</td> 
<td>${actionBean.result}</td> 
</tr> 
</table> 
</stripes:form> 
</body> 
</html> 

La première chose qui nous intéresse sur la page ci-dessus est à la deuxième ligne, celle qui commence avec <%@ taglib .... qui importe le Stripes Tag Library pour l'utiliser sur la page. Puis, un peu plus bas, la ligne :

 
<stripes:form beanclass="net.sourceforge.stripes.examples.quickstart.CalculatorActionBean" focus=""> 

ouvre un tag stripes:form. Ce tag fait beaucoup de choses dont nous n'allons pas parler ici, et produit finalement un tag form HTML sur la page une fois qu'elle se présente. L'attibut focus="" indique à Stripes de mettre le focus dans le premier champs visible (ou le premier champ en erreur, si il y en a).

Après ça, nous pouvons voir deux tags, qui ressemblent :

 
<stripes:text name="numberOne"/> 

Ceci est l'équivalant en Stripes du tag HTML <input type="text"/>, mais qui a une fonction de pre-population et re-population de la data formulaire, et peut modifier la façon dont un tag s'affiche quand il y a des erreurs. Le nom numberOne est le même que celui de la propriété dans l'ActionBean qui reçoit la requête.

Au lieu d'un <input type="submit"/> nous voyons :

 
<stripes:submit name="addition" value="Add"/> 

Le tag stripes:submit a aussi pour fonction de placer le texte localisé sur le bouton, dont on n'a pas besoin ici, donc le tag utilise tout simplement l'attribut de 'value' qui est 'Add'. Le nom du bouton submit, 'addition', est très important car il est lié à la méthode qui sera demandée à l'ActionBean recevant la requête.

Enfin, une courte expression EL est utilisée pour montrer la propriété result de l'ActionBean si celle-ci est présente.

 
<td>${actionBean.result}</td> 

Nous sommes maintenant prêt à voir notre page! Quand elle s'affiche pour la première fois il n'existe pas d'ActionBean (le tag stripes:form ne crée pas d'instance de l'ActionBeans et nous n'avons pas posté ce formulaire).

Page exemple de la calculatrice après n'avoir écrit que la JSP

L'ActionBean

Un ActionBean est l'objet qui reçoit les informations envoyées dans les requêtes et qui traite les données de l'utilisateur. Il définit à la fois les propriétés et que la logique de traitement du formulaire. Si on compare avec Struts, alors, l'ActionBean est l'équivalent de l'ActionForm et de l'Action combinés dans une seule classe.

Il faut noter que Stripes n'a aucun besoin de configuration externe pour connaître les implémentations de l'ActionBean dans une application, ni pour faire une liaison entre le JSP et l'ActionBean. Toute l'information nécessaire est dans l'ActionBean lui-même. Jetons alors un coup d'oeil à l'ActionBean simple qui reçoit la requête de la calculatrice.

CalculatorActionBean.java
 
package net.sourceforge.stripes.examples.quickstart; 

import net.sourceforge.stripes.action.DefaultHandler; 
import net.sourceforge.stripes.action.Resolution; 
import net.sourceforge.stripes.action.ForwardResolution; 
import net.sourceforge.stripes.action.ActionBean; 
import net.sourceforge.stripes.action.ActionBeanContext; 

/** 
* Une action de calcul simple. 
* @author Tim Fennell 
*/ 
public class CalculatorActionBean implements ActionBean { 
private ActionBeanContext context; 
private double numberOne; 
private double numberTwo; 
private double result; 

public ActionBeanContext getContext() { return context; } 
public void setContext(ActionBeanContext context) { this.context = context; } 

public double getNumberOne() { return numberOne; } 
public void setNumberOne(double numberOne) { this.numberOne = numberOne; } 

public double getNumberTwo() { return numberTwo; } 
public void setNumberTwo(double numberTwo) { this.numberTwo = numberTwo; } 

public double getResult() { return result; } 
public void setResult(double result) { this.result = result; }

@DefaultHandler 
public Resolution addition() { 
result = getNumberOne() + getNumberTwo(); 
return new ForwardResolution("/quickstart/index.jsp"); 
} 
} 

Notez que nous avons utiliser le nom de la classe de l'ActionBean dans le tag stripes:form. Néanmoins, c'est bon à savoir comment Stripes produit un URL à partir d'un nom de classe. Si vous regardez le code source de la page, vous verrez action="/examples/quickstart/Calculator.action dans l'HTML. Par défaut Stripes examinera les {{ActionBean}}s et détermine leur URL basé sur leur noms de classe et leur chemin d'accès. Pour convertir les noms de classe et créer les URL, Stripes...

  • Enlève les noms de package jusqu'aux noms de paquetages comme 'web', 'www', 'stripes' and 'action'
  • Enlève 'Action' et 'Bean' (ou 'ActionBean') si le nom de classe se termine comme cela
  • Le convertit pour avoir une URL et ajoute '.action'

Donc dans le cas ci-dessus, net.sourceforge.stripes.examples.quickstart.CalculatorActionBean est devenu une URL selon la transformation suivante :

  • examples.quickstart.CalculatorActionBean
  • examples.quickstart.Calculator
  • /examples/quickstart/Calculator.action

Notez que l'URL generée à partir du nom de la classe s'accorde avec l'action spécifiée dans le tag stripes:form dans la JSP. Dans ces deux cas l'action spécifiée est relative à la racine de l'application web. Tout ceci est détaillé dans la JavaDoc pour NameBasedActionResolver (fonctionnement et extension afin de générer des URLs différentes).

Outrepasser les Alliances d'URL

Les URLs generés par Stripes sont seulement le fonctionnement par défaut. Pour outrepasser l'URL qui est liée avec un ActionBean, il suffit d'annonter la classe avec l'annotation @UrlBinding. Ex. nous aurions pu écrire :

 
... 
@UrlBinding("/qs/calc") 
public class CalculatorActionBean ... 
... 

ce qui aurait nécessité ceci dans le source de la page HTML :

<stripes:form action="/qs/calc" ... >

Puis, la déclaration de la classe

public class CalculatorActionBean implements ActionBean

ActionBean (si vous ne l'avez pas déjà compris) est une interface, ce n'est pas une classe de base. Donc vos ActionBeans peuvent étendre n'importe quelle classe. L'interface ActionBean spécifie deux méthodes (à implémenter dans la classe) :

 
public ActionBeanContext getContext() { return context; } 
public void setContext(ActionBeanContext context) { this.context = context; } 

Ces fonctions permettent à l'ActionBean d'accéder à l'ActionBeanContext. Ce dernier permet d'accéder aux objets HttpServletRequest et HttpServletResponse si vous en avez besoin (le moins souvent possible, espérons-le !), ainsi qu'à beaucoup d'autres informations sur la requête (ex. des messages d'erreur).

Alors que les accesseurs 'getXxx' et 'setXxx' pour les trois propriétés (numberOne, numberTwo et result) définis sur l'ActionBean ne sont pas trop intéressantes, vous aurez noté qu'elles sont cependant nécessaires (sauf si les propriétés sont public, mais ce n'est pas recommandé). Stripes accède aux valeurs des ActionBeans par le mécanisme normal pour des JavaBeans en utilisant les accesseurs getXxx et setXxx, et si elles n'existent pas vous obtiendrez des erreurs. Les trois propriétés (donc trois paires de getXxx/setXxx) dans l'ActionBean s'accordent aux noms utilisés dans la JSP.

Venons-en au plus intéressant :

 
@DefaultHandler 
public Resolution addition() { 
result = numberOne + numberTwo; 
return new ForwardResolution("/quickstart/index.jsp"); 
} 

Vu que cette méthode est declarée public et retourne une Resolution, Stripes l'indentifiera comme "gestionnaire d'événement". Quand une requête arrive au CalculatorActionBean, et que l'utilisateur clique sur un bouton ou une image avec le nom (le nom, ne pas la valeur) "addition" qui s'accorde avec le nom d'une méthode gestionnaire d'évènement, Stripes l'invoquera. De même que pour les URLs d'Action, nous pouvons outrepasser le nom de l'événement qui s'accorde avec une fonction avec l'annotation @HandlesEvent si nous voulons :

 
@HandlesEvent("calcul") 
@DefaultHandler 
public Resolution addition() 
{ 
//... 
} 

donc nous devons modifier notre JSP comme ce qui suit :

 
<stripes:submit name="calcul" value="Add"/> 

L'annotation @DefaultHandler indique à Stripes que si jamais il ne sait pas quel bouton est cliqué (car normalement l'utilisateur tappe 'entrer' sur le clavier au lieu de cliquer sur un bouton), il doit choisir celle-ci.

Vous avez peut-être noté qu'il n'y a aucune fonction générique comme execute() ou do dans l'interface ActionBean. Toutes les fonctions qui gérent des événements sont des fonctions normales qui ont une signature reconnaissable (public, non-abstract, rendent une Resolution) ou qui ont été annotées pour informer Stripes. Stripes apelle ces fonctions gestionnaires d'événements, vu qu'elles gèrent des événements à partir du navigateur. Des fonctions gestionnaires d'événements retournent normalement une Resolution pour que Stripes sache quoi faire après que la méthode ait été invoquée (elles peuvent retourner n'importe quoi, mais si ce n'est pas une Resolution, Stripes l'ignorera).

Notre méthode additionne les deux chiffres ensemble et range la somme dans la propriété result puis nous dirige vers la même JSP dont nous venons en retournant une ForwardResolution. C'est tout!

Maintenant l'ActionBean est écrit, on peut y ajouter deux plus deux

Cette simple JSP, et cet ActionBean concis sont tout ce dont nous avons besoin pour obtenir un exemple qui fonctionne en Stripes. Mais nous pouvons faire encore mieux pour pas grand chose.

Ajouter de la Validation

Commençons d'abord par ajouter un peu de validation à la page. Il est plus sûr de mentionner qu'un utilisateur devrait toujours entrer les deux chiffres pour faire une addition. Pour faire cela nous annotons tout simplement les propriétés de l'ActionBean. Cela peut être fait soit sur les propriétés elles-mêmes, sur les fonctions getXxx, ou sur les fonctions setXxx. Alors qu'il est possible de mélanger les différentes façons d'annoter l'ActionBean, nous suggérons que vous choisissiez un élément type (propriétés, getXxx ou setXxx) et annotiez toujours de la même façon votre ActionBean. De plus, n'oubliez pas d'importer la classe Validate.

Ajouter la validation requise des propriétés
 
@Validate(required=true) private double numberOne; 
@Validate(required=true) private double numberTwo; 

Maintenant si un utilisateur oublie d'entrer soit une soit les deux valeurs, il obtiendra une ou plusieurs erreurs de validation. Pour afficher une erreur quelle qu'elle soit à l'utilisateur, nous devons ajouter un tag stripes:errors à la JSP, par exemple comme ce qui suit :

Montrer les erreurs de validation
 
<stripes:form action="/quickstart/Calculator.action"> 
<stripes:errors/> 

Le tag <stripes:errors/> affichera toutes les erreurs de validation pour le formulaire s'il y en a. Sa présentation est configurable, mais nous ne parlerons pas de ça ici. De plus tout champ sur le formulaire qui cause une erreur aura son attribut de classe css changé à error pour indiquer une erreur. Donc si nous ajoutions ce qui suit à la section <head></head> du JSP, les champs erronés auraient un fond jaune.

 
<style type="text/css"> 
input.error { background-color: yellow; } 
</style> 

Comment Stripes sait-il que la valeur envoyée est un chiffre et pas un mot ? En fait Stripes à une longueur d'avance sur nous. Il sait que les propriétés numberOne et numberTwo sont de type double et il a déjà appliqué des validations qui ne sont applicables qu'aux doubles. Allez-y, essayez de rentrer des lettres ! Cela ressemblera à ça :

Validation en Action(Beans)!

Ajouter (ou plutôt diviser) une autre Opération

C'est déjà pas mal, mais pourquoi ne pas construire d'autres opérations ? Disons des divisions ? Et bien, c'est extrêmement facile avec Stripes. D'abord nous faisons un ajout rapide à la JSP :

 
<td colspan="2"> 
<stripes:submit name="addition" value="Add"/> 
<stripes:submit name="division" value="Divide"/> 
</td> 

Puis nous ajoutons une nouvelle méthode (gestionnaire d'évènement) à l'ActionBean :

 
public Resolution division() { 
result = numberOne / numberTwo; 
return new ForwardResolution("/quickstart/index.jsp"); 
} 

Les validations que nous avons définies auparavant s'appliquent lorsque l'événement "division" est invoqué, comme lorsque l'événement "addition" est invoqué. Cependant, il vaut mieux que nous nous assurions que lorsqu'un événement division est invoqué, l'utilisateur n'essaie pas de piéger le système en divisant par zéro. Nous pourrions écrire le code de validation dans la méthode division() si nous voulions, mais à la place, voyons comment ajouter une méthode seulement spécifique à la validation (avec l'annotation @ValidationMethod) :

 
@ValidationMethod(on="division") 
public void eviterDeDiviserParZero(ValidationErrors errors) { 
if (this.numberTwo == 0) { 
errors.add("numberTwo", new SimpleError("La division par zéro est interdite.")); 
} 
} 

Les fonctions qui sont spécifiques à la validation sont marquées d'une annotation @ValidationMethod pour indiquer à Stripes de les executer en priorité, avant les méthodes de gestion d'évènements. Sauf si spécifié autrement, Stripes exécutera la méthode de validation pour tous les évènements; dans ce cas-ci, nous l'avons réduite afin fonctionner seulement pour les évènements division. La méthode reçoit une référence à l'objet ValidationErrors qui est utilisée pour stocker les erreurs de validation pour l'évènement courant.

La méthode vérifie si le dénominateur est zéro et si c'est le cas, elle crée une instance de l'objet SimpleError pour stocker un message d'erreur. Cette méthode marche, mais elle est assez rapide et pas très propre. Il serait meilleur de créer une instance de l'objet de LocalizableError et de lui fournir avec le clé d'un message stocké dans le fichier StripesResources.properties

Ressources

  • Le code source pour cette application exemple est inclus quand vous téléchargez Stripes ici. Un WAR prêt à l'utilisation qui comporte cette application exemple est aussi inclus, ainsi que...
  • L'Application Exemple « Bugzooky » est une application exemple plus détaillée qui démontre quelques-unes des caractéristiques les plus avancées de Stripes
  • La section Documentation de Stripes inclut de la documentation de référence ainsi que des conseils et méthodes : "How To's"