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

Spring Boot不同Get接口自定义JSON响应的实现方法

解决Spring Boot不同接口返回不同JSON结构的问题

下面给你三种可行的修改方案,按需选择:

方案一:使用DTO(数据传输对象,推荐)

这种方式最清晰,完全解耦实体类和接口返回结构,后续维护也方便。

步骤1:创建精简版的DTO类

专门为findAll接口定义返回的结构:

// 商铺精简DTO
public class ShopListDTO {
    private UUID id;
    private String name;
    private String city;
    private LocalDateTime created_at;
    private List<ProductListDTO> products;

    // 生成全参/必要参构造方法,以及getter、setter
}

// 商品精简DTO
public class ProductListDTO {
    private UUID id;
    private String name;

    // 生成构造方法、getter、setter
}

步骤2:修改控制器的findAll方法

把查询到的Shops实体转换成ShopListDTO返回:

@GetMapping
public List<ShopListDTO> findAll(){
    List<Shops> shops = shopService.findAll();
    // 流式转换实体到DTO
    return shops.stream().map(shop -> {
        ShopListDTO dto = new ShopListDTO();
        dto.setId(shop.getId());
        dto.setName(shop.getName());
        dto.setCity(shop.getCity());
        dto.setCreated_at(shop.getCreated_at());
        
        // 转换关联的商品列表
        List<ProductListDTO> productDTOs = shop.getProducts().stream()
                .map(product -> new ProductListDTO(product.getId(), product.getName()))
                .collect(Collectors.toList());
        dto.setProducts(productDTOs);
        
        return dto;
    }).collect(Collectors.toList());
}

findById方法保持原样即可,返回完整的Shops实体。

方案二:使用Jackson的@JsonView注解

通过视图注解标记哪些字段在不同接口返回,不需要额外创建DTO,但实体类会和视图规则耦合。

步骤1:定义视图接口

public interface Views {
    // 基础视图,用于findAll返回精简数据
    interface Basic {}
    // 详细视图,继承基础视图,用于findById返回完整数据
    interface Detail extends Basic {}
}

步骤2:给实体类字段添加视图注解

在Shops和Product类的字段上标记对应的视图:

public class Shops {
    @JsonView(Views.Basic.class)
    private UUID id;
    @JsonView(Views.Basic.class)
    private String name;
    @JsonView(Views.Basic.class)
    private String city;
    @JsonView(Views.Basic.class)
    private LocalDateTime created_at;
    
    // 这些字段只在Detail视图返回
    @JsonView(Views.Detail.class)
    private LocalDateTime updated_at;
    @JsonView(Views.Detail.class)
    private String purpose;
    @JsonView(Views.Detail.class)
    private User user;
    
    @JsonView(Views.Basic.class)
    private List<Product> products;
    
    // 其他getter、setter
}

public class Product {
    @JsonView(Views.Basic.class)
    private UUID id;
    @JsonView(Views.Basic.class)
    private String name;
    
    // 商品的其他字段标记为Detail视图
    @JsonView(Views.Detail.class)
    private BigDecimal price;
    @JsonView(Views.Detail.class)
    private String description;
    
    // getter、setter
}

步骤3:修改控制器方法添加视图注解

@GetMapping
@JsonView(Views.Basic.class)
public List<Shops> findAll(){
    return shopService.findAll();
}

@GetMapping("/{id}")
@JsonView(Views.Detail.class)
public Shops findById(@PathVariable("id") UUID id){
    return shopService.findOne(id);
}

方案三:动态过滤字段(适合临时需求)

通过Jackson的MappingJacksonValue动态指定返回字段,不需要修改实体类或创建DTO,但逻辑写在控制器里,复杂场景维护麻烦。

步骤1:给实体类添加@JsonFilter注解

@JsonFilter("ShopFilter")
public class Shops {
    // 原实体类内容不变
}

@JsonFilter("ProductFilter")
public class Product {
    // 原实体类内容不变
}

步骤2:修改findAll方法

@GetMapping
public MappingJacksonValue findAll(){
    List<Shops> shops = shopService.findAll();
    
    // 定义商铺需要保留的字段
    SimpleBeanPropertyFilter shopFilter = SimpleBeanPropertyFilter.filterOutAllExcept(
            "id", "name", "city", "created_at", "products");
    // 定义商品需要保留的字段
    SimpleBeanPropertyFilter productFilter = SimpleBeanPropertyFilter.filterOutAllExcept("id", "name");
    
    FilterProvider filters = new SimpleFilterProvider()
            .addFilter("ShopFilter", shopFilter)
            .addFilter("ProductFilter", productFilter);
    
    MappingJacksonValue mapping = new MappingJacksonValue(shops);
    mapping.setFilters(filters);
    
    return mapping;
}

findById方法保持原样即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 14:44:57