Grails Controller Action抽象命令对象参数

时间:2017-05-08 22:03:49

标签: grails grails-controller command-objects

是否支持在控制器操作参数中使用抽象命令对象?那么根据JSON请求中给定的参数,它会选择正确的命令对象吗?

例如:

class SomeController {

    def someAction(BaseCommand cmd){
        // cmd could be instance of ChildCommandOne or ChildCommandTwo
    }

    class BaseCommand {
        String paramOne
    }

    class ChildCommandOne extends BaseCommand {
        String paramTwo
    }

    class ChildCommandTwo extends BaseCommand {
        String paramThree
    }

}

截至目前,我一直在使用request.JSON来检测传入的参数并实例化正确的Command对象。这是我处理这种情况的唯一选择吗?

编辑:

在此澄清用例。我有两个共享相同基类域模型的域模型,并且我使用默认的table-per-hierarchy模型在数据库中建模继承。

在我的情况下,其中一个子域模型Model A需要一个名为body的非可空字符串,即文本条目,而另一个Model B需要一个不可为空的字符串名为directUrl的字符串。这些代表可以在平台上发布的公告。 Model A是包含公告正文的条目,而Model B表示包含实际公告的第三方网站的链接。

在这种情况下,我传统上在控制器动作中放置一个if语句来确定要实例化哪个相关命令对象,但我希望有一个更干净的方法。

2 个答案:

答案 0 :(得分:0)

它不会以这种方式工作。 Grails需要一个具体的类(使用默认的公共构造函数)来 <!DOCTYPE html> <html lang="en" id="facebook" class="no_js"> <head><meta charset="utf-8" /><meta name="referrer" content="origin-when-crossorigin" id="meta_referrer" /><script>function envFlush(a){function b(c){for(var d in a)c[d]=a[d];}if(window.requireLazy){window.requireLazy(['Env'],b);}else{window.Env=window.Env||{};b(window.Env);}}envFlush({"ajaxpipe_token":"AXjKg9wJIltZEBjN","khsh":"0`sj`e`rm`s-0fdu^gshdoer-0gc^eurf-3gc^eurf;1;enbtldou;fduDmdldourCxO`ld-2YLMIuuqSdptdru;qsnunuxqd;rdoe-0unjdojnx-0unjdojnx0-0gdubi^rdbsduOdv-0`sj`e`r-0q`xm`r-0StoRbs`qhof-0mhoj^q`xm`r"});</script><style></style><script>__DEV__=0;CavalryLogger=false;</script><noscript><meta http-equiv="refresh" content="0; URL=/?_fb_noscript=1" /></noscript><title id="pageTitle">Facebook - Log In or Sign Up</title><meta property="og:site_name" content="Facebook" /><meta property="og:url" content="https://www.facebook.com/" /><meta property="og:image" content="https://www.facebook.com/images/fb_icon_325x325.png" /><meta property="og:locale" content="en_GB" /><script type="application/ld+json">{"\u0040context":"http:\/\/schema.org","\u0040type":"WebSite","name":"Facebook","url":"https:\/\/www.facebook.com\/"} 请求命令对象实例的参数。因此,这个类将明确地定义为动作的参数。

答案 1 :(得分:0)

我猜您必须根据地图包含的内容手动调用绑定 请参见RootModel.from(地图)。在你的情况下,Map将是来自Controller的参数

import static com.google.common.base.Preconditions.checkNotNull

import spock.lang.Specification
import spock.lang.Unroll

class CommandHierarchySpec extends Specification {

    @Unroll
    def "should create object of type #type for map: #map"() {
        when:
            def modelObj = RootModel.from(map)
        then:
            modelObj.class == type
        where:
            type   | map
            ModelA | [body: 'someBody', test: 'test']
            ModelB | [directUrl: 'directUrl', test: 'test']
    }

    def "should throw ISE when map does not contain neither body nor url"() {
        when:
            RootModel.from(a: 'b')
        then:
            thrown(IllegalStateException)
    }
}


abstract class RootModel {
    static RootModel from(Map map) {
        checkNotNull(map, "Parameter map mustn't be null")

        RootModel rootModel
        if (map.body) {
            rootModel = new ModelA()
        } else if (map.directUrl) {
            rootModel = new ModelB()
        } else {
            throw new IllegalStateException("Cannot determine command type for map: $map")
        }

        map.findAll { key, value -> rootModel.hasProperty(key) }
                .each {
            rootModel.setProperty(it.key, it.value)
        }

        rootModel
    }
}

class ModelA extends RootModel {
    String body
}

class ModelB extends RootModel {
    String directUrl
}