How to set default value of exported as false in rest resource spring data rest

前端 未结 4 610

I want to use RestResource annotation of spring data rest. As you know it exposes ALL CRUD methods by default. But I only need findAll method. One way is to set exported val

相关标签:
4条回答
  • 2021-01-20 08:47

    You can achieve this by defining an intermediate generic interface which implements Repository, and expose, for example, all PagingAndSortingRepository methods annotated with

    @RestController(exported = false).
    

    With the help of that source : https://spring.io/blog/2011/07/27/fine-tuning-spring-data-repositories/, here's my solution :

    First of all, set the RepositoryDetectionStrategy to ANNOTATED so the only repositories exposed are those annotated @RepositoryRestResource. This can be done with :

    @Component
    public class SpringRestConfiguration extends 
    RepositoryRestConfigurerAdapter {
    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
    config.setRepositoryDetectionStrategy(RepositoryDetectionStrategy.RepositoryDetectionStrategies.ANNOTATED);
    }
    }
    

    Define your generic Rest repository. It has to implement only Repository interface, which is empty, and not CrudRepository or PagingAndSortingRepository, so you can control exactly which methods will be exposed, and the methods exposed doesn't depends on the Spring Data version you're using, or will use.

    To garantee the non-exposition you have to annotate with @RestResource(exported=false) each method. It's a bit annoying but done once for all (you can just copy-paste, I take all te methods define in CrudRepository and PagingAndSorting) :

    @RepositoryRestResource
    @NoRepositoryBean
    public interface RestRepositoryMethodExportedFalse<T, ID extends Serializable> 
    extends Repository<T, ID> {
    
    /**
     * Returns all entities sorted by the given options.
     * 
     * @param sort
     * @return all entities sorted by the given options
     */
    @RestResource(exported = false)
    Iterable<T> findAll(Sort sort);
    
    /**
     * Returns a {@link Page} of entities meeting the paging restriction
     * provided in the {@code Pageable} object.
     * 
     * @param pageable
     * @return a page of entities
     */
    @RestResource(exported = false)
    Page<T> findAll(Pageable pageable);
    
    /**
     * Saves a given entity. Use the returned instance for further operations as
     * the save operation might have changed the entity instance completely.
     * 
     * @param entity
     * @return the saved entity
     */
    @RestResource(exported = false)
    <S extends T> S save(S entity);
    
    /**
     * Saves all given entities.
     * 
     * @param entities
     * @return the saved entities
     * @throws IllegalArgumentException
     *             in case the given entity is {@literal null}.
     */
    @RestResource(exported = false)
    <S extends T> Iterable<S> save(Iterable<S> entities);
    
    /**
     * Retrieves an entity by its id.
     * 
     * @param id
     *            must not be {@literal null}.
     * @return the entity with the given id or {@literal null} if none found
     * @throws IllegalArgumentException
     *             if {@code id} is {@literal null}
     */
    @RestResource(exported = false)
    T findOne(ID id);
    
    /**
     * Returns whether an entity with the given id exists.
     * 
     * @param id
     *            must not be {@literal null}.
     * @return true if an entity with the given id exists, {@literal false}
     *         otherwise
     * @throws IllegalArgumentException
     *             if {@code id} is {@literal null}
     */
    @RestResource(exported = false)
    boolean exists(ID id);
    
    /**
     * Returns all instances of the type.
     * 
     * @return all entities
     */
    @RestResource(exported = false)
    Iterable<T> findAll();
    
    /**
     * Returns all instances of the type with the given IDs.
     * 
     * @param ids
     * @return
     */
    @RestResource(exported = false)
    Iterable<T> findAll(Iterable<ID> ids);
    
    /**
     * Returns the number of entities available.
     * 
     * @return the number of entities
     */
    @RestResource(exported = false)
    long count();
    
    /**
     * Deletes the entity with the given id.
     * 
     * @param id
     *            must not be {@literal null}.
     * @throws IllegalArgumentException
     *             in case the given {@code id} is {@literal null}
     */
    @RestResource(exported = false)
    void delete(ID id);
    
    /**
     * Deletes a given entity.
     * 
     * @param entity
     * @throws IllegalArgumentException
     *             in case the given entity is {@literal null}.
     */
    @RestResource(exported = false)
    void delete(T entity);
    
    /**
     * Deletes the given entities.
     * 
     * @param entities
     * @throws IllegalArgumentException
     *             in case the given {@link Iterable} is {@literal null}.
     */
    @RestResource(exported = false)
    void delete(Iterable<? extends T> entities);
    
    /**
     * Deletes all entities managed by the repository.
     */
    @RestResource(exported = false)
    void deleteAll();
    
    }
    

    Then, just extends your custom intermediate repository in your final repositories, and override uniquely the method you want to expose, with your example (you get auto-completion so it's quickly done) :

    @RestResource(path="questions")
    public interface QuestionRepository extends RestRepositoryMethodExportedFalse<Question,Long>{
    
    /**
     * Here is the only method I expose
     */
    @RestResource(exported = true)
    @Override
    Question findOne(Long id);
    
    }
    

    A parameter to set the default value of exported to false would be prefered, but until this is possible, here is the only safe way I find.

    0 讨论(0)
  • 2021-01-20 09:00

    To extend on the answer of Imran Tahir which helped me - thanks Imran! - you can override this for your entire repository by setting ExposeRepositoryMethodsByDefault to false.

    @Component
    public class SpringRestConfiguration extends RepositoryRestConfigurerAdapter {
        @Override
        public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
          config.setExposeRepositoryMethodsByDefault(false);
        }
    }
    

    The detection strategy can now be set in from your configuration file. (In my case YAML)

    spring:
      data:
        rest:
          base-path: /api/base/path
          detection-strategy: annotated
    

    And then in your repository only add @RestResource to (overridden) methods you need to have enabled:

    @RepositoryRestResource(collectionResourceRel = "someThing", path = "someThing")
    @PreAuthorize("hasRole('ROLE_ADMIN') OR hasRole('ROLE_USER')")
    public interface SomeThingRepository extends PagingAndSortingRepository<SomeThing, Long> {
    
        @Override
        @RestResource
        Page<Some> findAll(Pageable pageable);
    
        @Override
        @RestResource
        Optional<Some> findById(Long aLong);
    
        // All other methods are not exposed
    
    }
    
    0 讨论(0)
  • 2021-01-20 09:02

    You should implement a custom controller for GET /questions request that will return only the result of findAll method, for example:

    @RequiredArgsConstructor
    @BasePathAwareController
    @RequestMapping("/questions")
    public class QuestionController {
    
        private final @NonNull QuestionRepository repository;
        private final @NonNull PagedResourcesAssembler<Question> assembler;
        private final @NonNull EntityLinks links;
    
        @GetMapping
        ResponseEntity<?> get(Pageable pageable) {
            return ResponseEntity.ok(assembler.toResource(repository.findAll(pageable),
                    (ResourceAssembler<Question, ResourceSupport>) question -> 
                        new Resource<>(question,
                        links.linkToSingleResource(question).withSelfRel())));
        }
    }
    

    and disable your QuestionRepository to be exported:

    @RepositoryRestResource(exported = false)
    public interface QuestionRepository extends JpaRepository<Question, Long> {
    }
    

    Working example.

    0 讨论(0)
  • 2021-01-20 09:07

    There is an easy and standard solution and I tried and found it working in spring boot 2.0.2 Write a configuration class as shown below and setExposeRepositoryMethodsByDefault(false) and it's done :)

    @Component
    public class SpringRestConfiguration extends RepositoryRestConfigurerAdapter {
        @Override
        public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
            config.setRepositoryDetectionStrategy(RepositoryDetectionStrategy.RepositoryDetectionStrategies.ANNOTATED);
            config.setExposeRepositoryMethodsByDefault(false);
        }
    }
    
    0 讨论(0)
提交回复
热议问题