首页 文章

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

提问于
浏览
10

我正在将Spring Data REST和Hateoas与HAL浏览器结合使用 . 这很好用,但现在我想用一组特定的实体和一组相关的对象进行JSON转储 . 我使用了 @Projection 然后又被卡住了 .

仅供参考:正常行为(包含嵌入式和链接等)应保留在新 endpoints 之外(没有嵌入式和链接) .

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

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个级别,其中一些级别有“很多”关系) .

3 回答

  • 11

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

    @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的交钥匙解决方案,并且渲染深层对象图(如果这是您的意图)可能是您可能在临时基础上作为自定义控制器 endpoints 公开的内容可以彻底控制条件 .

  • 0

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

  • -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

相关问题