1

当有人向我的应用程序发出 servlet 请求时,会创建一个会话。我正在为此连接创建一个唯一 ID 并将其返回给客户端。

当客户端返回该唯一 ID 时,我想将它们重新附加到现有会话,而不管 jsessionid 附带什么。

想法?

4

4 回答 4

5

这就是应用程序/Web 容器的工作。默认情况下,应用程序/Web 容器关联所需的会话。我认为容器不会提供可用于查找会话的 API。

您的用例表明您不希望应用程序/Web 容器创建会话并且您希望自己管理它。在这种情况下,从应用程序/Web 容器的角度来看,每个请求都是无状态的。您可以使用地图(如果是集群环境,则为分布式地图)为自己管理会话。您将需要管理很多东西,包括安全性、持久性、超时等等。

于 2013-07-18T12:41:00.537 回答
0

我假设在收到请求之前服务器上的现有会话超时,而不是因为用户注销。

由于会话将被删除并且其数据丢失,您必须制作会话数据的副本以允许自动“会话继续”。

注意未经测试的代码,只是一个想法。

这个想法是观察HttpSessionListener.sessionDestroyed()事件:

class SessionDataBackupListener implements HttpSessionListener {
    private Map<String,Object> oldSessions = new HashMap<String,Object>();

    public void sessionDestroyed(HttpSessionEvent event) {
      final Session s = event.getSession();
      if (s.getAttribute("logOut")) {
        // Session was closed on-command, nothing to do.
        return;
      }

      // Session (probably) timed-out.
      Object sessionData = extractSessionData(s);

      // This should go into some kind of singleton DAO object.
      oldSessions.put(s.getAttribute("uniqueId"), sessionData);
    }
}

您的注销处理程序如下所示:

  public void logOut(HttpServletRequest req) {
    final Session s = req.getSession();
    final String userId = s.getParameter("userId");
    // Log the user out.

    // Mark the session was closed on-command.
    s.setAttribute("logOut", Boolean.TRUE);
  }

您的登录处理程序如下所示:

  public void logIn(HttpServletRequest req) {
    final String uniqueId = s.getParameter("uniqueId");
    Session s = req.getSession(false);

    // User returning after time-out?
    if (s == null && uniqueId != null) {
      // Create new session...
      s = req.getSession(true);

      // ...assign it the same uniqueId...
      s.setAttribute("uniqueId", uniqueId);

      // ...and put back old session data.
      copyDataToSession(s, getOldSessionData(uniqueId));
    }
    else {
      // User logging in as usual.
    }
  }

getOldSessionData(final String uniqueId)将查找较早会话的单例 DAO 对象。

于 2013-08-01T11:57:49.590 回答
0

使用 Session 对象获取会话 ID。

拿一张地图,TreeMap。SessionId 将是关键,您的 uniqueId 将是值。

对于检查地图之前的每个请求,都包含 SessionId,如果不存在,则将键值放入地图中。

确保您使用的 TreeMap 是静态的。

最后,当您使会话无效时,从 TreeMap 中删除密钥。

使用 TreeMap 的原因是它不允许空值。因此,即使错误地您也无法插入空值,但如果性能有问题,请使用 HashMap,它与 TreeMap 相比更好。

于 2013-07-30T18:09:11.353 回答
0

不确定您的真正要求是什么,但在我看来,您似乎想控制会话 ID,而不是依赖于生成的容器jsessionid

对我来说,最简单的解决方案是自定义应用程序服务器/Web 容器使用的会话标识符。所有的服务器都提供了这个功能,所以基本上我会通过以下方式实现它:

  1. 如果您不喜欢,自定义您的服务器以使用您想要的会话标识参数名称jsessionid

  2. 创建一个会话自定义会话存储库或管理器,它将管理您的容器的会话。此步骤将特定于您的服务器,基本上您要确保所有服务器实例都使用他们需要查找/更新会话的中央存储库。这将处理多服务器部署,而不需要基于粘性会话的负载平衡。

  3. 将创建/更新/重新附加/删除会话的工作留给容器。它的建立就是为了做到这一点。

现在,如果您认为这似乎是很多配置,并且非常特定于容器,我同意您的看法。但我也认为重复已经存在的功能(DRY)是没有意义的。

如果我阅读了您的问题并尝试将其分解为功能,那么它基本上完全是服务器处理 Http 会话的方式,使用了一个已识别的常规称为jsessionid. 因此,自定义现有功能感觉像是一个自然的解决方案。

希望这可以帮助。如果我误解了你的问题,请告诉我。

于 2013-08-05T10:48:14.647 回答