Json 使用Spring Boot和Jackson避免两种不同的域模型
我正在设计一个由MySQL支持的SpringBootRESTAPI。我突然想到,实际上,我希望为我的所有域对象提供两个独立的模型:Json 使用Spring Boot和Jackson避免两种不同的域模型,json,hibernate,jpa,spring-boot,jackson,Json,Hibernate,Jpa,Spring Boot,Jackson,我正在设计一个由MySQL支持的SpringBootRESTAPI。我突然想到,实际上,我希望为我的所有域对象提供两个独立的模型: 模型1:在外部世界(REST客户端)和我的SpringREST控制器之间使用;及 模型2:Spring Boot应用程序和MySQL数据库之间内部使用的实体 例如,我可能有一个联系人表,用于保存个人/联系人信息: CREATE TABLE contacts ( contact_id BIGINT UNSIGNED NOT NULL AUTO_INCREMEN
- 模型1:在外部世界(REST客户端)和我的SpringREST控制器之间使用;及
- 模型2:Spring Boot应用程序和MySQL数据库之间内部使用的实体
联系人
表,用于保存个人/联系人信息:
CREATE TABLE contacts (
contact_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
contact_ref_id VARCHAR(36) NOT NULL,
contact_first_name VARCHAR(100) NOT NULL,
...many more fields
);
相应的Spring/JPA/Hibernate实体可能如下所示:
// Groovy pseudo-code!
@Entity
class Contact {
@Id
@Column(name = "contact_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id
@Column(name = "contact_ref_id")
UUID refId
@Column(name = "contact_first_name")
String firstName
// ...etc.
}
如果我只有一个模型范例,那么当Jackson将一个联系人
实例(可能从DB取回)序列化为JSON并发送回客户端时,他们会看到JSON如下所示:
{
"id" : 45,
"refId" : "067e6162-3b6f-4ae2-a171-2470b63dff00",
"firstName" : "smeeb",
...
}
没有什么比向外界公开主键更重要的了!相反,我希望序列化的JSON省略id
字段(以及其他字段)。另一个示例可能是查找/引用表,如Colors
:
# Perhaps has 7 different color records for ROYGBIV
CREATE TABLE colors (
color_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
color_name VARCHAR(20) NOT NULL,
color_label VARCHAR(20) NOT NULL,
color_hexcode VARCHAR(20) NOT NULL,
# other stuff here
);
如果相应的颜色
实体如下所示:
@Entity
class Color {
@Id
@Column(name = "color_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id
@Column(name = "color_name")
String name
@Column(name = "color_label")
String label
@Column(name = "color_hexcode")
String hexcode
// ...etc.
}
然后,仅使用一个模型,它将序列化为JSON,如下所示:
{
"id" : 958,
"name" : "Red",
"label" : "RED",
"hexcode" : "ff0000"
}
但也许我只是想让它作为一个简单的字符串值返回:
{
"color" : "RED"
}
因此,在我看来,我要么需要两个独立的模型(以及在它们之间映射的映射器类),要么需要一种方法来注释我的实体,或者配置Spring、Jackson甚至Hibernate,以便在正确的时间对我的实体应用某些转换。这些框架是否提供了任何可以帮助我的东西,或者我必须在这里使用两个不同的域模型吗?实际上,您只需一个模型就可以实现这一点,我认为这是最简单的方法,如果您只需查找隐藏字段、自定义格式,属性的简单转换等。有两个模型需要从一个模型转换到另一个模型,反之亦然,这是一种痛苦。Jackson提供了许多有用的注释,可用于自定义输出。下面列出了一些对您有用的注释
@JsonIgnore
-忽略字段/属性。可以使用此批注隐藏id字段
@JsonInclude
-可用于指定输出中应出现字段的时间。例如:如果字段为空,则该字段是否应出现在输出中
@JsonSerialize
-您可以为属性指定自定义序列化程序。例如:您有一个属性“password”,并且希望将密码输出为“**”
@JsonFormat
-您可以对字段应用自定义格式。如果您有日期/时间字段,这非常有用
@JsonProperty
-如果要在输出中为字段指定其他名称。例如:您的模型中有一个字段“name”,您希望在输出中将其显示为“userName”。尽管可以使用注释和mixin控制Jackson序列化。对于DTO和实体,我总是有不同的类,对于它们的使用方式有不同的要求。如果不这样做,则必须处理诸如Hibernate惰性加载集合之类的无法序列化的问题,因为控制器方法退出后persistenceContext已关闭。如果使用Lombok,则创建DTO需要1分钟,并且可以根据需要在实体上创建任意多的DTO(视图)。