我可以使自定义控制器镜像Spring-Data-Rest / Spring-Hateoas生成的类的格式吗?

我试图做一些我认为应该很简单的事情。 我有一个Question对象,用spring-boot,spring-data-rest和spring-hateoas来设置。 所有的基本工作正常。 我想添加一个自定义控制器返回一个List<Question>与格式完全相同的格式,我的Repository/questions URL做,以便两者之间的响应是兼容的。

这是我的控制器:

 @Controller public class QuestionListController { @Autowired private QuestionRepository questionRepository; @Autowired private PagedResourcesAssembler<Question> pagedResourcesAssembler; @Autowired private QuestionResourceAssembler questionResourceAssembler; @RequestMapping( value = "/api/questions/filter", method = RequestMethod.GET, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public @ResponseBody PagedResources<QuestionResource> filter( @RequestParam(value = "filter", required = false) String filter, Pageable p) { // Using queryDSL here to get a paged list of Questions Page<Question> page = questionRepository.findAll( QuestionPredicate.findWithFilter(filter), p); // Option 1 - default resource assembler return pagedResourcesAssembler.toResource(page); // Option 2 - custom resource assembler return pagedResourcesAssembler.toResource(page, questionResourceAssembler); } } 

选项1:依靠提供的SimplePagedResourceAssembler

这个选项的问题是没有必要的_links呈现。 如果有解决这个问题,这将是最简单的解决scheme。

选项2:实现我的开放资源汇编程序

这个选项的问题是,根据Spring-Hateoas文档实现QuestionResourceAssembler ,导致QuestionResource最终成为QuestionResource一个近似重复的path,然后汇编器需要在这两个对象之间手动复制数据,而且我需要手工build立所有相关_links 。 这似乎是很多浪费的努力。

该怎么办?

我知道Spring已经生成了代码来执行所有这些时,它导出QuestionRepository 。 是否有任何方法可以利用该代码并使用它,以确保来自我的控制器的输出与生成的响应无缝并可互换?

我已经find了一种模仿Spring Data Rest完全行为的方法。 诀窍在于使用PagedResourcesAssembler和一个PersistentEntityResourceAssembler的参数注入实例的组合。 简单地定义你的控制器如下…

 @RepositoryRestController @RequestMapping("...") public class ThingController { @Autowired private PagedResourcesAssembler pagedResourcesAssembler; @SuppressWarnings("unchecked") // optional - ignores warning on return statement below... @RequestMapping(value = "...", method = RequestMethod.GET) @ResponseBody public PagedResources<PersistentEntityResource> customMethod( ..., Pageable pageable, // this gets automatically injected by Spring... PersistentEntityResourceAssembler resourceAssembler) { Page<MyEntity> page = ...; ... return pagedResourcesAssembler.toResource(page, resourceAssembler); } } 

这个工作得益于PersistentEntityResourceAssemblerArgumentResolver的存在,Spring用它来为你注入PersistentEntityResourceAssembler 。 结果正是你所期望的一个仓库查询方法!

我相信我已经以相当直接的方式解决了这个问题,尽pipe它可以被更好地logging下来。

在阅读SimplePagedResourceAssembler实现之后,我意识到混合解决scheme可能会起作用。 提供的Resource<?>类正确呈现实体,但不包含链接,所以您只需添加它们即可。

我的QuestionResourceAssembler实现如下所示:

 @Component public class QuestionResourceAssembler implements ResourceAssembler<Question, Resource<Question>> { @Autowired EntityLinks entityLinks; @Override public Resource<Question> toResource(Question question) { Resource<Question> resource = new Resource<Question>(question); final LinkBuilder lb = entityLinks.linkForSingleResource(Question.class, question.getId()); resource.add(lb.withSelfRel()); resource.add(lb.slash("answers").withRel("answers")); // other links return resource; } } 

一旦完成,在我的控制器我使用上面的选项2

  return pagedResourcesAssembler.toResource(page, questionResourceAssembler); 

这工作得很好,并不是太多的代码。 唯一的麻烦是你需要手动添加你需要的每个引用的链接。

更新了这个老问题的答案:你现在可以用PersistentEntityResourceAssembler来做到这一点

在你的@RepositoryRestController里面:

 @RequestMapping(value = "somePath", method = POST) public @ResponseBody PersistentEntityResource postEntity(@RequestBody Resource<EntityModel> newEntityResource, PersistentEntityResourceAssembler resourceAssembler) { EntityModel newEntity = newEntityResource.getContent(); // ... do something additional with new Entity if you want here ... EntityModel savedEntity = entityRepo.save(newEntity); return resourceAssembler.toResource(savedEntity); // this will create the complete HATEOAS response }