【发布时间】:2019-04-19 12:38:33
【问题描述】:
基于 stackoverflow 的不同线程,我正在尝试使用 Spring Data Rest 实现软删除行为。基本上,许多 JPA 查询都需要使用 @Query 注释来覆盖。当我在我的实际存储库上使用@Query 和所有@PreAuthorize、@PostFilter 等注释时,这一切都很好,但是我想在我自己的存储库类型中概括软删除,我想从中派生那些通过导出的存储库Spring 数据休息。
这是我所做的: 1) BaseEntity 以便 SoftDeleteRepository 中的 @Query 注释知道如何识别实体类型 2) SoftDeletable 签订关于如何使用软删除标志的合同 3) SoftDeletionRepository 将所有@Query 注释放到方法中 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 删除实例,并且可以验证数据库中仅更改了“已删除”标志。甚至安全注释也得到了尊重,因此我们可以得出结论,两个 repos(父和子)中的注释都变得有效。
但是:当我点击存储库的 /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 的父级,则它们不会出现在应有的列表中。
【问题讨论】:
-
您的问题到底是什么,因为我在您发布的内容中没有看到?
-
我在上面进行了编辑以希望清除
-
我是否不太清楚为什么只有一部分暴露的端点会出现在列表中。
-
好的,这是我目前对 SDR 的理解:SDR 采用 JPA 存储库并为其构建 REST 端点。有一个映射将某些 HTTP 请求链接到 JPA 存储库方法。示例:GET /foo/5 转到 findById(Long) 等此外,每个 repo (/foo/search) 都有一个 /search 端点,但只要我不使用自定义查询方法扩展 repo,它就是空的(docs.spring.io/spring-data/jpa/docs/current/reference/html/…)。在上面的示例中,我们在 /search 中看到了非自定义查询方法的方法。现在有意义吗?
-
文档指出“所有查询方法资源都暴露在搜索资源下”。如果要隐藏或自定义链接,可以在方法上使用
@RepositoryRestResource注释。
标签: java spring-data-jpa spring-data-rest