我想我在spring-session中遇到了一个bug,但我只想在这里问它是否真的是一个bug。在我忘记之前
https://github.com/paranoiabla/spring-session-issue.git
这里有一个github存储库,用于复制问题。基本上,我有2个控制器和2个jsps,所以流程如下:
http://localhost:8080/,流程通过HomepageController,在春季会话中放置一个属性,并返回呈现会话id和属性数量的homepage.jsp (1)。homepage.jsp中有一行:${pageContext.include("/include")},它调用要调用的IncludeController。IncludeController从会话存储库中查找会话,并记录属性的数量(现在它们被记录为0),并返回呈现会话id和会话属性数量(0)的include.jsp。两个jsp中的会话id是相同的,但是在pageContext.include调用之后,属性被重置为一个空映射!能不能请人确认一下这是不是个窃听器。谢谢。
发布于 2015-04-08 15:55:44
问题
问题是,当使用MapSessionRepository时,SessionRepositoryFilter将自动将HttpSession同步到Spring会话,这会覆盖API的显式使用。具体而言,正在发生以下情况:
解决方案
我认为解决这个问题有两种选择。
使用HttpSession API
那我该怎么解决这个问题。最简单的方法是停止直接使用Spring会话API。无论如何,这都是首选的,因为如果可能的话,我们不希望将自己绑定到Spring会话API。例如,不要使用以下方法:
@Controller
public class HomepageController {
@Resource(name = "sessionRepository")
private SessionRepository<ExpiringSession> sessionRepository;
@Resource(name = "sessionStrategy")
private HttpSessionStrategy sessionStrategy;
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(final Model model) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
final String sessionIds = sessionStrategy.getRequestedSessionId(request);
if (sessionIds != null) {
final ExpiringSession session = sessionRepository.getSession(sessionIds);
if (session != null) {
session.setAttribute("attr", "value");
sessionRepository.save(session);
model.addAttribute("session", session);
}
}
return "homepage";
}
}
@Controller
public class IncludeController {
private final static Logger LOG = LogManager.getLogger(IncludeController.class);
@Resource(name = "sessionRepository")
private SessionRepository<ExpiringSession> sessionRepository;
@Resource(name = "sessionStrategy")
private HttpSessionStrategy sessionStrategy;
@RequestMapping(value = "/include", method = RequestMethod.GET)
public String home(final Model model) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
final String sessionIds = sessionStrategy.getRequestedSessionId(request);
if (sessionIds != null) {
final ExpiringSession session = sessionRepository.getSession(sessionIds);
if (session != null) {
LOG.error(session.getAttributeNames().size());
model.addAttribute("session", session);
}
}
return "include";
}
}您可以使用以下方法简化它:
@Controller
public class HomepageController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(HttpServletRequest request, Model model) {
String sessionIds = request.getRequestedSessionId();
if (sessionIds != null) {
final HttpSession session = request.getSession(false);
if (session != null) {
session.setAttribute("attr", "value");
model.addAttribute("session", session);
}
}
return "homepage";
}
}
@Controller
public class IncludeController {
@RequestMapping(value = "/include", method = RequestMethod.GET)
public String home(HttpServletRequest request, final Model model) {
final String sessionIds = request.getRequestedSessionId();
if (sessionIds != null) {
final HttpSession session = request.getSession(false);
if (session != null) {
model.addAttribute("session", session);
}
}
return "include";
}
}使用RedisOperationsSessionRepository
当然,在我们不能直接使用HttpSession API的情况下,这可能会有问题。要处理这个问题,您需要使用不同的SessionRepository实现。例如,另一个修复方法是使用RedisOperationsSessionRepository。这是因为它足够聪明,只更新已更改的属性。
这意味着在上面的步骤3中,由于没有更新其他属性,Redis实现将只更新最后一次访问时间。当IncludeController请求Spring会话时,它仍然会看到保存在HomepageController中的属性。
那么为什么MapSessionRepository不这么做呢?因为MapSessionRepository是基于地图的,这是一个全部或根本不存在的东西。当值放在映射中时,它是一个put (我们不能将其分解为多个操作)。
https://stackoverflow.com/questions/29492954
复制相似问题