Archives pour la catégorie Play

Play Framework – Lancer / debugger directement une application Play depuis IntelliJ

Pour démarrer votre application Play, vous pouvez utiliser la ligne de commande « play run [nom_app] ». Pas très pratique d’avoir une fenêtre séparée, d’autant plus qu’elle va contenir les logs de l’application.

Si vous disposez d’un IDE, vous allez pouvoir lancer votre application directement. Pour Eclipse et Netbeans, consultez la documentation officielle:

http://www.playframework.org/documentation/1.2.4/ide

La méthode simple dans IntelliJ

Si vous avez activé l’extension Play dans IntelliJ, vous devriez disposer d’une nouvelle entrée dans le menu Tools:

Au premier lancement, on va vous demander ou se trouve votre installation de Play. Pour les fois d’après, IntelliJ va vous ouvrir une console dans laquelle il vous suffira de faire « run »:

Pour activer le debugger

Dans le cas d’IntelliJ, rendez-vous dans Run > Edit Configuration. Click droit sur « Application » > Add new configuration puis remplissez les champs suivants:

N’oubliez pas de décocher « Make » en bas de la fenêtre, sinon vous aurez une des erreurs ci-dessous !

Lancez maintenant l’application depuis le bouton Run de l’interface d’IntelliJ. Pour débugger, appuyez sur le bouton juste à droite. Votre application va s’arrêter sur les points d’arrêt, etc.

Erreurs potentielles

Si vous obtenez l’erreur « Cannot start compiler: the SDK is not specified for module « Tweep ». Specify the SDK at Project Structure dialog.« , cela signifie que votre JDK n’est pas correctement installée / configurée. Rendez-vous donc sur le site d’Oracle pour télécharger un JDK:

http://www.oracle.com/technetwork/java/javase/downloads/index.html

Dans la fenêtre Project Structure d’IntelliJ, cliquez sur New puis pointez sur la JDK que vous avez installé sur votre poste:

Si vous obtenez l’erreur « Cannot start compilation: the output path is not specified for module « Tweep ». Specify the output path in Configure Project« , cela signifie que vous avez laissé coché « Make dans la boîte de dialogue:

Décochez ce paramètre, sinon IntelliJ tente de compiler alors qu’il ne le devrait pas.

Si vous obtenez au lancement « Could not bind on port 9000« , cela signifie que Play n’a pas pu se lancer sur le port par défaut (9000). Soit vous avez un logiciel qui occupe déjà ce port (xdebug sous Eclipse par exemple), soit votre application Play est déjà lancée !

Play – Upload de fichiers multiples avec le composant jQuery File Upload (File API HTML5)

Les nouvelles APIs « HTML5 » apportent des nouveautés intéressantes comme la File API, permettant de faire du Drag n Drop de fichiers directement depuis sa machine vers une page web. Très pratique pour éviter d’utiliser les « input type file » classiques (boutons « Parcourir… »), surtout quand vous avez plusieurs fichiers à uploader.

Un bon exemple d’utilisation est celui de http://cartodb.com/ (après inscription) sur lequel on peut envoyer un fichier SIG ShapeFile qui n’est pas constitué d’un seul fichier mais de 5/6 fichiers différents. Il est plus pratique de faire glisser les 6 fichiers vers la page web que de créer une archive zip à uploader.

Bref, on va voir comment faire cela de manière simple avec jQuery et Play Framework côté serveur.

Le composant jQuery File Upload

La File API n’est pas facile à manipuler, avec notamment pas mal de cas spéciaux et des comportements qui diffèrent selon les navigateurs. Il y a donc plusieurs librairies qui ont émergé comme uploadify (merci @clacote). Pour ma part, j’ai trouvé ce composant assez puissant qui fonctionne plutôt bien, le jQuery File Upload:

http://blueimp.github.com/jQuery-File-Upload/

Première chose à faire, aller récupérer le code source (et lire les très bonnes docs accessoirement):

https://github.com/blueimp/jQuery-File-Upload/downloads

Application Play Framework 1.x

Si vous n’avez pas téléchargez Play, rendez-vous sur le site officiel. Prenez la 1.2.5:

http://www.playframework.org/download

Dans ce tutorial, on utilisera la 1.x (v1.2.5 lors de l’écriture de cet article). Créez une application si vous n’en avez pas déjà une:

play new tuto-upload

Puis lancez la commande qui permet d’ouvrir le projet dans votre IDE préféré (« play idealize » pour IntelliJ par exemple).

Copiez les fichiers du composant jQuery File Upload que vous avez téléchargé dans le dossier /public/javascripts de votre application. Prenez tout ce qu’il y a dans « /js/ » et copiez-le dans /public/javascripts/ ». Prenez aussi ce fichier qui va se charger de faire du templating pour jQuery (jQ Templates):

http://blueimp.github.com/JavaScript-Templates/tmpl.min.js

Mettez ensuite le contenu de /css/ dans /stylesheets/. Au passage, allez aussi chercher le CSS de Twitter Bootstrap, qui va donner une bonne tête à votre page:

http://twitter.github.com/bootstrap/assets/css/bootstrap.css

Le template de base de Play qui sert de squelette pour vos pages (app/views/main.html) contient déjà jQuery, rien à changer de ce côté là. On va travailler dans le fichier index.html directement.

On va commencer par rajouter les links vers les fichiers JS que l’on vient de copiez en utilisant les hooks « moreScripts » et « moreStyles » + les balises Groovy #{script} et #{style} qui se chargent de setter les attributs obligatoires autres que src:

#{extends 'main.html' /}
#{set title:'Home' /}
#{set 'moreScripts'}
    #{get 'moreScripts' /}
    #{script 'vendor/jquery.ui.widget.js'/}
    #{script 'jquery.iframe-transport.js'/}
    #{script 'tmpl.min.js'/}
    #{script 'jquery.fileupload.js'/}
    #{script 'jquery.fileupload-fp.js'/}
    #{script 'jquery.fileupload-ui.js'/}
    #{script 'locale.js'/}
#{/set}
#{set 'moreStyles'}
    #{get 'moreStyles' /}
    #{stylesheet 'jquery.fileupload-ui.css'/}
    #{stylesheet 'bootstrap.css'/}
#{/set}

Création de l’action d’upload

On commence par ajouter une route dans le fichier /conf/routes:

# Home page
GET     /                                       Application.index
POST    /upload                                 Application.upload

On est bien en POST car on souhaite faire de l’upload. On va créer l’action dans notre controller Application.java:

package controllers;

import play.*;
import play.mvc.*;

import java.io.File;
import java.util.*;

import models.*;

public class Application extends Controller {

    public static void index() {
        render();
    }

    public static void upload(File[] files) {

    }

}

Maintenant, on va créer notre formulaire à partir de cette action dans notre template Groovy (index.html, là où on a mis les moreScript). Pour cela, Play dispose d’un tag #{form} qui permet de faire du reverse routing et de ne pas avoir à taper l’url d’upload (attribut « action ») à la main, pratique:

#{extends 'main.html' /}
#{set title:'Home' /}
#{set 'moreScripts'}
    #{get 'moreScripts' /}
    #{script 'vendor/jquery.ui.widget.js'/}
    #{script 'jquery.iframe-transport.js'/}
    #{script 'jquery.fileupload.js'/}
    #{script 'jquery.fileupload-fp.js'/}
    #{script 'jquery.fileupload-ui.js'/}
    #{script 'locale.js'/}
#{/set}
#{set 'moreStyles'}
    #{get 'moreStyles' /}
    #{stylesheet 'jquery.fileupload-ui.css'/}
#{/set}

#{form @Application.upload() , id:'fileupload', enctype:'multipart/form-data'}
#{/form}

On lui a juste ajouté un simple id pour plus tard et un enctype qui dit que l’on va faire de l’upload.

On va lancer notre application pour voir ce que cela donne. Lancez la commande :

play run

Le serveur Play est lancé sur le port 9000. Rendez-vous donc sur :

http://localhost:9000/

Si tout va bien, vous devriez arriver sur une page blanche. Allez voir la source de la page et vous verrez que votre formulaire est bien là:

<form action="/upload" method="POST" accept-charset="utf-8" enctype="multipart/form-data" id="fileupload" ><input type="hidden" name="authenticityToken" value="58abd56b3f8b6c62a0e0180b59cc65e1e74a6b43">

</form>

Maintenant, on va ajouter le composant jQuery File Upload.

Lire la suite

Play – Fichier de configuration « routes », le lien entre vos URLs et vos Controller

Dans l’article précédent, on a vu que c’était Play, votre serveur d’application qui allait intercepter les requêtes HTTP et les traiter grâce aux classes Java « Controller »:

Play – Fonctionnement général et cycle de vie d’une requête HTTP

Pour décider quel Controller va devoir être appelé, Play va analyser un fichier nommé « routes », placé dans le répertoire « /conf/ » de votre application. Celui-ci va contenir des règles de redirection avec une syntaxe très simple. Pour ce qui ont déjà vu des règles de configuration de firewall, vous n’allez pas être perdu.

Play encourage le développement d’applications « RESTful »

Vous allez le voir par la suite, Play essaie de profiter pleinement de HTTP et vous permet notamment d’utiliser les différents verbes HTTP . Chaque URL est définie par une URL (ex. /user/135) et un verbe HTTP (GET, POST, PUT, DELETE, HEAD).

Une application dite « RESTful » possède les caractéristiques suivantes:

  • L’application est découpée en « ressources »
  • Chaque ressource peut-être accédée par une URL
  • Le serveur ne gère pas l’état du client (variables de session) = stateless

Play encourage le développement de telles applications, notamment grâce au mécanisme de routing. Ce type d’application a de nombreux avantages, comme:

  • la possibilité de les mettre facilement sur plusieurs serveurs. Peu importe qui demande la ressource et quand il la demande, la ressource servie sera toujours la même
  • la possibilité de mettre les ressources en cache (prévisible)

Syntaxe du fichier routes de Play! Framework

Le fichier « routes » est créé automatiquement lors de la création d’un nouveau projet Play. Celui-ci se trouve dans le dossier /conf/ de l’application.

Comme on l’a présenté plus tôt, chaque route est constituée de 3 éléments, dans cet ordre:

  1. Un verbe HTTP (GET, POST, PUT, DELETE, HEAD)
  2. Une URL (plutôt une URI en fait)
  3. Une référence vers une action d’un Controller (représentée par une de ses méthodes)

Voici un exemple:

GET    /clients/{id}             Clients.show

Pour ajouter un commentaire dans le fichier routes, ajoutez un « # » en début de ligne. Cela permet de documenter rapidement son API:

# Display a client
GET /clients/{id} Clients.show

Valeurs spéciales pour les verbes HTTP

Il existe deux valeurs spéciales qui peuvent remplacer les verbes HTTP:

  • « ws » indique une requête WebSocket
  • « * » est un joker, qui va être vérifié pour tout verbe HTTP

Valeurs et patterns pour les URI

De base, vous pouvez avoir des routes qui vont reconnaître qu’une URI exacte, comme:

/clients/list

Mais vous pouvez aussi indiquer que certaines parties de l’URL peuvent être dynamiques en les entourant d’accolades:

/clients/{id}

Cette règle va reconnaître les URI suivantes:

/clients/12121
/clients/toto

Vous pouvez avoir autant de parties dynamiques que vous le souhaitez:

/clients/{id}/accounts/{accountId}

Par défaut, Play va reconnaître tous les caractères jusqu’au prochain « / ». Mais vous pouvez aussi lui passer une expression régulière. Par exemple, la règle suivante ne va accepter que les id numériques:

/clients/{<[0-9]+>id}

Le nom du paramètres que vous placez entre accolades est important. En effet, il sera directement lié à la méthode de votre Controller.

Lire la suite

Play – Controller et Interceptor @Before, @After, @Finally, …

Dans les deux derniers articles, on a vu les différentes variantes de la méthode render(), permettant de répondre du JSON ou du contenu HTML avec les templates par exemple:

Play – Controller et les variantes de render() (JSON, XML, fichier, …)

Sur des exemples simples, cela semble suffisant mais chaque « action » d’un Controller est un point d’entrée de votre application. Pour gérer les traitements en commun, vous devriez ajouter du code dans chacun de vos Controller, une répétition de code qui n’est jamais bonne à écrire.

Prenez par exemple la vérification des droits utilisateurs sur une partie de votre site. Pour toutes les actions, vous devrez vérifier d’abord si l’utilisateur est bien administrateur et si non, le renvoyer sur la page de login.

Au lieu de devoir répéter ces codes, on va utiliser des « Interceptors » dans le jargon de Play. Ces méthodes font partie de votre vos Controller mais on peut aussi les modulariser en les isolant dans une classe à part. Les Interceptors sont « static » mais pas « public », contrairement aux actions. Des annotations Java permettent de leur donner un comportement précis.

Si je ne trompe pas, cela ressemble beaucoup à de la programmation orienté aspect.

Interceptor @Before

On va reprendre l’exemple de l’espace administrateur pour lequel on devra vérifier pour toutes les actions que l’utilisateur est bien connecté. Dans cet exemple, on ajoute une méthode checkAuthentification() avec l’annotation @Before:

public class Admin extends Controller {

    @Before
    static void checkAuthentification() {
        if(session.get("user") == null) login();
    }

    public static void index() {
        List<User> users = User.findAll();
        render(users);
    }
    …
}

A noter que notre Interceptor @Before sera appelé pour toutes les actions de ce Controller. Si vous voulez modifier cela, vous pouvez donner une liste d’action à exclure:

@Before(unless="login")
    static void checkAuthentification() {
        if(session.get("user") == null) login();
    }

Ou une liste exclusive avec « only »:

public class Admin extends Controller {

    @Before(only={"login","logout"})
    static void doSomething() {
        …
    }
    …
}

Ces modifiers only et unless sont utilisables avec @Before, @After et @Finally

Interceptor @After

Même combat mais effectué après l’appel à une action du Controller. Pratique pour le log par exemple:

public class Admin extends Controller {

    @After
    static void log() {
        Logger.info("Action executed ...");
    }

    public static void index() {
        List<User> users = User.findAll();
        render(users);
    }

    …
}

Interceptor @Catch

Permet de récupérer les exceptions qui peuvent être lancées par les actions du Controller de manière globale. L’exception est passée en paramètre de la méthode annotée @Catch:

public class Admin extends Controller {

    @Catch(IllegalStateException.class)
    public static void logIllegalState(Throwable throwable) {
        Logger.error("Illegal state %s…", throwable);
    }

    public static void index() {
        List<User> users = User.findAll();
        if (users.size() == 0) {
            throw new IllegalStateException("Invalid database - 0 users");
        }
        render(users);
    }
}

Notez que vous pouvez aussi réaliser un filtrage plus fin sur les exceptions à @Catch (voir documentation Play).

Interceptor @Finally

L’interceptor @Finally ressemble beaucoup à @After sauf qu’il sera appelé dans tous les cas, même si une erreur se produit pendant l’exécution de votre code (comme un try/catch/finally):

public class Admin extends Controller {

    @Finally
    static void log() {
        Logger.info("Response contains : " + response.out);
    }

    public static void index() {
        List<User> users = User.findAll();
        render(users);
    }
    …
}

L’annotation @With pour ajouter plus d’Interceptor

Pour l’instant, on a uniquement vu les Interceptor qui résidaient au sein de la classe de Controller. Pas terrible par exemple pour votre vérification administrateur que vous devrez faire dans plusieurs Controller. Heureusement, Play vous permet de décentraliser ce code dans un Controller dédié. Par exemple, on crée un Controller « Secure.java »:

public class Secure extends Controller {

    @Before
    static void checkAuthenticated() {
        if(!session.containsKey("user")) {
            unAuthorized();
        }
    }
}

Que l’on peut ensuite utiliser dans un autre Controller en ajoutant l’annotation @With sur le/les Controller à impacter:

@With(Secure.class)
public class Admin extends Controller {

    …
}

Cela vous évite de vous répéter et vous permet de laisser vos Controllers « propres », avec uniquement la Business Logic.