会话未正确失效,引发"Session is invalid"



我有一个使用Wildfly 10作为服务器的JSF 2.2应用程序。

用户登录并添加到在线用户列表中:

HttpSession session = request.getSession();
funcionario.setSessao(session);
funcionario.setIp(request.getRemoteAddr());
session.setAttribute("usuarioLogado", funcionario);

我从在线用户列表中删除注销的用户。

public class ActiveUserListener implements HttpSessionAttributeListene {
@Inject
Fixo fixo;
@Override
public void attributeAdded(HttpSessionBindingEvent event) {
if (event.getValue() instanceof Funcionario) {
fixo.getLogins().add((Funcionario) event.getValue());
}
}
@Override
public void attributeRemoved(HttpSessionBindingEvent event) {
if (event.getValue() instanceof Funcionario) {
if (event.getValue() instanceof Funcionario) {
fixo.getLogins().remove((Funcionario) event.getValue());
}
}
}
@Override
public void attributeReplaced(HttpSessionBindingEvent event) {
if (event.getValue() instanceof Funcionario) {
fixo.getLogins().add((Funcionario) event.getValue());
}
} }
public class SessionCounter implements HttpSessionListener {
@Inject
Fixo fixo;
public void sessionDestroyed(HttpSessionEvent se) {
if (se.getSession().getAttribute("usuarioLogado") != null) {            
Funcionario f = fixo.getLogins().stream().filter(o -> o.getSessaoId().equals(se.getSession().getId()))
.findAny().get();
fixo.getLogins().remove(f);
}
}
@Override
public void sessionCreated(HttpSessionEvent arg0) {
// TODO Auto-generated method stub
}}´

当我尝试打印一些用户/会话详细信息时:

public void usuConsole() {
System.out.println("nº " + fixo.getLogins().size());
for (Funcionario f : fixo.getLogins()) {
System.out.println(f.getMatricula());
if (f.getSessao() != null) {
System.out.println(f.getSessao().getId());
System.out.println(f.getSessao().getCreationTime());
System.out.println(f.getSessao().getLastAccessedTime());
}
}
}

打印一些行并在某个点:

会话无效R5EB6hKAzanm50PSRYqxcv361UMD6nJZWxJVc5P

如果很少有用户登录,这是可以的,但在很多用户登录和注销后,错误会出现

选项1:

尝试使用java.util.concurrent.CopyOnWriteArrayList实现Fixo类中的logins集合。

选项2

手动同步登录集合:

a) 使集合成为最终集合(使用对象进行同步时的良好做法。

b) 在事件侦听器方法中同步登录集合的插入和删除:

synchronized(fixo.getLogins()){
fixo.getLogins().remove((Funcionario) event.getValue());
}
synchronized(fixo.getLogins()){
fixo.getLogins().add((Funcionario) event.getValue());
}

c) 同步每个循环的:

synchronized(fixo.getLogins()){
for (Funcionario f : fixo.getLogins()) {
System.out.println(f.getMatricula());
if (f.getSessao() != null) {
System.out.println(f.getSessao().getId());
System.out.println(f.getSessao().getCreationTime());
System.out.println(f.getSessao().getLastAccessedTime());
}
}
}

现在,在任何同步块中,对logins集合的任何公共方法调用都将被阻止,直到应用程序离开块。这意味着,在运行for each循环时,将保留事件侦听器方法中对集合的任何修改,直到循环结束。根据侦听器规范,在sessionDestroyed方法完成处理之前,会话不会无效。

这至少是一个理论,尝试一下,让我们看看它是如何发展的。

最新更新