Java SpringDataREST如何内联添加嵌入式资源

Java SpringDataREST如何内联添加嵌入式资源,java,spring,rest,spring-data-rest,hateoas,Java,Spring,Rest,Spring Data Rest,Hateoas,我将SpringDataREST和Hateoas与HAL浏览器结合使用。这非常有效,但现在我想对一个特定实体及其关联对象(一组)进行JSON转储。我用了@Projection,但后来又卡住了 仅供参考:除了新端点(无嵌入和链接)外,正常行为(带有嵌入和链接等)应保持不变 为了进一步说明我的问题: class Person { String name; List<Company> companies; } class Company { String name; Ad

我将SpringDataREST和Hateoas与HAL浏览器结合使用。这非常有效,但现在我想对一个特定实体及其关联对象(一组)进行JSON转储。我用了
@Projection
,但后来又卡住了

仅供参考:除了新端点(无嵌入和链接)外,正常行为(带有嵌入和链接等)应保持不变

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

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

class Company {
  String name;
  Address address;
}

class Address {
  String street;
}
当我得到这个:

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


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

在第二个端点中,如果您不需要链接,则必须有一个控制器和一个资源,其中您将数据映射到资源,并从控制器返回资源集合

可接受的实体内联方法是投影,正如你所说的。投影始终是内联的,因此一个选项是为每个实体创建投影,并按如下方式组合它们:

@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();

}
或者,如果您不需要将
公司
地址
实体公开为rest资源,您可以使用
@RepositoryRestResource(exported=false)
标记它们的存储库,它们将被内联到引用的任何位置,而不需要任何投影


不过,最后一点需要注意的是,这个请求在某种程度上与SpringDataREST和SpringHateOAS的精神格格不入,并引发了n+1问题的大而笨拙的查询。请记住,SpringDataREST不是将域模型转换为API并呈现深层对象图(如果您有意的话)的交钥匙解决方案是一种潜在的东西,您可以在特定的基础上公开为自定义控制器端点,这样您可以完全控制条件。

我认为嵌入列表或哈希映射的最佳方法是将其转换为json字符串,并在读取时返回java对象

这可以通过使用

    @Convert(converter = PluginAnalyzerConfigConverter.class)
  private PluginAnalyzerConfig configuration;
//in Entity Class

// declare a converter class like this
public class PluginAnalyzerConfigConverter implements
    AttributeConverter<PluginAnalyzerConfig, String> {

  @Override public String convertToDatabaseColumn(PluginAnalyzerConfig config) {
    Gson parser = new Gson();
    return parser.toJson(config, PluginAnalyzerConfig.class);
  }

  @Override public PluginAnalyzerConfig convertToEntityAttribute(String source) {
    Gson parser = new Gson();
    return parser.fromJson(source, PluginAnalyzerConfig.class);
  }
}
@Convert(converter=PluginAnalyzerConfigConverter.class)
私有插件分析配置;
//在实体类中
//像这样声明一个转换器类
公共类PluginAnalyzerConfigConverter实现
属性转换器{
@重写公共字符串convertToDatabaseColumn(PluginAnalyzerConfig配置){
Gson parser=new Gson();
返回parser.toJson(config,PluginAnalyzerConfig.class);
}
@重写公共插件AnalyzerConfig convertToEntityAttribute(字符串源){
Gson parser=new Gson();
返回parser.fromJson(源代码,PluginAnalyzerConfig.class);
}
}
如图所示


我们在Spring Data DynamoDb中也有类似的功能—对于AWS DynamoDb,您可以不使用Spring Data REST。SpringDataREST对如何正确使用Rest持有一种固执己见的观点,即包括关系的链接,而不是完整的实体。谢谢Deinum。Spring数据Rest位于类路径上,并且必须保持在那里。那么你的评论还适用吗?嵌入链接对象值的其他方法:谢谢Fahad,但你能说明你的意思吗?你指的是
@控制器
@资源
还是更多?在您的视图中,这种数据映射是如何工作的?我所说的资源是指,一个与您想要的信息的实体相似的类。您可以使用dozer bean mapper将数据映射到资源。当关系也指向另一个方向(从地址到公司,从公司到个人)时,可能会出现问题。非spring数据rest方法将显示所有内容(无限递归循环).
@JsonIgnore
在本例中不是一个选项,因为这样hatoas视图将不正确地呈现。我还没有对此进行测试,但对我来说这似乎是合乎逻辑的。
{
  "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"
    }
  }
}
    @Convert(converter = PluginAnalyzerConfigConverter.class)
  private PluginAnalyzerConfig configuration;
//in Entity Class

// declare a converter class like this
public class PluginAnalyzerConfigConverter implements
    AttributeConverter<PluginAnalyzerConfig, String> {

  @Override public String convertToDatabaseColumn(PluginAnalyzerConfig config) {
    Gson parser = new Gson();
    return parser.toJson(config, PluginAnalyzerConfig.class);
  }

  @Override public PluginAnalyzerConfig convertToEntityAttribute(String source) {
    Gson parser = new Gson();
    return parser.fromJson(source, PluginAnalyzerConfig.class);
  }
}