一张表一个 ext 字段输出时却要“平铺”成普通 JSON 属性不用改实体、不用写死字段一个注解全搞定一、当前痛点在日常业务开发中我们经常会遇到这样一个场景数据库设计时预留一个 ext 或 extra 字段类型是 JSON 字符串用来存储一些可扩展的属性。比如用户表有个 ext里面可能放性别、地址、爱好等不确定的字段商品表也有个 ext里面可能放颜色、尺寸、产地……存的时候没问题直接把一个 Map 转成 JSON 字符串塞进去。但取出来给前端的时候前端希望得到的是平铺的 JSON 对象而不是嵌套的 { ext: {...} }。比如后端想要输出{ id: 1, age: 17, sex: 男, address: 山东省 }而不是{ id: 1, age: 17, ext: { sex: 男, address: 山东省 } }传统做法是什么在实体类里把 sex、address 全部定义成独立属性然后手动从 ext 里 get/set。问题是扩展属性随时可能增加难道每次加一个属性就要改一次实体、改一次 VO、改一次转换逻辑太痛苦了有没有一种方法不在实体里增加字段却能让扩展字段在序列化时像普通属性一样被平铺展示答案是有Jackson 的 JsonAnySetter 和 JsonAnyGetter 就是为此而生的。二、解决方案2.1 核心思路我们依然在实体中保留一个 MapString, Object dynamicProps 用于存储所有扩展属性。然后通过两个注解告诉 Jackson反序列化时遇到实体中没有定义的属性统统丢进这个 MapJsonAnySetter。序列化时把这个 Map 里的所有键值对直接“拉平”到 JSON 对象的顶层JsonAnyGetter。这样前端看到的 JSON 和实体里写死的普通属性一模一样而我们的实体类无需为扩展字段添加任何具体成员变量。2.2 代码实现import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonAnySetter; import java.util.HashMap; import java.util.Map; public class Student { private Long id; private Integer age; // 动态扩展属性容器 private MapString, Object dynamicProps new HashMap(); // --- 普通属性的 getter/setter --- public Long getId() { return id; } public void setId(Long id) { this.id id; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age age; } // --- 动态属性操作 --- JsonAnySetter public void setDynamicProp(String key, Object value) { dynamicProps.put(key, value); } JsonAnyGetter public MapString, Object getDynamicProps() { return dynamicProps; } // 便捷取值方法 SuppressWarnings(unchecked) public T T get(String key) { return (T) dynamicProps.get(key); } }2.3 测试效果RestController RequestMapping(/student) public class StudentController { // GET返回一个包含动态属性的 Student 对象 GetMapping(/info) public ResultObject getStudent() { Student stu new Student(); stu.setId(1L); stu.setAge(17); stu.setExt(name, 张三); stu.setExt(sex, 男); stu.setExt(address, 山东省); return Result.success(stu); } // 输出{code: 200, data: { id: 1, age: 17, name: 张三, sex: 男, address: 山东省 }} // POST接收前端 JSON自动将未知属性映射到 dynamicProps PostMapping(/save) public ResultObject saveStudent(RequestBody Student student) { String name student.get(name); String sex student.get(sex); String grade student.get(grade); // 假设前端还传了 grade return Result.success(name name , sex sex , grade grade); } // 输出{id: 2, age: 18, name: 李四, sex: 女, grade: 高三 } }完美没有任何额外实体字段扩展属性却被自然地平铺到了 JSON 中。三、进阶技巧与注意事项3.1 避免与普通字段冲突如果动态属性中的 key 和实体里已有的普通字段同名比如 idJackson会覆盖普通属性。这点要特别注意。3.2 处理 null 值Jackson 默认会忽略值为 null 的属性。如果你希望 null 的动态属性也被输出可以配置mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);3.3 反序列化时限制动态属性如果想只允许某些 key 进入动态 Map可以在 JsonAnySetter 方法中加入校验逻辑JsonAnySetter public void setDynamicProp(String key, Object value) { if (allowedKeys.contains(key)) { dynamicProps.put(key, value); } }3.4 与数据库 JSON 字段配合数据库中 ext 字段是 JSON 字符串从 DB 读取后可以用 Jackson 先反序列化成 Map再通过 JsonAnySetter 填充到实体中。也可以直接让 MyBatis 等 ORM 框架支持将 JSON 列映射为 Map 类型。四、总结对于需要预留扩展字段的业务场景使用 Jackson 的 JsonAnySetter / JsonAnyGetter 将 JSON 内容拉平到实体输出是一个非常优雅且实用的方案。存将扩展属性以 Map 形式存入 JSON 字段。用通过注解动态塞入/取出。展序列化时自动平铺前端无感知。从此告别“加一个扩展属性就要改一堆代码”的噩梦。
企业数字化 ERP 产品动态
相关推荐
课程内容介绍及Prism项目搭建(工业级上位机专篇) 1. 课程内容介绍及Prism项目搭建(工业级上位机专篇)
在工业自动化领域,上位机(HMI/SCADA系统)需要具备高可靠性、可维护性、模块化和实时性。Prism框架(Microsoft.Prism)正是构建工业级WPF上位机的首选MVVM框架,它支持模块化开发、区域导航、事件聚合器和对话服务,能… · 2026/11/10 8:23:35
Casdoor 身份管理平台:单点登录部署教程与 MFA 配置完整指南 Casdoor 身份管理平台:单点登录部署教程与 MFA 配置完整指南 【免费下载链接】casdoor An open-source Agent-first Identity and Access Management (IAM) /LLM MCP & agent gateway and auth server with web UI supporting OpenClaw, MCP, OAuth, OIDC, SAML… · 2026/11/5 22:46:49
建筑电工证去哪里年审 怎么报名不被中介坑 建筑电工证去哪里年审 怎么报名不被中介坑 你是不是也在网上到处找“建筑电工证去哪里年审”,结果一不小心就掉进中介的陷阱里?别急,今天我来带你一步步看清楚,怎么报名、去哪年审,怎么避免被坑,全是实操干货,适合济源本地初次报考的你。… · 2026/11/11 8:15:30
开发区电工证查询多久拿证不耽误工地进度 开发区电工证查询多久拿证不耽误工地进度 工地太忙根本没时间复习考试,很多电工证还没拿到手,就又要忙着赶工期了。特别是在开发区,像洛阳涧西区这样的劳务班组,经常面临证件办理流程不熟、考试时间紧张、复习没头绪等问题。 多久拿证… · 2026/11/11 8:15:30
施工行业的特种工千万别踩坑 老实人怎么报才不被坑 施工行业的特种工千万别踩坑 老实人怎么报才不被坑 你是不是也在担心,施工行业的特种工报名到底该去哪儿?怕被那些中间商忽悠,花大钱还拿不到证?我以前也跟你们一样,干了几年工地,想考个证多条路走,结果差点被中介坑了大几千,现在回头想想,真是后怕… · 2026/11/11 8:15:30
b类电工证种类区别实操考试多少钱 b类电工证种类区别实操考试多少钱 实操考试心里没底怕挂科,这事儿很多人都经历过。尤其是准备报考 b类电工证种类区别 的时候,很多人都会纠结到底该考哪个证,实操考试内容到底难不难, 多少钱… · 2026/11/11 8:15:30
广东省佛山电工证过期了怎么办?内部消息教你如何复审延期 广东省佛山电工证过期了怎么办?内部消息教你如何复审延期 证书过期了不知道怎么复审延期?广东省佛山电工证有效期到底是多久?很多电工朋友都遇到过这个问题,特别是那些在建筑、制造业、电力系统工作的人,如果证书没及时复审,轻则被单位暂停工作,重则影… · 2026/11/11 8:15:29
印度二级电工证图片含金量到底如何?外省证能转过来吗 印度二级电工证图片含金量到底如何?外省证能转过来吗 之前考的证在外省能不能转过来,这个问题我听得太多了。不少朋友手上拿着外省的电工证,尤其是印度二级电工证图片,总担心在别的地方不被认可。其实,含金量这个问题,关键不在于证上的地方,而在于它是… · 2026/11/11 8:14:29
电工证丢失还能补吗?千万别踩坑,丢了证等于失业 电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。… · 2026/11/10 2:16:10
电力电缆作业证直播报名入口与办理流程良心建议 电力电缆作业证直播报名入口与办理流程良心建议 你是不是也担心学历不高报不了名?别急,今天就给你讲讲 电力电缆作业证直播 的报名流程和那些你必须知道的干货, 良心建议 在这里,别错过。 电力电缆作业证直播报名需要什么条件?… · 2026/11/10 17:46:39
英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 怕考不过白交培训费?英德电工证报考费多少钱,你真的了解吗?现在市面上培训机构五花八门,价格参差不齐,很多人一不小心就花了冤枉钱,结果还考不过。别急,今天就来给你说清楚英德电工证的… · 2026/11/10 17:11:43
_中职电工证最新政策解读 中职电工证在哪考?工地太忙根本没时间复习考试的救星来了 工地太忙根本没时间复习考试,这是很多正在备考 中职电工证 的建筑工友的真实写照。你不是不想考,而是真的没时间。但别担心,这期内容是 新乡初次报考人员… · 2026/11/11 0:00:52
昆明电工证培训价格值不值得考?老电工告诉你真相 昆明电工证培训价格值不值得考?老电工告诉你真相 之前考的证在外省能不能转过来?这个问题是很多在外地打工、换城市生活、或者是想在昆明发展的朋友最关心的。尤其是现在云南发展快,很多企业都在招持证上岗的电工,如果你手头有证但不在本地,那这个证是不… · 2026/11/11 0:00:52
特种电缆张工网上查询全攻略:外省证如何转过来 特种电缆张工网上查询全攻略:外省证如何转过来 之前考的证在外省能不能转过来?这是很多特种作业从业者最关心的问题,尤其是像特种电缆张工这类证书,直接关系到日常工作是否合规、能否顺利晋升。很多小伙伴因为证书归属地的问题,陷入职业发展的瓶颈,甚至… · 2026/11/11 0:00:52
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/10 20:19:29
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/10 19:22:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/10 17:00:47