Вопрос

Добрый вечер,

В тестовом веб -приложении 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() Благодаря выходу из системы сеанс уничтожен, и для следующего запроса создается новый. Это нормальное поведение.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top