【发布时间】:2017-09-02 01:07:29
【问题描述】:
我正在设计一个由 MySQL 支持的 Spring Boot REST API。我突然想到,我想要为我的所有域对象创建两个独立的模型:
- 模型 1:在外部世界(REST 客户端)和我的 Spring REST 控制器之间使用;和
- 模型 2:Spring Boot 应用和 MySQL 数据库之间内部使用的实体
例如,我可能有一个 contacts 表用于保存个人/联系信息:
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 将 Contact 实例(可能从数据库中取回)序列化为 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
);
如果对应的Color 实体如下所示:
@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 以在我的实体上应用某些转换在正确的时间。这些框架是否提供了任何可以帮助我的东西,还是我必须在这里使用两个不同的领域模型?
【问题讨论】:
-
虽然可以使用注释和 Mixins 来控制 Jackson 序列化。我总是有不同的 DTO 和实体类,它们的使用方式只是不同的要求。如果您不这样做,您将不得不处理诸如 Hibernate 延迟加载集合之类的无法序列化的事情,因为在您的控制器方法退出后,persistenceContext 已关闭。如果您使用 Lombok,创建 DTO 需要 1 分钟,并且您可以在 Entity 上拥有任意数量的 DTO(视图)。
标签: json hibernate jpa spring-boot jackson