#java #spring #spring-data-jpa #spring-aop
#java #весна #spring-data-jpa #spring-aop
Вопрос:
У меня есть проект Spring Boot 2.3. Я широко использую Spring Data REST, Spring JPA, спящий режим.
Типичный репозиторий в моем приложении выглядит так:
@Transactional
public interface ContactRepository extends JpaRepository<Contact, Long>, ContactCustomRepository<Contact, Long>, JpaSpecificationExecutor<Contact> {
@Transactional(readOnly = true)
@Query("FROM Contact c WHERE c.id=:id")
Optional<ContactType> findByIdTest(@Param("id") long id);
}
Это мой фильтр:
@Aspect
@Order(1)
@Component
@Log4j2
public class EntityCustomerFilterAspect {
@Pointcut("execution(public * javax.persistence.EntityManager .*Query(..))")
private void createQuery() {
}
@Around(value = "createQuery() amp;amp; target(entityManager)")
public Object applyFilter(ProceedingJoinPoint pjp, Object entityManager) throws Throwable {
try {
if (SecurityUtils.getLoggedRoles().contains(Role.ROLE_CUSTOMER)) {
if (SecurityUtils.getLoggedId() != null) {
((EntityManager) entityManager).unwrap(Session.class).enableFilter("customerFilter").setParameter("contactId", SecurityUtils.getLoggedId());
log.trace(">>>>Enabling filter customer {}", SecurityUtils.getLoggedUser().getSid());
} else {
((EntityManager) entityManager).unwrap(Session.class).enableFilter("customerFilter").setParameter("contactId", -1l);
log.warn("Logged ID is null. Customer filter cannot be applied");
}
}
} catch (Exception e) {
log.warn("Unable to enable filter");
}
return pjp.proceed();
}
}
Когда из контроллера REST я вызываю метод findByIdTest
, с помощью EntityCustomerFilterAspect
которого применяется определенный фильтр. Напротив, если вместо этого я вызываю Spring JPA по умолчанию findById
, фильтр не применяется.
Я не понимаю, что не так и почему @Pointcut не работает с методами по умолчанию.
Комментарии:
1.
findById
не использует запрос, а скорее используетfind
методEntityManager
, даже если вы сможете перехватить это, фильтры в этом случае не будут применяться, они применяются только к запросам, а не кEntityManager.find
методу.2. @M.Deinum вы видите хороший способ решить эту проблему? Моя цель — добавить автоматический фильтр, когда клиент регистрируется в моем приложении. Я хочу, чтобы он мог видеть только свои данные. Фильтр, который, как я догадался, был лучшим способом сделать это, поэтому я не рискую забыть указать условие в запросе.
3. Фильтр — отличное решение, но он просто не будет работать, когда вы выполняете прямой запрос через JPA на основе первичного ключа.
EntityManager.find
. Поэтому, если у вас нет метода HTTP или иного, который напрямую вызывает это на основе идентификатора в запросе, это не должно быть проблемой. Если вы хотите обойти это, вам нужно будет повторно реализоватьfindById
using запрос (что может привести к проблемам из-за игнорирования сопоставления JPA!). Тем не менее, если кто-то напрямую используетEntityManager.find
вместо репозитория, у вас по-прежнему возникает та же проблема отсутствия фильтров.4. @M.Deinum Спасибо. На самом деле SDR предоставляет эти методы как ресурсы REST. Поэтому я должен настроить контроллер и вызвать пользовательский findByIdCustom, чтобы избежать проблемы. Еще раз спасибо за разъяснения!