提示:文章若有错误,欢迎评论区指正🍭
最近在学习过程中发现了Jackson库的@JsonView也可以改变JSON的输出结构,并且可以更加精细的控制,我平时一般都会定义一些DTO去封装响应数据,使用这种方法可以不用创建DTO,更加优雅且高效的方式来实现。🌈
一、如何使用@JsonView这个注解?
我们可以创建多个视图,每个视图代表了一组特定的字段。然后,在控制器的方法上,我们可以通过应用这些视图来指定应该使用哪些字段来序列化返回的实体对象。这种灵活性使得我们能够轻松应对各种复杂的业务需求。
二、应用场景
- 数据暴露级别的控制:
假设你有一个用户实体(User),包含了一些基本信息(如姓名、年龄)和一些敏感信息(如密码、邮箱、身份证)。当你需要提供一个 API 来获取用户的基本信息时,你可能不希望暴露敏感信息。通过使用
@JsonView
,你可以定义两个视图:一个包含基本信息,另一个包含所有信息。然后,在对应的 API 方法上,你可以使用相应的视图来控制输出的数据。
根据用户角色定制数据:
在某些情况下,不同的用户角色可能需要看到不同级别的数据。例如,管理员可能需要看到用户的所有信息,而普通用户只能看到基本信息。通过使用
@JsonView
和 Spring Security,你可以根据用户的角色来动态地决定应该暴露哪些数据。
API 版本控制:
当你的 API 随时间发展并引入新功能时,可能会有多个版本的 API。在某些情况下,旧版本的 API 可能不需要包含新引入的字段。通过
@JsonView
,你可以为每个 API 版本定义一个视图,并在需要时切换到相应的视图。
数据聚合和拆分:
在某些情况下,你可能需要将多个实体的数据聚合到一个 JSON 响应中,或者将一个大实体的数据拆分成多个小实体。通过使用
@JsonView
,你可以更轻松地实现这种数据的聚合和拆分。
三、实战案例
定义视图规则:
public interface UserView {
// 展示基本信息
interface Basic {}
// 没有密码
interface WithoutPassword extends Basic {}
// 展示所有的信息
interface Full extends Basic {}
}
定义一个User,在属性上面添加@JSsonView注解,并指定视图
@Data
@AllArgsConstructor
public class User {
@JsonView(UserView.Basic.class)
private Long id;
@JsonView(UserView.Basic.class)
private String username;
@JsonView(UserView.Full.class)
private String password;
@JsonView(UserView.Basic.class)
private String nickName;
@JsonView(UserView.Basic.class)
private String email;
@JsonView({UserView.Basic.class,UserView.WithoutPassword.class})
private String phone;
}
注解方式
@RestController
public class testController {
@GetMapping("/user/basic")
@JsonView(UserView.Basic.class)
public User userBasic(){
User user = new User(1L,"admin","123456","小杰不秃头","123456@xx.com","188xxxxxxxx");
return user;
}
@GetMapping("/user/noPassword")
@JsonView(UserView.WithoutPassword.class)
public User userNoPassword(){
User user = new User(1L,"admin","123456","小杰不秃头","123456@xx.com","188xxxxxxxx");
return user;
}
@GetMapping("/user/full")
@JsonView(UserView.Full.class)
public User userFull(){
User user = new User(1L,"admin","123456","小杰不秃头","123456@xx.com","188xxxxxxxx");
return user;
}
}
注意:@JsonView允许一个视图类的数组,但你只能为每个控制器方法指定一个。如果需要激活多个视图,可以使用复合接口。
对上面三个接口测试:
// user/basic
{
"id": 1,
"username": "admin",
"nickName": "小杰不秃头",
"email": "123456@xx.com",
"phone": "188xxxxxxxx"
}
// user/noPassword
{
"id": 1,
"username": "admin",
"nickName": "小杰不秃头",
"email": "123456@xx.com",
"phone": "188xxxxxxxx"
}
// user/full
{
"id": 1,
"username": "admin",
"password": "123456",
"nickName": "小杰不秃头",
"email": "123456@xx.com",
"phone": "188xxxxxxxx"
}
编程方式
@RestController
public class testController {
@GetMapping("/user/basic")
//@JsonView(UserView.Basic.class)
public MappingJacksonValue userBasic(){
User user = new User(1L,"admin","123456","小杰不秃头","123456@xx.com","188xxxxxxxx");
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(user);
mappingJacksonValue.setSerializationView(UserView.Basic.class);
return mappingJacksonValue;
}
@GetMapping("/user/noPassword")
//@JsonView(UserView.WithoutPassword.class)
public MappingJacksonValue userNoPassword(){
User user = new User(1L,"admin","123456","小杰不秃头","123456@xx.com","188xxxxxxxx");
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(user);
mappingJacksonValue.setSerializationView(UserView.WithoutPassword.class);
return mappingJacksonValue;
}
@GetMapping("/user/full")
//@JsonView(UserView.Full.class)
public MappingJacksonValue userFull(){
User user = new User(1L,"admin","123456","小杰不秃头","123456@xx.com","188xxxxxxxx");
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(user);
mappingJacksonValue.setSerializationView(UserView.Full.class);
return mappingJacksonValue;
}
}
//测试结果跟上面一致
注意:接口返回值必须为MappingJacksonValue。
总结
@JsonView提供了一种灵活且强大的方式来控制序列化的 JSON 数据。通过定义视图和将它们应用到属性和控制器方法上,你可以根据需要暴露不同级别的数据,实现 API 的数据定制化。
@JsonView也可以结合其他的注解一起使用,可以更精细的控制,比如:@JsonInclude、@JsonIgnore等等。
参考文章: