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

南笙酒味 提交于 2019-12-22 09:09:30

问题


Is there any way to use a @Projection interface as the default representation for a resource in SDR? Either through the SDR repositories or through a custom controller?

It used to be possible in a custom controller to do this by injecting a ProjectionFactory and using the createProjection method, but this has been broken by a recent Spring Data Rest update.

I would like to enforce a particular view on an entity, and the SDR projections seem like an ideal method for doing this, especially in the context of a HAL API, as opposed to writing hard DTO classes for a custom controller and mapping between them etc. Excerpt projections are not what I am after, as these only apply when looking at an associated resource.


回答1:


To answer my own question, there's now a couple of easyish ways to do this.

You can make SDR repository finders return projections by default:

public interface PersonRepository extends PagingAndSortingRepository<Person,Long> {

    Set<PersonProjection> findByLastName(String lastName);

}

You can also selectively override responses that SDR would have handled for you by default by creating a custom Spring MVC controller with the @BasePathAwareController. You will need to inject the ProjectionFactory and possibly the PagedResourcesAssembler if you're planning on providing a paged response.

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



回答2:


No it is not possible out of the box. Excerpt projections are always used if a resource is embedded. And on a single resource you can provide the desired projection as a query param.

What you can do is to use Jackson Mixins to change the json representation.

You can find some good examples here: https://github.com/olivergierke/spring-restbucks/blob/master/src/main/java/org/springsource/restbucks/JacksonCustomizations.java




回答3:


I would like to suggest yet another solution.

I used custom controller as @adam suggested untill I had to PATCH a resource and get new representation back. There is no way to override save method of a repository to use a projection by default. Implementing custom controllers all the time brings some boilerplate into the project.

Since I already used ResourceProcessors I decided to apply default projection right inside those processors.

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

The processor repacks the content of processing resource. Thsi way the projection is applied no matter which handler returned the resource as a response (GET, POST, PATCH anything).

The drawback of this approach is it assumes that spring-data-rest doesn't require that the type of the content would be the same after processing. That may change anytime in the future releases.



来源:https://stackoverflow.com/questions/33288486/using-a-spring-data-rest-projection-as-a-representation-for-a-resource-in-a-cus

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!