Grails 控制器操作抽象命令对象参数
Grails Controller Action Abstract Command Object Parameter
是否支持在控制器操作参数中使用抽象命令对象?然后根据 JSON 请求中给定的参数,它将 select 正确的命令对象?
例如:
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 对象。这是我处理这种情况的唯一选择吗?
编辑:
在这里澄清用例。我有两个共享相同基础 class 域模型的域模型,我正在使用默认 table-per-hierarchy
模型对数据库中的继承进行建模。
在我的例子中,其中一个子域模型 Model A
需要一个名为 body
的不可为 null 的字符串,这是一个文本条目,而另一个 Model B
需要一个非- 名为 directUrl
的可空字符串。这些代表可以在平台上发布的公告。 Model A
是包含公告正文的写入条目,而 Model B
代表 link 到包含实际公告的第三方站点。
在这种情况下,我通常会在控制器操作中放置一个 if 语句来确定要实例化哪个相关命令对象,但我希望有一个更简洁的方法。
这样不行。 Grails 需要一个具体的class(具有默认的public 构造函数)来bind
向命令对象实例请求参数。因此这个 class 被明确定义为动作的参数。
我想您将不得不根据地图包含的内容手动调用绑定。
见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
}
是否支持在控制器操作参数中使用抽象命令对象?然后根据 JSON 请求中给定的参数,它将 select 正确的命令对象?
例如:
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 对象。这是我处理这种情况的唯一选择吗?
编辑:
在这里澄清用例。我有两个共享相同基础 class 域模型的域模型,我正在使用默认 table-per-hierarchy
模型对数据库中的继承进行建模。
在我的例子中,其中一个子域模型 Model A
需要一个名为 body
的不可为 null 的字符串,这是一个文本条目,而另一个 Model B
需要一个非- 名为 directUrl
的可空字符串。这些代表可以在平台上发布的公告。 Model A
是包含公告正文的写入条目,而 Model B
代表 link 到包含实际公告的第三方站点。
在这种情况下,我通常会在控制器操作中放置一个 if 语句来确定要实例化哪个相关命令对象,但我希望有一个更简洁的方法。
这样不行。 Grails 需要一个具体的class(具有默认的public 构造函数)来bind
向命令对象实例请求参数。因此这个 class 被明确定义为动作的参数。
我想您将不得不根据地图包含的内容手动调用绑定。
见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
}