从Grails RestfulController索引/搜索操作渲染分页元数据

时间:2014-05-29 18:41:51

标签: json rest grails pagination metadata

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

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

  

PS:angularJS的$ resource或Restangular expect collection的结果为   JS数组。

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

我遇到了以下文章,它正在实现自定义JsonRenderer,但我正在寻找更简单/灵活的解决方案,通过调整JsonCollectionRenderer中的自定义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]
}

}

我在我的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)
} 

1 个答案:

答案 0 :(得分:2)

基于

的想法

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

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

  1. 创建自定义CollectionRenderer,例如, SumoJsonCollectionRenderer.groovy

  2. 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)
        }
    }
    

    在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&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}}