Как обрабатывать необязательные параметры запроса в платформе Play

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

http://localhost:9000/birthdays

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

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

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

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

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

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

Ответ 1

Кодируйте свои необязательные параметры как 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])

Ответ 2

Возможно, менее простой способ сделать это для пользователей 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)

Ответ 3

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

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

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

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

Ответ 4

Здесь пример Жюльена переписан в 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
  // …
}

Ответ 5

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

GET /birthdays/ controllers.Birthdays.getBirthdays(period: util.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 - это просто метод convienence, который я использую в своих контроллерах, если я хочу применить фильтрацию даты к запросу. Очевидно, вы могли бы использовать другие значения по умолчанию по умолчанию здесь или использовать другое значение по умолчанию, кроме нуля, для даты начала и окончания в методе bind.

Ответ 6

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

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

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

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

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

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