我可以使自定义控制器镜像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 }