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

JBC*_*BCP 24 spring spring-mvc spring-data spring-data-rest spring-hateoas

我正在尝试做一些我认为应该非常简单的事情.我有一个Question对象,设置有spring-boot,spring-data-rest和spring-hateoas.所有的基础工作都很好.我想添加一个自定义控制器,它返回一个List<Question>与我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);
    }

}
Run Code Online (Sandbox Code Playgroud)

选项1:依靠提供的 SimplePagedResourceAssembler

此选项的问题是没有必要_links呈现.如果有一个修复,这将是最简单的解决方案.

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

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

该怎么办?

我知道Spring已经生成了代码,以便在导出时执行所有这些操作QuestionRepository.有什么方法可以利用该代码并使用它,以确保我的控制器的输出是无缝的,可以与生成的响应互换?

小智 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这要归功于PersistentEntityResourceAssemblerArgumentResolverSpring 的存在,Spring会PersistentEntityResourceAssembler为你注入它.结果正是您对其中一个存储库查询方法的期望!

  • 除非没有找到结果,否则这样做有效.在这种情况下,REST响应中没有`_embedded`键,与自动生成的REST/HATEOAS控制器不同.在这个例子中,我不得不手动调用`pagedResourcesAssembler.toEmptyResource`. (3认同)

Rob*_*ert 8

关于这个老问题的更新答案:你现在可以用一个 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
}
Run Code Online (Sandbox Code Playgroud)


JBC*_*BCP 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

完成后,在我的控制器中我使用了上面的选项 2

    return pagedResourcesAssembler.toResource(page, questionResourceAssembler);
Run Code Online (Sandbox Code Playgroud)

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