Tracer sa route
Play! vous permet de créer des services web accessibles via de simples requêtes HTTP.
Vous devez pour cela définir des routes, pour que l'application sache quelle méthode exécuter
en fonction de la requête HTTP.
C'est le rôle du fichier conf/route
, dont voici un exemple :
# Routes
# Ce fichier définit les différentes routes (avec les routes prioritaires en premier)
# ~~~~
# Mappe les fichiers de ressources statiques du répertoire /public avec le chemin /assets dans l'URL
GET /assets/*file controllers.Assets.at(path="/public", file)
GET /test controllers.Application.test()
GET /helloYou controllers.Application.helloYou(firstName, lastName)
GET /userList controllers.Application.userList()
Explications :
-
Pour chaque service web, on définit une route de la forme :
<Type de requête (GET|POST)> <url> <package.Classe.method()>
.
-
L'appel de l'URL http://localhost:9000/test
retournera le résultat de la méthode test()
de la classe Application
du package controllers
.
-
La méthode helloYou()
nécessite les arguments firstName
et lastName
.
Pour l'appeler, l'url sera http://localhost:9000/helloYou?firstName=Jean-Louis&lastName=David
.
Comme la requête est définie en GET
, il suffit d'ajouter les paramètres dans l'url sous
la forme nom_param=valeur
.
Remarque :
La première route (GET /assets/*file...
) est un peu particulière et sert au
fonctionnement interne de Play!, pour gérer les fichiers statiques de l'application.
Une méthode qui a la classe (et vice-versa)
Voici un aperçu de la classe Java qui contient les méthodes définie dans le fichier route :
package controllers;
import java.util.Date;
import models.WSResult;
import models.beans.Bean;
import models.beans.MessageBean;
import play.libs.Json;
import play.mvc.Controller;
import play.mvc.Result;
public class Application extends Controller {
public static Result test() {
WSResult result = new WSResult();
result.addBean(new Bean() {
public String message = "Test";
public Date date = new Date();
});
return ok(Json.toJson(result));
}
public static Result helloYou(String firstName, String lastName) {
WSResult result;
if (!firstName.equals("") && !lastName.equals("")) {
result = new WSResult();
result.addBean(new MessageBean("Hello " + firstName + " " + lastName + "!"));
} else {
result = new WSResult("Paramètres incorrectes.", WSResult.ERROR_CODE_CUSTOM_PARAMS);
}
return ok(Json.toJson(result));
}
}
Explications :
- La classe
Application
étend la classe Controller
fournie par Play!.
- Pour chaque URL définie dans le fichier
route
, on retrouve bien la méthode dans la
classe Application
, avec ses arguments. (Notez que les noms des arguments doivent être identiques.)
- Chaque méthode est statique et retourne un objet
Result
(classe également fournie par Play!).
- Dans cet exemple, à chaque
Result
est associée une liste d'objets Bean
.
- Un objet
Bean
regroupe des informations à rendre accessible via un service web
(un message, le résultat d'un requête SQL, ...)
- Dans cet exemple, la classe
Result
a été étendue par la classe WSResult
,
pour lui ajouter une liste d'objets Bean
, un éventuel message d'erreur, et d'autres informations.
- Chaque méthode retourne un objet Result en JSON, via la méthode
ok(Json.toJson(result))
fournie par Play!.
- La seconde méthode vérifie si les paramètres sont vides.
Si oui, alors l'objet Result ne contiendra pas de Bean mais un message et un code d'erreur.
Si non, il contiendra un Bean comme dans la première méthode.
Un vrai Bean, monsieur
Normalement, un Bean représente une ligne de données provenant d'une source (base de données, fichier, ...).
C'est une classe Java des plus simples, avec juste des attributs et leurs getter()
et setter()
.
Imaginons par exemple qu'on veuille représenter un utilisateur de site web présent
dans une table de base de données, on pourrait avoir :
package models.beans;
public class UserBean extends Bean {
private int userID;
private String email;
private String login;
private String password;
public static final String FIELD_USER_ID = "user_id";
public static final String FIELD_EMAIL = "email";
public static final String FIELD_LOGIN = "login";
public static final String FIELD_PASSWORD = "password";
public int getUserID() {
return userID;
}
public void setUserID(int userID) {
this.userID= userID;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Explications :
- On étend la classe
Bean
, car la classe WSResult
attend des objets Bean
dans sa liste.
- En plus des attributs caractérisant un utilisateur, on ajoute des attributs publics et statiques
pour préciser quels champs de la base de données correspondent.
- Pour que Play! puisse se connecter à une base de données,
vous devez procéder à quelques configurations.
Retour à la base
Une fois que la classe UserBean
a été créée, il faut écrire dans la classe Application
la méthode
qui va consulter la base de données et retourner un objet Result :
package controllers;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import models.WSResult;
import models.beans.UserBean;
import play.libs.Json;
import play.mvc.Result;
public class Application extends ApplicationController {
/**
* Retourne la liste des utilisateurs de la base de données.
*
* @return Result
*/
public static Result userList() {
WSResult result = new WSResult();
String queryName = "user_list";
String query = ApplicationController.getQuery(queryName);
PreparedStatement statement;
try {
statement = ApplicationController.getConnection().prepareStatement(query);
ResultSet resultSet = statement.executeQuery();
// Parcours des lignes retournées
while (resultSet.next()) {
UserBean bean = new UserBean();
bean.setId(resultSet.getInt(UserBean.FIELD_ID));
bean.setEmail(resultSet.getString(UserBean.FIELD_EMAIL));
bean.setLogin(resultSet.getString(UserBean.FIELD_LOGIN));
bean.setPassword(resultSet.getString(UserBean.FIELD_PASSWORD));
result.addBean(bean);
}
} catch (SQLException e) {
result = new WSResult("Erreur SQL.", WSResult.ERROR_CODE_SQL);
result.setErrorCode(e.getErrorCode());
result.setErrorMessage(e.getMessage());
}
return ok(Json.toJson(result));
}
}
Explications :
- La méthode utilise l'api java
sql
, pour préparer les requêtes et les exécuter.
- On parcourt ensuite les lignes retournées par la source de données
- Pour chaque ligne de résultat, on instancie un nouveau Bean
(
UserBean
ici puisqu'il s'agit d'utilisateurs) et on l'ajoute à la liste de Beans de l'objet Result
.
- On retourne l'objet
Result
transformé en JSON.
- En cas d'erreur SQL, on retourne un objet
Result
contenant le message et le code d'erreur SQL.
Stockage des requêtes
Dans la méthode ci-dessus, on ne voit aucun code SQL.
Les requêtes sont stockées dans un fichier qui les regroupe toutes : conf/sql.properties
.
Comme tout fichier .properties
standard, chaque ligne est de la forme clé = valeur :
user_list = SELECT * FROM user
admin_user = SELECT * FROM user WHERE login = 'admin'
Ces requêtes sont récupérées dans les méthodes java à partir de leurs clés :
String queryName = "user_list";
String query = ApplicationController.getQuery(queryName);
Lancement des requêtes
Finalement, si vous tapez http://localhost:9000/userList
dans votre navigateur,
vous obtenez quelque chose de la forme :
En résumé :
- Play! reçoit votre requête HTTP.
- Il cherche dans son fichier
route
la méthode correspondante et l'appelle.
- La méthode cherche la requête SQL demandée, l'exécute et parcours les résultats.
- Ces résultats sont "transformés en Bean" et stockés dans un objet
Result
.
- L'objet
Result
est transformé en JSON et Play! vous en retourne le flux.
Remarque : Si vous avez un affichage du JSON illisible,
il existe une extension Firefox très utile.