• 10 heures
  • Facile

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 03/09/2019

Trouvez des solutions quand plus rien ne va

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Il est temps de voir comment s'en sortir quand plus rien ne va...

Struts fournit plusieurs moyens pour debugger votre application. Je vais vous en montrer quelques-uns.

Les logs

Struts génère beaucoup de log (de niveau debug et au dessus) surtout quand le mode développement est activé. Ceci est la première source d'information pour comprendre ce qui se passe dans votre application.

Pour gérer ses logs, Struts utilise Apache Log4j 2™.

Cependant, votre application utilise peut-être d'autres frameworks utilisant d'autres systèmes de log. C'est le cas ici avec Spring qui utilise Apache Commons Logging™.

Afin de centraliser la gestion des logs, je fais le choix de me baser sur Log4j et de rediriger les autres systèmes de log vers Log4j.

Ici, pour rediriger les logs de Commons Logging, je vais utiliser Commons Logging Bridge (dépendance Maven org.apache.logging.log4j:log4j-jcl).

Comme je veux gérer tous les logs de l'application (pas seulement ceux de Struts) avec Log4j, j'ai donc ajouté les dépendances dans le module Maven ticket-technical :

<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-jcl</artifactId>
</dependency>

Struts utilise deux loggers principaux pour les traces d'exécution :

  • com.opensymphony.xwork2

  • org.apache.struts2

Je crée un fichier de configuration de base ticket-technical/src/main/resources/log4j2.xml.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info">
    <!-- ===== Appenders ===== -->
    <Appenders>
        <!-- == Sortie sur la console == -->
        <Console name="STDOUT">
            <PatternLayout pattern="%highlight{%-5level} [%t] %c : %m%n"/>
        </Console>
    </Appenders>

    <!-- ===== Loggers ===== -->
    <Loggers>
        <!-- == Logger pour Struts == -->
        <Logger name="com.opensymphony.xwork2" level="debug">
            <AppenderRef ref="STDOUT"/>
        </Logger>
        <Logger name="org.apache.struts2" level="debug">
            <AppenderRef ref="STDOUT"/>
        </Logger>

        <!-- == Logger pour l'application == -->
        <Logger name="org.example.demo.ticket" level="debug" additivity="false">
            <AppenderRef ref="STDOUT"/>
        </Logger>

        <!-- == Logger de base == -->
        <Root level="warn">
            <AppenderRef ref="STDOUT"/>
        </Root>
    </Loggers>
</Configuration>

Le mode développement

Vous vous souvenez peut-être qu'au début de ce cours, je vous ai fait activer le mode développement (propriété struts.devMode).

L'activation du mode développement engendre ceci :

  • Les Resource Bundles (fichiers properties pour les messages de l'application) sont rechargés à chaque requête.

  • Les fichiers XML de configuration Struts (fichier struts.xml...) sont rechargés à chaque requête.

  • Le niveau de certains problèmes/logs sont relevés et considérés comme des erreurs. Par exemple, si vous envoyez un paramètre ou un champ de formulaire qui ne peut pas être affecté dans l'action, cela lèvera une Exception au lieu d'être ignoré dans le comportement normal.

Le tag debug

Lors du développement des JSP, il se peut que vous ayez besoin d'inspecter la Value Stack pour comprendre ce qui se passe.

Vous pouvez alors utiliser le tag <s:debug />. Ce tag va générer un lien [Debug] sur lequel vous pouvez cliquer pour afficher le contenu de la Value Stack.

Exemple de sortie du tag debug
Exemple de sortie du tag « s:debug »

Gérer les exceptions

Il est tout à fait possible que les méthodes de vos actions lèvent des exceptions vérifiées ou non.

Créons une petite classe action de démonstration.

DemoExceptionAction.java :

package org.example.demo.ticket.webapp.action;

import com.opensymphony.xwork2.ActionSupport;

import org.example.demo.ticket.model.exception.FunctionalException;
import org.example.demo.ticket.model.exception.NotFoundException;
import org.example.demo.ticket.model.exception.TechnicalException;


/**
 * Action de démo pour la gestion des exceptions
 */
public class DemoExceptionAction extends ActionSupport {


    public String doTechnicalException() throws TechnicalException {
        throw new TechnicalException("Une TechnicalException pour la démo...");
    }


    public String doNotFoundException() throws NotFoundException {
        throw new NotFoundException("Une NotFoundException pour la démo...");
    }


    public String doFunctionalException() throws FunctionalException {
        throw new FunctionalException("Une FunctionalException pour la démo...");
    }
}

struts.xml :

<!-- Actions de démonstration pour les Exceptions -->
<action name="demo_functionalException" class="org.example.demo.ticket.webapp.action.DemoExceptionAction" method="doFunctionalException" />
<action name="demo_notFoundException" class="org.example.demo.ticket.webapp.action.DemoExceptionAction" method="doNotFoundException" />
<action name="demo_technicalException" class="org.example.demo.ticket.webapp.action.DemoExceptionAction" method="doTechnicalException" />

Exception handling

Struts fournit un mécanisme d'exception handling. Grâce à celui-ci, vous pouvez indiquer à Struts d'utiliser des results particuliers en fonction des types d'exception levés par vos actions.

Ce mécanisme est géré par l'interceptorexception (classe ExceptionMappingInterceptor). Il fait partie de la defaultStack.

Le mapping des types d'exception sur les result se fait avec dans le fichier de configuration struts.xml, grâce aux éléments <exception-mapping>.

Dans mon application, je fais le choix de gérer les exceptions de manière globale :

  • NotFoundException : renvoie une erreur HTTP 404 avec le message « Objet introuvable » et le message de l'exception.

  • TechnicalException : renvoie une erreur HTTP 500 avec le message « Erreur technique » et le message de l'exception.

  • Exception : renvoie une erreur HTTP 500 avec le message de l'exception.

<struts>
    <!-- ===== Package de configuration de base ===== -->
    <package name="base" abstract="true" extends="struts-default">
        <global-results>
            <result name="Exception" type="httpheader">
                <param name="error">500</param>
                <param name="parse">true</param>
                <param name="errorMessage">%{exception}</param>
            </result>
            <result name="TechnicalException" type="httpheader">
                <param name="error">500</param>
                <param name="parse">true</param>
                <param name="errorMessage">Erreur technique - %{exception.message}</param>
            </result>
            <result name="NotFoundException" type="httpheader">
                <param name="error">404</param>
                <param name="parse">true</param>
                <param name="errorMessage">Objet introuvable - %{exception.message}</param>
            </result>
        </global-results>

        <global-exception-mappings>
            <exception-mapping exception="java.lang.Exception" result="Exception" />
            <exception-mapping exception="org.example.demo.ticket.model.exception.TechnicalException"
                               result="TechnicalException" />
            <exception-mapping exception="org.example.demo.ticket.model.exception.NotFoundException"
                               result="NotFoundException" />
        </global-exception-mappings>
        ...
    </package>


    <!-- ===== Package pour les actions publiques ===== -->
    <package name="public" extends="base">
        <!-- Actions de démonstration pour les Exceptions -->
        <action name="demo_functionalException" class="org.example.demo.ticket.webapp.action.DemoExceptionAction" method="doFunctionalException" />
        <action name="demo_notFoundException" class="org.example.demo.ticket.webapp.action.DemoExceptionAction" method="doNotFoundException" />
        <action name="demo_technicalException" class="org.example.demo.ticket.webapp.action.DemoExceptionAction" method="doTechnicalException" />
        ...
    </package>
    ...
</struts>

Ainsi les actions suivantes renverront :

  • demo_functionalException : renvoie une erreur HTTP 500 avec le message de l'exception.

  • demo_notFoundException : renvoie une erreur HTTP 404 avec le message « Objet introuvable » et le message de l'exception.

  • demo_technicalException : renvoie une erreur HTTP 500 avec le message « Erreur technique » et le message de l'exception.

Logger les exceptions

L'interceptorexception (classe ExceptionMappingInterceptor) gérant le mécanisme d'exception handling, permet également de logger les exceptions qu'il prend en charge.

Plusieurs paramètres de configuration permettent de configurer ceci :

  • logEnabled : permet d'activer le log des exceptions : true ou false

  • logLevel : permet de préciser le niveau de log de ces exceptions : TRACEDEBUG (par défaut), INFOWARNERROR ou FATAL

  • logCategory Catégorie (déterminant le logger) à utliser pour logger les exceptions : par défaut com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.

Afin de mettre en place ces logs dans mon application :

  • je crée une nouvelle stack pour mon application applicationDefaultStack, basée sur la defaultStack ;

  • j'y configure le log des exceptions à l'aide des paramètres exception.log* ;

  • la stackauthenticatedStack étend désormais la stackapplicationDefaultStack ;

  • je déclare la stackapplicationDefaultStack comme stack par défaut.

<!-- ===== Package de configuration de base ===== -->
<package name="base" abstract="true" extends="struts-default">
    <interceptors>
        <interceptor name="auth" class="org.example.demo.ticket.webapp.interceptor.AuthInterceptor" />

        <interceptor-stack name="applicationDefaultStack">
            <interceptor-ref name="defaultStack">
                <param name="exception.logEnabled">true</param>
                <param name="exception.logLevel">ERROR</param>
                <param name="exception.logCategory">org.example.demo.ticket.webapp</param>
            </interceptor-ref>
        </interceptor-stack>

        <interceptor-stack name="authenticatedStack">
            <interceptor-ref name="auth" />
            <interceptor-ref name="store">
                <param name="operationMode">AUTOMATIC</param>
            </interceptor-ref>
            <interceptor-ref name="applicationDefaultStack" />
        </interceptor-stack>

        <default-interceptor-ref name="applicationDefaultStack" />

        ...
    </interceptors>
    ...
</package>

Si vous voulez en apprendre d'avantage sur l'exception handling, vous pouvez consulter la documentation.

Conclusion

Dans ce chapitre, je vous ai montré quelques moyens de faciliter le développement et le débogage de vos applications. Bien évidemment certains d'entre eux sont réservés au développement et prohibés en production comme le tag <s:debug> ou le devMode !

Exemple de certificat de réussite
Exemple de certificat de réussite