Groovy闭包:Grails url映射的定义如何工作

请注意,这个问题并不直接与Grails中的url映射有关.它是关于如何定义url映射的方式.

在查看UrlMappings.groovy时,我们看到如下内容:

class UrlMappings {     
    static mappings = {         
        "/foo" (controller: "foo", action: "myaction")
        "/bar" (controller: "bar", action: "myaction")
        "404" (controller: 'error')
    }
}

括号表示存在函数/方法调用.从我的理解线

"/foo" (controller: "foo", action: "myaction")

执行UrlMappings的名为/ foo的函数.如果UrlMappings不包含名为/ foo的函数,它将查看闭包委托.

我的问题是你可以在mappings = {..}中使用的字符串不受限制.您可以添加任何您想要的定义.例如:

"!%&/()" (controller: "foo")

因此必须有某种动态的方式来定义这些功能.我想不出在UrlMappings类中定义这些函数的解决方案.所以我尝试使用闭包委托来提出解决方案.

使用简单的groovy脚本,我尝试了以下哪个对我很好:

def mappings = {
    "/foo" (controller: "foo", action: "myaction")
    "/bar" (controller: "bar", action: "myaction")
    "404" (controller: 'error')
    "!%&/()" (controller: "foo")
}

class MyMap extends LinkedHashMap {
    @Override
    public Object get(Object key) {
        if (!this.containsKey(key)) {
            this.put(key, { Map map -> println "$key called: $map" })
        }
        return super.get(key);
    }
}

mappings.delegate = new MyMap()
mappings()

因此,当/ foo应该在映射闭包内执行时,groovy将在我的委托映射中查找名为/ foo的键.因此使用MyMap的get()方法.如果不存在具有此名称的密钥,则将创建一个新密钥.键的值始终是一个将map作为参数的闭包.

执行脚本时,我得到:

/foo called: [controller:foo, action:myaction]
/bar called: [controller:bar, action:myaction]
404 called: [controller:error]
!%&/() called: [controller:foo]

所以它奏效了.但是我不知道这是否是grails使用的方式.也许有一个更简单的解决方案?

所以我的第一个问题是:还有另一种(可能更容易)的方法吗? / Grails如何解决这些函数调用?

当我作为代表试验地图时出现了另一个问题.

我们来看看这个:

def closure = {
    "foo" (arg: "foo")
}

closure.delegate = ["foo": { Map map -> println "called: $map" }]
closure() // error

我希望这段代码应该打印名为:[arg:foo]的字符串.但是我得到:

groovy.lang.MissingMethodException: No signature of method: Test.foo() is applicable for argument types: (java.util.LinkedHashMap) values: [[arg:foo]]

然后我尝试了以下结果(如预期的那样)在同一个异常中:

def delegate = new LinkedHashMap()
delegate["foo"] = { Map map -> println "called: $map" }
closure.delegate = delegate 
closure() // error

但是,如果我这样做:

class MyLinkedHashMap extends LinkedHashMap { }
def delegate = new MyLinkedHashMap()
delegate["foo"] = { Map map -> println "called: $map" }
closure.delegate = delegate 
closure() // prints "called: [arg:foo]"

有用.

所以我的第二个问题是:为什么这不适用于简单的LinkedHashMap,而是使用MyLinkedHashMap(它不会修改任何东西)?

最佳答案 你读过关于methodMissing的内容吗?

一个例子是:http://groovy.codehaus.org/Using+methodMissing+and+propertyMissing

另一个在这里:http://blog.vladimirvivien.com/2008/02/25/creating-a-simple-builder-with-groovys-methodmissing/

grails通过将这个闭包列表传递给this builder来覆盖invokeMethod来完成工作,as explained here

点赞