JSF 活动会话计数器。怎样做?
晚上好,
在测试 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}"/>
从另一个托管Bean:
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
Good evening,
In a test JSF 2.0 web app, I am trying to get the number of active sessions but there is a problem in the sessionDestroyed method of the HttpSessionListener.
Indeed, when a user logs in, the number of active session increases by 1, but when a user logs off, the same number remains as it is (no desincrementation happens) and the worse is that, when the same user logs in again (even though he unvalidated the session), the same number is incremented.
To put that in different words :
1- I log in, the active sessions number is incremented by 1.
2- I Logout (the session gets unvalidated)
3- I login again, the sessions number is incremented by 1. The display is = 2.
4- I repeat the operation, and the sessions number keeps being incremented, while there is only one user logged in.
So I thought that method sessionDestroyed is not properly called, or maybe effectively called after the session timeout which is a parameter in WEB.XML (mine is 60 minutes).
That is weird as this is a Session Listener and there is nothing wrong with my Class.
Does someone please have a clue?
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
I am retrieving the active sessions number this way:
<h:outputText id="sessionsfacet" value="#{UserBean.activeSessionsNumber}"/>
from another managedBean:
public String getActiveSessionsNumber() {
return String.valueOf(SessionEar.getActivesessions());
}
My logout method is as follow:
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我不知道。这对于单个访客来说似乎效果很好。但有些东西在您的 HttpSessionListener 中看起来肯定不正确。
为什么它是
@ManagedBean
?没有意义,删掉吧。在 Java EE 6 中,您可以使用@WebListener
< /a> 相反。这绝对不应该是实例变量。它不是线程安全的。将其声明为methodlocal。对于每个
HttpSessionListener
实现,在应用程序的整个生命周期中只有一个实例。当同时存在会话创建/销毁时,您的输出
会在繁忙时被另一个会话覆盖,并且您的文件将被损坏。这些也不应该是实例变量。每个新会话的创建都会覆盖它,并且它会反映到所有其他用户的演示中。即它不是线程安全的。如果您出于某种原因需要将其移至那里,请摆脱它们并在 EL 中使用
#{session.creationTime}
和#{session.maxInactiveInterval}</code> 。或者直接从 HTTP 请求中的 HttpSession 实例获取它。
在
sessionCreated()
方法中,这是始终为真。这毫无意义。将其删除。我不知道该方法到底在做什么,但我只是想警告一下,当会话即将进行时,不能保证
FacesContext
存在于线程中被创建或被摧毁。它可能发生在非 JSF 请求中。或者可能根本无法进行 HTTP 请求。因此,您将面临 NPE 的风险,因为此时FacesContext
为null
。尽管如此,我创建了以下测试片段,它对我来说效果很好。
@SessionScoped
bean 隐式创建会话。命令按钮使会话无效。所有方法均按预期调用。您在同一个浏览器选项卡中按下按钮的次数始终为 1。使用
和
(注意,在 Java EE 5 上,您需要将其注册为
in < code>web.xml 通常的方式)如果上面的示例适合您,那么您的问题可能出在其他地方。也许您根本没有在
web.xml
中将其注册为
,而您只是每次在某个登录方法中手动创建侦听器的新实例。无论如何,现在您至少有一个最小的启动示例可以进一步构建。I'm not sure. This seems to work fine for a single visitor. But some things definitely doesn't look right in your
HttpSessionListener
.Why is it a
@ManagedBean
? It makes no sense, remove it. In Java EE 6 you'd use@WebListener
instead.This should definitely not be an instance variable. It's not threadsafe. Declare it methodlocal. For every
HttpSessionListener
implementation there's only one instance throughout the application's lifetime. When there are simultaneous session creations/destroys, then youroutput
get overridden by another one while busy and your file would get corrupted.Those should also not be an instance variable. Every new session creation would override it and it would get reflected into the presentation of all other users. I.e. it is not threadsafe. Get rid of them and make use of
#{session.creationTime}
and#{session.maxInactiveInterval}
in EL if you need to get it over there for some reason. Or just get it straight from theHttpSession
instance within a HTTP request.This is always true inside
sessionCreated()
method. This makes no sense. Remove it.I don't know what that method exactly is doing, but I just want to warn that there is no guarantee that the
FacesContext
is present in the thread when the session is about to be created or destroyed. It may take place in a non-JSF request. Or there may be no means of a HTTP request at all. So you risk NPE's because theFacesContext
isnull
then.Nonetheless, I created the following test snippet and it works fine for me. The
@SessionScoped
bean implicitly creates the session. The commandbutton invalidates the session. All methods are called as expected. How many times you also press the button in the same browser tab, the count is always 1.with
and
(note on Java EE 5 you need to register it as
<listener>
inweb.xml
the usual way)If the above example works for you, then your problem likely lies somewhere else. Perhaps you didn't register it as
<listener>
inweb.xml
at all and you're simply manually creating a new instance of the listener everytime inside some login method. Regardless, now you at least have a minimum kickoff example to build further on.完全不同的方向——tomcat 支持 JMX。有一个 JMX MBean 会告诉您活动会话的数量。 (如果您的容器不是 tomcat,它应该仍然支持 JMX 并提供某种方法来跟踪它)
Something in a completely different direction - tomcat supports JMX. There is a JMX MBean that will tell you the number of active sessions. (If your container is not tomcat, it should still support JMX and provide some way to track that)
您的
public void sessionDestroyed(HttpSessionEvent se) {
被调用了吗?我不明白为什么它不会增加。用户通过注销调用session.invalidate()
后,会话将被销毁,并为下一个请求创建一个新会话。这是正常行为。Is your
public void sessionDestroyed(HttpSessionEvent se) {
called ? I don't see why it won't increment. After the user callssession.invalidate()
through logout, the session is destroyed, and for the next request a new one is created. This is normal behavior.