0

我有一个简单的问题,文档并没有帮助我解决它。

我创建了一个 Grails v3.3.3 演示项目 - 并创建了一个名为 JsonApiBook 的简单域类,具有像这样的“名称”属性

package ttrestapi

import grails.rest.*

@Resource (uri='/jsonApiBook', formats=['json','xml'])
class JsonApiBook {

    static constraints = {
    }

    String name
}

并标记了 URI,因为文档说 JSON API 渲染仅适用于域类(而不是控制器类)。

在我的引导程序中,我已将 book 的实例保存到表中 - 并且可以普遍查看。

在我的视图目录中,我创建了一个 jsonApiBook 文件夹并创建了两个 gson 文件。

像这样的“_jsonApIBook”模板

import ttrestapi.JsonApiBook

model {
    JsonApiBook book
}
json jsonapi.render(book)

它调用 jsonapi 辅助对象来呈现实例。

我在同一个目录中创建了一个 index.json,如下所示:

import ttrestapi.Book

model {
    List<Book> bookList
}

// We can use template namespace
// method with a Collection.
json tmpl.book(bookList) 

当我运行应用程序并使用邮递员或浏览器进行渲染时,我会得到一个结果,但它的 Json api 兼容(我认为它被忽略了模板)。

所以 localhost:8080/jsonApiBook 只是返回(看起来是默认布局):

[
    {
        "id": 1,
        "name": "json api book3"
    }
]

和 localhost:8080/jsonApiBook/1 只返回'null',这是不对的。

我应该如何设置 json 视图以呈现符合 JSON API 的输出?因为这似乎无法正常工作。

4

2 回答 2

0

好的 - 今天在火车上到了类似的地方。本质上,约定优于配置是这里发生的事情的核心。

首先,@Resource 注解会为你生成一个默认的 RestfulController。在这种方法中,默认基本模板 _resourceClassName.gson 期望模型变量与资源类型具有相同的名称,因此我的原始示例而不是“book”

import ttrestapi.JsonApiBook

model {
    JsonApiBook book
}
json jsonapi.render(book)

它应该真的读作(遵循惯例)

import ttrestapi.JsonApiBook

// variable should be same name as the Class name starting with lowercase
// as default (it can be different but the caller has to  change how the
// the template parameter is invoked 
model {
    JsonApiBook jsonApiBook
}
json jsonapi.render(jsonApiBook)

那么 index.gson 应该如下所示

import ttrestapi.JsonBookApi

//note although not obvious in the written docs which use the show command, the 
// default expected model variable is <resourceClass>List
model {
    List<JsonBookApi> jsonBookApiList  
}

// We can use template namespace
// method with a Collection.
json tmpl.jsonBookApi  (jsonBookApiList  ) 

如果您想使用另一个变量名,那么在基本模板中,您必须在调用基本模板时从 index.gson 将该名称声明为映射。例如说基本模板中的变量名是

model {
    JsonBookApi myBook...

然后当从我的 index.gson 调用这个模板时,你会放这样的东西

...
model {
    List<JsonBookApi> jsonBookApiList  
}

json tmpl.jsonBookApi  ("myBook", jsonBookApiList  ) 

这会调用正确的模板 _jsonBookApi,但采用 index.gson 中的模型变量 default 并强制它将 jsonBookApiList 的值绑定到基本模板 (_jsonBookApi.gson) 中的 myBook 变量。

使用默认生成的控制器,使用@Resource 注解,模型变量将始终为“resourceClassName”列表

我认为改变一点的唯一方法是不要在你的域类上使用 @Resource 注释,而是使用 URL 映射配置将你的 uri 映射到控制器,然后你必须自己手动创建一个控制器并确保你从 RestfulController 扩展。这样做您可以通过实现覆盖的“index()”方法并确保明确命名所需的模型变量来覆盖默认模型变量名称,并确保 index.gson 模型变量与控制器中设置的变量完全相同.

但是关键是我没有遵循核心约定默认值,因此最初构建的代码无法工作并返回 null。

当您开始时,文档并不清楚哪些位是约定的一部分,并且在示例中(使用 show.gson)不要告诉您 index.gson 的模型变量默认名称是什么(添加List to end) 所以很容易迷路

于 2018-03-15T23:30:22.880 回答
0

build.gradle

buildscript {
    ....

    dependencies {
      ........        
        classpath "org.grails.plugins:views-gradle:1.2.7"
    }
}

--

apply plugin: "org.grails.grails-web"
apply plugin: "org.grails.plugins.views-json"

dependencies {
. . .

compile "org.grails.plugins:views-json:1.2.7"
. . .
}

领域JsonApiBook.groovy

import grails.rest.Resource

@Resource (uri='/jsonApiBook', formats=['json','xml'])
class JsonApiBook {

    String name
    static constraints = {
    }
}

Bootstrap.groovy

class BootStrap {

    def init = { servletContext ->

        new JsonApiBook(name: 'first').save(flush:true)
        new JsonApiBook(name: 'second').save(flush:true)
        new JsonApiBook(name: 'third').save(flush:true)
        new JsonApiBook(name: 'fourth').save(flush:true)
        new JsonApiBook(name: 'fifth').save(flush:true)
    }
    def destroy = {
    }
}

在视图下创建的文件夹称为jsonApiBook

在文件夹中命名的创建模板_jsonApiBook.gsonjsonApiBook

model {
    JsonApiBook jsonApiBook
}
json {
    name jsonApiBook.name
}

show.gson在同一文件夹下创建

model {
    JsonApiBook jsonApiBook

}
json g.render(template:"jsonApiBook", model:[jsonApiBook:jsonApiBook])

当我跑步时,http://localhost:8080/jsonApiBook我得到以下信息:

在此处输入图像描述

当我跑步时,http://localhost:8080/jsonApiBook/1我得到以下信息:

在此处输入图像描述

注意:我使用 grails 3.3.3 和 h2 内存数据库

参考 希望对你有帮助

于 2018-03-14T20:48:04.970 回答