You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot/Spring REST如何为RESTful响应列表命名?

嘿,这事儿在Spring Boot里其实挺容易搞定的!你想要的就是把原来返回的嵌套列表转换成带自定义命名键的JSON对象对吧?咱们一步步来实现:

核心思路

不要直接返回List<List<...>>,而是用一个顶层DTO(数据传输对象)类来封装你的各个列表,通过Jackson的@JsonProperty注解指定每个列表在JSON中的键名,Spring会自动帮你完成序列化。

步骤1:定义子项的DTO类

先给每个列表里的元素创建对应的实体类,方便Jackson序列化:

市场统计项DTO

public class MarketStat {
    private String marketname;
    private int totalmarketcount;

    // 全参构造函数
    public MarketStat(String marketname, int totalmarketcount) {
        this.marketname = marketname;
        this.totalmarketcount = totalmarketcount;
    }

    // Getter和Setter(如果不用Lombok的话必须写)
    public String getMarketname() { return marketname; }
    public void setMarketname(String marketname) { this.marketname = marketname; }
    public int getTotalmarketcount() { return totalmarketcount; }
    public void setTotalmarketcount(int totalmarketcount) { this.totalmarketcount = totalmarketcount; }
}

处理状态统计项DTO

public class ProcessingMetric {
    private int discarded;
    private int received;
    private int coded;
    private int completed;

    // 全参构造函数
    public ProcessingMetric(int discarded, int received, int coded, int completed) {
        this.discarded = discarded;
        this.received = received;
        this.coded = coded;
        this.completed = completed;
    }

    // Getter和Setter
    public int getDiscarded() { return discarded; }
    public void setDiscarded(int discarded) { this.discarded = discarded; }
    public int getReceived() { return received; }
    public void setReceived(int received) { this.received = received; }
    public int getCoded() { return coded; }
    public void setCoded(int coded) { this.coded = coded; }
    public int getCompleted() { return completed; }
    public void setCompleted(int completed) { this.completed = completed; }
}

小技巧:如果不想写繁琐的Getter/Setter,可以用Lombok的@Data+@AllArgsConstructor注解,记得在项目里引入Lombok依赖哦!

步骤2:定义顶层响应DTO类

这个类用来封装你的所有列表,并用@JsonProperty指定每个列表在JSON中的名称:

import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;

public class ApiResponse {
    // 这里的"MarketStatsList"就是你想要给第一个列表起的名称
    @JsonProperty("MarketStatsList")
    private List<MarketStat> marketStats;

    // 这里的"ProcessingMetricsList"是第二个列表的名称
    @JsonProperty("ProcessingMetricsList")
    private List<ProcessingMetric> processingMetrics;

    // 全参构造函数
    public ApiResponse(List<MarketStat> marketStats, List<ProcessingMetric> processingMetrics) {
        this.marketStats = marketStats;
        this.processingMetrics = processingMetrics;
    }

    // Getter和Setter(同样,用Lombok可以省略)
    public List<MarketStat> getMarketStats() { return marketStats; }
    public void setMarketStats(List<MarketStat> marketStats) { this.marketStats = marketStats; }
    public List<ProcessingMetric> getProcessingMetrics() { return processingMetrics; }
    public void setProcessingMetrics(List<ProcessingMetric> processingMetrics) { this.processingMetrics = processingMetrics; }
}

步骤3:修改REST控制器的返回值

把原来返回List<List<Object>>的方法,改成返回我们定义的ApiResponse对象:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
public class StatsController {

    // 假设你的服务层返回的是List<List<Object>>类型的数据
    private List<List<Object>> getRawStatsFromService() {
        // 模拟你的服务返回数据
        return List.of(
                List.of(
                        Map.of("marketname", "East", "totalmarketcount", 22),
                        Map.of("marketname", "Midwest", "totalmarketcount", 9275),
                        Map.of("marketname", "West", "totalmarketcount", 25)
                ),
                List.of(
                        Map.of("discarded", 0, "received", 1268, "coded", 6031, "completed", 5951)
                )
        );
    }

    @GetMapping("/stats")
    public ApiResponse getStats() {
        List<List<Object>> rawData = getRawStatsFromService();

        // 把第一个子列表转换成List<MarketStat>
        List<MarketStat> marketStats = rawData.get(0).stream()
                .map(item -> {
                    Map<String, Object> map = (Map<String, Object>) item;
                    return new MarketStat(
                            (String) map.get("marketname"),
                            ((Number) map.get("totalmarketcount")).intValue()
                    );
                })
                .collect(Collectors.toList());

        // 把第二个子列表转换成List<ProcessingMetric>
        List<ProcessingMetric> processingMetrics = rawData.get(1).stream()
                .map(item -> {
                    Map<String, Object> map = (Map<String, Object>) item;
                    return new ProcessingMetric(
                            ((Number) map.get("discarded")).intValue(),
                            ((Number) map.get("received")).intValue(),
                            ((Number) map.get("coded")).intValue(),
                            ((Number) map.get("completed")).intValue()
                    );
                })
                .collect(Collectors.toList());

        // 返回顶层响应对象
        return new ApiResponse(marketStats, processingMetrics);
    }
}

最终返回的JSON效果

现在调用/stats接口,就能得到带命名列表的JSON了:

{
  "MarketStatsList": [
    {"marketname": "East", "totalmarketcount": 22},
    {"marketname": "Midwest", "totalmarketcount": 9275},
    {"marketname": "West", "totalmarketcount": 25}
  ],
  "ProcessingMetricsList": [
    {"discarded": 0, "received": 1268, "coded": 6031, "completed": 5951}
  ]
}

如果你的需求是只返回单个命名列表(比如你示例里的EncoderCodedlist),那只需要在顶层DTO里定义一个列表属性就行,逻辑是完全一样的~

内容的提问来源于stack exchange,提问作者sunil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:55:10