我想在Play应用程序中应用多个路线。这些路由对产品执行操作,产品可以具有各种版本。我希望我的API工作,以便用户可以显式指定版本(通过查询参数),如果他们没有指定版本,我们将从数据库中查找最新版本并对其进行操作。因此,此操作需要能够查找产品的最新版本,但我们需要知道要求的产品。在路线的控制器中,这是显而易见的。 Play使用路由参数作为参数调用路由控制器:
@RequireProductVersion()
public CompletionStage<Result> getProduct(String productId) {
...
}
但是在我们的操作中,我们只有这个Play内部Context
对象可以使用。我的行为看起来像这样:
public class RequireProductVersion extends Action<RequireProductVersion> {
@Override
public CompletionStage<Result> call(Http.Context ctx) {
final String version = ctx.request().getQueryString("version");
// if an explicit "version" parameter was specified, verify it and use it
if (version != null) {
...
} else {
// look up the latest version for this product
final String productId = ctx.request.????getParameter("productId");
return lookupLatestProductVersion(productId).thenCompose( ... );
}
}
}
虽然我在该操作中有一些额外的有效性检查。有时我会立即从那里返回错误。因此,我们可以通过将查询字符串参数“version”添加到所有路由并在每个路由控制器中添加六行代码来替换此动作组合解决方案:
@RequireProductVersion()
public CompletionStage<Result> getProduct(String productId, @Nullable String productVersion) {
final int productVersion;
try {
productVersion = Utils.getProductVersion(productId, productVersion);
} catch (ProductVersionException e) {
return CompletableFuture.completedFuture(e.getAppropriateResult());
}
...
}
但我认为,这个用例正是动作组合应该是什么。似乎缺少路线参数。实际上,Action call()方法中公开的Context
对象中有很多东西。标题在那里,查询参数在那里,甚至确切的路径都在那里!即使不是这样,框架已经解析了路由并确定了路由参数的值。这必须是真的,因为如果不是,那么它将如何知道要调用哪个动作?但是,似乎这些解析的参数对我们来说完全不可用。我们可以从路径中再次解析它们。但是我们为什么要这样做呢?我们将解析路径两次。为什么框架没有暴露这些值?
我发现有一篇有趣的文章,为了解决类似的问题,建议将一个url参数放入查询字符串参数映射中。 https://alots.wordpress.com/2014/05/01/accessing-url-parameters-as-get-parameters-in-play/ 然而,在我看来,这个方法基本上也是双重解析路径,虽然我可能会误解它,因为我不太熟悉Scala。如果是这样,我可能只是破解逻辑来重新解析我的行动中的路径。
答案 0 :(得分:1)
至少,你不能开箱即用。 Play没有提供在行动组合中获取请求参数的方法。
基本上:你必须解析自己。
答案 1 :(得分:0)
好的,这个问题在Scala中是可以解决的。由于Play Java如何使用注释进行动作合成(以及身体解析器,这是我遇到这个完全相同的问题的另一个地方),目前似乎没有任何方法可以在Java中解决它。您必须自己再次解析路径。但是,看起来在Scala中很容易实现。我没有测试其中任何一个,我对Scala不太熟悉,但看起来像Scala中的Play,动作组合的工作方式不同。
这个要点有一个例子,说明Play Scala动作组合应如何支持: https://gist.github.com/wolfendale/75e8b5e9a7ace95aa7e6d123e6c6dacd
jroper在本期帖子中的帖子也证明了我认为同样的解决方案: https://github.com/playframework/playframework/issues/3378#issuecomment-54925034
如果您使用Scala,那么article I linked in the original post中演示的技术根本不是解决此问题所必需的。但是,因为它只需要在Scala中编写一些代码(而对于wolfendale和jroper演示的技术,你需要在Scala中编写控制器),它可能是解决这个问题的有用方法,但仍然可以编写大部分代码Java中的应用程序。我不确定。我没有测试它,我对那种黑客不感兴趣。