0

是否支持在控制器操作参数中使用抽象命令对象?然后根据 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 语句来确定要实例化哪个相关命令对象,但我希望有一个更简洁的方法。

4

2 回答 2

0

它不会以这种方式工作。Grails 需要一个具体的类(具有默认的公共构造函数)来bind向命令对象实例请求参数。因此这个类被明确定义为动作的参数。

于 2017-05-09T11:31:11.327 回答
0

我想您将不得不根据地图包含的内容手动调用绑定。
请参阅 RootModel.from(地图地图)。在您的情况下,地图将是来自控制器的参数

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
}
于 2017-05-10T11:33:44.020 回答