【问题标题】:Dynamically Sort JSON output order动态排序 JSON 输出顺序
【发布时间】:2020-08-27 02:30:51
【问题描述】:

我有一个 spring-boot 应用程序,它正在读取 CSV 文件并将结果转换为 POJO 对象。但是 CSV 标头排序很重要。这意味着有些行包含与特定月份相关的数据。我的客户希望 JSON 顺序反映 CSV 中的标头顺序。问题是我的 JSON 订单是从我的模型中应用的订单而不是从标题订单中获取的。有没有办法动态地重新排序模型以反映 csv 顺序?

CSV 订单:

Base,Jun,May,Apr,Mar,Feb,Jan,Dec,Nov,Oct,Sep,Aug,Jul

型号:

pricate int base;
private String jan;
private String feb;
private String mar;
private String apr;
private String may:
private String jun;
private String jul;
private String aug;
private String sep;
private String oct;
private String nov;
private String dec;


// Typical Getters and Setters here

当前 Json 顺序:

data:[{
    base:,
    jan :,
    feb :,
    mar :,
    apr :,
    may :,
    jun :,
    jul :,
    aug :,
    sep :,
    oct :,
    nov :,
    dec :
}]

预期的 JSON 输出:

data:[{
    base :,     
    jun :,
    may :,
    apr :,
    mar :,
    feb :,
    jan :,
    dec :,
    nov :,
    oct :,
    sep :,
    aug :,
    jul :
}]

注意:此顺序每个月都会发生变化,这意味着 csv 中最左边的月份将比当前月份提前 1 个月,这应该根据 JSON 输出表示为下面的第一个月。

【问题讨论】:

    标签: java json spring-boot


    【解决方案1】:

    正如chelmertzanother anwer 中指出的那样,在其实现中不应依赖 JSON 对象键顺序 - 它可能(并且会更早或更晚)造成麻烦。试着说服你的客户不要这样做。如果顺序真的很重要 - 也许使用不同的表示形式(或者甚至可能使用不同于 JSON 的格式 - 例如为什么不使用 CSV?)。

    如果您仍想实现这一点,您可以将 POJO 更改为有序映射(例如 LinkedHashMap),如 this anwer

    只需使用 LinkedHashMap 来存储您的值,它将保持插入顺序:

    @RestController
    public class TestController {
        class Dto {
            private Map<String, List<Integer>> entries = new LinkedHashMap<>();
    
            public Dto() {
                final List<Integer> l1 = new ArrayList<>();
                l1.add(2);
                l1.add(1);
                entries.put("A", l1);
                final List<Integer> l2 = new ArrayList<>();
                l2.add(4);
                l2.add(6);
                entries.put("C", l2);
                final List<Integer> l3 = new ArrayList<>();
                l3.add(5);
                l3.add(3);
                entries.put("B", l3);
            }
    
            public Map<String, List<Integer>> getEntries() {
                return entries;
            }
        }
    
        @GetMapping("json")
        public ResponseEntity<Dto> getJson() {
            return ResponseEntity.ok(new Dto());
        }
    }
    

    /json的请求会得到{"entries":{"A":[2,1],"C":[4,6],"B":[5,3]}},但是如果你使用普通的Map,结果会是{"entries":{"A":[2,1],"B":[5,3],"C":[4,6]}}

    这假设您希望保留 插入 顺序(从您的问题中不清楚)。但是,如果您更喜欢按键对地图进行排序,请改用 TreeMap

    -- How to keep map key order in json when I return object from @RestControler

    【讨论】:

    • 按键将值分组为列表还允许不同长度的列表(在这种情况下可能不太有趣..)+1
    • @jannis 我喜欢这种方法。让我看看我能做什么。本质上,他们需要将对象映射到正确的键,以便他们的前端可以通过基本迭代器读取值,而不必执行任何逻辑来动态地将月份与值匹配。在测试和验证后,如果适用,我将返回并标记为答案。
    【解决方案2】:

    JSON 规范说对象是无序的,因此依赖实现细节非常脆弱。

    对象是零个或多个名称/值的无序集合 对,其中名称是字符串,值是字符串、数字、 布尔值、空值、对象或数组。

    数组是零个或多个值的有序序列。

    -- https://www.rfc-editor.org/rfc/rfc7159#section-1

    相反,您可以用数组表示有序值(例如表示 CSV 的索引列)。有多种表示形式,但这是有效的并且使用较少的空间(不重复标题):

    {
      "headers": [
        "base",
        "jan",
        "feb",
        "mar",
        "apr",
        "may",
        "jun",
        "jul",
        "aug",
        "sep",
        "oct",
        "nov",
        "dec"
      ],
      "data": [
        [ 
          "1",
          "1",
          "1",
          "1",
          "1",
          "1",
          "1",
          "1",
          "1",
          "1",
          "1",
          "1",
          "1"
        ],
        [    
          "2",
          "2",
          "2",
          "2",
          "2",
          "2",
          "2",
          "2",
          "2",
          "2",
          "2",
          "2",
          "2"
        ]
      ]
    }
    

    【讨论】:

      猜你喜欢
      • 2019-12-04
      • 2019-11-22
      • 1970-01-01
      • 2021-10-11
      • 2016-08-01
      • 1970-01-01
      • 2014-10-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多