2011-07-13 39 views
0

我想實現一些功能來獲取當前登錄的用戶(表示當前登錄人員的JPA實體)。但是,而不是在傳統的方式Spring Scope代理模式AspectJ?

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),它就會失敗(並非真正有用的異常)。 - (這個失敗是明確

的原因是,春天注入的currentUser的CGI代理。只要僅使用此代理的屬性,此工作正常,但如果開始使用引用本身,則失敗。

我知道我在規範的邊緣工作,我接受如果我的想法不起作用。但我想問你,我有一個想法讓它工作。這樣開發人員就可以像使用普通的JPA加載實體一樣使用這個currentUser對象。

我要的至少是這很容易只是當前用戶的使用情況:

@Resouce 
@CurrenctUser 
User currentUser; 

,就是這樣。

可能有人有一個想法讓它工作,例如一個AspectJ技巧(我正在使用編譯時AspectJ)?


反正:就像我之前說的例外是不是我的問題,我理解他們,因爲他們所描述的問題的唯一指標。

例外,當我試圖通過currentUser(Select b From Bookmark b Where user=?

java.lang.IllegalStateException加載:org.hibernate.TransientObjectException:對象引用一個未保存的瞬態的實例 - 沖洗之前保存的瞬態的實例:domain.User

例外,當我嘗試保存書籤(書籤有現場用戶)

可能不插入:[domain.Bookmark]; SQL [insert into bookmark (businessId, reference_Folder_fk, title, user_fk) values (?, ?, ?, ?)];約束[null];嵌套的例外是org.hibernate.exception.ConstraintViolationException:無法插入:[domain.Bookmark]

+0

這將有助於瞭解什麼是例外情況。 –

+0

@matt b:我添加了例外。 – Ralph

+0

是用戶對象在獲取它和'select b from bookmark b where user =?'query?之間被修改的任何地方? –

回答

1

春天代理由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)); 
+0

感謝您對「ScopedProxyFactoryBean」和「ScopedObject」的引用,以及如何展開的提示。無論如何,它不能解決問題。 「至少我想要的是當前用戶的這種非常簡單的用法......」您建議的是客戶端解決方案(程序員如何使用該樣式需要在他使用當前用戶的每一點處理正確的處理) ,我需要的是一個解決方案,用戶如何使用當前用戶必須不在乎。只有提供當前用戶的程序員才能執行這些額外的基礎結構。 – Ralph

+1

我明白了,所以你基本上反對客戶應該不知道@Resource是如何實現的。這是有效的(並且令人欽佩的是,您不會爲了權宜而犧牲架構純度)。如果你製作一個通用的API呢? 'public interface ICurrentUserHolder {User getCurrentUser(); ''不管怎樣,你必須打開代理;你可以隱藏在界面後面的展開,但仍然需要完成。 –

+0

你沒有說你如何構建查詢,但另一種選擇是創建一個Spring查詢包裝器,它可以自動解開傳遞給'setParameter'的任何Spring代理。 –