Spring Data Rest-存储库继承会创建奇怪的搜索端点

时间:2018-11-16 10:25:43

标签: java spring-data-jpa spring-data-rest

基于此处stackoverflow上的另一个线程,我试图使用Spring Data Rest实现软删除行为。基本上,许多JPA查询都需要使用@Query注释覆盖。当我在实际存储库中使用@Query以及所有@ PreAuthorize,@ PostFilter等批注时,一切都很好,但是我想对自己的存储库类型中的软删除进行概括,以从中导出要通过以下方式导出的存储库Spring Data Rest。

这是我所做的: 1)BaseEntity,以便SoftDeleteRepository中的@Query注释知道如何识别实体类型 2)SoftDeletable具有如何使用软删除标志的约定 3)将所有@Query注释放入方法中的SoftDeletionRepository 4)TrainingRequestRepository扩展了SoftDeletionRepository,添加了安全注释,然后由Spring Data Rest导出。

public interface BaseEntity {
    public Long getId();    
    public void setId(Long id); 
}

public interface SoftDeletable {
    public Boolean getDeleted();
    public void setDeleted(Boolean deleted);
}

@RepositoryRestResource
public interface SoftDeleteRepository<T extends BaseEntity & SoftDeletable, I extends Serializable> extends CrudRepository<T, I> {

    @Query("update #{#entityName} e set e.deleted = true where e.id = ?#{#request.id}")
    @Modifying
    @Override
    public void delete(@Param("request") T entity);

    @Transactional
    @Query("update #{#entityName} e set e.deleted = true where e.id = ?1")
    @Modifying
    @Override
    public void deleteById(I id);

    @Query("update #{#entityName} e set e.deleted = true")
    @Transactional
    @Modifying
    @Override
    public void deleteAll();

    @Query("select e from #{#entityName} e where e.deleted = false")
    @Override
    public Iterable<T> findAll();

    @Transactional(readOnly = true)
    @Query("select e from #{#entityName} e where e.id in ?1 and e.deleted = false")
    @Override
    public Iterable<T> findAllById(Iterable<I> requests);

    @Transactional(readOnly = true)
    @Query("select e from #{#entityName} e where e.id = ?1 and e.deleted = false")
    @Override
    public Optional<T> findById(@Param("id") I id);

    @Transactional(readOnly = true)
    @Query("select e from #{#entityName} e where e.deleted = true")
    public Iterable<T> findDeleted();

    @Override
    @Transactional(readOnly = true)
    @Query("select count(e) from #{#entityName} e where e.deleted = false")
    public long count();

}

@RepositoryRestResource
public interface TrainingRequestRepository extends SoftDeleteRepository<TrainingRequest, Long> {

    @PreAuthorize("hasAuthority('ADMIN') or principal.company.id == #request.owner.id")
    @Override
    public void delete(@Param("request") TrainingRequest request);

    @PreAuthorize("hasAuthority('ADMIN') or requests.?[owner.id != principal.company.id].empty")
    @Override
    public void deleteAll(Iterable<? extends TrainingRequest> entities);

    @PreAuthorize("hasAuthority('ADMIN') or @companyService.isOwnerOfRequest(id, principal)")
    @Override
    public void deleteById(Long id);

    @PreAuthorize("hasAuthority('ADMIN')")
    @Override
    public void deleteAll();

    @PreAuthorize("isFullyAuthenticated()")
    @PostFilter("hasAuthority('ADMIN') or hasAuthority('TRAINER') or filterObject.owner.id == principal.company.id")
    @Override
    public Iterable<TrainingRequest> findAll();

    @PreAuthorize("isFullyAuthenticated()")
    @PostFilter("hasAuthority('ADMIN') or hasAuthority('TRAINER') or !filterObject.owner.?[id == #root.principal.company.id].empty")
    @Override
    public Iterable<TrainingRequest> findAllById(Iterable<Long> requests);

    @PreAuthorize("isFullyAuthenticated()")
    @PostAuthorize("hasAuthority('ADMIN') or hasAuthority('TRAINER') or @ownershipValidator.isOwnerOf(principal.company, returnObject.orElse(null))")
    @Override
    public Optional<TrainingRequest> findById(@Param("id") Long id);

    @PreAuthorize("isFullyAuthenticated()")
    @PostFilter("hasAuthority('ADMIN') or hasAuthority('TRAINER') or filterObject.owner.id == principal.company.id")
    @Query("select e from #{#entityName} e where e.deleted = true")
    public Iterable<TrainingRequest> findDeleted();

    @PreAuthorize("hasAuthority('ADMIN') or (requests.?[id != null].empty or requests.?[owner.id != principal.owner.id].empty)")
    @Override
    public <S extends TrainingRequest> Iterable<S> saveAll(Iterable<S> requests);

    @PreAuthorize("hasAuthority('ADMIN') or (hasAuthority('CUSTOMER') and (#request.id == null or #request.owner.id == principal.owner.id))")
    @Override
    public <S extends TrainingRequest> S save(@Param("request") S request);

}

一切正常,一切顺利!我可以使用HTTP DELETE删除实例,并且可以验证数据库中仅更改了“ deleted”标志。甚至使用了安全注释,因此我们可以得出结论,回购(父项和子项)中的注释均有效。

但是:当我点击存储库的/ search端点时,我可以看到回购中提到的所有方法的端点。我看起来来自TrainingRequestRepository的所有方法都列为搜索端点:

curl -s -XGET -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" http://localhost:2222/trainingRequests/search
{
  "_links" : {
    "findById" : {
      "href" : "http://localhost:2222/trainingRequests/search/findById{?id}",
      "templated" : true
    },
    "deleteById" : {
      "href" : "http://localhost:2222/trainingRequests/search/deleteById{?id}",
      "templated" : true
    },
    "count" : {
      "href" : "http://localhost:2222/trainingRequests/search/count"
    },
    "delete" : {
      "href" : "http://localhost:2222/trainingRequests/search/delete{?request}",
      "templated" : true
    },
    "findAllById" : {
      "href" : "http://localhost:2222/trainingRequests/search/findAllById{?requests}",
      "templated" : true
    },
    "findAll" : {
      "href" : "http://localhost:2222/trainingRequests/search/findAll"
    },
    "deleteAll" : {
      "href" : "http://localhost:2222/trainingRequests/search/deleteAll"
    },
    "findOwn" : {
      "href" : "http://localhost:2222/trainingRequests/search/findOwn"
    },
    "findByOwner" : {
      "href" : "http://localhost:2222/trainingRequests/search/findByOwner{?owner}",
      "templated" : true
    },
    "findForeign" : {
      "href" : "http://localhost:2222/trainingRequests/search/findForeign"
    },
    "findByTraining" : {
      "href" : "http://localhost:2222/trainingRequests/search/findByTraining{?training}",
      "templated" : true
    },
    "findDeleted" : {
      "href" : "http://localhost:2222/trainingRequests/search/findDeleted"
    },
    "self" : {
      "href" : "http://localhost:2222/trainingRequests/search"
    }
  }
}

如果有人可以指出我的方向,那就太好了!

编辑:问题是:为什么我在/ trainingRequests / search端点中看到像findAll,delete,deleteAll等方法,而只有findDeleted,findByTraining,findForeign,findByOwner,findOwn应该在列表中。如果没有SoftDeletionRepository作为TrainingRequestRepository的父级,则这些不在应有的列表中。

1 个答案:

答案 0 :(得分:0)

问题是SpringDataRest自动为每个模型生成CRUD端点,并按照HATEOS范式公开它们。

如果不需要此功能,只需删除SpringDataRest依赖项。 [编辑]我只是重新阅读了问题标题。 @RepositoryRestResource引入了自动生成的终结点,而不是继承。[/ EDIT]

如果需要此功能,则应配置要公开的内容。有官方文档here,下面的示例摘自here

# Exposes all public repository interfaces but considers @(Repository)RestResource\u2019s `exported flag.
spring.data.rest.detection-strategy=default

# Exposes all repositories independently of type visibility and annotations.
spring.data.rest.detection-strategy=all

# Only repositories annotated with @(Repository)RestResource are exposed, unless their exported flag is set to false.
spring.data.rest.detection-strategy=annotated

# Only public repositories annotated are exposed.
spring.data.rest.detection-strategy=visibility