Spring Data REST和JPA @OneToMany重复"_links"

3
我遇到了一个问题,使用Spring Data JPA时使用Spring Data Rest。我正在使用Spring-boot 1.4.4.RELEASE。
这是我的spring-data-rest存储库:
public interface ProfileJpaRepository extends JpaRepository<Profile, Long> {
}

这是我的实体(为了简洁起见,未显示getter和setter)。

Profile.java:

@Entity
@Table(name = "PROFILE")
public class Profile {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;

    private String description;

    // Don't use mappedBy="profile" because attributes are not persisted properly
    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "PROFILE_ID")
    private Set<Attribute> attributes;

    ...
}

Attribute.java

@Entity
@Table(name = "ATTRIBUTE")
public class Attribute {

     @Id
     @GeneratedValue(strategy=GenerationType.AUTO)
     @Column(name = "ID")
     private Long id;

     private String uri;

     @ManyToOne(fetch = FetchType.EAGER)
     private Profile profile;

     @ElementCollection(fetch = FetchType.EAGER)
     @CollectionTable(name="ATTRIBUTE_DATAS")
     private List<String> datas = new ArrayList<>();

     public Attribute() {}

     public Attribute(String uri, List<String> datas) {
        this.uri = uri;
        this.datas = datas;
    }

    ...
}

在 "http://localhost:8880/profiles" 上发送POST请求以创建实体:
{
    "description" : "description-value",
    "attributes" : [
        {
            "uri" : "uri-a",
            "datas" : ["uri-a-value"]
        },
        {
            "uri" : "uri-b",
            "datas" : ["uri-b-value"]
        }
    ]
}

这是我点击http://localhost:8880/profiles后的结果:
{
  "_embedded" : {
    "profiles" : [ {
      "description" : "description-value",
      "attributes" : [ {
        "uri" : "uri-a",
        "datas" : [ "uri-a-value" ],
        "_links" : {
          "profile" : {
            "href" : "http://localhost:8880/profiles/1"
          }
        }
      }, {
        "uri" : "uri-b",
        "datas" : [ "uri-b-value" ],
        "_links" : {
          "profile" : {
            "href" : "http://localhost:8880/profiles/1"
          }
        }
      } ],
      "_links" : {
        "self" : {
          "href" : "http://localhost:8880/profiles/1"
        },
        "profile" : {
          "href" : "http://localhost:8880/profiles/1"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8880/profiles"
    },
    "profile" : {
      "href" : "http://localhost:8880/profile/profiles"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}

我认为存在一个问题,因为在每个属性下都指定了"_links"。相反,我会期望类似这样的东西:
{
  "_embedded" : {
    "profiles" : [ {
      "description" : "description-value",
      "attributes" : [ {
        "uri" : "uri-a",
        "datas" : [ "uri-a-value" ]
      }, {
        "uri" : "uri-b",
        "datas" : [ "uri-b-value" ]
      } ],
      "_links" : {
        "self" : {
          "href" : "http://localhost:8880/profiles/1"
        },
        "profile" : {
          "href" : "http://localhost:8880/profiles/1"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8880/profiles"
    },
    "profile" : {
      "href" : "http://localhost:8880/profile/profiles"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}

请注意,我已经从MongoRepository切换到JpaRepository,并且在使用MongoRepository时,这些“_links”没有“重复”。
有人能够解释一下吗?我是否在我的JPA实体上配置了错误的设置?我需要在rest存储库中进行某些配置吗?
如果您需要更多关于依赖版本的信息,请单击此处查看,我没有覆盖这些(http://docs.spring.io/spring-boot/docs/1.4.4.RELEASE/reference/html/appendix-dependency-versions.html
谢谢。

你知道在你的代码中_links是如何/为什么生成的吗?我猜想这是在JSON串行化期间发生的,但我从未在使用默认配置时遇到过它们。 - Torsten N.
2
@TorstenN.,这是由ProfileJpaRepository自动完成的,Spring Data Rest会看到它扩展了JpaRepository并且“使用HAL作为媒体类型公开可发现的REST API来处理您的领域模型”,自动地完成了这个过程。 - Nis
1个回答

1
为了解决这个问题,我一直在使用投影(更多信息请参见此处:http://docs.spring.io/spring-data/rest/docs/current/reference/html/#projections-excerpts)。发布时我不知道这个功能。
我必须注释我的存储库并告诉它使用我的InlineAttributes投影。
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

@RepositoryRestResource(excerptProjection = InlineAttributes.class)
public interface ProfileJpaRepository extends JpaRepository<Profile, Long> {
}

在Attribute类中,我不得不添加@JsonIgnore注释:
import com.fasterxml.jackson.annotation.JsonIgnore;

@Entity
@Table(name = "ATTRIBUTE")
public class Attribute {
     ...

     @ManyToOne(fetch = FetchType.EAGER)
     @JsonIgnore
     private Profile profile;

     ...
}

我需要创建一个InlineAttributes投影类。由于顺序不同,我进行了指定:

import org.springframework.data.rest.core.config.Projection;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;    

@Projection(name = "inlineAttributes", types = { Profile.class })
@JsonPropertyOrder({ "description", "attributes" })
public interface InlineAttributes {

    public String getDescription();
    public Set<Attribute> getAttributes();
}

然后在调用 REST 端点时需要应用投影:

http://localhost:8880/profiles?projection=inlineAttributes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接