博主介紹:✌全網粉絲22W+,博客專家、Java領域優質創作者華為雲/阿里雲/等平台優質作者、專注於Java技術領域✌

技術範圍:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大數據、物聯網、機器學習等設計與開發。

感興趣的可以先關注收藏起來,在工作中、生活上等遇到相關問題都可以給我留言諮詢,希望幫助更多的人。

Spring Boot 返回排序後的 Map 但前端接收順序不對的解決方案

  • 一、背景描述
  • 二、問題原因
  • 三、解決方案
  • 3.1 方案1:使用有序集合代替 Map(推薦)
  • 3.2 方案2:使用自定義對象包裝
  • 3.3 方案3:確保使用正確的 Map 實現類
  • 3.4 方案4:前端處理方案
  • 四、最佳實踐建議
  • 五、拓展:為什麼LinkedHashMap有時也不起作用?

一、背景描述

返回給頁面的VO中有一個List和一個Map,兩個屬性,而且都需要排序後返回,現象是List排序結果在頁面中顯示正常,而Map排序結果在頁面中顯示跟在服務器中排序後的不同。這就奇了怪了,明明是處理好排序後才返回給頁面的,但是頁面接收後就順序不一致了。

二、問題原因

  • Map 的實現類問題:即使你使用了 LinkedHashMap 保持順序,在 JSON 序列化過程中可能會丟失順序
  • JSON 規範:標準的 JSON 對象本身是無序的鍵值對集合
  • 前端處理:JavaScript 的 JSON.parse() 默認不保證對象屬性的順序

三、解決方案

3.1 方案1:使用有序集合代替 Map(推薦)

@GetMapping("/sorted-data")
public ResponseEntity<List<Map.Entry<String, Object>>> getSortedData() {
    Map<String, Object> data = new LinkedHashMap<>();
    // 添加數據並排序
    data.put("A", 1);
    data.put("B", 2);
    data.put("C", 3);
    
    // 轉換為保持順序的Entry列表
    List<Map.Entry<String, Object>> sortedList = new ArrayList<>(data.entrySet());
    
    return ResponseEntity.ok(sortedList);
}

前端將收到類似這樣的結構:

[
    {"key": "A", "value": 1},
    {"key": "B", "value": 2},
    {"key": "C", "value": 3}
]

3.2 方案2:使用自定義對象包裝

@Data // Lombok 註解
public class KeyValuePair {
    private String key;
    private Object value;
    // 構造方法
}

@GetMapping("/sorted-data")
public ResponseEntity<List<KeyValuePair>> getSortedData() {
    Map<String, Object> data = new LinkedHashMap<>();
    // 添加數據
    data.put("A", 1);
    data.put("B", 2);
    data.put("C", 3);
    
    // 轉換為KeyValuePair列表
    List<KeyValuePair> result = data.entrySet().stream()
        .map(e -> new KeyValuePair(e.getKey(), e.getValue()))
        .collect(Collectors.toList());
    
    return ResponseEntity.ok(result);
}

3.3 方案3:確保使用正確的 Map 實現類

@GetMapping("/sorted-data")
public ResponseEntity<Map<String, Object>> getSortedData() {
    // 使用LinkedHashMap保持插入順序
    Map<String, Object> data = new LinkedHashMap<>();
    
    // 添加數據(已排序)
    data.put("A", 1);
    data.put("B", 2);
    data.put("C", 3);
    
    // 配置Jackson保留Map順序
    ObjectMapper mapper = new ObjectMapper();
    mapper.enable(SerializationFeature.INDENT_OUTPUT);
    mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, false);
    
    return ResponseEntity.ok(data);
}

3.4 方案4:前端處理方案

如果必須返回 Map,可以在前端處理:

// 假設後端返回的是保持順序的LinkedHashMap序列化的JSON
fetch('/api/sorted-data')
  .then(response => response.json())
  .then(data => {
    // 轉換為數組保持順序
    const sortedArray = Object.entries(data);
    console.log(sortedArray); // 這會保持順序
  });

四、最佳實踐建議

  1. 推薦使用方案1或方案2:返回 List<Entry>List<自定義對象> 是最可靠的方式
  2. 避免依賴JSON對象的屬性順序:這是不符合JSON規範的
  3. 如果需要嚴格順序:可以在數據結構中包含順序字段
@Data
public class OrderedItem {
    private int order;
    private String key;
    private Object value;
    // 構造方法
}

@GetMapping("/sorted-data")
public ResponseEntity<List<OrderedItem>> getSortedData() {
    // 實現...
}

五、拓展:為什麼LinkedHashMap有時也不起作用?

即使在Java端使用了LinkedHashMap,以下情況仍可能導致順序丟失:

  1. 某些JSON庫可能不保留Map順序
  2. 前端JavaScript引擎對對象屬性的處理
  3. 中間件(如網關、代理)可能重新序列化JSON

因此,使用有序的列表結構是最可靠的跨平台解決方案。



好了,今天分享到這裏。希望你喜歡這次的探索之旅!不要忘記 “點贊” 和 “關注” 哦,我們下次見!🎈

本文完結!