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

时间:2016-06-29 09:56:26

标签: java spring rest spring-data-rest hateoas

我将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

在我的例子中,我介绍了两个难点:列表(公司)和多个级别:person-&gt; company-&gt;地址。两者都需要工作(可能有5个级别,其中一些级别有很多&#39;很多关系)。

3 个答案:

答案 0 :(得分:14)

正如您所确定的那样,可接受的内联实体方法是预测。投影总是内联的,因此一个选项是为每个实体创建投影,并将它们组合起来:

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

}

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"
    }
  }
}

或者,如果您不需要将CompanyAddress实体公开为其他资源,则可以使用@RepositoryRestResource(exported=false)标记其存储库,并在任何地方对其进行内联它们被引用,无需任何预测。

最后需要注意的是 - 这个请求在某种程度上与Spring Data REST和Spring HATEOAS的精神作斗争,并邀请遭遇n + 1问题的大型,笨拙的查询。请记住,Spring Data REST不是将域模型转换为API的交钥匙解决方案,并且渲染深层对象图(如果这是您的意图)可能是您可能在临时基础上作为自定义控制器端点公开的内容可以彻底控制条件。

答案 1 :(得分:0)

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

答案 2 :(得分:-1)

我认为嵌入List或HashMap的最佳方法是将其转换为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);
  }
}

Spring Data with Mysql JSON type

所示

我们在Spring Data DynamoDb中有类似的东西 - 对于AWS DynamoDB