Play – Controller et mapping des paramètres de requête HTTP (GET, POST, File, …)

Dans la conception d’une application web, un des aspects les plus importants est la logique métier, alias Business Logic. Cette logique métier est le lien entre la couche de présentation (vos View) et votre couche de donnée (vos Model).

Dans Play! Framework, la définition de votre logique métier se fait au sein des Controller, des classes Java (ou Scala) qui vont faire le lien entre une requête HTTP et votre Model. Bien sûr, aucune application ne se ressemble. On voit souvent les différences au niveau de l’interface utilisateur mais c’est surtout votre Business Logic qui va faire la différence avec les applications de vos concurrents.

Play va vous aider à écrire ces classes de Controller en vous fournissant des raccourcis ou des mappings automatique (par convention) qui vous éviterons de répéter inutilement certaines lignes de code.

Fonctionnement général d’un Controller Play

Un Controller dans le jargon Play est une classe qui se situe dans le package « controllers » et qui hérite de play.mvc.Controller. Par exemple:

package controllers;

import models.Client;
import play.mvc.Controller;

public class Clients extends Controller {

    public static void show(Long id) {
        Client client = Client.findById(id);
        render(client);
    }

    public static void delete(Long id) {
        Client client = Client.findById(id);
        client.delete();
    }

}

Chaque méthode « public static » est appelée une « action » dans Play. Ces actions renvoient la plupart du temps un type « void » (rien). En effet, pour indiquer à un Controller que l’on veut afficher une View (interface utilisateur), on va utiliser la méthode « render(…) » qui va exécuter le rendu d’un template.

Récupérer des paramètres de la requête HTTP

Ces « actions » peuvent avoir des paramètres qui seront automatiquement assignés par rapport à la requête HTTP entrante.

Mapping automatique

Imaginez que vous ayez la route suivante définie dans votre fichier de configuration routes:

GET    /clients/{id}             Clients.show

Les accolades signifient que l’id est la partie dynamique de l’URI. Si vous interrogez donc votre serveur avec l’URI /clients/1541, 1541 est votre id. Voici la méthode de votre Controller Clients qui va être appelée:

    public static void show(Long id) {
        Client client = Client.findById(id);
        render(client);
    }

Play va automatiquement faire le mapping entre le paramètre {id} de votre URI et le paramètre « id » de la méthode « show(Long id) ». Dans ce cas-là, Play va donc effectuer l’opération Client.findById(1541).

Play va aussi récupérer automatiquement les listes de paramètres que vous allez donner à votre requête. Par exemple pour:

/clients?id=1541&id=1654

Play va vous permettre de récupérer directement la liste des ids:

public static void show(Long[] id) {

Voici les types Java que vous pouvez utiliser directement dans la signature de vos paramètres, Play fera la conversion de type tout seul:

 

int, long, boolean, char, byte, float, double, Integer, Long, Boolean, Char, String, Byte, Float, Double.

Mapping manuel

Dans tous les cas, Play garde une Map<String, String[]> qui va contenir la liste des paramètres HTTP passés à la requête. En plus de cela, Play vous explose une méthode permettant de faire directement une conversion de type grâce à get(paramName, Class).

On aurait donc aussi pu écrire notre méthode show() comme ceci:

public static void show() {
	Long id = params.get("id", Long.class);
	Client client = Client.findById(id);
	render(client);
}

Bien sûr, cela fonctionne aussi avec les paramètres GET « classiques », comme avec l’URL /clients?id=1541 par exemple.

Le cas de l’upload de fichier

L’upload de fichier est assez commun dans une application web, ne serait-ce que pour que votre utilisateur envoie sa photo de profil. Lorsque Play reçoit un fichier issu d’un formulaire web « multipart/form-data », il va le stocker le temps de la requête dans un dossier temporaire et vous pourrez directement le récupérer dans votre Controller, en déclarant un paramètre de type « File »:

public static void create(String comment, File attachment) {
    String s3Key = S3.post(attachment);
    Document doc = new Document(comment, s3Key);
    doc.save();
    show(doc.id);
}

Si vous voulez conserver le fichier, n’oubliez pas de la copier dans votre logique métier car il sera détruit automatiquement par Play à la fin de la requête.

Mapping direct avec un objet Java

Play peut mapper directement les paramètres de la requête HTTP avec un de vos model Java en suivant toujours les mêmes conventions de nommage. Par exemple, vous avez un objet Client avec une propriété « name » et une propriété « email ».

Si vous avez dans votre Controller la méthode:

public static void create(Client client ) {
    client.save();
    show(client);
}

Vous pouvez envoyer directement la requête suivante:

?client.name=Zenexity&client.email=contact@zenexity.fr

Le mapping est fait de manière récursif, vous pouvez donc avoir une requête du type:

?client.name=Zenexity
&client.address.street=64+rue+taitbout
&client.address.zip=75009
&client.address.country=France

Vous pouvez aussi utiliser la notation tableau pour référence un élément d’une List Java:

?client.customers[0].id=123
&client.customers[1].id=456
&client.customers[2].id=789

Dans le cas que nous venons de voir, Play va créer une nouvelle instance de la classe Client et la sauvegarder. Si vous voulez agir sur un objet en particulier, il vous faudra faire la correspondance avec un objet JPA (Java Persistence API)

Mapping avec un objet JPA

Si vous souhaitez que le model récupéré soit automatiquement mappé par rapport à un objet de votre couche de persistance (base de données le plus souvent), vous devrez envoyer un paramètre « id ». Lorsque Play! trouve celui-ci, il va charger l’instance correspondante depuis la base de données avant que vous puissiez l’éditer.

Par exemple, en exécutant la requête suivante, Play va automatiquement allez chercher l’User qui a l’id 1 en BDD, sur lequel vous pourrez travailler directement dans votre Controller:

user.id = 1
&user.name=morten
&user.address.id=34
&user.address.street=MyStreet

La méthode du Controller reste aussi simple:

public static void save(User user) {
   // actions ...
    user.save();
}

5 réflexions au sujet de « Play – Controller et mapping des paramètres de requête HTTP (GET, POST, File, …) »

  1. admin Auteur de l’article

    Merci ;)
    C’est juste un code d’exemple dont il manque un bout. En l’occurence, la classe S3 qui sera à uploader le fichier dans le cloud vers un Amazon WS

    Fab

    Répondre
    1. Frédéric THOMAS

      Ah ok, bah je ne sais pas si dans un prochain tut, tu prévois de détailler le stockage de la référence/lien et du document lui-même mais ça pourrait être un intéressant complément, je pense.

      Répondre
      1. admin Auteur de l’article

        Le stockage est fait par JPA comme ton Model est une Entity. Donc stockage automatique dans le système de stockage précisé dans ta config Play (file, BDD, …)
        C’est pour plus tard :)

        Fab

        Répondre
  2. Ping : Play – Controller et les variantes de render() (JSON, XML, fichier, …) | HTML5 Tutorial

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *