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

Java 使用Spring Data Rest@Projection作为自定义控制器中资源的表示形式,java,spring,spring-boot,spring-data-rest,spring-hateoas,Java,Spring,Spring Boot,Spring Data Rest,Spring Hateoas,有没有办法使用@Projection接口作为SDR中资源的默认表示形式?是通过SDR存储库还是通过自定义控制器 在自定义控制器中,通过注入ProjectionFactory并使用createProjection方法可以实现这一点,但最近的Spring数据Rest更新打破了这一点 我想在一个实体上实施一个特定的视图,SDR投影似乎是实现这一点的理想方法,特别是在HAL API的环境中,而不是为自定义控制器编写硬DTO类并在它们之间映射等。摘录投影不是我想要的,因为这些仅在查看关联资源时适用 不,这

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

在自定义控制器中,通过注入
ProjectionFactory
并使用
createProjection
方法可以实现这一点,但最近的Spring数据Rest更新打破了这一点


我想在一个实体上实施一个特定的视图,SDR投影似乎是实现这一点的理想方法,特别是在HAL API的环境中,而不是为自定义控制器编写硬DTO类并在它们之间映射等。摘录投影不是我想要的,因为这些仅在查看关联资源时适用

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

您可以使用jacksonmixins来更改json表示

你可以在这里找到一些好例子:
回答我自己的问题,现在有两种简单的方法可以做到这一点

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

public interface PersonRepository extends PagingAndSortingRepository<Person,Long> {

    Set<PersonProjection> findByLastName(String lastName);

}
公共接口PersonRepository扩展了分页和排序存储库{
设置findByLastName(字符串lastName);
}
您还可以通过使用@BasePathAwareController创建自定义SpringMVC控制器,选择性地覆盖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);
}
@BasePathAwareController
公共类CustomPersonController{
@自动连线
私营工程厂;
@自动连线
个人知识库;
@自动连线
专用页数据源汇编程序;
@RequestMapping(value=“/persons”,method=RequestMethod.GET,products=“application/hal+json”)
公共响应getPeople(可分页){
Page people=personRepository.findAll(可分页);
Page projected=people.map(l->factory.createProjection(PersonProjection.class,l));
PagedResources resources=assembler.toResource(投影);
返回ResponseEntity.ok(资源);
}

我想提出另一种解决方案

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

因为我已经使用了
ResourceProcessor
s,所以我决定在这些处理器内部应用默认投影

@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;
    }
}
@组件
公共类ProductResourceProcessor实现ResourceProcessor{
@自动连线
私人项目工厂项目工厂;
@凌驾
@抑制警告(“未选中”)
公共资源流程(资源){
产品内容=resource.getContent();
ProductInline projection=projectionFactory.createProjection(ProductInline.class,content);
资源结果=新资源(预测);
//复制和添加链接
返回(资源)结果;
}
}
处理器重新打包处理资源的内容。无论哪个处理程序返回资源作为响应(
GET
POST
PATCH
任何内容),投影都是以这种方式应用的


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

谢谢。以前(SDR 2.4.0之前),可以只将
SpelAwareProxyProjectionFactory的实例注入控制器类,然后在自定义控制器中,对要投影的域对象调用
createProjection
,然后在响应中返回投影,但不幸的是,这被一个或多个SDR方面的NGE。Jackson Mixins路线涉及面更广、更笨重。之前也有类似的问题,Oliver Gierke直接回答了这个问题,并提出了一些很好的论据,说明为什么对单一资源使用预测不是一个好主意——是的,我看到了,尽管这主要与摘录和使用标准SDR导出有关不过,奥利弗也概述了我到底在追求什么(以及我在做什么)这里:这里:但是这些代码示例在当前版本的SDR中不再工作,引发了Jackson异常。除了@adam respone之外,还需要在一些
@Configuration
文件中添加
@Bean
,例如
@Configuration class SomeConfig{@Bean public-SpelAwareProxyProjectionFactory(){return new SpelAwareProxyProjectionFactory();}}
非常好!谢谢!