JSF Active Sessions Счетчик. Как?
-
26-10-2019 - |
Вопрос
Добрый вечер,
В тестовом веб -приложении JSF 2.0 я пытаюсь получить количество активных сеансов, но в методе SessionDestroyed of HttpsessionListener есть проблема. Действительно, когда пользователь входит в систему, количество активного сеанса увеличивается на 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}"/>
от другого управляемого бобов:
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
Решение
Я не уверен. Похоже, это отлично работает для одного посетителя. Но некоторые вещи определенно не выглядят правильно в вашем HttpSessionListener
.
@ManagedBean
public class SessionEar implements HttpSessionListener {
Почему это @ManagedBean
? Это не имеет смысла, удалите его. В Java EE 6 вы бы использовали @WebListener
вместо.
BufferedWriter output = null;
Это должно определенно не быть переменной экземпляра. Это не Threadsafe. Объявить это метод. Для каждого HttpSessionListener
Реализация есть только один экземпляр на протяжении всей жизни приложения. Когда существуют одновременные создания/уничтожения сессии, то ваши output
Получите переопределение другим, пока занят, и ваш файл будет поврежден.
public static long creationTime = 0;
public static int remTime = 0;
Это также не должно быть переменной экземпляра. Каждое создание нового сеанса будет переопределить его, и оно будет отражено в представлении всех других пользователей. Т.е. это не Threadsafe. Избавиться от них и использовать #{session.creationTime}
а также #{session.maxInactiveInterval}
В EL, если вам нужно получить его там по какой -то причине. Или просто получите это прямо из HttpSession
экземпляр в HTTP -запросе.
if (hse.getSession().isNew()) {
Это всегда верно внутри sessionCreated()
метод Это не имеет никакого смысла. Убери это.
JsfUtil.addErrorMessage(ex, "Cannot append session Info to File");
Я не знаю, что именно делает этот метод, но я просто хочу предупредить, что есть нет гарантии что FacesContext
присутствует в потоке, когда сеанс будет создан или уничтожен. Это может произойти в запросе без JSF. Или не может быть никаких средств для HTTP -запроса вообще. Так что вы рискуете NPE, потому что FacesContext
является null
тогда.
Тем не менее, я создал следующий тестовый фрагмент, и он отлично работает для меня. А @SessionScoped
Бин косвенно создает сессию. Командовая дама лишает снятия недействительной сеанс. Все методы называются, как и ожидалось. Сколько раз вы также нажимаете кнопку на одной и той же вкладке браузера, счет всегда 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
Вообще, и вы просто вручную создаете новый экземпляр слушателя каждый раз внутри какого -то метода входа в систему. Несмотря на это, теперь у вас, по крайней мере, у вас есть минимальный пример старта для дальнейшего строительства.
Другие советы
Что -то в совершенно другом направлении - Tomcat поддерживает JMX. Есть JMX MBEN, который расскажет вам количество активных сессий. (Если ваш контейнер не Tomcat, он все равно должен поддерживать JMX и предоставить какой -то способ отслеживать это)
Это ваш public void sessionDestroyed(HttpSessionEvent se) {
называется ? Я не понимаю, почему это не увеличит. После звонков пользователя session.invalidate()
Благодаря выходу из системы сеанс уничтожен, и для следующего запроса создается новый. Это нормальное поведение.