如何处理 Play 框架中的可选查询参数

Posted

技术标签:

【中文标题】如何处理 Play 框架中的可选查询参数【英文标题】:How to handle optional query parameters in Play framework 【发布时间】:2012-03-28 06:25:39 【问题描述】:

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

http://localhost:9000/birthdays

返回所有已知生日的列表

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

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

(此处的日期解释为 yyyyMMdd)

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

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

【问题讨论】:

【参考方案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])

【讨论】:

对我来说,这不足以在没有参数的情况下进行路由。我把它扩展到GET /birthday controllers.Application.birthday(from: Option[String] ?= None, to: Option[String] ?= None) 更成功:GET /birthday controllers.Application.birthday(Option[from], Option[to]) 现在记录在playframework.com/documentation/2.4.x/… 这里描述了可选参数 (v2.7+) => playframework.com/documentation/2.7.x/…【参考方案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)

【讨论】:

有人可以确认 (max : java.lang.Integer = null) 有效吗? 'max' 对我来说总是为空...... 我修正了答案,应该是 ?= 在Java中你可以使用play.libs.F.Option而不是Scala Option 你有使用 Scala 或 F 选项的整个例子吗?困扰我的是模板中默认设置的重复。我总是收到将 _ 用于部分应用函数的建议【参考方案3】:

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

你可以在控制器方法中使用RequestHeader获取这个属性

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

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

【讨论】:

您的路由器文件看起来如何?我有类似GET /url @com.mycompany.controllers.MyClass.fetchget() 的东西,但它找不到路线 @Zennichimaro ***.com/questions/16301211/… 看看【参考方案4】:

这是 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
  // …

【讨论】:

【参考方案5】:

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

在路由文件中,声明API

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

你也可以给一些默认值,如果 API 不包含这些查询参数,它会自动为这些参数分配默认值

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

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

【讨论】:

感谢您的回答,现在它以带有默认值的字段的形式出现。就我而言,我有一个强制参数和一个可选参数。【参考方案6】:

我的做法是使用自定义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 方法中使用其他默认值而不是 null 作为开始和结束日期。

【讨论】:

知道如何让 swagger 使用这个解决方案吗?

以上是关于如何处理 Play 框架中的可选查询参数的主要内容,如果未能解决你的问题,请参考以下文章

Go中的make函数如何处理可选参数? [复制]

如何处理失败的可选绑定

如何处理Swift 4中的按钮重叠?

Swift之深入解析如何处理非可选的可选项类型

Javascript:函数中的可选参数[重复]

Python中的类/函数中的可选参数[重复]