Le scope Flash du pauvre

Afin de rendre une application navigable, il est généralement judicieux de s’appuyer sur une stratégie redirect-after-post.

Le petit hic est qu’il peut être difficile de passer des informations entre la requête de mise à jour et le redirect d’affichage du résultat, par exemple un message “votre mise à jour a bien été effectuée”. Le scope request est trop court (2 requêtes HTTP consécutives) et le scope session trop long (on ne veut afficher le message que lors du prochain affichage de page).

Ce scope particulier dont la durée de vie est de 2 requêtes consécutives est souvent appelé Flash. Certains frameworks l’intègre en natif : Spring Webflow, Stripes
Il est également aisé de mettre en place un tel scope à la mimine. La technique consiste simplement à stocker les informations dans la session et à les déplacer vers la request lors de la prochaine requête, en s’appuyant par exemple sur un Filter.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class FlashScopeHelper {

    private static final String FLASH_SCOPE_KEY = "com.excilys.flash";

    public static void setFlashAttribute(ServletRequest request, String name, Object value) {
        Map<String, Object> flash = getFlash(request);
        flash.put(name, value);
    }

    static Map<String, Object> getFlash(ServletRequest request) {
        HttpSession session = HttpServletRequest.class.cast(request).getSession();
        @SuppressWarnings("unchecked")
        Map<String, Object> flash = Map.class.cast(session.getAttribute(FLASH_SCOPE_KEY));
        if (flash == null) {
            flash = new HashMap<String, Object>();
            session.setAttribute(FLASH_SCOPE_KEY, flash);
        }
        return flash;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public class FlashScopeFilter implements Filter {

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        Map<String, Object> flash = FlashScopeHelper.getFlash(request);
        for (Entry<String, Object> attribute : flash.entrySet()) {
            request.setAttribute(attribute.getKey(), attribute.getValue());
        }
        flash.clear();
        chain.doFilter(request, response);
    }
    ...
}

Et voilou! Vous n’avez plus qu’à récupérer vos attributs en tant qu’attributs de request.

———————-
Update 05/04/2011 : La release 1.0.0 est disponible :
http://repository.excilys.com/content/repositories/releases

1
2
3
4
5
<dependency>
    <groupId>com.excilys.utils</groupId>
    <artifactId>flash-scope</artifactId>
    <version>1.0.0</version>
</dependency>
VN:R_U [1.9.22_1171]
Rating: 0 (from 0 votes)
Share
Ce contenu a été publié dans Non classé, avec comme mot(s)-clef(s) , . Vous pouvez le mettre en favoris avec ce permalien.

7 réponses à Le scope Flash du pauvre

  1. mpicque@excilys.com dit :

    Super !!

    J’avais justement ce genre de problématiques à gérer dans des actions struts :)

    Merci !

    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
  2. Good tip!

    Comme le dit mon médecin : les statics, c’est pas automatique. Mais des fois, c’est bien pratique…

    Petite évo possible : “FlashScopeHelper.setFlashAttribute(request, name, value);” c’est bien, mais ça veut dire qu’il faut se balader la request. On pourrait donc proposer une API ainsi faite : “FlashScopeHelper.setFlashAttribute(name, value);”

    Comment ? En utilisant un ThreadLocal bien sûr (héhé, j’attend la réponse de Stéphane :p).

    Et pour ceux qui aiment passer du temps à créer des API, on pourrait aussi envisager une approche plus “paramètres nommés”, du type “FlashScopeHelper.bind(name).to(value);”

    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
  3. Et a bien y réfléchir, il serait probablement intéressant de remonter le code qui passe le contenu de session en request directement dans la classe FlashScopeHelper, de rendre getFlash() private et de créer une méthode “flash()” qui soit package private.

    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
  4. Pour ce qui est du ThreadLocal, j’y avais songé, mais je l’avais écarté pour 2 raisons :
    *) je ne voulais pas alourdir le code, le but était de bien mettre en évidence le concept en quelques lignes de code
    *) je ne voulais pas forcer l’utilisation d’un ThreadLocal à l’heure où les serveurs web asynchrones font le buzz

    Maintenant, soyons pragmatiques, la plupart des applications web que nous développons à ce jour sont synchrones, et utilisent de manière massive des ThreadLocals (cf Spring)…
    A suivre sur github! ;)

    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
  5. Effectivement, l’aventure continue sur GitHub ;-)

    L’API a évolué, et désormais c’est : FlashScope.bind(name).to(value);

    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
  6. La release 1.0.0 est disponible (cf maj dans le post).
    Merci à Piwaï pour ses contributions.

    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)

Laisser un commentaire