75

假设我在 Scala 中有一个已经运行的基于 Play 2.0 框架的应用程序,它提供如下 URL:

http://localhost:9000/生日

它以所有已知生日的列表作为响应

我现在想通过添加使用可选的“from”(日期)和“to”请求参数来限制结果的能力来增强这一点,例如

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

(此处的日期解释为 yyyyMMdd)

我的问题是如何使用 Scala 在 Play 2.0 中处理请求参数绑定和解释,特别是考虑到这两个参数都应该是可选的。

这些参数是否应该在“路由”规范中以某种方式表达?或者,响应控制器方法是否应该以某种方式从请求对象中挑选参数?还有另一种方法可以做到这一点吗?

4

6 回答 6

63

将您的可选参数编​​码为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])
于 2012-03-11T18:45:40.453 回答
19

对于 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)
于 2012-03-13T09:09:49.700 回答
13

除了朱利安的回答。如果您不想将其包含在路由文件中。

您可以使用 RequestHeader 在控制器方法中获取此属性

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

这将为您提供所需的请求参数,并保持您的路由文件干净。

于 2015-05-12T06:04:18.310 回答
8

这是 Julien 使用 F.Option 用 java 重写的示例:(从 play 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
  // …
}
于 2013-03-27T14:52:15.043 回答
5

对于可选的查询参数,你可以这样做

在 routes 文件中,声明 API

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

您还可以提供一些默认值,如果 API 不包含这些查询参数,它会自动为这些参数分配默认值

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

在控制器应用程序内部编写的方法中,null如果未分配默认值,则这些参数将具有值,否则为默认值。

于 2015-03-09T15:10:03.523 回答
2

我这样做的方式涉及使用自定义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如果我想对查询应用日期过滤,这只是我在控制器中使用的一种方便方法。显然,您可以在此处使用其他日期默认值,或者在方法中使用其他默认值而不是 null 作为开始和结束日期bind

于 2013-04-28T10:54:44.297 回答