如何自行 Link 在 Spring 数据 REST 服务器中加载实体?

How to Load an Entity Inside a Spring Data REST Server by Self Link?

给定一个 Spring Data REST (SDR) server built with Spring Boot Gradle Plugin 2.2.5.RELEASE,是否可以通过自己 link 服务器应用程序中加载一个 @Entity

我知道如何使用 HTTP 客户端访问它,例如使用卷曲:

$ curl localhost/users/1 # Responds with 200 OK and JSON representation

我正在寻找的是一种仅使用 Java 在服务器中执行此操作的机制,最好使用标准 SDR 机制:

@Service
public class SelfLinkResolver {

    public Object findBySelfLink(Link self) {
        if (self == null || !self.getRel().equals(SELF)) {
            throw new IllegalArgumentException("Non-null self link expected");
        }
        return null; // How to return the entity using a standard SDR mechanism?
    }

    public void exampleCall() {
        Link self = new Link("localhost/users/1");
        Object entity = findBySelfLink(self);
        requireNonNull(entity, "Failed to load entity by self link");
    }

}

内部解决方案是解析您的 link 并提取 ID(在您的示例中为 1),调用 repository.findById(id).

另一种解决方案是新建 RestTemplate,调用您自己的 API。

我终于想到了这个解决方案,它使用了 SDR UriToEntityConverter。与我的问题相反,它不仅需要自我link,还需要实体class。因此它没有完全回答我最初的问题。

猜测没有不需要实体class的SDR解决方案,因为在框架内不需要这个,至少对于通常情况API 来电。 SDR 始终通过 Repository 提供类型信息,自身 link 引用。但是,我没有深入研究其他 class,例如 PersistentEntitiesRepositoryInvokerFactoryRepositories,它们可能会为此提供解决方案。

警告:我测试的实现与此不同。此代码未经测试,但应该可以说明这个想法。

import lombok.NonNull;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.data.repository.support.Repositories;
import org.springframework.data.repository.support.RepositoryInvokerFactory;
import org.springframework.data.rest.core.UriToEntityConverter;
import org.springframework.hateoas.Link;
import org.springframework.stereotype.Component;

import java.net.URI;
import java.util.Optional;

import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static org.springframework.hateoas.IanaLinkRelations.SELF;

@Component
public class SelfLinkToEntityConverter extends UriToEntityConverter {

    private static final TypeDescriptor URI_DESCRIPTOR = TypeDescriptor.valueOf(URI.class);

    SelfLinkToEntityConverter(@NonNull PersistentEntities entities,
                              @NonNull RepositoryInvokerFactory invokerFactory,
                              @NonNull Repositories repositories) {
        super(entities, invokerFactory, repositories);
    }

    @NonNull
    public <T> Optional<T> findBySelfLink(@NonNull Link self, @NonNull Class<T> entityClass) {
        checkArgument(self.getRel().equals(SELF), "Non-null self link expected");

        URI uri = self.expand().toUri();
        TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(entityClass);

        try {
            @SuppressWarnings("unchecked")
            T entity = (T) super.convert(uri, URI_DESCRIPTOR, typeDescriptor);

            return Optional.ofNullable(entity);
        } catch (IllegalArgumentException o_O) {
            throw new IllegalArgumentException(format("Failed to load %s: %s",
                    entityClass.getSimpleName(), self.getHref()));
        }
    }

}