将@RequestBody 中的 HAL URI 映射到 Spring Data Rest 托管实体

xsr*_*ity 7 spring-mvc spring-data spring-data-rest spring-hateoas

我使用 Spring Data JPA 来管理 JPA 实体,Spring Data Rest 将存储库导出到 REST API。

我还在构建一个自定义控制器,我想在其中获取实体的 URI(HAL 链接)并通过CrudRepository.

自定义控制器

@RequestMapping(path = MeLinks.ELEVATE, method = RequestMethod.PUT, consumes = RestMediaTypes.TEXT_URI_LIST_VALUE)
HttpEntity<?> elevate(@RequestBody @Valid CollectionModel<Contact> contact) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

当尝试使用 Content-Type 之PUT类的联系链接时,我可以使用而不是 Contact 对象本身访问链接。http://localhost:8080/contacts/1text/uri-listcontact.getLinks()

Spring Data Rest 是否可以从 URI 自动推断实体?我知道一个内置的,UriToEntityConverter但我如何使用它?

编辑

这是一种有效但并没有真正优雅地解决问题的尝试。

下面的代码初始化 aUriToEntityConverter并将传入的 URI 转换为域对象。

@Autowired
private ApplicationContext applicationContext;

@Autowired
private MappingContext<?, ?> mappingContext;

@RequestMapping(path = MeLinks.ELEVATE, method = RequestMethod.PUT, consumes = RestMediaTypes.TEXT_URI_LIST_VALUE)
HttpEntity<?> elevate(@RequestBody @Valid CollectionModel<Contact> uris) {

    URI uri = URI.create(uris.getLinks().get(0).getHref());

    Repositories repositories = new Repositories(applicationContext);

    PersistentEntity<?,?> contactPersistentEntity = repositories.getPersistentEntity(Contact.class);

    UriToEntityConverter uriToEntityConverter = new UriToEntityConverter(
        new PersistentEntities(Collections.singleton(mappingContext)), 
        new DefaultRepositoryInvokerFactory(repositories), 
        repositories);

    Contact t = (Contact) uriToEntityConverter.convert(uri, TypeDescriptor.valueOf(URI.class), TypeDescriptor.valueOf(Contact.class));
}
Run Code Online (Sandbox Code Playgroud)

可以想象,从 中获取域对象Repository比上面的要容易得多。假设 URI 使用ID链接的唯一部分,这也有效。就我而言,我已将其自定义为使用 UUID。所以默认行为是UriToEntityConverter行不通的。

注意:HATEOAS 首次发布时已将Resources重命名CollectionModel

Dan*_*iel 1

如果您想继续使用,UriToEntityConverter我建议您查看Spring Data REST 文档的这一部分,以使用该类将资源 URI 自定义为不同的属性EntityLookupSupport<T>。然后应该UriToEntityConverter正确返回实体。

如果您希望按照您的说明直接使用存储库,请考虑以下事项:

看源码UriToEntityConverter,它使用URI的最后一部分作为对象的标识符。你也可以这样做。(在此代码片段中,我刚刚修改了上面的代码,假设您正确检索了对象URI

private ContactRepository contactRepository;

// You should use constructor injection, as it is preferred over field injection.
@Autowired
public CustomController(ContactRepository contactRepository){
    this.contactRepository = contactRepository;
}


@RequestMapping(path = MeLinks.ELEVATE, method = RequestMethod.PUT, consumes = RestMediaTypes.TEXT_URI_LIST_VALUE)
HttpEntity<?> elevate(@RequestBody @Valid CollectionModel<Contact> uris) {
    URI uri = URI.create(uris.getLinks().get(0).getHref());

    Optional<Contact> optionalContact = contactRepository.findByName(getLastUriPart(uri));

    if (optionalContact.isPresent()){
        return optionalContact.get();
    } else {
        // Error handling
    }
}

private String getLastUriPart(URI uri) {
    String[] uriParts = uri.getPath().split("/");

    if (uriParts.length < 2) {
        // Error handling
    }

    return uriParts[uriParts.length - 1];
}
Run Code Online (Sandbox Code Playgroud)