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
相关产品推荐
相关产品推荐

