奇怪的Spring@SessionAttributes行为

奇怪的Spring@SessionAttributes行为,spring,spring-mvc,session-state,tomcat7,Spring,Spring Mvc,Session State,Tomcat7,我在2个控制器上使用@SessionAttributes,遇到了一些非常奇怪的行为。我的第一个控制器(ViewController)只是一个显示JSP页面的视图控制器。另一个是处理Ajax请求的控制器(AjaxController)。我有一个session属性,它只是一个拥有HashMap作为成员的对象。对象是地图的包装器。地图从数据库填充并放入会话中,会话通过ViewController显示良好。但是,当我通过ajax请求(AjaxController)从映射中删除并刷新页面时,ViewCon

我在2个控制器上使用@SessionAttributes,遇到了一些非常奇怪的行为。我的第一个控制器(ViewController)只是一个显示JSP页面的视图控制器。另一个是处理Ajax请求的控制器(AjaxController)。我有一个session属性,它只是一个拥有HashMap作为成员的对象。对象是地图的包装器。地图从数据库填充并放入会话中,会话通过ViewController显示良好。但是,当我通过ajax请求(AjaxController)从映射中删除并刷新页面时,ViewController有时会显示元素已被删除,但有时元素仍在。以下是代码片段:

ViewController(主页仅显示用户设置包含的地图内容

@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="/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);    
}
}
@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";
}
@RequestMapping(value="/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); 
}
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);
    }
  }
在AjaxController中:

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

@RequestMapping(value="/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);    
}
}
@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";
}
@RequestMapping(value="/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); 
}
@RequestMapping(value=“/users/listeners/{externalId}”,method=RequestMethod.DELETE)
公共@ResponseBody
AjaxResponse deleteListener(模型映射模型,
@路径变量(长外部ID){
CustomUserPrincipal userPrincipal=authenticationHelpers.getUserPrincipal();
UserSettings UserSettings=userPrincipal.getUserSettings();
userSettings.removeListener(externalId);
返回新的AjaxResponse(null,true);
}

我希望这有助于阐明这个问题!

我在@SessionAttributes中遇到了类似的问题。控制器在类级别上有@SessionAttributes注释,其中一个方法处理POST请求,并将会话管理对象的一个实例作为参数包含在内。该实例保存到数据库中,但被删除e-被后续请求使用,导致一些数据损坏。我们必须添加另一个SessionStatus类型的方法参数,并调用
SessionStatus.setComplete()
。这会导致实例从会话中删除,并防止重用和损坏。因此,请尝试将SessionStatus实例添加到控制器的处理程序方法中,并在适当的情况下调用setComplete()


编辑:我在初始答案中意外引用了getter
isComplete()
;我的意思是引用setter
setComplete()

我在@SessionAttributes上遇到了类似的问题。控制器在类级别上有@SessionAttributes注释,其中一个方法处理POST请求,并包含会话管理对象的实例作为参数。该实例已保存到数据库中,但被后续请求重新使用,导致some数据损坏。我们必须添加另一个SessionStatus类型的方法参数,并调用
SessionStatus.setComplete()
。这导致实例从会话中删除,并防止重用和损坏。因此,请尝试将SessionStatus实例添加到控制器的处理程序方法中,然后调用setComplete()在适当情况下


编辑:我在最初的回答中意外引用了getter
isComplete()
;我的意思是引用setter
setComplete()

@SessionAttributes特定于一个控制器,并且不在多个控制器之间共享。 相反,考虑使用手动SeaSt.Stand(class HtpScript).< /P>
您应该看看这里:

@SessionAttributes是特定于一个控制器的,并且不在多个控制器之间共享。 相反,考虑使用手动SeaSt.Stand(class HtpScript).< /P>
你应该看看这里:

你可能想看看这个谢谢链接。问题是,线程说@SessionAttributes工作的方式与我看到的行为不同。对象在两个控制器中都存在,但当我通过userSettings.removeSetting(..)删除设置时,它有时删除,有时不删除。“每个控制器都有自己的模型映射,因此在controller1中作为@SessionAttributes放置的某些内容在controller2中不可用,反之亦然。要实现这一点,您必须自己手动在会话中放置内容。"-从上面的链接看,这也不是我看到的行为。当我在ViewController中设置属性时,当请求进入AjaxController时,它就在模型中。在这种情况下,跨控制器访问属性可能仍然是错误的。此外,添加一点可能会有帮助,即我在停止时看到相同的行为我们在UserPrincipal(SpringSecurity)中包含了所有这些内容。这也是不正确的用法吗?从数据库中填充userSettings的位置在哪里?您可以提供此代码,以及removeSetting方法的代码吗?您可能需要查看此代码。感谢链接。问题是,线程表示@SessionAttributes工作的方式与我看到的行为不同。对象在两个controlle中都存在rs,但当我通过userSettings.removeSetting(..)删除设置时,它有时删除,有时不删除。“每个控制器都有自己的模型映射,因此在controller1中作为@SessionAttributes放置的某些内容在controller2中不可用,反之亦然。要使其工作,您必须自己手动将这些内容放置在会话中。”-从上面的链接看,这也不是我看到的行为。当我在ViewController中设置属性时,当请求进入AjaxController时,它就在模型中。在这种情况下,跨控制器访问属性可能仍然是错误的。此外,添加一点可能会有帮助,即我在停止时看到相同的行为UserPrincipal(SpringSecurity)中包含所有这些内容。这也是不正确的用法吗?从数据库中填充userSettings的位置在哪里?能否提供此代码以及removeSetting方法的代码?我尝试了setComplete()和isComplete()行为没有改变。如果我在会话中从映射中删除,则需要1到n次尝试“粘住”。我尝试了setComplete()和isComplete(),但行为没有改变。如果我删除f