Frage

Guten Abend,

In einem Test JSF 2.0 -Web -App versuche ich, die Anzahl der aktiven Sitzungen zu erhalten, aber es gibt ein Problem in der SessionDestroyed -Methode des httpSessionListener. Wenn sich ein Benutzer anmeldet, erhöht sich die Anzahl der aktiven Sitzungen um 1, aber wenn sich ein Benutzer anmeldet, bleibt dieselbe Zahl so wie sie ist (es kommt zu einer Desinkrementierung), und das schlimmer ist, wenn sich derselbe Benutzer erneut anmeldet (sich erneut anmeldet ( Obwohl er die Sitzung nicht validiert hat), wird die gleiche Zahl erhöht. Um das in verschiedene Worte zu bringen:

1- I Anmeldung, die aktive Sitzungsnummer wird durch 1. 2- I-Anmeldung (die Sitzung wird nicht validiert) 3- I Login erneut. Der Betrieb, und die Sitzungsnummer wird immer wieder inkrementiert, während nur ein Benutzer angemeldet ist.

Daher dachte ich, dass Method SessionDestroyed nicht ordnungsgemäß aufgerufen oder nach dem Timeout der Sitzung, der ein Parameter in Web.xml ist, effektiv aufgerufen wurde (meine beträgt 60 Minuten). Das ist seltsam, da dies ein Session -Hörer ist und an meiner Klasse nichts falsch ist.

Hat jemand bitte eine Ahnung?

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

Ich rufe die aktive Sitzungsnummer auf diese Weise ab:

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

von einer anderen Managedbean:

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

Meine Abmeldemethode lautet wie folgt:

 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
War es hilfreich?

Lösung

Ich bin mir nicht sicher. Dies scheint für einen einzelnen Besucher gut zu funktionieren. Aber einige Dinge sehen definitiv nicht richtig in Ihrem aus HttpSessionListener.


@ManagedBean
public class SessionEar implements HttpSessionListener {

Warum ist es ein @ManagedBean? Es macht keinen Sinn, entfernen Sie es. In Java ee 6 würden Sie verwenden @WebListener stattdessen.


    BufferedWriter output = null;

Das sollte bestimmt keine Instanzvariable sein. Es ist kein Threadsafe. Deklarieren Sie es methodlocal. Für jeden HttpSessionListener Implementierung gibt es nur eines Instanz während der gesamten Lebensdauer der Anwendung. Wenn es gleichzeitige Sitzungskreationen/Zerstörungen gibt, dann Ihre output Lassen Sie sich von einem anderen überschrieben, während Sie beschäftigt sind und Ihre Datei wird beschädigt.


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

Dies sollte auch keine Instanzvariable sein. Jede neue Sitzungserstellung würde sie außer Kraft setzen und sich in der Präsentation aller anderen Benutzer widerspiegeln. Dh es ist nicht threadsafe. Sie loswerden und benutzen #{session.creationTime} und #{session.maxInactiveInterval} In El, wenn Sie es aus irgendeinem Grund dort hinüberholen müssen. Oder bekommen Sie es einfach direkt von der HttpSession Instanz innerhalb einer HTTP -Anfrage.


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

Das ist stets wahr im Inneren sessionCreated() Methode. Das macht keinen Sinn. Entfernen Sie es.


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

Ich weiß nicht, was diese Methode genau tut, aber ich möchte nur warnen, dass es gibt keine Garantie dass die FacesContext ist im Thread vorhanden, wenn die Sitzung erstellt oder zerstört wird. Es kann in einer Nicht-JSF-Anfrage stattfinden. Oder es gibt möglicherweise überhaupt keine HTTP -Anfrage. Sie riskieren also NPEs, weil die FacesContext ist null dann.


Trotzdem habe ich das folgende Test -Snippet erstellt und es funktioniert gut für mich. Das @SessionScoped Bean erstellt implizit die Sitzung. Der Befehlsbutton macht die Sitzung ungültig. Alle Methoden werden wie erwartet bezeichnet. Wie oft drücken Sie auch die Taste auf der gleichen Browser -Registerkarte, die Anzahl ist immer 1.

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

mit

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

}

und

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

}

(Hinweis zu Java ee 5 Sie müssen es registrieren als <listener> in web.xml der übliche Weg)

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

Wenn das obige Beispiel für Sie funktioniert, liegt Ihr Problem wahrscheinlich woanders. Vielleicht hast du es nicht als registriert als <listener> in web.xml Erstellen Sie überhaupt einfach eine neue Instanz des Hörers in einer Login -Methode manuell manuell. Unabhängig davon haben Sie jetzt zumindest ein minimales Auftakt -Beispiel zum weiteren Aufbau.

Andere Tipps

Etwas in einer ganz anderen Richtung - Tomcat unterstützt JMX. Es gibt eine JMX -MBEAN, die Ihnen die Anzahl der aktiven Sitzungen mitteilt. (Wenn Ihr Container kein Tomcat ist, sollte er JMX weiterhin unterstützen und eine Möglichkeit bieten, dies zu verfolgen.)

Ist dein public void sessionDestroyed(HttpSessionEvent se) { genannt ? Ich verstehe nicht, warum es nicht zunehmen wird. Nach dem Benutzeraufruf session.invalidate() Durch Abmelden wird die Sitzung zerstört und für die nächste Anfrage wird eine neue erstellt. Dies ist ein normales Verhalten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top