我想实现一些功能来获取当前登录的用户(代表当前登录的人的 JPA 实体)。但不是用经典的方式来做
CurrentUserService.getCurrentUser(){load the user from db by login})
我想以更 CDI 的方式做到这一点。
我想要一个 CurrentUserFactory
,它将当前用户提供为具有自定义限定符(当前 bean)的请求范围 bean。
预选赛:
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface CurrentUser {
}
工厂:
@Component
public class CurrentUserFactory {
@CurrentUser
@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST,
proxyMode = ScopedProxyMode.TARGET_CLASS)
public User currentUser() throws IllegalStateException {
return
<DoWhatIMean>
User load form DB by:
SecurityContextHolder.getContext().getAuthentication().getName()
</dwim>
}
用法:
@Controller
@RequestMapping(…)
public AccountController() {
@Resource
@CurrentUser
private User currentUser;
@RequestMapping(params=”my”)
public String myAccount () {
return “redirect:/account/”+currentUser.id;
}
}
效果很好。
但是,如果我使用当前用户进行直接 JPA (Hibernate) 操作(例如通过引用 currentUser 搜索实体或引用 currentUser 存储实体),它会失败(没有真正有用的异常(exception))。 --(这个失败是显而易见的。)
原因是spring在currentUser中注入(inject)了一个CGI代理。只要仅使用该代理的属性,这种方法就可以正常工作,但如果开始使用引用本身,这种方法就会失败。
我知道我正在规范的边缘工作,如果我的想法行不通,我会接受。但我想问你我有一个让它发挥作用的想法。这样开发人员就可以像普通 JPA 加载的实体一样使用这个 currentUser 对象。
我至少想要的是仅当前用户可以非常轻松地使用:
@Resouce
@CurrenctUser
User currentUser;
就是这样。
可能有人有一个想法让它工作,例如 AspectJ 技巧(我正在使用编译时 AspectJ)?
<小时/>无论如何:正如我之前所说,异常不是我的问题,我理解它们,因为它们只是所描述问题的指标。
当我尝试通过 currentUser 加载时出现异常(从书签 b 中选择 b 其中 user=?
)
java.lang.IllegalStateException
:org.hibernate.TransientObjectException
: object references an unsaved transient instance - save the transient instance before flushing:domain.User
尝试保存书签时出现异常(书签有字段用户)
could not insert: [
domain.Bookmark
]; SQL [insert into bookmark (businessId, reference_Folder_fk, title, user_fk) values (?, ?, ?, ?)
]; constraint [null
]; nested exception isorg.hibernate.exception.ConstraintViolationException
: could not insert: [domain.Bookmark
]
最佳答案
Spring代理是由ScopedProxyFactoryBean创建的。它的文档说代理实现了“ScopedObject”,它允许您访问原始 bean。
@Resource
@CurrentUser
private User currentUser;
public static <T> T unwrapScopedProxy(T maybeProxy) {
if (maybeProxy instanceof ScopedObject) {
return (T) ((ScopedObject) maybeProxy).getTargetObject();
} else {
return maybeProxy;
}
}
...
query.setParameter("user", unwrapScopedProxy(currentUser));
关于java - Spring Scope代理模式AspectJ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6678458/