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

时间:2014-10-23 21:56:28

标签: spring spring-mvc spring-data spring-data-rest spring-hateoas

我正在尝试做一些我认为应该非常简单的事情。我有一个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时已经生成了代码来完成所有这些操作。有没有什么方法可以利用它来使用它,以确保我的控制器的输出是无缝的,可以与生成的响应互换?

3 个答案:

答案 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);

这很好用,代码也不多。唯一的麻烦是你需要为你需要的每个参考手动添加链接。