域/存储库
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
显示项目根据predicate
其中 user 是owner
.
- 如果用户是
ROLE_ADMIN
显示项目根据predicate
filter.
我尝试通过几种替代方案解决:
Option 1:覆盖@RepositoryRestController
正如所说弹簧数据休息 https://docs.spring.io/spring-data/rest/docs/current/reference/html/#customizing-sdr.overriding-sdr-response-handlers doc:
@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 列表中(数据休息-838 https://jira.spring.io/browse/DATAREST-838):
Failed to instantiate [com.querydsl.core.types.Predicate]: Specified class is an interface
列表中最相似的 argumentResolver 是QuerydslAwareRootResourceInformationHandlerMethodArgumentResolver
但我不知道它是否对这个问题有用。
Option 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"
}
}
}
Option 3
Using @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 注释能够得到修复,并且文档能够通过更多关于此问题的示例得到改进。