2017-05-08 57 views
0

是否有在控制器的动作参数使用抽象命令对象的任何支持?那么根据JSON请求中给定的参数,它会选择正确的命令对象?Grails的控制器动作摘要Command对象参数

例如像:

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语句中,确定其中相关的命令对象实例化,但我希望有一个更清洁方法控制器动作。

+1

嗯,我不认为它是一个很好的方法,如果你有3个不同的命令,为什么不ü创建3个不同的动作?也许这会更容易,如果你解释你的用例 – rgrebski

+0

@rgrebski我已经更新了包含我的实际用例的问题。另外,如何区分这3个操作,而不必在我的url映射中正式声明单独的终结点? – dvisco

回答

0

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

+0

传统上,如何处理这种情况?使用单独的端点来区分不同的命令? – dvisco

+0

你自己调用特定实例的'bindData()'。这很简单 – injecteer

0

我想你将不得不调用结合手动取决于什么地图都包含。
见RootModel.from(地图)。你的情况地图将PARAMS从控制器

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 
} 
+0

这是一个有趣的方法。为了发挥它的作用,我认为我可以注释有效的域命令对象,并有一个鉴别符注释,用于注释区分其他命令的属性。然后测试,直到找到在参数映射中具有匹配鉴别符属性的第一个命令对象。 – dvisco