从Grails RestfulController索引/搜索操作呈现分页元数据 [英] Render metadata for pagination from Grails RestfulController index/search actions

查看:122
本文介绍了从Grails RestfulController索引/搜索操作呈现分页元数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找最佳实践/解决方案,以使'响应'方法在生成的json中生成额外的元数据以及从数据库获取的实体集合。

基本上我想在前端单页面应用程序(SPA)中使用这些元数据实现分页,这些元数据由angularJS和Restangular插件构建。
$ b


PS:angularJS的$ resource或Restangular预期收集结果为
JS数组。

blockquote>
$ b 标准Grails JsonCollectionRenderer / JsonRenderer 忽略提供给map参数中'respond'的元数据。



我遇到了下面的文章,它实现了自定义JsonRenderer,但我寻找更简单/灵活的解决方案,通过调整自定义 JsonCollectionRenderer in resources.groovy



http://groovyc.net/non-trivial-restful-apis-in-grails-part-2/

我的RestfulController:

  @Secured(value = [hasRole(' ROLE_USER')])
class DrugController扩展了RestfulController< Drug> {

静态scaffold = true $ b $静态responseFormats = ['html','json','xml','hal']
static allowedMethods = [show:GET ]

DrugController(){
super(Drug,true)
}

@Override
def index(Integer max){
params.max = Math.min(max?:10,100)
//我们传递要使用包含属性
渲染的字段//我们排除所有响应的类属性。 ***当include被定义时,排除被忽略。
//params.fetch = [recordTypeRs:eager] from params.fields ???
响应resource.list(params),
[includes:includeFields,不包括:['class','errors','version'],
metadata:[total:countResources(), psize:params.max,offset:params.offset?:0],
model:[($ {resourceName} InstanceCount.toString()):countResources()]]
}

@Override
def show(Drug drug){
JSON.use(deep){
回应药物,
[include:includeFields,不包括:[ '''''''''''''''$'$'$'$'$'$'$'$'$'$'$'$'$'$'$'$'$'$'$' )


def search(Integer max){
params.max = Math.min(max?:10,100)
def c = Drug.createCriteria ()
def results = c.list(params){
//你的条件在这里用params.q
和{
like('ndc',params.ndc?params .ndc +'%':'%')
like('recordTypeJ.j017',params。 labelerName?'%'+ params.labelerName +'%':'%')
like('recordTypeE.e017',params.productName?'%'+ params.productName +'%':'%')

//缓存(true)
}
log.debug(results.totalCount)
响应结果,模型:[drugCount:results.totalCount]
}

}



我的resources.groovy。

  //为应用程序中的所有域类注册Renderer / CollectionRenderer。 
for(domainClass in grailsApplication.domainClasses){
json $ {domainClass.shortName} CollectionRenderer(JsonCollectionRenderer,domainClass.clazz)
json $ {domainClass.shortName} Renderer(JsonRenderer ,domainClass.clazz)
hal $ {domainClass.shortName} CollectionRenderer(HalJsonCollectionRenderer,domainClass.clazz)
hal $ {domainClass.shortName} Renderer(HalJsonRenderer,domainClass.clazz)
}


解决方案

b
$ b

http:// mrhaki .blogspot.com / 2013/12 / grails-goodness-rendering-partial.html b
$ b

http://groovyc.net/non-trivial-restful-apis-in-grails-part-2/


  1. 创建一个自定义的CollectionRenderer,例如
    SumoJsonCollectionRenderer.groovy
    li>






  import grails.converters.JSON 
import grails.rest.render.RenderContext

import grails.rest.render.json.JsonCollectionRenderer
import org.codehaus.groovy.grails.web.mime.MimeType

导入groovy.transform.CompileStatic
导入静态groovy.transform.TypeCheckingMode.SKIP

@CompileStatic
类SumoJsonCollectionRenderer扩展JsonCollectionRenderer {

SumoJsonCollectionRenderer (class componentType){
super(componentType)
}

public SumoJsonCollectionRenderer(Class componentType,MimeType ... mimeTypes){
super(componentType,mimeTypes)

$ b @CompileStatic(SKIP)
@Override
protected void renderJson(object,RenderContext context){
log.debug(object)
log.debug(object.size())
log.debug(object.getTotalCount())
Map tObject = ['results':obje ct]
if(context.arguments?.metadata){
tObject ['metadata'] = context.arguments.metadata
}
super.renderJson(tObject,context)


在resource.groovy注册自定义CollectionRenderer






  for(domainclass in grailsApplication.domainClasses){
json $ {domainClass.shortName } CollectionRenderer(SumoJsonCollectionRenderer,domainClass.clazz)
json $ {domainClass.shortName} Renderer(JsonRenderer,domainClass.clazz)
hal $ {domainClass.shortName} CollectionRenderer(HalJsonCollectionRenderer,domainClass。 clazz)
hal $ {domainClass.shortName} Renderer(HalJsonRenderer,domainClass.clazz)
}

请求/响应




http://api.mydomain.com:8080/ApiApp/drugs.json?max=5& amp; fields = ndc,id

  {results:[{id:1,ndc : 000020803031 },{ ID :2,NDC : 000021200011 },{ ID :3,NDC : 000021407011 },{ ID :4,NDC: 000021975901},{id:5,ndc:000023004751}],metadata:{total:851,psize:5,offset:0}} 


I am looking for best practices / solution to make 'respond' method generate extra metadata in the resulting json along with the collection of entities got from DB.

Basically I wanted to implement pagination using that metadata in my frontend single-page-application (SPA) built with angularJS and Restangular plugin.

PS: angularJS's $resource or Restangular expect collection results as JS array.

Standard Grails JsonCollectionRenderer/JsonRenderer ignores the metadata supplied to 'respond' in the map argument.

I came across following article which is implementing custom JsonRenderer, but I looking for simpler/flexible solution to make 'respond' output metadata via tweaking custom JsonCollectionRenderer in resources.groovy

http://groovyc.net/non-trivial-restful-apis-in-grails-part-2/

My RestfulController:

@Secured(value=["hasRole('ROLE_USER')"])
class DrugController extends RestfulController<Drug> {

static scaffold = true
static responseFormats = ['html', 'json', 'xml', 'hal']
static allowedMethods = [show: "GET"]

DrugController() {
    super(Drug, true)
}

@Override
def index(Integer max) {
    params.max = Math.min(max ?: 10, 100)
    // We pass which fields to be rendered with the includes attributes,
    // we exclude the class property for all responses. ***when includes are defined excludes are ignored.
    //params.fetch = [recordTypeRs:"eager"] from params.fields???
    respond resource.list(params),
            [includes: includeFields, excludes: ['class', 'errors', 'version'],
             metadata: [total: countResources(), psize: params.max, offset: params.offset?:0],
             model: [("${resourceName}InstanceCount".toString()): countResources()]]
}

@Override
def show(Drug drug) {
    JSON.use("deep") {
        respond drug,
                [includes: includeFields, excludes: ['class', 'errors', 'version']]
    }
}

private getIncludeFields() {
    params.fields?.tokenize(',')
}

def search(Integer max) {
    params.max = Math.min(max ?: 10, 100)
    def c = Drug.createCriteria()
    def results = c.list(params) {
        //Your criteria here with params.q
        and {
            like('ndc', params.ndc?params.ndc+'%':'%')
            like('recordTypeJ.j017', params.labelerName?'%'+params.labelerName+'%':'%')
            like('recordTypeE.e017', params.productName?'%'+params.productName+'%':'%')
        }
        //cache(true)
    }
    log.debug(results.totalCount)
    respond results, model:[drugCount: results.totalCount]
}

}

I have following in my resources.groovy.

// register Renderers/CollectionRenderers for all domain classes in the application.
for (domainClass in grailsApplication.domainClasses) {
    "json${domainClass.shortName}CollectionRenderer"(JsonCollectionRenderer, domainClass.clazz)
    "json${domainClass.shortName}Renderer"(JsonRenderer, domainClass.clazz)
    "hal${domainClass.shortName}CollectionRenderer"(HalJsonCollectionRenderer, domainClass.clazz)
    "hal${domainClass.shortName}Renderer"(HalJsonRenderer, domainClass.clazz)
} 

解决方案

Based on ideas from

http://mrhaki.blogspot.com/2013/12/grails-goodness-rendering-partial.html

http://groovyc.net/non-trivial-restful-apis-in-grails-part-2/

  1. Creat a custom CollectionRenderer e.g., SumoJsonCollectionRenderer.groovy


import grails.converters.JSON
import grails.rest.render.RenderContext

import grails.rest.render.json.JsonCollectionRenderer
import org.codehaus.groovy.grails.web.mime.MimeType

import groovy.transform.CompileStatic
import static groovy.transform.TypeCheckingMode.SKIP

@CompileStatic
class SumoJsonCollectionRenderer extends JsonCollectionRenderer{

    SumoJsonCollectionRenderer(Class componentType) {
        super(componentType)
    }

    public SumoJsonCollectionRenderer(Class componentType, MimeType... mimeTypes) {
        super(componentType, mimeTypes)
    }

    @CompileStatic(SKIP)
    @Override
    protected void renderJson(object, RenderContext context) {
        log.debug(object)
        log.debug(object.size())
        log.debug(object.getTotalCount())
        Map tObject = ['results':object]
        if(context.arguments?.metadata) {
            tObject['metadata'] = context.arguments.metadata
        }
        super.renderJson(tObject,context)
    }
}

register custom CollectionRenderer at resource.groovy


for (domainClass in grailsApplication.domainClasses) {
    "json${domainClass.shortName}CollectionRenderer"(SumoJsonCollectionRenderer, domainClass.clazz)
    "json${domainClass.shortName}Renderer"(JsonRenderer, domainClass.clazz)
    "hal${domainClass.shortName}CollectionRenderer"(HalJsonCollectionRenderer, domainClass.clazz)
    "hal${domainClass.shortName}Renderer"(HalJsonRenderer, domainClass.clazz)
}

Request/Response


http://api.mydomain.com:8080/ApiApp/drugs.json?max=5&fields=ndc,id

{"results":[{"id":1,"ndc":"000020803031"},{"id":2,"ndc":"000021200011"},{"id":3,"ndc":"000021407011"},{"id":4,"ndc":"000021975901"},{"id":5,"ndc":"000023004751"}],"metadata":{"total":851,"psize":5,"offset":0}}

这篇关于从Grails RestfulController索引/搜索操作呈现分页元数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆