web-dev-qa-db-fra.com

Comment gérer les paramètres de requête facultatifs dans le cadre de lecture

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?

67
magicduncan

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])
60
Julien Richard-Foy

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)
17
Somatik

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.

11
Dave Ranjan

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
  // …
}
7
Max

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.

4
Himanshu Goel

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) + "&amp;" + "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.

2
stian