基于此处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的父级,则这些不在应有的列表中。
答案 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