我有一个操作想要应用于 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());
}
...
}
但我认为,这个用例正是动作组合的用途。看来只是缺少路由参数。这Context
实际上,Action call() 方法中公开的对象包含很多内容。标头在那里,查询参数在那里,甚至所命中的确切路径也在那里!即使事实并非如此,此时框架已经解析了路由并确定了路由参数的值。这一定是真的,因为如果不是,那么它如何知道要调用哪个操作?然而,这些解析的参数似乎对我们来说完全不可用。我们可以自己从路径中再次解析它们。但为什么我们必须这样做呢?我们将解析路径两次。为什么框架不公开这些值?
我发现有一篇有趣的文章,为了解决类似的问题,建议了一种 hack,将 url 参数放入查询字符串参数映射中。https://alots.wordpress.com/2014/05/01/accessing-url-parameters-as-get-parameters-in-play/ https://alots.wordpress.com/2014/05/01/accessing-url-parameters-as-get-parameters-in-play/然而,在我看来,这个方法基本上也是双重解析路径,尽管我可能会误解它,因为我对 Scala 不太熟悉。如果是这样,我不妨修改逻辑来重新解析我的操作中的路径。