26

我正在尝试做一些我认为应该非常简单的事情。我有一个Question对象,使用 spring-boot、spring-data-rest 和 spring-hateoas 设置。所有的基础工作都很好。我想添加一个自定义控制器,它以与 GET 到 my的urlList<Question>完全相同的格式返回 a ,以便两者之间的响应兼容。Repository/questions

这是我的控制器:

@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呈现任何必要的内容。如果对此有解决方案,那将是最简单的解决方案。

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

这个选项的问题在于,QuestionResourceAssembler根据Spring-Hateoas 文档实现会导致一条路径QuestionResource接近于 的重复Question,然后汇编器需要在两个对象之间手动复制数据,我需要构建所有相关_links的手工。这似乎浪费了很多精力。

该怎么办?

我知道 Spring 在导出QuestionRepository. 有什么方法可以利用该代码并使用它,以确保我的控制器的输出是无缝的并且可以与生成的响应互换?

4

3 回答 3

26

我找到了一种完全模仿 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);
    }
}

这要归功于PersistentEntityResourceAssemblerArgumentResolverSpring 用来为您注入 的的存在PersistentEntityResourceAssembler。结果正是您对存储库查询方法之一的期望!

于 2015-04-28T16:03:30.560 回答
9

更新了这个老问题的答案:你现在可以用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
}
于 2017-01-06T19:16:22.357 回答
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);

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

于 2014-10-24T16:10:12.440 回答