Umgang mit optionalen Abfrageparametern im Play Framework

72

Nehmen wir an, ich habe eine bereits funktionierende Play 2.0-Framework-basierte Anwendung in Scala, die eine URL wie die folgende bereitstellt:

http: // localhost: 9000 / Geburtstage

die mit einer Auflistung aller bekannten Geburtstage antwortet

Ich möchte dies jetzt verbessern, indem ich die Möglichkeit hinzufüge, Ergebnisse mit optionalen "von" (Datum) und "bis" Anforderungsparametern wie z

http: // localhost: 9000 / geburtstage? von = 20120131 & bis = 20120229

(Daten hier interpretiert als JJJJMMTT)

Meine Frage ist, wie die Bindung und Interpretation von Anforderungsparametern in Play 2.0 mit Scala behandelt werden soll, insbesondere angesichts der Tatsache, dass beide Parameter optional sein sollten.

Sollten diese Parameter irgendwie in der "Routen" -Spezifikation ausgedrückt werden? Sollte die antwortende Controller-Methode alternativ die Parameter irgendwie vom Anforderungsobjekt trennen? Gibt es einen anderen Weg, dies zu tun?

magicduncan
quelle

Antworten:

60

Codieren Sie Ihre optionalen Parameter als Option[String](oder Option[java.util.Date], aber Sie müssen Ihre eigenen implementieren QueryStringBindable[Date]):

def birthdays(from: Option[String], to: Option[String]) = Action {
  // …
}

Und deklarieren Sie die folgende Route:

GET   /birthday       controllers.Application.birthday(from: Option[String], to: Option[String])
Julien Richard-Foy
quelle
8
Für mich war dies nicht genug, um Routing ohne Parameter durchzuführen. Ich verlängerte es aufGET /birthday controllers.Application.birthday(from: Option[String] ?= None, to: Option[String] ?= None)
Marius Soutier
Erfolgreicher:GET /birthday controllers.Application.birthday(Option[from], Option[to])
Paul Draper
1
Jetzt dokumentiert unter playframework.com/documentation/2.4.x/…
matanster
Optionale Parameter werden hier beschrieben (v2.7 +) => playframework.com/documentation/2.7.x/…
sentenza
19

Eine möglicherweise weniger saubere Methode für Java-Benutzer ist das Festlegen von Standardeinstellungen:

GET  /users  controllers.Application.users(max:java.lang.Integer ?= 50, page:java.lang.Integer ?= 0)

Und in der Steuerung

public static Result users(Integer max, Integer page) {...}

Ein weiteres Problem: Sie müssen die Standardeinstellungen wiederholen, wenn Sie auf Ihre Seite in der Vorlage verlinken

@routes.Application.users(max = 50, page = 0)
Somatik
quelle
Kann jemand bestätigen, dass (max: java.lang.Integer = null) funktioniert? 'max' endet für mich immer null ...
ejain
1
Ich habe die Antwort
korrigiert
6
In Java können Sie play.libs.F.Optionanstelle von ScalaOption
Julien Richard-Foy
1
Haben Sie ein Beispiel für das Ganze mit der Scala- oder F-Option? Was mich stört, ist die Wiederholung der Standardeinstellungen in den Vorlagen. Ich bekomme immer diesen Vorschlag, _ für teilweise angewendete Funktionen zu verwenden
Somatik
12

Zusätzlich zu Juliens Antwort. Wenn Sie es nicht in die Routendatei aufnehmen möchten .

Sie können dieses Attribut in der Controller-Methode mit RequestHeader abrufen

String from = request().getQueryString("from");
String to = request().getQueryString("to");

Dadurch erhalten Sie die gewünschten Anforderungsparameter und halten Ihre Routendatei sauber.

Dave Ranjan
quelle
Wie sieht Ihre Router-Datei aus? Ich habe so etwas wie GET /url @com.mycompany.controllers.MyClass.fetchget()und es kann die Route nicht finden
Zennichimaro
1
@ Zennichimaro stackoverflow.com/questions/16301211/… werfen Sie einen Blick
iku
7

Hier ist Juliens Beispiel, das mit F.Option in Java umgeschrieben wurde: (funktioniert ab Spiel 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])

Sie können auch einfach beliebige Abfrageparameter als Zeichenfolgen auswählen (Sie müssen die Typkonvertierung selbst durchführen):

public static Result birthdays(Option<String> from, Option<String> to) {
  String blarg = request().getQueryString("blarg"); // null if not in URL
  // …
}
Max
quelle
5

Bei optionalen Abfrageparametern können Sie dies auf diese Weise tun

Deklarieren Sie in der Routendatei die API

GET   /birthdays     controllers.Application.method(from: Long, to: Long)

Sie können auch einen Standardwert angeben. Falls die API diese Abfrageparameter nicht enthält, werden diesen Parametern automatisch die Standardwerte zugewiesen

GET   /birthdays    controllers.Application.method(from: Long ?= 0, to: Long ?= 10)

In der in der Controller-Anwendung geschriebenen Methode haben diese Parameter einen Wert, nullwenn keine Standardwerte zugewiesen sind, andernfalls Standardwerte.

Himanshu Goel
quelle
Vielen Dank für diese Antwort. Jetzt wird sie in Prahlerei mit einem Feld mit einem Standardwert angezeigt. In meinem Fall hatte ich einen obligatorischen und einen optionalen Parameter.
Karsten314159
2

Meine Art, dies zu tun, beinhaltet die Verwendung eines Brauchs QueryStringBindable. Auf diese Weise drücke ich Parameter in Routen aus als:

GET /birthdays/ controllers.Birthdays.getBirthdays(period: util.Period)

Der Code für Periode sieht so aus.

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());
  }

}

applyDateFilterist nur eine Convenience-Methode, die ich in meinen Controllern verwende, wenn ich die Datumsfilterung auf die Abfrage anwenden möchte. Natürlich können Sie hier auch andere Datumsstandards verwenden oder einen anderen Standard als null für das Start- und Enddatum in der bindMethode verwenden.

Stian
quelle