Spring Data Rest - наследование репозитория создает странные конечные точки поиска - PullRequest
0 голосов
/ 16 ноября 2018

Основываясь на другом потоке здесь в 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 их нет в списке, как это должно быть.

1 Ответ

0 голосов
/ 16 ноября 2018

Проблема в том, что SpringDataRest автоматически генерирует конечные точки CRUD для каждой модели и предоставляет их в соответствии с парадигмой HATEOS.

Если вам не нужна эта функция, просто удалите зависимость SpringDataRest. [РЕДАКТИРОВАТЬ] Я просто перечитал название вопроса. @RepositoryRestResource - это то, что представляет автоматически генерируемые конечные точки, а не наследование. [/ EDIT]

Если вам нужны эти функции, вы должны настроить, что выставлять. Здесь есть официальная документация , а следующий пример взят из здесь .

# 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
...