Как обрабатывать необязательные параметры запроса в платформе Play - PullRequest
66 голосов
/ 11 марта 2012

Допустим, у меня есть уже работающее приложение на платформе Play 2.0 в Scala, которое обслуживает URL-адрес, такой как:

http://localhost:9000/birthdays

, который отвечает со списком всех известных дней рождения

Теперь я хочу улучшить это, добавив возможность ограничивать результаты необязательными параметрами "from" (date) и "to", такими как

http://localhost:9000/birthdays?from=20120131&to=20120229

(даты здесь интерпретируются как yyyyMMdd)

Мой вопрос заключается в том, как обрабатывать привязку параметров запроса и их интерпретацию в Play 2.0 с помощью Scala, особенно учитывая, что оба эти параметра должны быть необязательными.

Должны ли эти параметры быть как-то выражены в спецификации "маршрутов"? В качестве альтернативы, должен ли отвечающий метод Controller как-то отделить параметры от объекта запроса? Есть ли другой способ сделать это?

Ответы [ 6 ]

58 голосов
/ 11 марта 2012

Кодируйте ваши необязательные параметры как Option[String] (или Option[java.util.Date], но вам придется реализовать свой собственный QueryStringBindable[Date]):

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

И объявить следующий маршрут:

GET   /birthday       controllers.Application.birthday(from: Option[String], to: Option[String])
17 голосов
/ 13 марта 2012

Возможно, менее чистый способ сделать это для пользователей java - установить значения по умолчанию:

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

А в контроллере

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

Еще одна проблема, вам придется повторять настройки по умолчанию всякий раз, когда вы ссылаетесь на свою страницу в шаблоне

@routes.Application.users(max = 50, page = 0)
11 голосов
/ 12 мая 2015

В дополнение к ответу Жюльена.Если вы не хотите включать его в файл routs .

Вы можете получить этот атрибут в методе контроллера, используя RequestHeader

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

Это даст вамтребуемые параметры запроса, а также сохраняйте файл маршруты в чистоте.

7 голосов
/ 27 марта 2013

Вот пример Жюльена, переписанный на Java с использованием F.Option: (работает с версии 2.1)

import play.libs.F.Option;
public static Result birthdays(Option<String> from, Option<String> to) {
  // …
}

Маршрут:

GET   /birthday       controllers.Application.birthday(from: play.libs.F.Option[String], to: play.libs.F.Option[String])

Вы также можете просто выбрать произвольные параметры запроса в виде строк (вы должны выполнить преобразование типа самостоятельно):

public static Result birthdays(Option<String> from, Option<String> to) {
  String blarg = request().getQueryString("blarg"); // null if not in URL
  // …
}
4 голосов
/ 09 марта 2015

Для необязательных параметров запроса вы можете сделать это следующим образом

В файле маршрутов объявить API

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

Вы также можете указать некоторое значение по умолчанию, если API не содержит этих параметров запроса, он автоматически назначит значения по умолчанию этим параметрам

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

В методе, написанном в приложении контроллера, эти параметры будут иметь значение null, если никакие значения по умолчанию не назначены, иначе значения по умолчанию.

2 голосов
/ 28 апреля 2013

Мой способ сделать это включает использование пользовательского QueryStringBindable. Таким образом, я выражаю параметры в маршрутах как:

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

Код для Period выглядит следующим образом.

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 - это всего лишь метод удобства, который я использую в своих контроллерах, если я хочу применить фильтрацию даты к запросу. Очевидно, что вы можете использовать другие значения по умолчанию для даты здесь или использовать другое значение по умолчанию, отличное от нуля, для даты начала и окончания в методе bind.

...