【问题标题】:Grails rest-api app to handle multiple params用于处理多个参数的 Grails rest-api 应用程序
【发布时间】:2016-03-07 23:36:41
【问题描述】:

使用 Grails 3.1.3,我创建了一个 rest-api,以便我能够捕获 GET 请求,这些请求不仅可以查询一个参数,还可以在需要时获取多个参数。我不知道如何在 UrlMappings 文件中正确编码。以下是详细信息。

领域类:

class ProdDetail {
  Integer pid
  String title
  String category
  Integer year
}

其中一些在 BootStrap 中:

new ProdDetail(pid:'101', title:'No Highway', author:'Nevil Shute', category:'fiction', year:1948).save(failOnError:true)
new ProdDetail(pid:'214', title:'In the Country of Men', author:'Hisham Matar', category:'misery', year:2007).save(failOnError:true)

控制器:

protected List<ProdDetail> listAllResources(Map params) {

  println params

  try {
     ProdDetail.where {
        if (params.category && params.maxYear) {
           category == params.category && year <= params.int('maxYear')
        } else if (params.category) {
           category == params.category
        } else if (params.maxYear) {
           year <= params.int('maxYear')
        } else {
           pid > 0
        }
     }.list()
  } catch (Exception e) {
     []
  }
}

网址映射:

static mappings = {
   "/prodDetails"(resources:'prodDetail')
   "/prodDetails/category/$category?"(controller:'prodDetail', action:'index')
   "/prodDetails/yearUnder/$maxYear?"(controller:'prodDetail', action:'index')
   // the line below is not right I think, what's the correct format?
   "/prodDetails/combo/$category?&$maxYear?"(controller:'prodDetail', action:'index')
}

现在,这两个卷发在哪里起作用:

curl localhost:8080/prodDetails/category/misery
curl localhost:8080/prodDetails/yearUnder/2007

这一项未能进入控制器中所需的子句以检测两个参数:

curl localhost:8080/prodDetails/combo/?category=misery&maxYear=2007

它只检测到 'category' 而不是它认为是 'null' 的 'maxYear'。

请问这样的curl怎么办?

【问题讨论】:

  • 如果您将 UrlMappings 发送到:"/prodDetails/combo/$category"(controller:'prodDetail', action:'index') 然后 curl localhost:8080/prodDetails/combo/misery?maxYear=2007 params 映射的内容是什么?
  • 刚试过。它返回两条记录(它不应该)。 println params 的控制器输出为 [controller:prodDetail, action:index, category:misery, max:10]
  • 等等,抱歉,您的建议成功了!它适用于我在 curl 命令中删除了-i。知道为什么...我会再写一些,但现在想谢谢你。
  • 是的,我错误地将 -i 留在 curl 命令中而没有正确的标题来应用您的建议(已编辑和修复)。所以,你的建议有效。但让我更进一步。如果我想对三个或更多参数进行查询,这种方法行不通,对吧?例如,假设我想查询类别、maxYear 和名称,那么 UrlMappings 中的条目会是什么样子? curl 命令类似于curl localhost:8080/prodDetails/combo/misery?maxYear=2010&amp;title=common
  • 这里,println params' didn't see 'title', and swapping the &amp; for ? gave this: [maxYear:2010?title=common, controller:prodDetail, action:index, category:misery, max:10]`。

标签: rest grails


【解决方案1】:

这取决于您希望您的 URL 看起来像什么,但假设您希望您的请求看起来像这样:

http://localhost:8080/prodDetails/combo/misery?maxYear=2007&amp;title=common

UrlMappings 应该是这样的

static mappings = {
   "/prodDetails/combo/$category"(controller:'prodDetail', action:'index')
}

那么控制器中的params 对象应该同时具有$category 的位置,在这个例子中是痛苦的,以及? 之后的其他参数。

如果您希望参数位于路径中,您可以这样做:

static mappings = {
   "/prodDetails/combo/$category/$title/$maxYear"(controller:'prodDetail', action:'index')
}

然后请求将是:

http://localhost:8080/prodDetails/combo/misery/common/2007

另一种选择是使用命令对象。所以如果你有:

static mappings = {
   "/prodDetails/combosearch"(controller:'prodDetail', action:'comboSearch')
}

然后在控制器旁边创建了一个名为 ComboSearchCommand.groovy 的对象,如下所示:

import grails.validation.Validateable
class ComboSearchCommand implements Validetable {
    String category
    String title
    int maxYear

    static constraints = {
        category blank: false, nullable: true
        title blank: false, nullable: true
        maxYear blank: false, nullable: true
    }
}

(您可以像域对象一样对其进行验证)

然后在您的控制器中,您可以使用命令对象而不是参数的方法

protected List<ProdDetail> comboSearch(ComboSearchCommand command) {
    println command.category
}

那么你的网址就是

http://localhost:8080/prodDetails/combosearch?category=misery&maxYear=2007&title=common

并且参数会绑定到命令对象。

我已经使用了很多次,您可以共享验证或让您的命令对象从域对象继承验证,非常灵活。

https://grails.github.io/grails-doc/latest/guide/single.html#commandObjects

【讨论】:

  • 谢谢!最后一个解决方案也是我一直在寻找的。今晚我会试一试。
【解决方案2】:

如果这些参数不是 URL 的一部分,则无需在 UrlMappings 中指定这些参数:

不需要这个:

"/prodDetails/combo/$category&?$maxYear?"(controller:'prodDetail', action:'index')

是的,您需要将 URL 与控制器/操作匹配(但删除 ?)

"/prodDetails/yearUnder/$maxYear?"(controller:'prodDetail', action:'index')

另外,您不需要 listAllResources(Map params) 中的 Map 参数

“params”是控制器的注入属性,println 参数可以正常工作:listAllResources()

我要做的是定义:

listAllResources(String category, int maxYear, ...) 其中 ... 是操作可以接收的所有参数,大多数是可选的,因此如果您的请求中未包含,您将收到一个空值。

记住:UrlMappings 是将 URL 映射到控制器/动作,并且您有相同的控制器/动作,所以我会删除所有映射并处理动作中的可选参数,只是检查哪些为空。

编辑(考虑 cmets)

问:该方法没有重载来处理这样的参数

A:方法是动态的,这是 Grails / Groovy,而不是 Java。即使所有参数都为空,它也会调用 action 方法。我建议您详细阅读 Grails 控制器文档。

问:发现listAllResources方法从来没有被调用过

A:从动作中删除受保护的关键字,只有子类才能调用该方法。此外,您可以添加一个 UrlMapping 以避免用户调用该 URL(匹配该 URL 并返回 404 Not Available 或类似的东西)

问:我想处理像 localhost:8080/prodDetails/combo?category=misery&year=2016&title=commonTitle 这样的 GET 请求,i) UrlMappings 中的条目和 ii) listAllResources 方法的外观应该如何喜欢吗?

答:

static mappings = {
   // if "compo" comes in the action portion, map that to the listAllResources method
   // as I said, if all parameters comes in the query string, no further actions are needed, if you need parameters to be part of the URL path, then you need to play with the $xxxx in the URL
   "/prodDetails/combo"(controller:'prodDetail', action:'listAllResources')
}

def listAllResources()
{
   println params
   // logic here
   render "OK"
}

检查:

【讨论】:

  • 我认为您使用 listAllResources 的方式行不通 - 该方法不会重载以处理这样的参数。
  • 我没有尝试过,但我很确定我也见过这样使用的控制器方法。它可以工作,虽然我个人不喜欢接受大量参数的方法。
  • @mohsenmadi 我从 v0.4.3 开始使用 Grails 构建应用程序。是的,最新版本工作,检查mrhaki.blogspot.com.uy/2012/02/…
  • @photon 您始终可以为操作定义无参数方法并通过注入的 params 变量访问所有参数,这已在我的回答中说明。
  • 我在回答@PabloPazos之前尝试过,发现从未调用过listAllResources方法(从未执行过println语句),这导致我认为不接受重载本身在这里。我会看看你的参考资料,并在我发现时说更多。非常感谢。
猜你喜欢
  • 2015-02-09
  • 2019-09-24
  • 2012-04-13
  • 1970-01-01
  • 2017-10-01
  • 1970-01-01
  • 2020-05-28
  • 1970-01-01
  • 2019-07-20
相关资源
最近更新 更多