首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Grails LinkedHashMap到JSON在RoundTrip上保持顺序

Grails LinkedHashMap到JSON在RoundTrip上保持顺序
EN

Stack Overflow用户
提问于 2014-01-07 18:59:29
回答 2查看 1.3K关注 0票数 0

tl;dr

我需要将GSP模板中的LinkedHashMap中的数据发送给Controller,并保留元素的顺序。

我假设像JSON这样的结构化数据格式是理想的方法,但是Grails的JSON转换器不会从LinkedHashMap创建有序的JSON对象。

将LinkedHashMap数据结构从GSP发送到Controller的最佳方法是什么,这样我就可以保持顺序,但在解析数据时只做最少的工作。

长版

我正在开发一个taglib,以在表中呈现搜索结果。

在taglib中,我构造了一个LinkedHashMap,它指定用户希望为列名显示的数据列和标签。例如:

代码语言:javascript
复制
def tableFields = [firstName: "First Name", lastName: "Surname", unique_id: "Your Whizbang ID"]

该地图被发送到视图,然后视图将其发送回控制器,以便从数据库检索搜索结果。我需要保持元素的顺序(因此使用了LinkedHashMap)。

我的第一个想法是将LinkedHashMap转换为JSON字符串,然后通过隐藏的form元素将其发送到控制器。所以,

代码语言:javascript
复制
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对象。我把它放在一个隐藏字段的值属性中。

代码语言:javascript
复制
<input type="hidden" name="columns" value="{"firstName": "First Name", "lastName": "Surname", "unique_id": "Your Whizbang ID"}" id="columns">

这里是JSON对象本身。

代码语言:javascript
复制
{"firstName": "First Name", "lastName": "Surname", "unique_id": "Your Whizbang ID"}

您可以看到,JSON字符串的属性与JSON字符串中的LinkedHashMap的顺序相同。但是,JSON对象实际上不应该保留其属性的顺序。因此,当我的控制器接收到列参数,并在其上使用JSON.parse()方法时,它将创建一个普通的ol‘无序HashMap,而不是LinkedHashMap。因此,当我将这些列呈现到HTML表中时,我的搜索结果中的列以错误的顺序显示。

至少有一个人也遇到了类似的问题。在运行as LinkedHashMap ()之后添加JSON.parse()并不会削减它,因为.parse()方法会破坏get的顺序。

丹尼尔·伍兹在对上述帖子的答复中指出:

如果grails数据绑定器不适合您,那么您应该能够覆盖隐式属性设置器,将对象强制转换为您最喜欢的Map实现。

我假设他说我可以编写自己的解析器,这将遵守JSON元素的顺序(尽管技术上不应该这样)。我还可以编写自己的转换器,以便生成的JSON元素如下所示:

代码语言:javascript
复制
{[{firstName: "First Name"}, {lastName: "Surname"}, {unique_id "Your Whizbang ID"}]}

不过,我有点害怕JSON解析器会如何处理这个问题。我能拿回一份HashMaps的清单吗?

同样,我真正的问题是--从GSP向Controller发送LinkedHashMap数据结构的最佳方式是什么,这样我就可以保持顺序,但在解析数据时只做最少的工作?--我假设这是JSON,但是我非常高兴地被告知,“为什么不只是.”

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-01-07 20:48:30

现在我要做的是传递当前的JSON对象和一个可以迭代的列表。在GSP模板中,如下所示:

代码语言:javascript
复制
<g:hiddenField name="columns" value="${colJson}"/>
<g:hiddenField name="columnOrder" value="${columns.collect{it.key}}"/>

其中columns是LinkedHashMap。

然后,在得到这些参数的控制器中,我这样做:

代码语言:javascript
复制
def columnTitles = params.columnOrder.tokenize(",[] ")
def unorderedColumns = JSON.parse(params.columns)
def columns = columnTitles.collectEntries{ [(it): unorderedColumns[it]] }

不优雅,但它确实有效,它所需的重构比Joe的建议要少一些。

票数 0
EN

Stack Overflow用户

发布于 2014-01-07 20:41:10

我认为问题在于Java/Groovy集合的性质与JSON的简单“它是列表或映射”性质之间的不匹配。在不进行自定义解析的情况下,我建议稍微改变一下您要发送的内容。与其试图将Groovy的LinkedHashMap概念强加到Javascriptland中,不如坚持使用Javascript理解的成语,比如地图列表。

在代码中,而不是:

代码语言:javascript
复制
def tableFields = [firstName: "First Name", lastName: "Surname", unique_id: "Your Whizbang ID"]

不如:

代码语言:javascript
复制
List tableFields = [
    [ name: 'firstName', label: 'First Name' ],
    [ name: 'lastName', label: 'Surname' ],
    [ name: 'unique_id', label: 'Your Whizbang ID' ],
]

这将您转移到JSON,它维护您需要的数据(我认为),同时给JSON一些它理解的排序(列表):

代码语言:javascript
复制
<input type="hidden" name="columns" id="columns" value="[
    { "name": "firstName", "label": "First Name" },
    { "name": "lastName", "label": "Surname" },
    { "name": "unique_id", "label": "Your Whizbang ID" }
]" />

不管如何处理,这将是一个稍微深一点的迭代器,但这是从一个好集合的土地到更简单的类型的代价.

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20979606

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档