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

开发 前端
前后端分离的项目中,使用Json字符串来完成前后端之间的通信。在默认情况下,只要前端发起请求,就会返回对象的所有字段。但有的时候,后端不能把所有字段全部返回。

前后端分离的项目中,使用Json字符串来完成前后端之间的通信。在默认情况下,只要前端发起请求,就会返回对象的所有字段。但有的时候,后端不能把所有字段全部返回。

一方面,是因为有些字段前端不需要,返回过多的数据会占用网络带宽;

另一方面是出于安全性考虑,比如,不可以将密码返回给前端,否则,网站攻击者可以用REST工具直接获取密码。

而JsonView的作用,就是用来控制C层返回哪些字段的。

@JsonView 它是 Jackson 库中的一个强大注解。通过定义不同的视图类(通常为接口或类),并在实体类的字段上使用 @JsonView 注解标记该字段在哪个视图中可见,同时在控制器方法中通过 @JsonView 注解指定返回的视图,就可以灵活控制返回的字段内容,实现了根据不同场景动态选择序列化字段的目的,大大提高了代码的简洁性和可维护性。

JsonView的效果

通过以下几个实例的对比,来展示JsonView的效果。

以下的代码,我们通过一个小Demo来演示:

在这个小小的教务系统中,有三种实体——教师、学生、班级

为了清晰的展示实体关系,提供简单的E-R图:

图片图片

由图可知: 班级和教师是多对一的关系, 学生和班级是多对一的关系 因此,如果查询学生,班级会包含在学生的字段中,教师会包含在班级的字段中。 这是典型的“对象套对象套对象”的例子。

下面实体的代码供参考(可略过):

图片图片

图片

1、不使用JsonView

在不使用JsonView的情况下,使用REST工具直接取出一个学生,返回了学生的所有字段,也包含关联查询得到的对象:

{
    "id":1,
    "name":"学生1",
    "sno":"123456",
    "klass":{
        "id":1,
        "teacher":{
            "id":1,
            "name":"张三",
            "sex":false,
            "username":"zhangsan",
            "email":"123@123.com"
        },
        "name":"班级1"
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

因此,很容易得到结论一:

不使用JsonView时,返回所有字段,包括外键关联对象的所有字段

2、在实体的字段上使用JsonView

在原来的基础上,对姓名和学号字段分别使用JsonView,同时,定义对应的接口:

图片图片

在C层控制器中加入NameJsowView: (注意:此时只有姓名,并没有加入学号和班级)

图片图片

返回结果如下:

{
    "name":"学生1"
}
  • 1.
  • 2.
  • 3.

由于我们在C层只使用了姓名的字段,除了姓名,其他字段均不返回。关注公众号:码猿技术专栏,回复关键词:1111 获取阿里内部Java性能调优手册!

因此可以得出结论二:

对于已经定义JsowView的对象,C层只返回注解中的JsonView接口里面包含的字段,其他字段一概不返回。

3、在实体的关联对象中使用JsonView

前一节的基础上,把C层的注解由 **@JsonView(Student.NameJsonView.class)改为@JsonView(Student.KlassJsonView.class)**来返回学生对象关联的班级。

图片图片

这次的返回结果比较有意思,只返回了空的Klass,里面一个字段也没有:

{
    "klass":
        {
            
        }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

所以,结论三:通过外键关联的对象,使用JsonView只会返回关联空对象本身,而不返回关联对象的任何字段。

4、在关联对象的字段中使用JsonView

为了解决结论三的问题,我们需要像上文一样,在学生关联的班级实体中也启用JsonView。

然后新建一个接口,分别继承班级字段以及班级实体中的姓名教师等其他字段:

public interface GetByIdJsonView extends Student.KlassJsonView, Klass.NameJsonView, Klass.TeacherJsonView {}
  • 1.

把这个新接口写到C层方法的注解上:

@GetMapping("{id}")
    @JsonView(GetByIdJsonView.class)
    public Student getById(@PathVariable Long id) {
        return this.studentService.findById(id);
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

再次运行,查看返回结果:

{
    "klass":
    {
        "teacher":{ },
        "name":"班级1"
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

符合预期,因此,结论四:

如果想返回关联对象中的字段,只需要继承这个实体中,相关字段的JsonView接口即可。

细心的你可以发现,Teacher中依然没有字段,如果也想返回Teacher的字段,只需要在接口中继续继承即可。

JsonView的使用方法

接下来说具体如何在Spring的项目中应用JsonView。

1、在实体类中定义接口

需要记住接口名称

// 定义了一个接口,用于JsonView控制返回字段
    public interface SnoJsonView {}
  • 1.
  • 2.

2、在实体中的字段中加入注解

找到一个字段,加入**@JsonView(XXXJsonView.class)**,名称与刚才写的接口名称相同。

@JsonView(SnoJsonView.class)
    private String sno;
  • 1.
  • 2.

3、继承接口

实际的项目中,不可能只返回一个字段,如果返回多个字段,那就在C层再定一个接口,继承所以要返回字段的接口即可。 原则上,每个控制器方法,都必须有唯一的JsonView接口,接口名与方法名相同,不能混用。

定义一个与C层方法名相同的接口,继承业务逻辑中需要返回的所有字段:

public interface GetByIdJsonView extends Student.KlassJsonView, Student.NameJsonView, Student.SnoJsonView {}
  • 1.

4、在C层方法上加入注解

最后一步,就是把刚才的接口,加到要控制字段的C层方法上:

@GetMapping("{id}")
    @JsonView(GetByIdJsonView.class)
    public Student getById(@PathVariable Long id) {
        return this.studentService.findById(id);
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

到此,就可以实现用JsonView控制返回字段了。 这种做法的优点在于: 实体层中,接口名字段名一致,到C层引用时,就可以根据名称知道这个接口控制哪个字段; 控制器中,接口名方法名一致,通过接口名可以知道是这个方法返回哪些字段。

总结

前后端分离的项目中,使用Json字符串来完成前后端之间的通信,但有的时候,后端不能把所有字段全部返回,因此可以使用JsonView,来控制C层返回哪些字段

如果不使用JsonView,默认返回所有字段,包括外键关联对象的所有信息; 如果使用JsonView,只返回接口中声明的所有字段,如果出现关联对象,只返回关联对象本身,而不返回其中的字段。 JsonView接口可以通过继承,来实现返回不同字段的组合。

责任编辑:武晓燕 来源: 码猿技术专栏
相关推荐

2025-04-08 02:22:22

SpringJackson注解

2023-04-17 23:49:09

开发代码Java

2025-04-10 00:25:00

Spring@JsonView注解

2021-10-22 14:50:23

Spring BootJava

2023-06-02 16:24:46

SpringBootSSM

2020-04-23 15:59:04

SpringKafka集群

2025-02-07 09:11:04

JSON对象策略

2017-08-02 14:44:06

Spring Boot开发注解

2022-09-22 13:28:34

Redis分布式锁

2022-09-29 08:28:57

SpringRedis分布式

2024-08-09 08:52:26

2009-09-27 14:01:29

Spring MVC

2024-08-02 09:15:22

Spring捕捉格式

2025-03-11 00:55:00

Spring停机安全

2021-04-13 20:24:57

Spring Boot注解spring

2024-10-14 17:18:27

2021-04-20 10:50:38

Spring Boot代码Java

2024-12-06 09:27:28

2022-10-26 07:14:25

Spring 6Spring业务

2021-03-09 13:18:53

加密解密参数
点赞
收藏

51CTO技术栈公众号