我正在尝试做一些我认为应该非常简单的事情。我有一个Question
对象,设置有spring-boot,spring-data-rest和spring-hateoas。所有的基础工作都很好。我想添加一个自定义控制器,它返回List<Question>
的格式与GET到Repository
的{{1}}网址的格式完全相同,以便两者之间的响应兼容
这是我的控制器:
/questions
选项1:依靠提供的@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);
}
}
此选项的问题是没有必要呈现SimplePagedResourceAssembler
。如果有一个修复,这将是最简单的解决方案。
选项2:实施我的开源资源汇编程序
此选项的问题在于,根据Spring-Hateoas documentation实施_links
导致QuestionResourceAssembler
最终成为QuestionResource
的近似副本的路径,并且然后汇编程序需要在两个对象之间手动复制数据,我需要手动构建所有相关的Question
。这似乎耗费了很多精力。
怎么做?
我知道Spring在导出_links
时已经生成了代码来完成所有这些操作。有没有什么方法可以利用它来使用它,以确保我的控制器的输出是无缝的,可以与生成的响应互换?
答案 0 :(得分:24)
我找到了一种完全模仿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
。结果正是您对其中一个存储库查询方法的期望!
答案 1 :(得分:8)
关于这个旧问题的更新答案:您现在可以使用@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
}
在@RepositoryRestController中:
hashfile
答案 2 :(得分:4)
我相信我已经以相当直接的方式解决了这个问题,尽管可以更好地记录下来。
在阅读SimplePagedResourceAssembler
的实现后,我意识到混合解决方案可能会有效。提供的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);
这很好用,代码也不多。唯一的麻烦是你需要为你需要的每个参考手动添加链接。