JSF活动会话计数器.如何



晚上好,

在一个测试JSF 2.0 web应用程序中,我试图获取活动会话的数量,但HttpSessionListener的sessionDestroyed方法出现了问题。事实上,当用户登录时,活动会话的数量会增加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}"/> 

来自另一个managedBean:

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?它没有意义,删除它。在JavaEE6中,你会使用@WebListener


    BufferedWriter output = null;

这应该肯定不是实例变量。它不安全。声明它为methodlocal。对于每个HttpSessionListener实现,在应用程序的整个生命周期中只有一个实例。当同时创建/销毁会话时,您的output会在繁忙时被另一个会话覆盖,并且您的文件会被损坏。


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

这些也不应该是实例变量。每一个新的会话创建都会覆盖它,它会反映到所有其他用户的演示中。也就是说,它不安全。如果出于某种原因需要,请去掉它们,并在EL中使用#{session.creationTime}#{session.maxInactiveInterval}。或者直接从HTTP请求中的HttpSession实例获取它。


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

这在sessionCreated()方法中总是正确的。这毫无意义。移除它。


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

我不知道该方法到底在做什么,但我只想警告一下,当会话即将创建或销毁时,不能保证线程中存在FacesContext。它可能发生在非JSF请求中。或者可能根本没有HTTP请求的方法。所以你有NPE的风险,因为FacesContext就是null


尽管如此,我还是创建了下面的测试片段,它对我来说很好。@SessionScopedbean隐式地创建了会话。命令按钮使会话无效。所有方法都按预期调用。您在同一浏览器选项卡中按下按钮的次数,计数始终为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上,您需要以通常的方式在web.xml中将其注册为<listener>

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

如果上面的例子对你有效,那么你的问题很可能在其他地方。也许您根本没有在web.xml中将其注册为<listener>,您只是每次在某个登录方法中手动创建侦听器的新实例。无论如何,现在您至少有一个最小的启动示例可以进一步构建。

完全不同的方向-tomcat支持JMX。有一个JMXMBean将告诉您活动会话的数量。(如果您的容器不是tomcat,它应该仍然支持JMX,并提供一些跟踪方法)

是否调用了您的public void sessionDestroyed(HttpSessionEvent se) {?我不明白为什么它不会增加。用户通过注销调用session.invalidate()后,会话被破坏,并为下一个请求创建一个新的会话。这是正常行为。

相关内容

  • 没有找到相关文章

最新更新