gpt4 book ai didi

java - Spring Data Rest 覆盖存储库( Controller 与 AOP)

转载 作者:行者123 更新时间:2023-11-30 06:33:57 25 4
gpt4 key购买 nike

域/存储库

Project {
User owner;
}

//Querydsl repositories
@RepositoryRestResource
public interface ProjectRepository extends PagingAndSortingRepository<Project, Long>, QueryDslPredicateExecutor<Project>, QuerydslBinderCustomizer<QProject> {
default void customize(QuerydslBindings bindings, QProject project) {
(...)
}
}

要求:根据经过身份验证的用户上下文过滤数据:

  • 如果用户是ROLE_PUBLIC,则根据谓词显示项目,并且用户是所有者
  • 如果用户是ROLE_ADMIN,则根据谓词过滤器显示项目。

我尝试通过几种替代方案解决:

选项 1:覆盖 @RepositoryRestController,如 Spring DATA REST 所示文档:

@RepositoryRestController
public class ProjectController {

@RequestMapping(value = "/projects", method = RequestMethod.GET)
@ResponseBody
public PagedResources<?> search(
@QuerydslPredicate(root=Project.class ,bindings =ProjectRepository.class) Predicate predicate,
@PageableDefault Pageable pageable, //
@AuthenticationPrincipal Principal principal) {

(...) // Update predicate wit user context

projectRepository.findAll(predicate,pageagle);
(...)
}

}

由于 @QueryDslPredicat 不在 RepositoryRestHandlerAdapter 列表 ( DATAREST-838 ) 上,因此引发异常:

Failed to instantiate [com.querydsl.core.types.Predicate]: Specified class is an interface

列表中最相似的argumentResolver是QuerydslAwareRootResourceInformationHandlerMethodArgumentResolver,但我不知道它是否对这个问题有用。

选项 2:这个问题是一个典型的横切问题,所以我尝试应用 AOP。定义建议并更新参数(谓词):

@Around("this(com.xxx.yyy.repository.ProjectRepository)")
public void filterProjectsByUser(final ProceedingJoinPoint pjp) throws Throwable {
Object[] args = pjp.getArgs();
// .. Find args Predicate, update it adding user profile expression and procceed.
pjp.proceed(args);
}

结果与默认存储库方法不同,而不是原始 JSON 对象(带有 _embedded、page、_links),响应为:

{
"_links" : {
"profile" : {
"href" : "http://localhost:8087/api/profile/projects"
}
}
}

选项 3使用@RestController:

@RestController
public class ProjectController {

@RequestMapping(value = "/projects/search", method = RequestMethod.GET)
@ResponseBody
public PagedResources<?> search(
@QuerydslPredicate(root=Project.class ,bindings =ProjectRepository.class) Predicate predicate,
@PageableDefault Pageable pageable, //
@AuthenticationPrincipal Principal principal) {

(...) // Update predicate wit user context

projectRepository.findAll(predicate,pageagle);
(...)
}

}

使用相同的路径@RequestMapping("/projects",...)也会覆盖其他端点(PUT、POST,...),这是不希望的。这迫使定义另一个端点(“projects/search”)。我认为这种解决方法并不优雅,并且需要新闻端点。我确信 Spring Data REST 存在更好的替代方案。

问题:

  • 对于如何解决此要求有什么建议吗?
  • 如何将 AOP 应用于 Spring Data REST 来解决横切需求?
  • 为什么在参数解析器中使用@QuerydslPredicate?

Spring Data REST 版本 2.5.6

虽然问题已经解决,但我希望收到反馈和建议。我希望 QueryDSLPredicate 注释能够得到修复,并且文档能够通过更多关于此问题的示例得到改进。

最佳答案

最后我运行了选项2,我的错误是没有返回继续调用结果:

@Aspect
@Transactional
@Component
public class FilterProjectsAspect {

@Pointcut("execution(* com.xxx.ProjectRepository.findAll(..))")
public void projectFindAll() {
}

@Around("projectFindAll()")
public Object filterProjectsByUser(final ProceedingJoinPoint pjp) throws Throwable {

Object[] args = pjp.getArgs();
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof Predicate) {
Predicate predicate=(Predicate) args[i];
BooleanExpression isProjectOwner =buildExpressionForUser()
predicate = ExpressionUtils.allOf(isProjectOwner, predicate);
args[i]=predicate; //Update args
}
return pjp.proceed(args);
}

}

关于java - Spring Data Rest 覆盖存储库( Controller 与 AOP),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45531195/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com