在
Spring中为Web应用程序创建一个restful api非常简单.
假设我们有一个电影实体,名称,年份,类型列表和演员列表.为了以json格式返回所有电影的列表,我们只需在某个控制器中创建一个方法,该方法将查询数据库并将列表作为ResponseEntity的主体返回. Spring会神奇地序列化它,一切都很棒:)
但是,如果我在某些情况下希望将电影中的演员列表序列化,而不是在其他场景中呢?在其他一些情况下,除了电影类的字段外,我还需要为列表中的每个电影添加一些其他属性,哪些值是动态生成的?
我目前的解决方案是在某些字段上使用@JsonIgnore,或者创建一个MovieResponse类,其中包含Movie类中的字段和所需的其他字段,并且每次都要从Movie转换为MovieResponse类.
有一个更好的方法吗?
最佳答案
JSONIgnore注释的要点是告诉DispatcherServlet(或Spring处理呈现响应的任何组件)忽略某些字段(如果这些字段为null或以其他方式省略).
在某些情况下,这可以为您向客户端公开的数据提供一些灵活性.
在JSONIgnore的下方:
但是,使用我最近在自己的项目中遇到的这个注释有一些缺点.这主要适用于PUT方法和控制器序列化数据的对象与用于在数据库中存储该数据的对象相同的情况.
PUT方法意味着您要么在服务器上创建新集合,要么使用您正在更新的新集合替换服务器上的集合.
在服务器上替换集合的示例:
想象一下,你正在向服务器发出PUT请求,而RequestBody包含一个序列化的Movie实体,但是这个Movie实体不包含actor,因为你已经省略了它们!稍后,您将实现一项新功能,允许用户编辑和更正电影描述中的拼写错误,并使用PUT将Movie实体发送回服务器,然后更新数据库.
但是,让我们说 – 因为你将JSONIgnore添加到你的对象已经很久了 – 你忘记了某些字段是可选的.在客户端,您忘记包含演员集合,现在您的用户不小心用演员B,C和D覆盖电影A,电影A没有任何演员!
为什么JSONIgnore选择加入?
按理说,迫使您选择不再需要某些字段的目的正是为了避免这些类型的数据完整性问题.在您不使用JSONIgnore的世界中,您保证您的数据永远不会被部分数据替换,除非您自己明确设置该数据.使用JSONIgnore,您可以删除这些安全措施.
话虽如此,JSONIgnore非常有价值,我自己也以同样的方式使用它来减少发送给客户端的有效负载的大小.但是,我开始重新考虑这个策略,而是选择在单独的层中使用POJO类将数据发送到前端而不是用于与数据库交互的方法.
可能更好的设置?:
从我处理这个特定问题的经验来看,理想的设置是为您的Entity对象而不是setter使用构造函数注入.强制自己必须在实例化时传递每个参数,以便您的实体永远不会被部分填充.如果您尝试部分填充它们,编译器会阻止您做一些您可能会后悔的事情.
要将数据发送到客户端,您可能希望省略某些数据,可以使用单独的,断开连接的实体POJO,或使用org.json中的JSONObject.
当从客户端向服务器发送数据时,您的前端实体对象会从模型数据库层接收部分或全部数据,因为您并不真正关心前端是否获得部分数据.但是,当将数据存储在数据存储区中时,您首先要从数据存储区中获取已存储的对象,更新其属性,然后将其存储回数据存储区.换句话说,如果您错过了演员,那么无关紧要,因为您从数据存储区更新的对象已经将角色分配给它的属性.因此,您只需替换明确要替换的字段.
虽然这种设置会有更多的维护开销和复杂性,但您将获得强大的优势:Java编译器会让您回来!它不会让您或甚至不幸的同事在代码中做任何可能危及数据存储区中数据的事情.如果您尝试在模型层中动态创建实体,则将被迫使用构造函数,并强制提供所有数据.如果您没有所有数据且无法实例化该对象,那么您将需要传递空值(应向您发出红色标记)或首先从数据存储区获取该数据.