Spring 数据 REST:一个实体的多个端点

Spring Data REST: Multiple endpoints for one entity

前提:
Web 服务通过 REST 公开其数据。每条记录都属于创建该记录的用户(行级安全性)。用户只能检索自己的记录。

@RepositoryRestResource(path = "talks")
public interface TalkRepository extends PagingAndSortingRepository<Talk, Long> {

    @Override
    @Query("select t from Talk t where t.owner.id= ?#{principal?.id}")
    Page<Talk> findAll(Pageable pageable);
}

该存储库现在可在 /talks 端点下使用。

问题:
有没有办法 1) 在多个端点公开相同的域实体和 2) 根据端点定义不同的 @Query 注释?

此问题与 https://jira.spring.io/browse/DATAREST-555 部分相关,但目前尚不支持附加路径段。

依据:
我喜欢这样的想法,即不必将太多条件逻辑放入 is owner or has_some_role(某些示例 here)等 SPeL 查询中。此外,通过与默认 API 不同的策略保护 /me/** 端点将变得容易(例如,只有 /me/** 可能受 OAuth2 的约束)。

如果你知道better/more简洁的解决方案,我很乐意接受其他答案。

根据@OliverGierke 的建议,official docs and various other SO answers (also almost exclusively by Oliver, mostly , 2 and 3) 我实现了一个自定义控制器来为端点提供服务。

这还会在自定义端点上启用投影并使用 Spring Data REST 的 HATEOS 汇编程序来提供 HAL+JSON 输出。到目前为止我还没有研究的是如何重用 SDR 开箱即用但在自定义控制器中丢失的配置文件和 alps 逻辑。

@BasePathAwareController
public class MyTalksController {

    private final TalkRepository repository;
    private final PagedResourcesAssembler pagedResourcesAssembler;

    @Autowired
    public MyTalksController(TalkRepository repo, PagedResourcesAssembler assembler) {
        repository = repo;
        pagedResourcesAssembler = assembler;
    }

    @RequestMapping(method = RequestMethod.GET, value = "/me/talks")
    @ResponseBody
    public PagedResources<?> getTalks(Pageable pageable, PersistentEntityResourceAssembler entityAssembler) {
        Page<Talk> talks = repository.meFindAll(pageable);
        return pagedResourcesAssembler.toResource(talks, entityAssembler);
    }
}

回答 1) — 是的,可能如下:

// skipping old requests for the sake of the backward compatibility with the clients
// just returning ok with HTTP status 200
@RequestMapping(method = {RequestMethod.GET, RequestMethod.POST, RequestMethod.OPTIONS, RequestMethod.DELETE},
                value = {"/lock", "/configure", "/cancel", "/initialize", "/register"})
public ApiResponse ok() {
    return ApiResponse.success();
}

回答 2) — 不同的查询逻辑自然会适合不同的端点,因此我认为需要为每个端点创建相应的方法。