使用Spring Data Rest @Projection作为自定义控制器

时间:2015-10-22 18:48:28

标签: java spring spring-boot spring-data-rest spring-hateoas

有没有办法使用@Projection接口作为SDR中资源的默认表示?通过SDR存储库还是通过自定义控制器?

以前可以通过注入ProjectionFactory并使用createProjection方法在自定义控制器中执行此操作,但最近的Spring Data Rest更新已经破坏了这一点。

我想在实体上强制执行特定视图,并且SDR投影看起来像是一种理想的方法,特别是在HAL API的上下文中,而不是为自定义控制器和映射编写硬DTO类他们之间的摘录预测不是我所追求的,因为这些仅适用于查看相关资源时。

3 个答案:

答案 0 :(得分:12)

要回答我自己的问题,现在有几种简单的方法可以做到这一点。

默认情况下,您可以让SDR存储库查找器返回投影:

public interface PersonRepository extends PagingAndSortingRepository<Person,Long> {

    Set<PersonProjection> findByLastName(String lastName);

}

通过使用@BasePathAwareController创建自定义Spring MVC控制器,您还可以选择性地覆盖SDR默认为您处理的响应。如果您计划提供分页响应,则需要注入ProjectionFactory和可能的PagedResourcesAssembler。

@BasePathAwareController
public class CustomPersonController {

@Autowired
private ProjectionFactory factory;

@Autowired
private PersonRepository personRepository;

@Autowired
private PagedResourcesAssembler<PersonProjection> assembler;

@RequestMapping(value="/persons", method = RequestMethod.GET, produces = "application/hal+json")
public ResponseEntity<?> getPeople(Pageable pageable) {
    Page<Person> people = personRepository.findAll(pageable);
    Page<PersonProjection> projected = people.map(l -> factory.createProjection(PersonProjection.class, l));
    PagedResources<Resource<PersonProjection>> resources = assembler.toResource(projected);
    return ResponseEntity.ok(resources);
}

答案 1 :(得分:2)

不可以开箱即用。如果嵌入了资源,则始终使用摘录投影。在单个资源上,您可以提供所需的投影作为查询参数。

你可以做的是使用Jackson Mixins改变json表示。

你可以在这里找到一些很好的例子: https://github.com/olivergierke/spring-restbucks/blob/master/src/main/java/org/springsource/restbucks/JacksonCustomizations.java

答案 2 :(得分:2)

我想建议另一个解决方案。

我使用自定义控制器作为@adam建议,直到我不得不PATCH一个资源并获得新的表示。默认情况下,无法覆盖存储库的save方法以使用投影。始终实现自定义控制器为项目带来了一些样板。

由于我已经使用过ResourceProcessor,我决定在这些处理器中应用默认投影。

@Component
public class ProductResourceProcessor implements ResourceProcessor<Resource<Product>> {

    @Autowired
    private ProjectionFactory projectionFactory;

    @Override
    @SuppressWarnings("unchecked")
    public Resource<Product> process(Resource<Product> resource) {
        Product content = resource.getContent();
        ProductInline projection = projectionFactory.createProjection(ProductInline.class, content);
        Resource<ProductInline> result = new Resource<>(projection);
        //copying and adding links
        return (Resource) result;
    }
}

处理器重新打包处理资源的内容。无论哪个处理程序将资源作为响应返回(GETPOSTPATCH任何内容),都会应用投影。

这种方法的缺点是假设spring-data-rest并不要求处理后内容的类型相同。这可能会在将来的版本中随时改变。