Accueil > Non classé > Faire une application Comet avec Play 2

Faire une application Comet avec Play 2

Cet article a pour but de présenter l’utilisation de l’approche Comet au sein du framework Play a travers la création d’une application de chat basique.

Rappel sur les protagonistes

Play est un framework MVC de développement rapide pour Java et Scala, dont la version 2 est sortie le 13 mars 2012.
Comet est une approche permettant au serveur web d’envoyer des informations au navigateur web sans que celui-ci l’ait explicitement demandé.

Premier pas

Pour utiliser Play vous devez avoir au moins java 6. L’installation de Play est simple, une fois le zip téléchargé, il suffit de le décompresser dans un dossier où vous avez les droits de lecture et d’écriture (lancer play écrit des fichiers dans les dossiers de l’archive), ajouter le dossier de play dans votre PATH et vous êtes prêt à continuer.
Pour créer le projet, placer vous dans le répertoire où vous souhaitez créer le projet et tapez la commande suivante:

play new chatApp

 
Play vous demande un titre pour votre application, mettons par exemple “Chat application”, puis vous avez à choisir le modèle d’application, nous allons utiliser le modèle java. Play crée alors le dossier chatApp pour vous, si vous explorez son contenu vous y trouverez notamment les dossiers suivants:

  • app/ qui contient le coeur de l’application séparé entre modèles (models/), vues (views/) et contrôleurs (controllers/)
  • conf/ qui contient les fichiers de configuration dont application.conf, routes et messages (pour l’i18n)
  • project/ qui contient les scripts de build sbt
  • public/ qui contient les fichiers statiques (javascript, css, image, etc…)
  • test/ qui contient les fichiers de test JUnit

L’utilisation d’eclipse

Bien que l’on puisse utiliser un simple éditeur de texte (Play gère la compilation et le déploiement), personnellement j’ai du mal à me passer de l’auto complétion, or Play s’intègre très facilement avec Eclipse, pour cela placez-vous dans le dossier de votre projet puis lancez la console Play:

play

 
et utilisez la commande suivante :

eclipsify

 
Vous pouvez alors importer le projet dans Eclipse. Si vous utiliser un autre IDE référez vous à cette documentation.

Attention ! Play utilise l’encodage UTF-8, assurez vous d’avoir correctement configuré votre éditeur.

Lancer le serveur

Pour lancer le serveur utilisez la commande suivante dans la console Play:

run

 
Vous pouvez alors ouvrir votre navigateur et aller à l’adresse http://localhost:9000/ pour constater que vous avez une belle page de démonstration. La question existentielle que vous devez vous posez c’est : “mais pourquoi ?”, un début de réponse se trouve dans le fichier conf/routes, plus précisement la ligne :

GET     /                           controllers.Application.index()

 
Celle-ci indique au serveur de rediriger un HTTP Get sur l’url / vers la méthode index de la classe Application qui ressemble à ça :


1
2
3
    public static Result index() {
        return ok(index.render("Your new application is ready."));
    }

Comme vous pouvez le constater celle-ci renvoie un objet Result qui represente la réponse HTTP à renvoyer au navigateur, ici ok (qui correspond au code HTTP 200) avec un contenu. Ce contenu est généré par un template compilé en une simple classe java avec une méthode render. Ce template est défini dans app/views/index.scala.html :


1
2
3
4
5
6
7
@(message: String)

@main("Welcome to Play 2.0") {

    @play20.welcome(message)

}

La première ligne indique la signature de la méthode, la suite peut être un mélange de code Scala préfixé par @, et du HTML, ici @main appelle le template défini dans main.scala.html et @play20.welcome génère le contenu de la page de démonstration. Le template main.scala.html définit la structure de la page :


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@(title: String)(content: Html)

<!DOCTYPE html>

<html>
    <head>
        <title>@title</title>
            <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">
            <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">
            <script src="@routes.Assets.at("javascripts/jquery-1.7.1.min.js")" type="text/javascript"></script>
    </head>
    <body>
        @content
    </body>
</html>

Les instructions @routes.Assets.at permettent de pointer vers le contenu du dossier public.

Et si on commençait…

Pour commencer changeons simplement le retour de la méthode index pour ok(“Hello world”). Pour voir le changement, pas besoin de redémarrer le serveur, vous avez juste à rafraichir la page. Et si vous vous trompez ? Essayez d’enlever la parenthèse fermante par exemple, le serveur Play affiche une belle page vous indiquant l’erreur de compilation…
Pour notre application de chat, nous allons avoir besoin de trois actions : l’affichage de la page, l’envoi d’un message et la récupération des messages. On met à jour le fichier routes :


1
2
3
GET     /                           controllers.Application.index()
GET     /comet                      controllers.Application.comet()
POST    /ajax                       controllers.Application.ajax()

Toujours pareil, on recharge la page et on voit le résultat, et là PAF, ça ne compile pas, eh oui, le fichier routes lui aussi est compilé. Pour corriger cette erreur on ajoute à Application les méthodes suivantes :


1
2
3
4
5
6
7
    public static Result comet() {
        return TODO;
    }

    public static Result ajax() {
        return TODO;
    }

On rafraichit la page, victoire ! ça compile, on essaye /ajax ou /comet, et là, on a une belle page TODO. En fait, le serveur renvoie le code HTTP 501 not implemented.
Passons aux choses sérieuses, l’utilisation de Comet. Pour Play un résultat Comet est un résultat comme les autres :


1
2
3
4
5
6
7
8
9
    public static Result comet() {
        Comet comet = new Comet("parent.receiveMessage") {
            @Override
            public void onConnected() {
                // TODO
            }
        };
        return ok(comet);
    }

Vous remarquerez l’argument passé au constructeur indiquant la méthode javascript qui sera appelée par le navigateur ainsi que la méthode onConnected qui sera appelée lorsque le flux sera prêt.
Maintenant il nous faut nous occuper des messages, on va donc créer une classe Message (oui j’aime faire des surprises) :


1
2
3
4
5
6
7
8
9
10
package models;

import play.data.validation.Constraints.Required;

public class Message {

    @Required
    public String message;

}

Notez l’utilisation de l’annotation @Required qui permet à play de gérer la validation du formulaire. Pour tester la validation et récupérer le contenu, on utilise la classe Form (immutable) :


1
2
3
4
5
6
7
8
9
10
    public static Form<Message> messageForm = form(Message.class);

    public static Result ajax() {
        Form<Message> filledForm = messageForm.bindFromRequest();
        if (!filledForm.hasErrors()) {
            Message message = filledForm.get();
            // TODO utilisation du message
        }
        return ok();
    }

Il ne nous manque plus que le serveur de chat avec la classe ChatServer (encore une surprise) :


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package models;

import java.util.ArrayList;
import java.util.List;

import play.libs.Comet;

public class ChatServer {

    public static ChatServer INSTANCE = new ChatServer();

    private List listeners = new ArrayList();

    public void addListener(Comet listener) {
        listeners.add(listener);
    }

    public void sendMessage(String message) {
        for(Comet listener : listeners) {
            listener.sendMessage(message);
        }
    }
}

Comme vous pouvez le constater notre serveur de chat se contente de renvoyer à tous les flux Comet le message reçu. Nous avons tous les composants, maintenant éditons la vue :


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@(messageForm: Form[Message])

@import helper._

@main("Chat application") {

    <ul id="messageList"></ul>

    @form(routes.Application.ajax()) {
        @inputText(messageForm("message"))
       
        <input type="submit" value="send">
    }

    <script>
        var form = $("form");
        form.submit(function(event) {
            event.preventDefault();
            $.ajax({
                type: "POST",
                url: form.attr("action"),
                data: form.serialize()
            });
            $("#message").val("");
        });

        var receiveMessage = function(event) {
            $("#messageList").append("<li>" + event + "</li>");
        }
    </script>

    <iframe class="invisible" src="/comet"></iframe>

}

 
L’import de helper._ permet d’utiliser les tags @form et @input pour créer le formulaire. On utilise JQuery pour transformer la soumission du formulaire en appel Ajax et effacer le contenu du champ. La classe css invisible sert juste à masquer l’iframe qui reçoit le flux Comet :


1
2
3
.invisible {
    display: None;
}

Au final, votre Application.java devrait ressembler à ça :


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package controllers;

import models.ChatServer;
import models.Message;
import play.*;
import play.data.*;
import play.libs.*;
import play.mvc.*;

import views.html.*;

public class Application extends Controller {

    public static Form messageForm = form(Message.class);

    public static Result index() {
        return ok(index.render(messageForm));
    }

    public static Result comet() {
        Comet comet = new Comet("parent.receiveMessage") {
            @Override
            public void onConnected() {
                ChatServer.INSTANCE.addListener(this);
            }
        };
        return ok(comet);
    }

    public static Result ajax() {
        Form filledForm = messageForm.bindFromRequest();
        if (!filledForm.hasErrors()) {
            ChatServer.INSTANCE.sendMessage(filledForm.get().message);
        }
        return ok();
    }

}

Et voilà, c’est fini, vous pouvez ouvrir plusieurs navigateur et envoyer des messages entre eux…

Conclusion

Les sources sont disponible sur github. Pour aller plus loin vous pouvez jeter un oeil dans le dossier samples de play, vous y trouverez des exemples en java et en scala, dont notamment une application de chat avancée utilisant les websockets avec chatRoom et robot. Et bien sur il y a la documentation (en anglais).

A bientôt pour de nouvelles aventures sur le blog Excilys…

Share
Categories: Non classé Tags: , ,
  1. Pas encore de commentaire
  1. 02/05/2014 à 01:51 | #1
  2. 14/03/2015 à 04:13 | #2