【发布时间】:2017-09-19 20:16:05
【问题描述】:
我想在我的 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 参数放入查询字符串参数映射的 hack。 https://alots.wordpress.com/2014/05/01/accessing-url-parameters-as-get-parameters-in-play/ 但是在我看来,这种方法基本上也是对路径的双重解析,尽管我可能会误解它,因为我对 Scala 不是很熟悉。如果是这样,我还不如破解逻辑来重新解析我的 Action 中的路径。
【问题讨论】:
标签: java playframework