【问题标题】:Grails json views : opaque view selection - picks out default template in another directoryGrails json 视图:不透明视图选择 - 在另一个目录中选择默认模板
【发布时间】:2019-01-18 10:28:15
【问题描述】:

我正在使用 Grails 3.3.9 和 json 视图 1.2.10。

在另一个测试中,我有一个这样的 url 映射

    "/api/test"(resources:'test')

我有一个空的 views/test 文件夹,而且我没有 Test 域对象。

但我确实有一个设备域实体,并且在该目录中有一个 views/device/_device.gson 模板来帮助呈现设备对象。

TestController 的显示动作如下所示

def show (Device device) {
    if(device == null) {
        render status:404
    } else {
        respond device}
}

这会在域模型中查找一个设备并填充到 Shows 参数列表中,然后我用该设备进行响应。

但是,views/test 目录中没有 show.gson(它是空的)。

但是,当您在浏览器中点击“http://localhost:8080/api/test/1”网址时,grails 会使用“views/device/_device.gson”模板呈现响应。

这非常令人困惑,因为很难准确地确定视图视图响应实际使用的是什么(除非您使用 view:'xxx' 映射变量强制它。

TestController/show 操作响应如何/为什么返回,拾取“views/device/_device.gson”模板?

【问题讨论】:

    标签: grails view controller


    【解决方案1】:

    (代表问题作者发布答案)

    步骤 1)如果您创建一个新控制器(我使用 grails create-controller <controller>,然后编辑生成的控制器以从 RestfulController<domain type> 扩展(但不要覆盖任何方法)。然后为您的控制器设置 URL 映射,在我的例子中这是

    "/api/org"(resources:'OrgRoleInstance')
    

    我的模型中有相应的域类“OrgRoleInstance”。

    create-controller 操作还会生成一个空视图包“views/orgRoleInstance”(不生成 gson 文件)

    a) 如果你现在运行应用程序并打开 url

    http://localhost:8080/api/org
    

    那么你仍然会得到一个呈现的响应(像这样)!

    [{"id":1,"sites":[],"domains":[],"role":{"enumType":"com.softwood.domain.OrgRoleInstance$OrgRoleType","name":"Service_Provider"},"name":"Vodafone","mags":[{"id":2}]},{"id":2,"sites":[],"domains":[],"role":{"enumType":"com.softwood.domain.OrgRoleInstance$OrgRoleType","name":"Maintainer"},"name":"Cisco","mags":[{"id":1}]},{"id":3,"sites":[],"domains":[],"role":{"enumType":"com.softwood.domain.OrgRoleInstance$OrgRoleType","name":"Supplier"},"name":"Cisco","mags":[]},{"id":4,"sites":[{"id":1},{"id":2}],"domains":[{"id":1}],"role":{"enumType":"com.softwood.domain.OrgRoleInstance$OrgRoleType","name":"Customer"},"name":"Acme","mags":[]}]
    

    事实上,有一些“默认框架逻辑”试图呈现从 RestfulController 继承的“索引”(和“显示”等)动作的默认实现。即使没有预先存在的 gson,也可以这样做 - 不提供警告。

    第 2 步:下一步停止应用(它仍在缓存之前的“默认”行为)。

    现在转到空视图目录并创建一个像这样没有模型的“index.gson”

    json ([1,2,3])
    

    然后在您的 IDE 中重新启动应用程序。现在,当它启动时,它会检测到 index.gson 存在,当您调用 url 'http://localhost:8080/api/org' 时,您得到的是静态列表 [1,2,3] 的渲染 json

    第 3 步:gson 视图在幕后使用静态编译,并且非常繁琐以完全正确。然而,在默认 RestfulController index action 的情况下,从域模型中选择一个 OrgRoleInstances 列表并作为 lit 传递给视图。如果您希望数据绑定到视图工作,那么如果您的域对象是类型 T,您会得到一个 List<T> 返回。

    代码库中的内部默认设置是,如果您返回 List<T> 进行响应,则视图中的数据模型假定为 List<T> <T>List,即在我的示例中为

    List<OrgRoleInstance> orgRoleInstanceList 在 gson 视图模型中。现在使用修改后的 index.gson(您可以在开发模式下不停止/启动服务器的情况下对其进行编辑)

    import com.softwood.domain.OrgRoleInstance
    
    model {
        List<OrgRoleInstance> orgRoleInstanceList
    }
    
    json {
    
        recordCount orgRoleInstanceList.size()
    }
    

    现在,当您获取 URL 时,您会得到一个包含列表大小的 json 响应:

    {"recordCount":4}
    

    请注意,如果您像这样向模型添加额外变量:

    import com.softwood.domain.OrgRoleInstance
    
    model {
        List<OrgRoleInstance> orgRoleInstanceList
        Integer orgRoleInstanceCount
    }
    
    json {
    
        recordCount orgRoleInstanceList.size()
        size orgRoleInstanceCount
    }
    

    并修改 index.gson 以打印新的 Integer 变量 - 然后它不是来自默认响应操作的数据绑定。

    浏览器响应如下所示:

    {"recordCount":4,"size":null}
    

    选项 4:-查看调用“模板”类。建立一个期望List&lt;T&gt; 的模型后,通过数据绑定构建的运行时类型是“grails.orm.PagedResultList”的一个实例。这是一个 Iterable 类型。

    在文档中阅读这非常令人困惑 - 但是如果您创建一个名为 _&lt;file&gt;.gson 的文件,这真的不清楚。那么这个被处理的是一个模板gson文件。

    这可以有自己的模型/json,但是因为所有这些都是静态编译的,所以你必须让类型完全匹配,并在调用模板时在必要时声明模型变量的“名称”(通过 g.render 或隐式tmpl.&lt;file&gt;

    当您从父视图调用模板时,您可以传递 List&lt;T&gt; 可迭代模型类型或在父视图中迭代并将每个 &lt;T&gt; 传递给模板。您必须确保您传递给 tmpl 的模型类型在 tmpl 模型中声明为相同的类型。

    例如假设父视图中有一个List&lt;T&gt;,但模板中有一个&lt;T&gt;,您需要为列表中的每个项目调用tmpl。例如 如果你有一个像“_orgRoleInstance.gson”这样的tmpl。

    如果你有这样的父视图(注意单个 &lt;T&gt; 声明和名为 'org' 的模型变量

    import com.softwood.domain.OrgRoleInstance
    
    model {
        OrgRoleInstance org
    }
    json {
        id org.id
        name org.name
    }
    

    然后父视图“index.gson”你需要这样的东西,它调用 tmpl 的次数与列表中的条目一样多,但是我必须告诉框架 tmpl 模型变量名称是 'org ' 通过传递一张地图。这将按照您的预期呈现。

    import com.softwood.domain.OrgRoleInstance
    
    model {
        List<OrgRoleInstance> orgRoleInstanceList
        Integer orgRoleInstanceCount
    }
    
    orgRoleInstanceList.each { OrgRoleInstance org ->
        json tmpl.orgRoleInstance(org:org)
    }
    

    如果您将 tmpl 变量声明为“def org”,它仍然有效,但由于它是静态类型的,因此该变量作为 Object 的静态实例传递(运行时类型是正确的,但您不能只访问属性为静态类型是 Object),并且很难整理出访问属性所需的强制转换。

    如果你想让父视图将模型List&lt;T&gt;变量传递给tmpl,你可以=但你必须确保tmpl中的模型变量是List&lt;T&gt;否则数据绑定不起作用。

    现在您可以在模板中调用 json 并遍历 List

    例如像这样修改 tmpl

    import com.softwood.domain.OrgRoleInstance
    
    model {
        //OrgRoleInstance org
        List<OrgRoleInstance> orgs
    }
    json {
        id orgs.id
        name orgs.name
    }
    

    和这样的修改后的父视图来调用 tmpl:

    import com.softwood.domain.OrgRoleInstance
    
    model {
        List<OrgRoleInstance> orgRoleInstanceList
        Integer orgRoleInstanceCount
    }
    
    /*
    orgRoleInstanceList.each { OrgRoleInstance org ->
        json tmpl.orgRoleInstance(orgs:org)
    }*/
    
    //alternate approach
    json tmpl.orgRoleInstance (orgs:orgRoleInstanceList)
    

    渲染的是这样的:

    {"id":[1,2,3,4],"name":["Vodafone","Cisco","Cisco","Acme"]}
    

    您会注意到有一个 json 子句,因此它首先迭代所有 id,然后迭代所有名称。

    如果这不是您想要的,则必须遍历列表以依次执行每个操作

    即像这样修改过的 tmpl 将依次遍历每个条目

    import com.softwood.domain.OrgRoleInstance
    
    model {
        //OrgRoleInstance org
        List<OrgRoleInstance> orgs
    }
    json (orgs) {OrgRoleInstance org ->
            id org.id
            name org.name
    }
    

    并在浏览器中生成它

    [{"id":1,"name":"Vodafone"},{"id":2,"name":"Cisco"},{"id":3,"name":"Cisco"},{"id":4,"name":"Acme"}]
    

    对于其他对 Grails 视图感到困惑的人,我希望这能说明这在 url 映射之间是如何工作的(您可以使用 Gradle“urlMappingsReport”来查看这些),并显示哪些 url 映射到哪些操作。然后,您需要创建与这些操作同名的 gson 视图,并配置您的 gson 视图和您创建的任何 tmpl,以了解 JsonViews 在处理您的代码时应用的隐式行为。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-07
      • 1970-01-01
      相关资源
      最近更新 更多