【发布时间】:2014-03-29 10:17:09
【问题描述】:
我将启动一个使用 Spring 和 Hibernate 管理模型的 REST 应用程序项目。
我知道 Spring 允许您从 HTTP 请求中获取 Java 对象(带有@Consumes(JSON) 注释)。如果这个 Java 对象也是一个 Hibernate 实体,会不会有冲突?嵌套对象是否有效(如@ManyToOne 关系)?
【问题讨论】:
标签: java json spring hibernate rest
我将启动一个使用 Spring 和 Hibernate 管理模型的 REST 应用程序项目。
我知道 Spring 允许您从 HTTP 请求中获取 Java 对象(带有@Consumes(JSON) 注释)。如果这个 Java 对象也是一个 Hibernate 实体,会不会有冲突?嵌套对象是否有效(如@ManyToOne 关系)?
【问题讨论】:
标签: java json spring hibernate rest
我们使用这种方法来简化设计并摆脱许多 dto(我们滥用它们太多了)。基本上,它对我们有用。
但是,在我们的 REST 模型中,我们试图不公开对象的其他关系,因为您始终可以创建另一个 REST 资源来访问它们。
因此,我们只需将 @JsonIgnore 注释添加到关系映射中,例如 @OneToMany 或 @ManyToOne,使它们成为瞬态的。
另一个问题我看到,如果您仍然想返回这些关系,则必须对它们使用 Join.FETCH 策略或将事务管理移到更高的位置,以便在将响应序列化为 JSON 时事务仍然存在(在视图中打开会话模式)。
在我看来,这两种解决方案都不是很好。
【讨论】:
@JsonIgnore 注释但我仍然需要两个不同的对象,我可以从我的 HTTP 请求中获取两个参数吗? (比如那种方法:public void createPeople(@RequestBody AnEntity entityOne, AnOtherEntity entityTwo) {...})
@JsonIgnore 分别用于序列化/反序列化,方法是将其分别放在 getter/setter 上。另外我仍然相信在一个请求中创建对象及其关系并不是那么 RESTful。我会创建另一个 REST 端点来保存对象关系并使用它。
您可以在不使用 REST Web 服务 (Jersy) 上的任何库的情况下映射 json 请求
此代码示例:
这个名为 book 的休眠实体:
@Entity
@Table(name = "book", schema = "cashcall")
public class Book implements java.io.Serializable {
private int id;
private Author author; // another hibernate entity
private String bookName;
//setters and getters
}
这个网络服务功能
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public String addBook(Book book) {
String bookName=book.getName();
return bookName;
}
这是示例 json 请求:
{
"bookName" : "Head First Java",
"author" : {
"id" : 1
}
}
【讨论】:
是的,这不是问题,实际上是一种相当普遍的做法。
近年来,我开始意识到,有时候,始终直接基于您的域构建视图并不是一个好主意。你可以看看这个帖子:
http://codebetter.com/jpboodhoo/2007/09/27/screen-bound-dto-s/
也称为“演示模型”:
http://martinfowler.com/eaaDev/PresentationModel.html
其背后的思路基本如下:
想象一下你有一个域条目用户,他看起来像这样:
@Entity
@Data
public class User {
@Id private UUID userId;
private String username;
@OneToMany private List<Permission> permissions;
}
现在让我们假设您有一个要显示该用户名的视图,而您完全不关心权限。如果您使用立即将用户返回到视图的方法,Hibernate 将从 Permissions 表中进行附加连接,因为尽管默认情况下会延迟加载权限,但没有简单的方法可以向 jackson 序列化程序或任何您发出信号使用,在这个特定的场合你不关心它们,所以杰克逊会尝试取消代理它们(如果你的事务在你的对象被放入 json 序列化时仍然存在,否则你会得到一个讨厌的异常)。是的,您可以在权限字段中添加@JsonIgnore 注释,但是如果您在其他视图中需要它,那您就完蛋了。
这是一个非常基本的示例,但您应该明白,由于代码可维护性和性能问题,有时您的域模型无法立即用于返回到表示层。
【讨论】:
你需要做的第一件事是在你的项目pom.xml配置文件中设置如下Hibernate TypesMaven依赖:
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>${hibernate-types.version}</version>
</dependency>
现在,如果您使用的是 PostgreSQL,则需要使用 Hibernate Types 中的 JsonType。
为了在您的实体中使用它,您必须在类级别或 package-info.java 包级别描述符中声明它,如下所示:
@TypeDef(name = "json", typeClass = JsonType.class)
而且,实体映射将如下所示:
@Type(type = "json")
@Column(columnDefinition = "json")
private Location location;
如果您使用的是 Hibernate 5 或更高版本,则 JSON 类型将由 Postgre92Dialect 自动注册。
否则需要自己注册:
public class PostgreSQLDialect extends PostgreSQL91Dialect {
public PostgreSQL92Dialect() {
super();
this.registerColumnType( Types.JAVA_OBJECT, "json" );
}
}
JsonType 也适用于 Oracle、SQL Server、PostgreSQL、MySQL 和 H2。查看the project 页面,了解有关如何在各种关系数据库系统上映射 JSON 列类型的更多详细信息。
【讨论】:
Location,是否可以存储通用JSON对象?例如,@Type(type = "jsonb") @Column(columnDefinition = "json") private JSONObject document;
既然你刚刚开始,也许你可以使用 Spring Data REST?
这是项目:http://projects.spring.io/spring-data-rest/
这里有一些简单的例子:
正如您在示例中看到的那样,除了 @Entity 注释的 POJO 之外,没有额外的 DTO。
【讨论】: