【问题标题】:Mapping JSON object to Hibernate entity将 JSON 对象映射到 Hibernate 实体
【发布时间】:2014-03-29 10:17:09
【问题描述】:

我将启动一个使用 Spring 和 Hibernate 管理模型的 REST 应用程序项目。

我知道 Spring 允许您从 HTTP 请求中获取 Java 对象(带有@Consumes(JSON) 注释)。如果这个 Java 对象也是一个 Hibernate 实体,会不会有冲突?嵌套对象是否有效(如@ManyToOne 关系)?

【问题讨论】:

    标签: java json spring hibernate rest


    【解决方案1】:

    我们使用这种方法来简化设计并摆脱许多 dto(我们滥用它们太多了)。基本上,它对我们有用。

    但是,在我们的 REST 模型中,我们试图不公开对象的其他关系,因为您始终可以创建另一个 REST 资源来访问它们。

    因此,我们只需将 @JsonIgnore 注释添加到关系映射中,例如 @OneToMany@ManyToOne,使它们成为瞬态的。

    另一个问题我看到,如果您仍然想返回这些关系,则必须对它们使用 Join.FETCH 策略或将事务管理移到更高的位置,以便在将响应序列化为 JSON 时事务仍然存在(在视图中打开会话模式)。 在我看来,这两种解决方案都不是很好。

    【讨论】:

    • 如果我添加了 use @JsonIgnore 注释但我仍然需要两个不同的对象,我可以从我的 HTTP 请求中获取两个参数吗? (比如那种方法:public void createPeople(@RequestBody AnEntity entityOne, AnOtherEntity entityTwo) {...}
    • 据我所知,您只能将请求正文映射到一个对象。所以我不太确定这是可能的。但是请注意,如果需要,您可以将 @JsonIgnore 分别用于序列化/反序列化,方法是将其分别放在 getter/setter 上。另外我仍然相信在一个请求中创建对象及其关系并不是那么 RESTful。我会创建另一个 REST 端点来保存对象关系并使用它。
    【解决方案2】:

    您可以在不使用 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
       }
    }  
    

    【讨论】:

      【解决方案3】:

      是的,这不是问题,实际上是一种相当普遍的做法。

      近年来,我开始意识到,有时候,始终直接基于您的域构建视图并不是一个好主意。你可以看看这个帖子:

      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 注释,但是如果您在其他视图中需要它,那您就完蛋了

      这是一个非常基本的示例,但您应该明白,由于代码可维护性和性能问题,有时您的域模型无法立即用于返回到表示层。

      【讨论】:

      【解决方案4】:

      Maven 依赖

      你需要做的第一件事是在你的项目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;
      • 当然。这更容易。您可以改用此示例来存储/检索 JsonNode。
      【解决方案5】:

      既然你刚刚开始,也许你可以使用 Spring Data REST?

      这是项目:http://projects.spring.io/spring-data-rest/

      这里有一些简单的例子:

      正如您在示例中看到的那样,除了 @Entity 注释的 POJO 之外,没有额外的 DTO。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-09-15
        • 2013-04-05
        • 2019-05-27
        • 1970-01-01
        相关资源
        最近更新 更多