Jakarta ee 如果上一个会话已处于活动状态(如果用户忘记注销),请使用JAAS删除该会话

Jakarta ee 如果上一个会话已处于活动状态(如果用户忘记注销),请使用JAAS删除该会话,jakarta-ee,servlets,jaas,java-ee-7,jdbcrealm,Jakarta Ee,Servlets,Jaas,Java Ee 7,Jdbcrealm,让下面的类成为会话范围的CDI托管bean @Named @SessionScoped public class SessionUtils implements Serializable { private Map<String, Object>sessionMap; private static final long serialVersionUID=1l; public SessionUtils() {} @PostConstruct

让下面的类成为会话范围的CDI托管bean

@Named
@SessionScoped
public class SessionUtils implements Serializable
{
    private Map<String, Object>sessionMap;
    private static final long serialVersionUID=1l;

    public SessionUtils() {}

    @PostConstruct
    private void init() {
        sessionMap=new HashMap<String, Object>();
    }

    public Map<String, Object> getSessionMap() {
        return sessionMap;
    }
}
我需要调用以下
HttpSessionBindingListener

public final class User implements HttpSessionBindingListener {
    private static final Map<UserTable, HttpSession> logins = new HashMap<UserTable, HttpSession>();

    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        System.out.println("valueBound() called.");
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        System.out.println("valueUnbound() called.");           
    }
}
但是,如果将
User
的一个实例简单地存储到会话映射中(在该cdibean中),它们就不会被调用

JAAS/CDI中是否有其他方法来处理相同的问题—模拟HttpSessionBindingListener

我想做的是:如果用户忘记注销,那么在他/她下次尝试登录时,应该删除(上一次仍处于活动状态)会话


另外一件事:
UserTable
(不是
User
——它只是一个示例。)是一个实际的JPA实体类。
HttpSessionBindingListener
需要在JPA实体上实现,而JPA实体又需要从
javax.servlet
包中获得对服务层的额外依赖,这不必要地增加了模块之间的耦合

这是否可以隔离开来,以便在web层上实现
HttpSessionBindingListener
(无论JPA实体类-
UserTable
是否仍为该类服务,即当
UserTable
的实例放入会话时,
valueBound()当从
HttpSession
中删除
UserTable
的一个实例时,将调用
方法…并且
valueUnbound()
,替换为另一个会话属性,或者会话本身被销毁/无效)?我希望在高级JavaEE中有一些方法


题目没有应有的意义。我将在以后编辑它,当我设想一个更有意义的标题时,或者如果您愿意,您可以在此之前自愿编辑它。

据我所知,问题是,为什么只有在您调用
request.getSession()
时才会调用
HttpSessionBindingListener

只有当您调用
request.getSession()
时,会话才会被创建,因此监听器被调用。 所以您需要调用该方法来启动会话,否则,如果您稍后在请求期间调用该方法,会话将启动

顺便说一下,在静态变量中存储
HttpSession
是一种不好的做法,如果您“忘记”删除它,可能会导致内存泄漏

为了实现您想要做的事情,我将只在会话侦听器中存储一组静态的
request.getSession().getId()
。在过滤器中,我将检查集合是否有这样的
id
,这样您将获得一个现有会话或创建一个新会话。 或者,如果您确实需要知道会话属于哪个用户,则仍然存储在map中

如果用户忘记注销,则(上一个仍处于活动状态)会话 应在他/她下次尝试登录时删除

我通常只需在呈现登录页面时放弃“当前”会话:

request.getSession().invalidate();

换句话说,进入登录页面意味着退出当前会话。

实际上,当HttpSessionBindingListener
的一个实现实例被设置为会话属性并且调用了
valueUnbound()
方法时,调用了
HttpSessionBindingListener
的重写方法
valueUnbound(),当其实现的实例从会话中删除、替换为另一个属性或会话本身被销毁/失效时。会话实际上已经创建(当客户端发送第一个请求时)。我正在寻找一种方法来调用这些方法,而不必公开
HttpSession
,比如
request.getSession()
(因为我使用的是CDIBeans)并删除服务层上的
javax.servlet.*
API的额外依赖项,因为实体类在需要实现此接口的服务层(EJB模块)上可用。对该层的这种依赖意味着模块之间的紧密耦合。无论如何,感谢您花时间讨论这个问题:)我将使用
HttpSessionAttributeListener
,因为当您将
User
设置为属性时,而不仅仅是在创建会话时,将调用它。然后使用
@ApplicationScoped
bean存储
UserId
SessionId
的映射。需要注意的是,如果需要扩展到单个服务器之外,则需要某种外部存储来处理
UserId
/
SessionId
映射,但这需要在与用户相关联的实体类(
User
)上实现
HttpSessionAttributeListener
)。实体类在服务层上可用,这反过来需要来自
javax.servlet
API的额外依赖,这是不正确的,并且增加了模块之间的耦合-服务层上的EJB不一定是本地的(如
@local
所示)。它们可以是部署在单独服务器上的远程EJB,只有在添加了单独的库的情况下才能获取
javax.servlet
javax.servlet
是一个web层的东西,服务层应该不知道。不需要在实体类上实现侦听器类
HttpSessionaDistributeListener
,用
@WebListener
正确注释,在web层上是独立的,仅在会话映射中添加或删除
用户
(或任何类)对象时侦听。在这种情况下,分离很容易保持。使用远程EJB进行会话管理当然是可以做到的,但在操作上会很复杂且成本高昂。使用memcached之类的工具会更简单、更具可扩展性。在放弃当前用户的会话之前,需要验证正在登录的用户是否已经有一个活动HTTP会话,该会话将导致维护一个用户会话列表。这个问题暗示着这类事情。对于e
request.getSession().setAttribute("newUser", new User()); //Or remove
sessionMap.put("newUser", new User());
request.getSession().invalidate();