从Grails RestfulController索引/搜索操作呈现分页元数据 [英] Render metadata for pagination from Grails RestfulController index/search actions
问题描述
我正在寻找最佳实践/解决方案,以使'响应'方法在生成的json中生成额外的元数据以及从数据库获取的实体集合。
基本上我想在前端单页面应用程序(SPA)中使用这些元数据实现分页,这些元数据由angularJS和Restangular插件构建。
$ b
PS:angularJS的$ resource或Restangular预期收集结果为
blockquote>
JS数组。
$ b 标准GrailsJsonCollectionRenderer / JsonRenderer
忽略提供给map参数中'respond'的元数据。
我遇到了下面的文章,它实现了自定义JsonRenderer,但我寻找更简单/灵活的解决方案,通过调整自定义
JsonCollectionRenderer
inresources.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
$ bhttp:// mrhaki .blogspot.com / 2013/12 / grails-goodness-rendering-partial.html b
$ bhttp://groovyc.net/non-trivial-restful-apis-in-grails-part-2/
- 创建一个自定义的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
inresources.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/
- 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屋!