晚上好,
在测试JSF 2.0 Web应用程序中,我试图获取活动会话的数量,但是HttpSessionListener的sessionDestroyed方法存在问题。 实际上,当用户登录时,活动会话的数量增加1,但是当用户注销时,相同的数字保持原样(没有发生去除),更糟糕的是,当同一用户再次登录时(即使他没有验证会话),相同的数字也会增加。 用不同的词语表达:
1-我登录时,活动会话号码加1。 2- I注销(会话未经验证) 3-我再次登录,会话号增加1.显示为= 2。 4-我重复操作,会话编号不断增加,而只有一个用户登录。
所以我认为sessionDestroyed方法没有被正确调用,或者可能在会话超时后被有效地调用,这是WEB.XML中的一个参数(我的是60分钟)。 这很奇怪,因为这是一个会话监听器,我的班级没有任何问题。
请有人知道吗?
package mybeans;
import entities.Users;
import java.io.*;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import jsf.util.JsfUtil;
/**
* Session Listener.
* @author TOTO
*/
@ManagedBean
public class SessionEar implements HttpSessionListener {
public String ctext;
File file = new File("sessionlog.csv");
BufferedWriter output = null;
public static int activesessions = 0;
public static long creationTime = 0;
public static int remTime = 0;
String separator = ",";
String headtext = "Session Creation Time" + separator + "Session Destruction Time" + separator + "User";
/**
*
* @return Remnant session time
*/
public static int getRemTime() {
return remTime;
}
/**
*
* @return Session creation time
*/
public static long getCreationTime() {
return creationTime;
}
/**
*
* @return System time
*/
private String getTime() {
return new Date(System.currentTimeMillis()).toString();
}
/**
*
* @return active sessions number
*/
public static int getActivesessions() {
return activesessions;
}
@Override
public void sessionCreated(HttpSessionEvent hse) {
// Insert value of remnant session time
remTime = hse.getSession().getMaxInactiveInterval();
// Insert value of Session creation time (in seconds)
creationTime = new Date(hse.getSession().getCreationTime()).getTime() / 1000;
if (hse.getSession().isNew()) {
activesessions++;
} // Increment the session number
System.out.println("Session Created at: " + getTime());
// We write into a file information about the session created
ctext = String.valueOf(new Date(hse.getSession().getCreationTime()) + separator);
String userstring = FacesContext.getCurrentInstance().getExternalContext().getRemoteUser();
// If the file does not exist, create it
try {
if (!file.exists()) {
file.createNewFile();
output = new BufferedWriter(new FileWriter(file.getName(), true));
// output.newLine();
output.write(headtext);
output.flush();
output.close();
}
output = new BufferedWriter(new FileWriter(file.getName(), true));
//output.newLine();
output.write(ctext + userstring);
output.flush();
output.close();
} catch (IOException ex) {
Logger.getLogger(SessionEar.class.getName()).log(Level.SEVERE, null, ex);
JsfUtil.addErrorMessage(ex, "Cannot append session Info to File");
}
System.out.println("Session File has been written to sessionlog.txt");
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
// Desincrement the active sessions number
activesessions--;
// Appen Infos about session destruction into CSV FILE
String stext = "\n" + new Date(se.getSession().getCreationTime()) + separator;
try {
if (!file.exists()) {
file.createNewFile();
output = new BufferedWriter(new FileWriter(file.getName(), true));
// output.newLine();
output.write(headtext);
output.flush();
output.close();
}
output = new BufferedWriter(new FileWriter(file.getName(), true));
// output.newLine();
output.write(stext);
output.flush();
output.close();
} catch (IOException ex) {
Logger.getLogger(SessionEar.class.getName()).log(Level.SEVERE, null, ex);
JsfUtil.addErrorMessage(ex, "Cannot append session Info to File");
}
}
} // END OF CLASS
我正在以这种方式检索活动会话号码:
<h:outputText id="sessionsfacet" value="#{UserBean.activeSessionsNumber}"/>
来自另一个managedBean:
public String getActiveSessionsNumber() {
return String.valueOf(SessionEar.getActivesessions());
}
我的退出方法如下:
public String logout() {
HttpSession lsession = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
if (lsession != null) {
lsession.invalidate();
}
JsfUtil.addSuccessMessage("You are now logged out.");
return "Logout";
}
// end of logout
答案 0 :(得分:10)
我不确定。这似乎适用于单个访问者。但有些事情在你的HttpSessionListener
中看起来并不合适。
@ManagedBean
public class SessionEar implements HttpSessionListener {
为什么是@ManagedBean
?没有意义,删除它。在Java EE 6中,您将改为使用@WebListener
。
BufferedWriter output = null;
这应该肯定不是实例变量。这不是线程安全的。声明它是methodlocal。对于每个HttpSessionListener
实现,在整个应用程序的生命周期中只有一个实例。当同时进行会话创建/销毁时,您的output
会在忙碌时被另一个覆盖,并且您的文件会被破坏。
public static long creationTime = 0;
public static int remTime = 0;
那些也不应该是实例变量。每个新会话创建都会覆盖它,它会反映到所有其他用户的演示文稿中。即它不是线程安全的。摆脱它们并在EL中使用#{session.creationTime}
和#{session.maxInactiveInterval}
如果由于某种原因需要将它放在那里。或者直接从HTTP请求中的HttpSession
实例中获取它。
if (hse.getSession().isNew()) {
sessionCreated()
方法中总是为true。这毫无意义。删除它。
JsfUtil.addErrorMessage(ex, "Cannot append session Info to File");
我不知道该方法到底在做什么,但我只是想警告,当会话是关于无保证时,线程中存在FacesContext
<{1}}被创造或毁灭它可能发生在非JSF请求中。或者可能根本没有HTTP请求。因此您冒着NPE的风险,因为FacesContext
当时是null
。
尽管如此,我创建了以下测试片段,它对我来说很好。 @SessionScoped
bean隐式创建会话。命令按钮使会话无效。所有方法都按预期调用。在同一浏览器选项卡中按下按钮的次数,计数始终为1。
<h:form>
<h:commandButton value="logout" action="#{bean.logout}" />
<h:outputText value="#{bean.sessionCount}" />
</h:form>
与
@ManagedBean
@SessionScoped
public class Bean implements Serializable {
public void logout() {
System.out.println("logout action invoked");
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
}
public int getSessionCount() {
System.out.println("session count getter invoked");
return SessionCounter.getCount();
}
}
和
@WebListener
public class SessionCounter implements HttpSessionListener {
private static int count;
@Override
public void sessionCreated(HttpSessionEvent event) {
System.out.println("session created: " + event.getSession().getId());
count++;
}
@Override
public void sessionDestroyed(HttpSessionEvent event) {
System.out.println("session destroyed: " + event.getSession().getId());
count--;
}
public static int getCount() {
return count;
}
}
(关于Java EE 5的注意事项,您需要以<listener>
通常的方式将其注册为web.xml
<listener>
<listener-class>com.example.SessionCounter</listener-class>
</listener>
如果以上示例适合您,那么您的问题可能就在其他地方。也许你根本没有在<listener>
中将它注册为web.xml
,而你只是在一些登录方法中手动创建一个新的侦听器实例。无论如何,现在你至少要有一个最小的启动示例来进一步构建。
答案 1 :(得分:3)
完全不同的方向 - tomcat支持JMX。有一个JMX MBean将告诉您活动会话的数量。 (如果你的容器不是tomcat,它应该仍然支持JMX并提供一些跟踪它的方法)
答案 2 :(得分:1)
你的public void sessionDestroyed(HttpSessionEvent se) {
被叫了吗?我不明白为什么它不会增加。在用户通过注销调用session.invalidate()
之后,会话被销毁,并且对于下一个请求,将创建一个新会话。这是正常行为。