Question

Bonsoir,

Dans un test JSF 2.0 application web, je tente d'obtenir le nombre de sessions actives, mais il y a un problème dans la méthode sessionDestroyed du HttpSessionListener. En effet, lorsqu'un utilisateur se connecte, le nombre d'augmentations de session active par 1, mais lorsqu'un utilisateur se déconnecte, le même nombre reste tel qu'il est (pas desincrementation arrive) et le pire est que, lorsque les mêmes utilisateur se connecte à nouveau ( même si il unvalidated la session), le même nombre est incrémenté. Pour mettre cela en des termes différents:

1 je me connecte, le nombre de sessions actives est incrémenté de 1. 2- Je Déconnexion (la session se unvalidated) 3- Je me connecte à nouveau, le nombre de sessions est augmenté de 1. L'affichage est = 2. 4- Je répète l'opération et le nombre de séances continue à être incrémentée, alors qu'il n'y a qu'un seul utilisateur connecté.

Je pense que la méthode sessionDestroyed est pas correctement appelé, ou peut-être appelé efficacement après le délai d'expiration de la session qui est un paramètre dans WEB.XML (le mien est de 60 minutes). C'est bizarre que cela est une session d'écoute et il n'y a rien de mal de ma classe.

quelqu'un ne s'il vous plaît avoir un indice?

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

Je suis en train de récupérer le nombre de sessions actives ainsi:

<h:outputText id="sessionsfacet" value="#{UserBean.activeSessionsNumber}"/> 

d'un autre managedBean:

public String getActiveSessionsNumber() {
        return String.valueOf(SessionEar.getActivesessions());
    }

Ma méthode logout est comme suit:

 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
Était-ce utile?

La solution

Je ne suis pas sûr. Cela semble fonctionner très bien pour un seul visiteur. Mais certaines choses ne certainement pas l'air directement dans votre HttpSessionListener.


@ManagedBean
public class SessionEar implements HttpSessionListener {

Pourquoi est-il un @ManagedBean? Il n'a pas de sens, retirez-le. En Java EE 6 que vous souhaitez utiliser @WebListener à la place.


    BufferedWriter output = null;

Cela devrait certainement ne pas être une variable d'instance. Ce n'est pas threadsafe. Déclarer methodlocal. Pour chaque mise en œuvre de HttpSessionListener il n'y a que une instance tout au long de la durée de vie de l'application. Quand il y a des créations de session simultanée / Détruit, votre output se redéfinie par un autre tout occupé et votre fichier sera altéré.


    public static long creationTime = 0;
    public static int remTime = 0;

Les devraient pas être une variable d'instance. Chaque nouvelle création de la session emporterait et il se reflète dans la présentation de tous les autres utilisateurs. C'est à dire. il n'est pas threadsafe. Débarrassez-vous d'eux et de faire usage de #{session.creationTime} et #{session.maxInactiveInterval} à EL si vous avez besoin pour l'obtenir là-bas pour une raison quelconque. Ou tout simplement l'obtenir directement de l'instance HttpSession dans une requête HTTP.


    if (hse.getSession().isNew()) {

Ceci est vrai toujours méthode à l'intérieur de sessionCreated(). Cela n'a aucun sens. Retirez-le.


        JsfUtil.addErrorMessage(ex, "Cannot append session Info to File");

Je ne sais pas ce que cette méthode est exactement fait, mais je veux juste avertir qu'il ya aucune garantie que le FacesContext est présent dans le fil lorsque la session est sur le point d'être créé ou détruit. Il peut avoir lieu dans une demande non JSF. Ou il peut y avoir aucun moyen d'une requête HTTP du tout. Donc, vous risquez de NPE est parce que le FacesContext est null alors.


Néanmoins, j'ai créé l'extrait de test suivant et il fonctionne très bien pour moi. La fève de @SessionScoped crée implicitement la session. La commandbutton annule la session. Toutes les méthodes sont appelées comme prévu. Combien de fois vous appuyez également sur le bouton dans le même onglet du navigateur, le compte est toujours 1.

<h:form>
    <h:commandButton value="logout" action="#{bean.logout}" />
    <h:outputText value="#{bean.sessionCount}" />
</h:form>

avec

@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();
    }

}

et

@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;
    }

}

(note sur Java EE 5 vous devez vous inscrire comme <listener> dans web.xml la manière habituelle)

<listener>
    <listener-class>com.example.SessionCounter</listener-class>
</listener>

Si l'exemple ci-dessus fonctionne pour vous, alors votre problème est probablement quelque part ailleurs. Peut-être que vous n'avez pas enregistré comme <listener> dans web.xml du tout et vous êtes tout simplement créer manuellement une nouvelle instance de l'auditeur à chaque fois de l'intérieur d'une méthode de connexion. Peu importe, maintenant, vous avez au moins un exemple minimum de coup d'envoi pour construire plus loin.

Autres conseils

Quelque chose dans une direction complètement différente - tomcat supports JMX. Il y a un MBean JMX qui vous indiquera le nombre de sessions actives. (Si votre conteneur n'est pas tomcat, il devrait encore soutenir JMX et de fournir un moyen de piste)

Votre public void sessionDestroyed(HttpSessionEvent se) { appelé? Je ne vois pas pourquoi il ne sera pas augmenter. Après l'utilisateur appelle session.invalidate() par fermeture de session, la session est détruite, et pour la prochaine demande un nouveau est créé. Ce comportement est normal.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top