2012-05-25 40 views
2

我在2控制器上使用@SessionAttributes,並遇到一些非常奇怪的行爲。我的第一個控制器(ViewController)只是一個顯示JSP頁面的視圖控制器。另一個是處理Ajax請求的控制器(AjaxController)。我有一個會話屬性,它只是一個HashMap作爲成員的對象。該對象是地圖周圍的包裝。該映射從數據庫填充並放入會話中,該會話通過ViewController顯示正常。但是,當我通過ajax請求(AjaxController)從地圖中刪除並刷新頁面時,ViewController SOMETIMES顯示該元素已被刪除,但其他時間元素仍然存在。這裏的代碼片段:奇怪的春天@SessionAttributes行爲

的ViewController(網頁僅顯示通過userSettings

@Controller 
@SessionAttributes({"userSettings"}) 
public class ViewController { 

@RequestMapping(value="/", method=RequestMethod.GET) 
    public String home(ModelMap model) { 
     UserSettings userSettings = (UserSettings) model.get("userSettings"); 
     String userListenersJson = userSettings.toJson(); // for bootsrtapping the js on the front end 

     return "views/home"; 
    } 
} 

AjaxController包含地圖的內容:

@Controller 
@SessionAttributes({"userSettings"}) 
public class AjaxController { 

@RequestMapping(value="https://stackoverflow.com/users/listeners/{externalId}", method=RequestMethod.DELETE) 
public @ResponseBody 
AjaxResponse<?> deleteListener(ModelMap model, 
     @PathVariable long externalId) { 

      UserSettings userSettings = (UserSettings) model.get("userSettings"); 
      userSettings.removeSetting(externalId); 
      return new AjaxResponse<String>(null, true);  
} 
} 

我使用@SessionAttributes錯在這裏爲什麼會產生?這項工作有時而不是其他人?我也嘗試將所有視圖和ajax功能放在同一個控制器中,並且經歷相同的行爲。

感謝您的幫助!

編輯:

我已經重構我的代碼位通過springsecurity使用UserPrincipal。我的理解是這個對象存儲在會話中。無論如何,我看到完全一樣的行爲。

以下是填充用戶設置映射的UserPrincipal構造函數。我在這裏設置了斷點,以確保正確的listenerDBO被設置 - 每次都是這樣。這是偵聽器唯一一次從數據庫設置到CustomUserPrincipal的UserSettings對象中。所有其他增加/移除了通過控制器進行(快速預留:將永遠不會失敗...只是刪除):

public CustomUserPrincipal(UserDBO userDBO) { 
    // set UserSettings obj 
    UserSettingsAdapter.addListeners(userDBO.getUserListenerDBOs(), userSettings); 
} 

的UserSettings對象本身:

public class UserSettings implements Serializable { 

    private static final long serialVersionUID = -1882864351438544088L; 
    private static final Logger log = Logger.getLogger(UserSettings.class); 

    private Map<Long, Listener> userListeners = Collections.synchronizedMap(new HashMap<Long, Listener>(1)); 

    // get the listeners as an arraylist 
    public List<Listener> userListeners() { 
     return new ArrayList<Listener>(userListeners.values()); 
    } 

    public Map<Long, Listener> getUserListeners() { 
     return userListeners; 
    } 

    public Listener addListener(Listener listener) { 
     userListeners.put(listener.getId(), listener); 
     return listener; 
    } 

    // I'm logging here to try and debug the issue. I do see the success 
    // message each time this function is called 
    public Listener removeListener(Long id) { 
     Listener l = userListeners.remove(id); 
     if (l == null) { 
      log.info("failed to remove listener with id " + id); 
     } else { 
      log.info("successfully removed listener with id " + id); 
     } 

     log.info("Resulting map: " + userListeners.toString()); 
     log.info("Map hashcode: " + userListeners.hashCode()); 

     return l; 
    } 


    public Listener getListener(long id) { 
     return userListeners.get(id); 
    } 
    } 

這是輔助功能UserSettingsAdapter類,增加了UserSettings對象,從CustomUserDetails構造函數調用:

public static void addListeners(Set<UserListenerDBO> userListeners, UserSettings userSettings) { 
    for (UserListenerDBO userListenerDBO : userListeners) { 
     if (userListenerDBO.isActive()) { 
      addListener(userListenerDBO, userSettings); 
     } 
    } 
} 

我也改變了控制器代碼用戶CustomUserPrincipal objec的T代替@SessionAttributes:

在視圖控制器:

@RequestMapping(value="/", method=RequestMethod.GET) 
public String home(ModelMap model) { 
    CustomUserPrincipal userPrincipal = authenticationHelpers.getUserPrincipal(); 
    UserSettings userSettings = userPrincipal.getUserSettings(); 
    String userListenersJson = userSettings.toJson(); 
    return "views/home"; 
} 

在AjaxController:

@RequestMapping(value="https://stackoverflow.com/users/listeners/{externalId}", method=RequestMethod.DELETE) 
public @ResponseBody 
AjaxResponse<?> deleteListener(ModelMap model, 
     @PathVariable long externalId) { 
    CustomUserPrincipal userPrincipal = authenticationHelpers.getUserPrincipal(); 
    UserSettings userSettings = userPrincipal.getUserSettings(); 
    userSettings.removeListener(externalId); 

    return new AjaxResponse<String>(null, true); 
} 

我希望這有助於闡明這個問題一些輕!

+0

[@SessionAttributes問題(http://forum.springsource.org/showthread.php?49396-SessionAttribute-problems),你可能想看看這個 –

+0

感謝鏈接。事情就是,線程說@SessionAttributes工作的方式與我所看到的行爲不同。該對象在兩個控制器中,但是當我通過userSettings.removeSetting(..)刪除設置時,它有時會刪除,有時不會。 – threejeez

+0

「每個控制器都有它自己的ModelMap,因此控制器2中沒有可用的控制器1中的@SessionAttributes,反之亦然。爲此,您必須自己手動將這些內容放在會話中。」 - 從上面的鏈接 –

回答

0

我遇到了@SessionAttributes類似的問題。控制器在類級別有一個@SessionAttributes註釋,其中一個方法處理POST請求,並將會話管理對象的一個​​實例作爲參數。這個實例保存到數據庫中,但被後續請求重複使用,導致一些數據損壞。我們必須添加SessionStatus類型的另一個方法參數,並調用SessionStatus.setComplete()。這導致實例從會話中刪除,並阻止重用和損壞。因此,請嘗試將SessionStatus實例添加到您的控制器的處理程序方法中,並在適當的地方調用setComplete()。

編輯:我不小心引用了我最初的答案中的getter isComplete();我打算參考setter setComplete()

+0

我試過setComplete()和isComplete(),行爲沒有改變。如果我在會話中從地圖中刪除,它會從1到n嘗試「粘貼」。 – threejeez