Основываясь на другом потоке здесь в stackoverflow, я пытаюсь реализовать поведение мягкого удаления с помощью Spring Data Rest.По сути, многие запросы JPA необходимо перезаписать с помощью аннотации @Query.Все это хорошо работает, когда я использую @Query и все аннотации @PreAuthorize, @PostFilter и т. Д. В моем реальном репозитории, но я хотел обобщить мягкое удаление в своем собственном типе репозитория, из которого я хотел извлечь те репозитории, которые экспортируются черезSpring Data Rest.
Вот что я сделал: 1) BaseEntity, чтобы аннотации @Query в SoftDeleteRepository знали, как идентифицировать тип сущности 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, и могу убедиться, что в базе данных изменен только флаг «удален».Даже аннотации безопасности соблюдаются, поэтому мы можем сделать вывод, что аннотации в обоих репозиториях (родительских и дочерних) вступают в силу.
НО: когда я нажимаю на / 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"
}
}
}
Если бы кто-то мог указать мне направление, это было бы здорово!
РЕДАКТИРОВАТЬ: Вопрос: ПочемуЯ вижу такие методы, как findAll, delete, deleteAll и т. Д. В конечной точке / trainingRequests / search, в то время как в списке должны быть только findDeleted, findByTraining, findForeign, findByOwner, findOwn.Без SoftDeletionRepository в качестве родителя для TrainingRequestRepository их нет в списке, как это должно быть.