如何通过带有ALPS / HATEOAS元数据的Spring Data MongoDB存储库公开新的REST方法?

时间:2015-07-22 22:39:22

标签: mongodb spring-data spring-data-mongodb spring-hateoas

如何将MongoRepository扩展类中的新方法公开给生成的REST API,并包含相同的ALPS / HATEOAS元数据,链接等。

我有通常的Spring Data MongoDB存储库:

public interface CollectionRepository extends Repository<Collection, String> {    
    // Simple queries
    Collection findFirstByName(@Param("name") String name);   
}

现在我想添加另一个方法,并将其集成到生成的Repository REST API中,以便它与QueryDSL生成的元素一起包含在{repository} / collection / search响应中。

我被困在两件事上 1)使用PersistentEntityResourceAssembler和PersistentEntityResource提供参数并将响应转换为适当的格式。 2)自动生成HATEOAS / ALPS元数据,以便父URL在API浏览器中显示带参数的方法。

这是我的自定义控制器。 请注意,我必须在自动装配的模板上指定一个@Qualifier,因为我有多个数据库,并且选择了错误的默认值。

@Component
@RepositoryRestController
@RequestMapping(value = "{repository}/search")
public class CollectionRepositoryController implements ResourceProcessor<RepositorySearchesResource> {

    @Autowired private EntityLinks entityLinks;
    @Autowired private PagedResourcesAssembler pagedResourcesAssembler;
    @Autowired Repositories repositories;
    @Autowired
    @Qualifier("mongoTemplateCollections")
    private MongoTemplate mongoTemplate;
    private final CollectionRepository repository;
    @Autowired
    public CollectionRepositoryController(CollectionRepository repo) {
        repository = repo;
    }
    @SuppressWarnings("unchecked")
    @RequestMapping(value = "findText", method = RequestMethod.GET,
            produces = MediaType.APPLICATION_JSON_VALUE)
    public PagedResources<PersistentEntityResource> findText(
            Pageable pageable, @RequestParam(value = "findText", required = false) String findText,
            PersistentEntityResourceAssembler resourceAssembler) {
        TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingAny(findText);
        Query query = TextQuery.queryText(criteria).sortByScore();
        List<Collection> collections = mongoTemplate.find(query, Collection.class);
        Page<Collection> page = new PageImpl<Collection>(Arrays.asList(new Collection()), pageable, pageable.getOffset());

       // What goes below here to convert List<Collections> into PersistentEntityResource ?

        PersistentEntity<?, ?> persistentEntity = repositories.getPersistentEntity(Collection.class);
        for(Collection collection : collections) {
            PersistentEntityResource collectionResource = PersistentEntityResource.build(collection, persistentEntity).
                    withLink(new Link("/collection/" + collection.getId())).build();
            Log.info("collections resource: " + collectionResource);
        }

        return pagedResourcesAssembler.toResource(page, resourceAssembler);
    }

    // https://stackoverflow.com/questions/29570962/how-to-add-custom-methods-to-spring-data-rest-jpa-implementation-and-leverage-ha
    @Override
    public RepositorySearchesResource process(RepositorySearchesResource resource) {
        LinkBuilder lb = entityLinks.linkFor(Collection.class, "name");
        resource.add(new Link(lb.toString() + "/search/findText{?findText}", "findText"));
        return resource;
    }
}

我也创建了这个,但我不确定如何/在哪里连线:

@Component
public class CollectionResourceAssembler implements ResourceAssembler<Collection, Resource<Collection>> {

    @Autowired
    EntityLinks entityLinks;

    @Override
    public Resource<Collection> toResource(Collection collection) {
        Resource<Collection> resource = new Resource<Collection>(collection);

        final LinkBuilder lb = entityLinks.linkForSingleResource(Collection.class, collection.getId());
        resource.add(lb.withSelfRel());
        resource.add(lb.slash("answers").withRel("answers"));
        // other links

        return resource;
    }
}

我遇到麻烦的是“这里有什么东西”,这样就像奥利弗建议的那样:

  

调用存储库并使用PersistentEntityResourceAssembler   可注入到handler方法中来生成一个   PersistentEntityResource返回。

并且,我是否真的必须使用ResourceProcessor.process()方法手动设置ALPS / HATEOAS数据,还是有自动化的技巧?

这是一个无价的例子。我很确定SO中没有任何内容可以说明如何做到这一点,至少在我需要的手持水平上。 这个也很接近:Defining a resource assembler for a REST Spring HATEOAS controller但也假设比我知道的更多。

1 个答案:

答案 0 :(得分:2)

TL;博士

它需要存储库和控制器的自定义实现。

详细

我们必须确保我们不会在您提到的所有不同方面迷失方向。我试着从下到上解开树枝:

执行MongoDB脚本

作为reference documentation on executing scripts with MongoDB状态(您已经发现),功能已提供by MongoTemplate&#39; s ScriptOperations。因此,应该清楚如何使用该API。有关更多信息,请咨询Javadoc。

通过Spring Data存储库执行脚本

您要求的下一件事是通过存储库抽象执行这些脚本。为了不让宝宝在这里洗澡,请确保我们了解存储库的用途:它模拟聚合根的集合并访问它,而不暴露底层持久性机制。在存储库中公开类似ExecutableMongoScript的类型会破坏后者的特征。因此,正确的方法是为reference documentation on Spring Data repositories

中描述的特定功能制定自定义实现

通过REST公开功能

我假设您正在引用Spring Data REST的功能,以便在您的问题中为存储库查询方法公开专用资源。 Spring Data REST目前仅自动公开声明性查询方法,主要是因为我们很难推断出支持自定义实现的正确HTTP方法,因为我们无法猜测方法内部发生了什么。

使用符合您目的的@RequestMapping自定义控制器公开自定义存储库查询方法的推荐方法,调用存储库并在处理程序方法中使用PersistentEntityResourceAssembler注入来生成{{1}返回。