使用 Spring Data Rest @Projection 作为自定义控制器中资源的表示

Using a Spring Data Rest @Projection as a representation for a resource in a custom controller

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

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

我想对实体强制执行特定视图,SDR 投影似乎是执行此操作的理想方法,尤其是在 HAL API 的上下文中,而不是编写硬 DTO 类 用于自定义控制器和它们之间的映射等。摘录投影不是我所追求的,因为这些仅在查看相关资源时适用。

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

您可以使用 Jackson Mixins 来更改 json 表示。

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

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

默认情况下,您可以进行 SDR 存储库查找器 return 投影:

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);
}

我想提出另一种解决方案。

我按照 @adam 的建议使用自定义控制器,直到我不得不 PATCH 一个资源并取回新的表示。默认情况下,无法覆盖存储库的 save 方法以使用投影。一直实施自定义控制器会给项目带来一些样板文件。

因为我已经使用了 ResourceProcessors 我决定在这些处理器中应用默认投影。

@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 不要求处理后内容的类型相同。这可能会在未来的版本中随时更改。