我的目标是向Predicate
的{{1}}方法中添加动态findAll
。应该使用它来基于当前活动用户的组织来过滤实体。
我正在将Spring Data与Spring Data REST结合使用以立即使用REST API,即我没有专用的REST服务,可以在其中截获传入的数据并对其进行修改。
通过扩展QuerydslPredicateExecutor
并向SimpleJpaRepository
注册,可以覆盖方法并更改其默认行为。我想这样做,但是我的@EnableJpaRepositories
接口正在实现Repository
,这似乎不起作用。
我失败的方法开始于:
QuerydslPredicateExecutor
,但显然,此扩展名不提供要覆盖的方法。我调试了实现public class CustomizedJpaRepositoryIml<T, ID extends Serializable> extends
SimpleJpaRepository<T, ID> {
private EntityManager entityManager;
@Autowired
public CustomizedJpaRepositoryIml(JpaEntityInformation<T, ?>
entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
this.entityManager = entityManager;
}
}
的连接方式,但这相当复杂,我看不出在这里轻松插入某些内容的方法。
另一个想法是使用过滤器拦截URL调用并添加参数,但这听起来不太好。
我还可以使用QuerydslJpaPredicateExecutor
覆盖查找程序的控制器路径,但这将意味着对所有我拥有的实体(而不是在单个位置)执行此操作。
有什么想法可以实现我的目标?也许还有完全不同的选项可以实现我为Querydsl @BasePathAwareController
答案 0 :(得分:0)
与此同时,我找到了一种方法。它需要提供自己的QuerydslPredicateExecutor
实现。但这在Spring Data中并不容易。答案是由https://stackoverflow.com/a/53960209/3351474推动的,但是与此同时,在较新的Spring Data中,构造函数发生了变化,为什么不能将其设为1:1。
我使用与问题中不同的示例,但是使用此解决方案,您还有完全的自由来添加和附加任何Predicate
。作为示例,我在此处采用自定义的Querydsl实现,如果不进行任何传递,则始终使用实体的creationDate
作为排序标准。在此示例中,我假设所有实体的此列都存在于@MappedSuperClass
中。在现实生活中使用生成的静态元数据代替硬编码字符串“ creationDate”。
首先,将所有CustomQuerydslJpaRepositoryIml
委派给所有QuerydslJpaPredicateExecutor
的包装委派:
/**
* Customized Querydsl JPA repository to apply custom filtering and sorting logic.
*
*/
public class CustomQuerydslJpaRepositoryIml<T> implements QuerydslPredicateExecutor<T> {
private final QuerydslJpaPredicateExecutor querydslPredicateExecutor;
public CustomQuerydslJpaRepositoryIml(QuerydslJpaPredicateExecutor querydslPredicateExecutor) {
this.querydslPredicateExecutor = querydslPredicateExecutor;
}
private Sort applyDefaultOrder(Sort sort) {
if (sort.isUnsorted()) {
return Sort.by("creationDate").ascending();
}
return sort;
}
private Pageable applyDefaultOrder(Pageable pageable) {
if (pageable.getSort().isUnsorted()) {
Sort defaultSort = Sort.by(AuditableEntity_.CREATION_DATE).ascending();
pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), defaultSort);
}
return pageable;
}
@Override
public Optional<T> findOne(Predicate predicate) {
return querydslPredicateExecutor.findOne(predicate);
}
@Override
public List<T> findAll(Predicate predicate) {
return querydslPredicateExecutor.findAll(predicate);
}
@Override
public List<T> findAll(Predicate predicate, Sort sort) {
return querydslPredicateExecutor.findAll(predicate, applyDefaultOrder(sort));
}
@Override
public List<T> findAll(Predicate predicate, OrderSpecifier<?>... orders) {
return querydslPredicateExecutor.findAll(predicate, orders);
}
@Override
public List<T> findAll(OrderSpecifier<?>... orders) {
return querydslPredicateExecutor.findAll(orders);
}
@Override
public Page<T> findAll(Predicate predicate, Pageable pageable) {
return querydslPredicateExecutor.findAll(predicate, applyDefaultOrder(pageable));
}
@Override
public long count(Predicate predicate) {
return querydslPredicateExecutor.count(predicate);
}
@Override
public boolean exists(Predicate predicate) {
return querydslPredicateExecutor.exists(predicate);
}
}
接下来,CustomJpaRepositoryFactory
发挥作用,并提供Querydsl包装器类,而不是默认的包装器类。默认值作为参数传递并包装。
/**
* Custom JpaRepositoryFactory allowing to support a custom QuerydslJpaRepository.
*
*/
public class CustomJpaRepositoryFactory extends JpaRepositoryFactory {
/**
* Creates a new {@link JpaRepositoryFactory}.
*
* @param entityManager must not be {@literal null}
*/
public CustomJpaRepositoryFactory(EntityManager entityManager) {
super(entityManager);
}
@Override
protected RepositoryComposition.RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata) {
final RepositoryComposition.RepositoryFragments[] modifiedFragments = {RepositoryComposition.RepositoryFragments.empty()};
RepositoryComposition.RepositoryFragments fragments = super.getRepositoryFragments(metadata);
// because QuerydslJpaPredicateExecutor is using som internal classes only a wrapper can be used.
fragments.stream().forEach(
f -> {
if (f.getImplementation().isPresent() &&
QuerydslJpaPredicateExecutor.class.isAssignableFrom(f.getImplementation().get().getClass())) {
modifiedFragments[0] = modifiedFragments[0].append(RepositoryFragment.implemented(
new CustomQuerydslJpaRepositoryIml((QuerydslJpaPredicateExecutor) f.getImplementation().get())));
} else {
modifiedFragments[0].append(f);
}
}
);
return modifiedFragments[0];
}
}
最后是CustomJpaRepositoryFactoryBean
。这必须在Spring Boot应用程序中注册,以使Spring知道从何处获取存储库实现。与:
@SpringBootApplication
@EnableJpaRepositories(basePackages = "your.package",
repositoryFactoryBeanClass = CustomJpaRepositoryFactoryBean.class)
...
现在是课程:
public class CustomJpaRepositoryFactoryBean<T extends Repository<S, I>, S, I> extends JpaRepositoryFactoryBean<T, S, I> {
/**
* Creates a new {@link JpaRepositoryFactoryBean} for the given repository interface.
*
* @param repositoryInterface must not be {@literal null}.
*/
public CustomJpaRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
super(repositoryInterface);
}
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new CustomJpaRepositoryFactory(entityManager);
}
}