使用Spring projection Data REST HATEOAS的嵌套资源中缺少的链接

时间:2019-06-07 08:51:46

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

我正在使用Spring Boot 2.x,Spring Data REST,Spring HATEOAS,Spring JPA,Hibernate。 我知道this question,但是它已经很老了,我想详细说明一下我的情况。

我有两个像这样的简单豆子:

@Entity
@Data
public class Contact extends AbstractEntity {
    private String sid;

    private String firstName;

    private String lastName;

    private String companyName;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "store_id", updatable = false)
    private Store store;

    //more custom fields
}

和:

@Entity
@Data
public class Store extends AbstractEntity {

    private String code;

    private String name;

    private String sid;

    //more custom fields
}

我正在通过REST公开存储库:

@Transactional
@PreAuthorize("isAuthenticated()")
public interface ContactRepository extends JpaRepository<Contact, Long> {
}

@Transactional
@PreAuthorize("isAuthenticated()")
public interface StoreRepository extends JpaRepository<Store, Long>, StoreCustomRepository<Store, Long> {
}

如果我致电http://localhost:8082/api/v1/contacts/1,我会得到:

{
    "sid": "962732c2-68a8-413b-9762-f676d42046b4",
    "createdBy": "1ccf2329-4aa3-4d55-8878-25517edf1522",
    "createdDate": "2019-05-28T14:06:07.011Z",
    "lastModifiedDate": "2019-06-04T08:46:02.591Z",
    "lastModifiedBy": "system",
    "createdByName": "Agent",
    "lastModifiedByName": null,
    "type": "CUSTOMER",
    "personType": "NATURAL_PERSON",
    "firstName": "Daniele",
    "lastName": "LastName",
    "companyName": null,
    "fullName": "Full name",
    "gender": "MALE",
    "birthDate": "2019-05-21T00:00:00Z",
    "birthCity": null,
    "job": null,
    "billingAddress": "Via 123",
    "billingZipCode": "14018",
    "billingCity": "Roatto",
    "billingDistrict": "AT",
    "billingCountry": "IT",
    "shippingAddress": "Via 123",
    "shippingZipCode": "14018",
    "shippingCity": "Roatto",
    "shippingDistrict": "AT",
    "shippingCountry": "IT",
    "taxCode": "",
    "vatNumber": null,
    "landlinePhone": null,
    "mobilePhone": null,
    "fax": null,
    "email": "aaa@sdfg.it",
    "certifiedEmail": null,
    "survey": null,
    "iban": null,
    "swift": null,
    "publicAdministration": false,
    "sdiAccountId": "0000000",
    "preset": false,
    "_links": {
        "self": {
            "href": "http://localhost:8082/api/v1/contacts/1"
        },
        "contact": {
            "href": "http://localhost:8082/api/v1/contacts/1{?projection}",
            "templated": true
        },
        "notes": {
            "href": "http://localhost:8082/api/v1/contacts/1/notes"
        },
        "auditLogs": {
            "href": "http://localhost:8082/api/v1/contacts/1/auditLogs"
        },
        "media": {
            "href": "http://localhost:8082/api/v1/contacts/1/media"
        },
        "privacyAgreements": {
            "href": "http://localhost:8082/api/v1/contacts/1/privacyAgreements"
        },
        "eyeExams": {
            "href": "http://localhost:8082/api/v1/contacts/1/eyeExams"
        },
        "contactLensEyeTests": {
            "href": "http://localhost:8082/api/v1/contacts/1/contactLensEyeTests"
        },
        "eyeExamsCount": {
            "href": "http://localhost:8082/api/v1/contacts/1/eyeExams/count"
        },
        "documents": {
            "href": "http://localhost:8082/api/v1/contacts/1/documents"
        },
        "pendingSalesOrders": {
            "href": "http://localhost:8082/api/v1/contacts/1/pendingSalesOrders"
        },
        "latestPurchasedFrames": {
            "href": "http://localhost:8082/api/v1/contacts/1/latestPurchasedFrames"
        },
        "latestPurchasedItems": {
            "href": "http://localhost:8082/api/v1/contacts/1/latestPurchasedItems"
        },
        "latestSoldItems": {
            "href": "http://localhost:8082/api/v1/contacts/1/latestSoldItems"
        },
        "latestDocuments": {
            "href": "http://localhost:8082/api/v1/contacts/1/latestDocuments"
        },
        "store": {
            "href": "http://localhost:8082/api/v1/contacts/1/store{?projection}",
            "templated": true
        }
    }
}

如Spring Data REST文档所述,如果有相关资源(存储)的存储库,它将显示为链接,并且未嵌入。

我还使用https://github.com/bohnman/squiggly-java来动态选择字段。最终目标是调用联系人端点,仅选择很少的联系人字段,并使嵌套商店仅包含代码和自我链接。

所以我想收到这样的答复:

{
    "store": {
        "code": "RO",
        "_links": {
            "self": {
                "href": "http://localhost:8082/api/v1/stores/1{?projection}",
                "templated": true
            }
        }
    },
    "lastName": "LastName",
    "_links": {
        "self": {
            "href": "http://localhost:8082/api/v1/contacts/1"
        },
        "contact": {
            "href": "http://localhost:8082/api/v1/contacts/1{?projection}",
            "templated": true
        },
        "store": {
            "href": "http://localhost:8082/api/v1/contacts/1/store{?projection}",
            "templated": true
        }
    }
}

要拥有嵌入式嵌套资源,我必须创建一个投影:

@Projection(名称=“内联”,类型= {Contact.class}) 公共接口ContactInlineProjection {

String getFirstName();

String getLastName();

Store getStore();

//All other fields

}

但是结果没有嵌套资源的链接:

{
    "store": {
        "code": "RO"
    },
    "lastName": "LastName",
    "_links": {
        "self": {
            "href": "http://localhost:8082/api/v1/contacts/1"
        },
        "contact": {
            "href": "http://localhost:8082/api/v1/contacts/1{?projection}",
            "templated": true
        },
        "store": {
            "href": "http://localhost:8082/api/v1/contacts/1/store{?projection}",
            "templated": true
        }
    }
}

为了使其工作,我还必须为Store创建一个投影:

@Projection(name = "inline", types = {Store.class})
public interface StoreLightProjection {

    String getName();

    String getCode();
    //other fields
}

,然后将“联系人投影”更改为:

@Projection(name = "inline", types = {Contact.class})
public interface ContactInlineProjection {


    String getFirstName();

    String getLastName();

    StoreLightProjection getStore();
}

这样做,回复看起来就像我想要的。这是正常现象还是潜在的错误?有没有其他方法可以用更少的代码来实现目标?

0 个答案:

没有答案
相关问题