Disons que j'ai une application basée sur le framework Play 2.0 qui fonctionne déjà dans Scala qui sert une URL telle que:
http: // localhost: 9000/anniversaires
qui répond avec une liste de tous les anniversaires connus
Je veux maintenant améliorer cela en ajoutant la possibilité de restreindre les résultats avec des paramètres de demande facultatifs "de" (date) et "à" tels que
http: // localhost: 9000/anniversaires? de = 20120131 & à = 20120229
(dates interprétées ici comme aaaaMMjj)
Ma question est de savoir comment gérer la liaison et l'interprétation des paramètres de demande dans Play 2.0 avec Scala, d'autant plus que ces deux paramètres doivent être facultatifs.
Ces paramètres devraient-ils être exprimés d'une manière ou d'une autre dans la spécification "routes"? Sinon, la méthode Controller qui répond devrait-elle séparer les paramètres de l'objet de requête d'une manière ou d'une autre? Y a-t-il une autre façon de procéder?
Encodez vos paramètres facultatifs comme Option[String]
(ou Option[Java.util.Date]
, mais vous devrez implémenter votre propre QueryStringBindable[Date]
):
def birthdays(from: Option[String], to: Option[String]) = Action {
// …
}
Et déclarez l'itinéraire suivant:
GET /birthday controllers.Application.birthday(from: Option[String], to: Option[String])
Une façon peut-être moins propre de le faire pour les utilisateurs de Java définit les paramètres par défaut:
GET /users controllers.Application.users(max:Java.lang.Integer ?= 50, page:Java.lang.Integer ?= 0)
Et dans le contrôleur
public static Result users(Integer max, Integer page) {...}
Encore un problème, vous devrez répéter les valeurs par défaut chaque fois que vous créez un lien vers votre page dans le modèle
@routes.Application.users(max = 50, page = 0)
En complément de la réponse de Julien. Si vous ne voulez pas l'inclure dans le fichier routes.
Vous pouvez obtenir cet attribut dans la méthode du contrôleur à l'aide de RequestHeader
String from = request().getQueryString("from");
String to = request().getQueryString("to");
Cela vous donnera les paramètres de demande souhaités, et gardera votre fichier routes propre.
Voici l'exemple de Julien réécrit en Java, en utilisant F.Option: (fonctionne à partir du jeu 2.1)
import play.libs.F.Option;
public static Result birthdays(Option<String> from, Option<String> to) {
// …
}
Route:
GET /birthday controllers.Application.birthday(from: play.libs.F.Option[String], to: play.libs.F.Option[String])
Vous pouvez également sélectionner des paramètres de requête arbitraires sous forme de chaînes (vous devez effectuer la conversion de type vous-même):
public static Result birthdays(Option<String> from, Option<String> to) {
String blarg = request().getQueryString("blarg"); // null if not in URL
// …
}
Pour les paramètres de requête facultatifs, vous pouvez le faire de cette façon
Dans le fichier de routes, déclarez l'API
GET /birthdays controllers.Application.method(from: Long, to: Long)
Vous pouvez également donner une valeur par défaut, au cas où l'API ne contient pas ces paramètres de requête, elle attribuera automatiquement les valeurs par défaut à ces paramètres
GET /birthdays controllers.Application.method(from: Long ?= 0, to: Long ?= 10)
Dans la méthode écrite à l'intérieur de l'application du contrôleur, ces paramètres auront la valeur null
si aucune valeur par défaut n'est affectée à d'autres valeurs par défaut.
Ma façon de procéder consiste à utiliser un QueryStringBindable
personnalisé. De cette façon, j'exprime les paramètres dans les itinéraires comme:
GET /birthdays/ controllers.Birthdays.getBirthdays(period: util.Period)
Le code de Period ressemble à ceci.
public class Period implements QueryStringBindable<Period> {
public static final String PATTERN = "dd.MM.yyyy";
public Date start;
public Date end;
@Override
public F.Option<Period> bind(String key, Map<String, String[]> data) {
SimpleDateFormat sdf = new SimpleDateFormat(PATTERN);
try {
start = data.containsKey("startDate")?sdf.parse(data.get("startDate") [0]):null;
end = data.containsKey("endDate")?sdf.parse(data.get("endDate")[0]):null;
} catch (ParseException ignored) {
return F.Option.None();
}
return F.Option.Some(this);
}
@Override
public String unbind(String key) {
SimpleDateFormat sdf = new SimpleDateFormat(PATTERN);
return "startDate=" + sdf.format(start) + "&" + "endDate=" + sdf.format(end);
}
@Override
public String javascriptUnbind() {
return null;
}
public void applyDateFilter(ExpressionList el) {
if (this.start != null)
el.ge("eventDate", this.start);
if (this.end != null)
el.le("eventDate", new DateTime(this.end.getTime()).plusDays(1).toDate());
}
}
applyDateFilter
n'est qu'une méthode de convenance que j'utilise dans mes contrôleurs si je veux appliquer un filtrage de date à la requête. Évidemment, vous pouvez utiliser ici d'autres valeurs par défaut de la date, ou utiliser une autre valeur par défaut que null pour les dates de début et de fin dans la méthode bind
.