JSF Active Sessions计数器.如何?

Han*_*sky 4 jsf servlets java-ee-5 servlet-listeners

晚上好,

在测试JSF 2.0 Web应用程序中,我试图获取活动会话的数量,但HttpSessionListener的sessionDestroyed方法中存在问题.实际上,当用户登录时,活动会话的数量增加1,但是当用户注销时,相同的数字保持原样(没有发生去除),更糟糕的是,当同一用户再次登录时(即使他没有验证会话),相同的数字也会增加.用不同的话来说:

1- I登录,活动会话编号增加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
Run Code Online (Sandbox Code Playgroud)

我正在以这种方式检索活动会话号码:

<h:outputText id="sessionsfacet" value="#{UserBean.activeSessionsNumber}"/> 
Run Code Online (Sandbox Code Playgroud)

来自另一个managedBean:

public String getActiveSessionsNumber() {
        return String.valueOf(SessionEar.getActivesessions());
    }
Run Code Online (Sandbox Code Playgroud)

我的注销方法如下:

 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
Run Code Online (Sandbox Code Playgroud)

Bal*_*usC 10

我不确定.这似乎适用于单个访问者.但有些事情肯定不适合你的HttpSessionListener.


@ManagedBean
public class SessionEar implements HttpSessionListener {
Run Code Online (Sandbox Code Playgroud)

为什么@ManagedBean?没有意义,删除它.在Java EE 6中,您可以使用它@WebListener.


    BufferedWriter output = null;
Run Code Online (Sandbox Code Playgroud)

绝对不应该是一个实例变量.这不是线程安全的.声明它是methodlocal.对于每个HttpSessionListener实现,在整个应用程序的生命周期中只有一个实例.当同时进行会话创建/销毁时,那么output在忙碌时你会被另一个被覆盖,你的文件就会被破坏.


    public static long creationTime = 0;
    public static int remTime = 0;
Run Code Online (Sandbox Code Playgroud)

那些也不应该是一个实例变量.每个新会话创建都会覆盖它,它会反映到所有其他用户的演示文稿中.即它不是线程安全的.摆脱他们和利用#{session.creationTime},并#{session.maxInactiveInterval}在EL如果你需要得到它那边的某些原因.或者直接从HttpSessionHTTP请求中的实例中获取它.


    if (hse.getSession().isNew()) {
Run Code Online (Sandbox Code Playgroud)

这是始终里面真正的sessionCreated()方法.这毫无意义.去掉它.


        JsfUtil.addErrorMessage(ex, "Cannot append session Info to File");
Run Code Online (Sandbox Code Playgroud)

我不知道那是什么方法究竟是干什么的,但我只是想提醒,有没有保证的是,FacesContext出现在线程当会话即将被创造或毁灭.它可能发生在非JSF请求中.或者可能根本没有HTTP请求.所以,你的风险NPE的,因为FacesContextnull那么.


尽管如此,我创建了以下测试片段,它对我来说很好.该@SessionScoped豆隐式创建会话.命令按钮使会话无效.所有方法都按预期调用.您在同一浏览器选项卡中按下按钮的次数,计数始终为1.

<h:form>
    <h:commandButton value="logout" action="#{bean.logout}" />
    <h:outputText value="#{bean.sessionCount}" />
</h:form>
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)

(在Java EE 5的注意,你需要将其注册为<listener>web.xml通常的方式)

<listener>
    <listener-class>com.example.SessionCounter</listener-class>
</listener>
Run Code Online (Sandbox Code Playgroud)

如果上面的示例适合您,那么您的问题可能就在其他地方.也许你并没有把它注册为<listener>web.xml所有和你只是手动创建里面的一些登录方法听者每次的新实例.无论如何,现在你至少要有一个最小的启动示例来进一步构建.