How to disable paging for JpaRepository in spring-

2020-07-04 02:47发布

问题:

I'm using spring-data-rest with JpaRepository to create the Rest-Endpoints. By default, paging is enabled for all JpaRepository, what is a good thing. But I have a legacy application that we port to our new stack that does not support paging. I would like to disable paging depending on an URL-Parameter to still be able to use paging in new application code.

I tried various approaches to expose the resources with and without paging:

  • Use CrudRepository: Results in only having an unpaged endpoint and the method flush is missing.
  • Override the List<T> findAll() method in my repository interface and annotated it with RestResource. I would have expected that the method will be exposed as search method, but it is not.
  • Annotate Page<T> findAll(Pageable pageable) with @RestResource(exported=false) and annotate List<T> findAll() as in the bullet before. I have hopped that this replaces the default method. But this is not valid solution anyway, because only a non paged endpoint is exposed.
  • Pass size=-1 to get an unlimited result -> Default paging size is used

I've seen that the spring-controller RepositoryEntityController uses a RepositoryInvoker to call the methods on the repository. The Pageable is resolved using the PageableHandlerMethodArgumentResolver which always returns a pageable (specified in query, annotated or default pageable). The only solution that I see for the moment is to implement a custom PageableHandlerMethodArgumentResolver that returns null, if a custom url parameter is passed.

Do you know any other solutions or is anything similar planned for the future?

回答1:

I use PagingAndSortingRepository and this config to set my pageableResolver:

@Configuration
public class RestApiConfiguration extends RepositoryRestConfigurerAdapter {

    @Bean
    public HateoasPageableHandlerMethodArgumentResolver customResolver(
        HateoasPageableHandlerMethodArgumentResolver pageableResolver) {
        pageableResolver.setOneIndexedParameters(true);
        pageableResolver.setFallbackPageable(new PageRequest(0, Integer.MAX_VALUE));
        pageableResolver.setMaxPageSize(Integer.MAX_VALUE);
        return pageableResolver;
    }
}

See: https://jira.spring.io/browse/DATACMNS-929

This way if page and size are included in the request you get the page requested, but if they are not in the request you get all records. In both cases if a sort is specified it is used to sort the data. In the second case, the records are returned inside a page, but I can live with that.

EDIT https://jira.spring.io/browse/DATACMNS-929 has been fixed, so with the new versions you'll be able to configure your resolver with a null fallbackPageable. That way, when pageable data (ie page and size) is present you retrieve one page, but when it's not you retrieve all records:

@Configuration
public class RestApiConfiguration extends RepositoryRestConfigurerAdapter {

    @Bean
    public HateoasPageableHandlerMethodArgumentResolver customResolver(
        HateoasPageableHandlerMethodArgumentResolver pageableResolver) {
        pageableResolver.setOneIndexedParameters(true);
        pageableResolver.setFallbackPageable(null);
        return pageableResolver;
    }
}


回答2:

You could add your own methods to the Repository interface, and have a return type of List<DomainObject> or Collection<DomainObject> and no Pageable parameter. That will cause a non-paged response to be used. You could then point your legacy client at those methods instead of the default ones.

Or, you could configure the default page size to be very large. Set spring.data.rest.default-page-size in application.properties.



回答3:

This is not the cleanest solution, but the following code with allow you to pass unpaged=true as a query parameter, in order to get all the result in one page.

@Configuration
public class RestApiServletConfig implements WebMvcConfigurer {
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        PageableHandlerMethodArgumentResolver pageableResolver = new PageableHandlerMethodArgumentResolver() {
            @Override
            public Pageable resolveArgument(MethodParameter methodParameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
                if ("true".equals(webRequest.getParameter(getParameterNameToUse("unpaged", methodParameter)))) {
                    return Pageable.unpaged();
                }

                return super.resolveArgument(methodParameter, mavContainer, webRequest, binderFactory);
            }
        };
        resolvers.add(pageableResolver);
    }
}


回答4:

The highest rated answer indicates a null for setFallbackPageable, which is no longer valid. Use the default static constructor for PageRequest like this:

@Configuration
public class RestApiConfiguration extends RepositoryRestConfigurerAdapter {

    @Bean
    public HateoasPageableHandlerMethodArgumentResolver customResolver(
        HateoasPageableHandlerMethodArgumentResolver pageableResolver) {
        pageableResolver.setOneIndexedParameters(true);
        pageableResolver.setFallbackPageable(PageRequest.of(0, Integer.MAX_VALUE));
        pageableResolver.setMaxPageSize(Integer.MAX_VALUE);
        return pageableResolver;
    }
}


回答5:

Using spring.data.rest and JpaRepoistoy to keep the paging Add a config class Mural.class is the class I wanted to limit access to

package com.chicagomural.mural.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;
import org.springframework.http.HttpMethod;

import com.chicagomural.mural.entity.Mural;

@Configuration
public class MuralDataRestConfig implements RepositoryRestConfigurer {

    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        HttpMethod[] theUnsupportedActions = {HttpMethod.PUT, HttpMethod.POST, HttpMethod.DELETE, HttpMethod.PATCH};

        config.getExposureConfiguration()
            .forDomainType(Mural.class)
            .withItemExposure((metdata, httpMethods) -> httpMethods.disable(theUnsupportedActions))
            .withCollectionExposure((metdata, httpMethods) -> httpMethods.disable(theUnsupportedActions));
    }
}

https://docs.spring.io/spring-data/rest/docs/current/api/org/springframework/data/rest/core/config/RepositoryRestConfiguration.html