当前位置: 首页 > java >正文

@JsonView + 单一 DTO:如何实现多场景 JSON 字段动态渲染

@JsonView + 单一 DTO:如何实现多场景 JSON 字段动态渲染

  • @JsonView + 单一 DTO:如何实现多场景 JSON 字段动态渲染
    • 1、@JsonView 注解产生的背景
    • 2、为了满足不同场景下返回对应的属性的做法有哪些?
      • 2.1 最快速的实现则是针对不同场景新建不同的 DTO 对象
      • 2.2 使用 @JsonView 注解实现不同DTO对象的返回
        • 2.2.1 定义同一个 DTO 对象
        • 2.2.2 区分不同的响应视图
        • 2.2.3 Controller 层的调用
        • 2.2.4 简要信息 视图 DTO
        • 2.2.5 详情信息 视图 DTO
      • 2.3 问题已解决(引入原理实现篇)
    • 3、Debug调试篇
      • 3.1 SpringMvc 切入点 对应的核心代码片段
      • 3.2 字段属性序列化核心逻辑
      • 3.3 多种 DTO 视图 Demo 验证
        • 3.3.1 ObjectMapper 配置视图 View
        • 3.3.2 ObjectWriter 配置视图 View
      • 3.4 小结
    • 4、扩展点
      • 4.1 ResponseBodyAdvice接口
      • 4.2 RequestBodyAdvice接口

@JsonView + 单一 DTO:如何实现多场景 JSON 字段动态渲染

1、@JsonView 注解产生的背景

@JsonView 是 Jackson 库提供的一个注解,用于控制 Java 对象序列化为 JSON 时的字段可见性。通过定义不同的“视图”(View),可以灵活地决定哪些字段在特定场景下被序列化,从而避免为不同接口编写多个相似的 DTO 类。

2、为了满足不同场景下返回对应的属性的做法有哪些?

2.1 最快速的实现则是针对不同场景新建不同的 DTO 对象

在这里插入图片描述

细心的童鞋可以发现:虽然是不同的 DTO,但是存在共同的属性,而且比如后面再来一个需求,这个接口仅返回基本信息的字段(外加一个手机号字段),那么我们是不是还需要创建一个新的 DTO 对象呢?如果针对每一个接口返回都定义一个 DTO 对象的话,对于后端代码的维护也是相当的冗余操作,鉴于这种需求,有没有一种对应后端的 其他 解决方案呢?答案是有的。即就是(@JsonView注解)。

2.2 使用 @JsonView 注解实现不同DTO对象的返回

2.2.1 定义同一个 DTO 对象
/*** @Description 用户DTO* @Author Mr.Gao* @Date 2025/4/16 23:43*/
@Getter
@Setter
public class User {/*** 用户姓名*/@JsonView(SimpleInfoView.class)private String username;/*** 用户年龄*/@JsonView(SimpleInfoView.class)private Integer age;/*** 用户性别*/@JsonView(SimpleInfoView.class)private String sex;/*** =================以下信息为用户敏感信息不能给用户返回================*//*** 手机号码*/@JsonView(SensitiveInfoView.class)private String mobileNo;/*** 登录密码*/@JsonView(SensitiveInfoView.class)private String loginPwd;/*** 支付密码*/@JsonView(SensitiveInfoView.class)private String payPwd;
}
2.2.2 区分不同的响应视图
/*** @Description 简单视图展示View信息* @Author Mr.Gao*/
public interface SimpleInfoView {
}------ 视图与视图之间是可以继承的,那么也就实现既包含基础信息字段又包含需要的字段,进而实现不同DTO的返回 ---
/*** @Description 敏感信息* @Author Mr.Gao*/
public interface SensitiveInfoView extends SimpleInfoView {
}
2.2.3 Controller 层的调用
/*** @Description 用户控制层* @Author Mr.Gao* @Date 2025/4/16 23:50*/
@RestController
public class UserController {/*** 模拟从数据库获取用户信息** @return*/public static User getUserInfoFromDB() {User user = new User();user.setUsername("Mr.Gao");user.setAge(18);user.setSex("男");user.setMobileNo("12345678901");user.setLoginPwd("123456");user.setPayPwd("123456");return user;}/*** 获取用户简要信息** @return*/@JsonView(SimpleInfoView.class) // 返回简要信息的视图DTO@GetMapping("/user/getUserSimpleInfo")public User getUserSimpleInfo() {return getUserInfoFromDB();}/*** 获取用户详细信息** @return*/@JsonView(SensitiveInfoView.class)// 返回详情信息的视图DTO@GetMapping("/user/getUserDetailInfo")public User getUserDetailInfo() {return getUserInfoFromDB();}}
2.2.4 简要信息 视图 DTO

在这里插入图片描述

2.2.5 详情信息 视图 DTO

在这里插入图片描述

2.3 问题已解决(引入原理实现篇)

经过上述代码案例操作,确实是可以解决我们后端程序猿的新建多个 DTO 对象的冗余问题,童鞋们可以都试试,但是出于好奇,为了什么在 一个实体对象 DTO 和 controller 层的方法 增加 @JsonView 注解之后就能实现不同视图的效果呢?其中究竟是使用了什么魔法呢?接下来我们继续进入 Debug 调试篇,继续 gank 它。

3、Debug调试篇

3.1 SpringMvc 切入点 对应的核心代码片段

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.2 字段属性序列化核心逻辑

在这里插入图片描述
在这里插入图片描述

经过上述分析可得,设置视图的核心代码为 objectMapper.writerWithView(serializationView) ,然后调用 objectMapper.writeValueAsString 方法是否可以实现不同视图的 DTO 输出呢?

3.3 多种 DTO 视图 Demo 验证

3.3.1 ObjectMapper 配置视图 View
@Test
public void testJsonViewAnnotationConvertMutiDTOByObjectMapper() throws JsonProcessingException {User user = UserController.getUserInfoFromDB();// @1: 设置序列化视图为SimpleInfoView(输出简要信息)objectMapper.setConfig(objectMapper.getSerializationConfig().withView(SimpleInfoView.class));// @2: 设置序列化视图为SensitiveInfoView(输出详细信息)//objectMapper.setConfig(objectMapper.getSerializationConfig()//        .withView(SensitiveInfoView.class));System.out.println("采用Object序列化视图:" + objectMapper.getSerializationConfig().getActiveView());String JsonResult = objectMapper.writeValueAsString(user);System.out.println(JsonResult);
}
3.3.2 ObjectWriter 配置视图 View
@Test
public void testJsonViewAnnotationConvertMutiDTOByObjectWriter() throws JsonProcessingException {User user = UserController.getUserInfoFromDB();// @1: 设置序列化视图为SimpleInfoView(输出简要信息)//ObjectWriter objectWriter = objectMapper.writerWithView(SimpleInfoView.class);// @2: 设置序列化视图为SensitiveInfoView(输出详细信息)ObjectWriter objectWriter = objectMapper.writerWithView(SensitiveInfoView.class);System.out.println("ObjectWriter中的序列化视图为: " + objectWriter.getConfig().getActiveView());String JsonResult = objectWriter.writeValueAsString(user);System.out.println(JsonResult);
}

3.4 小结

最后,我本地的项目 SpringBoot 版本是 2.6.13,而我的 Pom 文件依赖中仅仅引入了spring-boot-starter-web,我可以确定的是没有引入任何 jackson 包的依赖的,而@JsonView 注解是 jackson 包下的注解,那么只有一种可能,那就是对应的 springboot 的 web 依赖集成了对应 jackson 相关 jar 包,出于好奇的我还是点开了 spring-boot-starter-web 依赖,结果发现确实是这样。
在这里插入图片描述

4、扩展点

4.1 ResponseBodyAdvice接口

对响应的内容可以进行二次包装处理,例如对响应参数内容统一进行签名、加密等逻辑处理。

4.2 RequestBodyAdvice接口

用来对请求的内容进行请求参数重写处理,例如对接收到请求参数统一进行验签、解密等逻辑处理。

综上所述,相信我们已经掌握了 如何通过一个 DTO 对象来渲染不同需求场景下的 DTO 对象,不过存在唯一的缺点,经过 Debug 调试篇我们可以发现,只有在 序列化的时候才会过滤对应的字段,那么如果一个 DTO 对象的属性太多,根据类的单一设计原则还是建议使用新建新的 DTO 对象来完成。所以我觉得可以视情况而定,想要代码的逻辑清晰一些就新建 DTO 实体,想要减少的代码的编码量(即减少 DTO 实体对象)那么就用@JsonView注解实现。
在这里插入图片描述

http://www.xdnf.cn/news/209.html

相关文章:

  • 大语言模型智能体:安全挑战与应对之道
  • echarts饼图中心呈现一张图片,并且能动态旋转的效果react组件
  • 天梯赛数据结构合集
  • 51单片机实验三:数码管动态显示
  • Oracle 19c新特性:OCP认证考试与职业跃迁的关键?
  • 如何选择适合您的过程控制器?
  • VSCODE插值表达式失效问题
  • 4.18学习总结
  • CNN与VGG16的关系:从基础到经典模型的通俗解析
  • 【前沿】成像“跨界”测量——扫焦光场成像
  • 【AI部署】腾讯云GPU -—SadTalker的AI数字人访问web服务—未来之窗超算中心
  • 2025mathorcup妈妈杯数学建模挑战赛C题:汽车风阻预测,详细思路,模型,代码更新中
  • 专精特新政策推动,B端UI设计如何赋能中小企业创新发展?
  • 使用VHDL语言实现TXT文件的读写操作
  • 【LeetCode】大厂面试算法真题回忆(61)--组装新的数组
  • 7.Rust+Axum:打造高效 RESTful API 的最佳实践
  • FastGPT安装前,系统环境准备工作?
  • AI Agent系列(十) -Data Agent(数据分析智能体)开源资源汇总
  • Qt QTimer 详解与使用指南
  • PHP最新好看UI个人引导页网页源码
  • Flash存储器(二):SPI NAND Flash与SPI NOR Flash
  • 基于linux 设置无线网卡Monitor模式 sniffer抓包
  • 经济指标学习(二)
  • 神经网络优化 - 小批量梯度下降之批量大小的选择
  • ChatGPT-o3辅助学术写作的关键词和引言效果如何?
  • 鸿蒙NEXT开发键值型数据工具类(ArkTs)
  • PyTorch快速入门
  • 《软件设计师》复习笔记(12.1)——范围管理、进度管理
  • 全栈架构设计图
  • 浅谈验证(Verification)和确认(Validation)