Spring Data REST 如何内联添加嵌入式资源

2022-09-04 20:20:16

我正在将Spring Data REST和Hateoas与HAL浏览器结合使用。这很完美,但现在我想使用(一组)其关联对象对特定实体进行JSON转储。我用过,但后来我又卡住了。@Projection

仅供参考:正常行为(带有嵌入式和链接等)应保留在新端点之外(没有嵌入式和链接)。

为了进一步说明我的问题/问题:

class Person {
  String name;
  List<Company> companies;
}

class Company {
  String name;
  Address address;
}

class Address {
  String street;
}

现在我希望看到这样的东西:

{
   "name": "John",
   "companies": [
        {
            "name": "Stackoverflow",
            "address": {"street": "Highway blvd."}
        },
        {
            "name": "Oracle",
            "address": {"street": "Main rd."}
        }
   ]
}

当我得到这个:

{
   "name": "John",
   "_links": {
        "self": {"href": "http...."},
        "companies": {"href": "http ..."}
   },
}

参见:http://docs.spring.io/spring-data/rest/docs/current/reference/html/#projections-excerpts

在我的例子中,我介绍了我遇到的两个困难:列表(公司)和多个级别:人员>公司>地址。两者都需要工作(可能是5个级别,其中一些具有“许多”关系)。


答案 1

内联实体的可接受方法是投影,如您所标识的那样。投影始终是内联的,因此一种选择是为每个实体创建投影并按如下方式组合它们:

@Projection(name = "personProjection", types = Person.class)
public interface PersonProjection {

    String getFirstName();
    List<CompanyProjection> getCompanies();

}

@Projection(name = "companyProjection", types = Company.class)
public interface CompanyProjection {

    String getName();
    AddressProjection getAddress();

}

@Projection(name = "addressProjection", types = Address.class)
public interface AddressProjection {

    String getStreet();

}

A 仍将呈现元素,但您将获得所需的嵌套:GET people/1?projection=personProjection_links

{
  "companies" : [ {
    "address" : {
      "street" : "123 Fake st",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/addresses/1{?projection}",
          "templated" : true
        }
      }
    },
    "name" : "ACME inc.",
    "_links" : {
      "self" : {
        "href" : "http://localhost:8080/companies/1{?projection}",
        "templated" : true
      },
      "address" : {
        "href" : "http://localhost:8080/companies/1/address"
      }
    }
  } ],
  "firstName" : "Will",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people/1"
    },
    "person" : {
      "href" : "http://localhost:8080/people/1{?projection}",
      "templated" : true
    },
    "companies" : {
      "href" : "http://localhost:8080/people/1/companies"
    }
  }
}

或者,如果不需要将 和 实体公开为 rest 资源,则可以使用 标记其存储库,并且它们将内联到引用它们的任何位置,而无需任何投影。CompanyAddress@RepositoryRestResource(exported=false)

不过,最后一点需要注意的是,这个请求在某种程度上与Spring Data REST和Spring HATEOAS的精神作斗争,并邀请了遭受n + 1问题的大而笨拙的查询。请记住,Spring Data REST 不是将域模型转换为 API 的统包解决方案,并且呈现深层对象图(如果这是您的意图)可能是您可以临时公开为自定义控制器终结点的东西,您可以在其中彻底控制条件。


答案 2

在第二个终结点中,如果你不需要链接,你必须有一个控制器和资源,在那里你可以将数据映射到资源,并从控制器返回资源集合。