我需要将GSP模板中LinkedHashMap的数据发送到Controller并保留元素的顺序。
我假设像JSON这样的结构化数据格式是执行此操作的理想方式,但Grails的JSON转换器不会从LinkedHashMap创建有序的JSON对象。
将LinkedHashMap数据结构从GSP发送到Controller的最佳方法是什么,这样我可以保留顺序,但在解析数据时只做最少的工作?
我正在开发一个taglib来在表格中呈现搜索结果。
在taglib中,我构造了一个LinkedHashMap,它指定了数据列和用户想要为列名显示的标签。例如:
def tableFields = [firstName: "First Name", lastName: "Surname", unique_id: "Your Whizbang ID"]
该地图被发送到视图,然后视图将其发送回控制器以从数据库中检索搜索结果。我需要保留元素的顺序(因此使用LinkedHashMap)。
我的第一个想法是将LinkedHashMap转换为JSON字符串,然后通过隐藏的表单元素将其发送到控制器。所以,
import grails.converters.JSON
//taglib class and other code
def tableFields = [firstName: "First Name", lastName: "Surname", unique_id: "Your Whizbang ID"] as JSON
但是,这会在HTML中创建这样的JSON对象。我把它放在隐藏字段的值属性中。
<input type="hidden" name="columns" value="{"firstName": "First Name", "lastName": "Surname", "unique_id": "Your Whizbang ID"}" id="columns">
这是JSON对象本身。
{"firstName": "First Name", "lastName": "Surname", "unique_id": "Your Whizbang ID"}
您可以看到JSON字符串的属性与JSON字符串中的LinkedHashMap的顺序相同。但是,JSON对象实际上不应该保留其属性的保留顺序。因此,当我的控制器收到columns参数,并在其上使用JSON.parse()
方法时,它会创建一个普通的无序HashMap而不是LinkedHashMap。因此,当我将它们渲染到HTML表格中时,搜索结果中的列显示的顺序错误。
At least one fellow遇到了类似的问题。在运行JSON.parse()之后添加as LinkedHashMap
不会削减它,因为.parse()方法会搞定从get go开始的顺序。
Daniel Woods在回复上述帖子时指出:
如果grails数据绑定器无法正常工作,您应该能够覆盖隐式属性设置器,将对象强制转换为您喜欢的Map实现。
我认为他说我可以编写自己的解析器,它将遵循JSON元素的顺序(即使它在技术上不应该)。我想我也可以编写自己的转换器,以便生成的JSON元素类似于:
{[{firstName: "First Name"}, {lastName: "Surname"}, {unique_id "Your Whizbang ID"}]}
我只是害怕JSON解析器如何处理它。我会找回HashMaps列表吗?
同样,我真正的问题是将LinkedHashMap数据结构从GSP发送到Controller的最佳方法是什么,以便我可以保留顺序,但在解析数据时只做最少的工作? I我假设这是JSON,但我很高兴被告知,“为什么不只是......”
答案 0 :(得分:2)
我认为问题是Java / Groovy集合的性质与JSON的简单“它是列表或它是地图”的本质不匹配。没有进入自定义解析,我建议你改变你发送的东西。而不是试图强迫LinkedHashMap的Groovy概念进入Javascriptland,也许坚持Javascript理解的习惯用法,例如地图列表。
在代码中,而不是:
def tableFields = [firstName: "First Name", lastName: "Surname", unique_id: "Your Whizbang ID"]
怎么样:
List tableFields = [
[ name: 'firstName', label: 'First Name' ],
[ name: 'lastName', label: 'Surname' ],
[ name: 'unique_id', label: 'Your Whizbang ID' ],
]
这会让你转向JSON,它会维护你需要的数据(我认为),同时给予JSON它理解的东西(列表):
<input type="hidden" name="columns" id="columns" value="[
{ "name": "firstName", "label": "First Name" },
{ "name": "lastName", "label": "Surname" },
{ "name": "unique_id", "label": "Your Whizbang ID" }
]" />
无论处理什么,这将是一个稍微深一点的迭代器,但这是从好的收藏品到更简单的类型的价格......
答案 1 :(得分:0)
我现在正在做的是传递当前的JSON对象和我可以迭代的列表。在GSP模板中,这看起来像:
<g:hiddenField name="columns" value="${colJson}"/>
<g:hiddenField name="columnOrder" value="${columns.collect{it.key}}"/>
其中columns
是LinkedHashMap。
然后,在获得这些参数的控制器中,我这样做:
def columnTitles = params.columnOrder.tokenize(",[] ")
def unorderedColumns = JSON.parse(params.columns)
def columns = columnTitles.collectEntries{ [(it): unorderedColumns[it]] }
不优雅,但确实有效,而且需要的重构比Joe Rinehart的建议要少一些。