⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 网络 「网络」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

前后端分离的项目中,使用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"
}
}

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

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

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

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

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

返回结果如下:

{
"name":"学生1"
}

由于我们在C层只使用了姓名的字段,除了姓名,其他字段均不返回。

因此可以得出结论二:

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

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

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

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

{
"klass":
{

}
}

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

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

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

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

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

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

@GetMapping("{id}")
@JsonView(GetByIdJsonView.class)
public Student getById(@PathVariable Long id) {
return this.studentService.findById(id);
}

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

{
"klass":
{
"teacher":{ },
"name":"班级1"
}
}

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

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

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

JsonView的使用方法

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

1、在实体类中定义接口

需要记住接口名称

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

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

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

@JsonView(SnoJsonView.class)
private String sno;

3、继承接口

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

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

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

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

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

@GetMapping("{id}")
@JsonView(GetByIdJsonView.class)
public Student getById(@PathVariable Long id) {
return this.studentService.findById(id);
}

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

总结

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

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

文章目录
  1. 1. JsonView的效果
    1. 1.1. 1、不使用JsonView
    2. 1.2. 2、在实体的字段上使用JsonView
    3. 1.3. 3、在实体的关联对象中使用JsonView
    4. 1.4. 4、在关联对象的字段中使用JsonView
  2. 2. JsonView的使用方法
    1. 2.1. 1、在实体类中定义接口
    2. 2.2. 2、在实体中的字段中加入注解
    3. 2.3. 3、继承接口
    4. 2.4. 4、在C层方法上加入注解
  3. 3. 总结