首页
学习
活动
专区
圈层
工具
发布

Spring Boot+原生注解@JsonView 轻松过滤字段,真的优雅!

在公司茶水间刷咖啡的时候,隔壁组的小王突然问我:“哥,你平时项目里用过@JsonView吗?我看文档里写着能过滤字段,可是我一脸懵逼啊。”我笑了笑说,这玩意儿其实特别适合咱们日常接口开发,尤其是 Spring Boot 项目里经常要根据不同场景返回不同数据,很多人第一反应就是自定义 DTO 或者写一堆转换逻辑,其实原生注解就能轻松搞定,优雅得一批。

什么是 @JsonView?

简单点说,@JsonView是 Jackson 提供的一个注解,用来在序列化对象时动态过滤字段。比如同一个User对象,有时候你只想返回id和name,有时候又要把email也返回出来,甚至在后台管理接口里要完整信息,这时候写多个 DTO 就太麻烦了。@JsonView直接定义几套“视图”,然后在控制器里用不同的视图来序列化,字段就会自动过滤掉。

举个例子,先定义一个用户实体:

import com.fasterxml.jackson.annotation.JsonView;

publicclass User {

  publicinterface SimpleView {}

  publicinterface DetailView extends SimpleView {}

  @JsonView(SimpleView.class)

  private Long id;

  @JsonView(SimpleView.class)

  private String name;

  @JsonView(DetailView.class)

  private String email;

  @JsonView(DetailView.class)

  private String address;

  // getter & setter

}

上面代码里,我定义了两个视图:SimpleView和DetailView。DetailView继承了SimpleView,意思就是它包含了基础信息 + 详细信息。

在 Controller 里使用

再看 Controller 层的用法。比如有两个接口:一个是获取公开用户信息,一个是获取用户详细信息。

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.annotation.JsonView;

@RestController

publicclass UserController {

  @GetMapping("/user/simple")

  @JsonView(User.SimpleView.class)

  public User getSimpleUser() {

      User u = new User();

      u.setId(1L);

      u.setName("Tom");

      u.setEmail("tom@example.com");

      u.setAddress("Beijing");

      return u;

  }

  @GetMapping("/user/detail")

  @JsonView(User.DetailView.class)

  public User getDetailUser() {

      User u = new User();

      u.setId(1L);

      u.setName("Tom");

      u.setEmail("tom@example.com");

      u.setAddress("Beijing");

      return u;

  }

}

当你访问/user/simple,返回结果是:

{

"id": 1,

"name": "Tom"

}

访问/user/detail,返回的就是完整信息:

{

"id": 1,

"name": "Tom",

"email": "tom@example.com",

"address": "Beijing"

}

这时候小王点点头,说“哦,这不就是免去了 DTO 的锅嘛!”我说对啊,很多场景特别省事。

为什么说它优雅?

你想啊,如果不用@JsonView,大多数人会这么搞:

新建一个UserSimpleDTO

再建一个UserDetailDTO

在 Service 层把User转换成这几个 DTO

最后再返回

这流程写多了就烦了,尤其是实体字段变动时,DTO 也得跟着改,成本很高。反而@JsonView直接标记在字段上,一劳永逸。

而且因为@JsonView是 Jackson 原生支持的,Spring Boot 里也无缝集成,完全不用额外依赖或者复杂配置。

高级用法:结合集合和泛型

有人问,那如果返回的是集合呢?比如一个List<User>?很简单,@JsonView依然有效。Spring 在序列化的时候会统一应用视图规则。

@GetMapping("/users/simple")

@JsonView(User.SimpleView.class)

public List<User> getSimpleUsers() {

  return Arrays.asList(

      new User(1L, "Tom", "tom@example.com", "Beijing"),

      new User(2L, "Jerry", "jerry@example.com", "Shanghai")

  );

}

结果就是过滤后的简化视图。

注意事项

不过用的时候也有一些坑。比如:

如果 Controller 方法没加@JsonView,默认会序列化所有字段。

如果你在返回对象上没加任何@JsonView注解,那@JsonView就相当于失效。

当一个字段打了多个视图注解时,Spring 会根据你指定的视图去决定是否输出。

再有一个小技巧是,你可以在DetailView里继承SimpleView,就不用重复写注解了,很符合层级化的场景。

实际应用场景

举几个工作中常见的:

前端展示:对外接口只需要展示用户昵称和头像,这时候用SimpleView。

管理后台:需要返回更多字段,比如手机号、邮箱等,就用DetailView。

内部接口:可能还要返回一些敏感字段,比如注册 IP,这就可以定义一个更深的视图。

这样下来,代码简洁,逻辑清晰,字段控制粒度也够。

和 @JsonIgnore 的区别

有的同学可能会疑惑,那我直接用@JsonIgnore不就完了?确实,@JsonIgnore能永久忽略某字段,但它是“全局忽略”,一旦标记就再也返回不了了。而@JsonView则是“按需返回”,灵活多了。

总结

Spring Boot 配合 Jackson 的@JsonView,可以说是轻量级字段过滤的神器,不需要造 DTO,不需要写复杂的转换逻辑,就能应对不同的返回场景。写法简单,维护成本低,完全值得在项目里推广。

不过话说回来,如果场景特别复杂,比如对象间关系过深、接口差异过大,DTO 还是有它的价值的,两者不是互斥关系,而是可以结合使用。

小王听完之后眼睛一亮:“这也太优雅了吧!”我笑着说,“下次你再写接口,就别一上来造 DTO 了,先想想能不能用@JsonView。”说完我咖啡凉了,赶紧回去敲代码了。

  • 发表于:
  • 原文链接https://page.om.qq.com/page/Oz8qqdJqM4lfiVPRqpvI0TNw0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。
领券