2011-06-10 67 views
4

晚上好,JSF活動會話計數器。如何?

在測試JSF 2.0 web應用程序中,我試圖獲取活動會話的數量,但在HttpSessionListener的sessionDestroyed方法中存在問題。 實際上,當用戶登錄時,活動會話的數量會增加1,但是當用戶註銷時,同樣的數字將保持原樣(不會發生解除聚集),更糟糕的是,當同一用戶再次登錄時(即使他未驗證會話),相同的數字會增加。 爲了把在不同的詞:

1-我登錄時,活動會話數量由1 2-遞增我退出(會話被未經驗證的) 3-我再次登錄時,會話編號遞增顯示= 2. 4-我重複操作,會話編號不斷增加,而只有一個用戶登錄。

所以我認爲,方法sessionDestroyed沒有正確調用,或者可能會在會話超時後被有效地調用,這是WEB.XML中的一個參數(我的時間是60分鐘)。 這很奇怪,因爲這是一個Session Listener,並且我的Class沒有任何問題。

請問有人有線索嗎?

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 

回答

10

我不確定。這對於單個訪客來說似乎很好。但有些東西肯定看起來不正確HttpSessionListener


@ManagedBean 
public class SessionEar implements HttpSessionListener { 

爲什麼是@ManagedBean?它沒有任何意義,刪除它。在Java EE 6中,您將使用@WebListener


BufferedWriter output = null; 

這應該絕對不是一個實例變量。這不是線程安全的。聲明它是locallocal。對於每個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的危險,因爲FacesContextnull


儘管如此,我創建了以下測試代碼片段,它對我來說工作正常。 @SessionScoped bean隱式創建會話。命令按鈕使會話無效。所有方法都按預期調用。有多少次你還按在同一瀏覽器選項卡中的按鈕,計數始終爲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> 

如果上面的例子爲你工作,那麼你的問題可能出在別處。也許你根本沒有在web.xml中註冊爲<listener>,你只需在某個登錄方法中手動創建一個監聽器的新實例。無論如何,現在你至少有一個最低限度的開球例子來進一步構建。

+0

一如既往的一絲不苟,它是偉大的stackoverflow有你! 是的,我在Java-EE-5下,並且監聽器在web.xml中註冊。對於聽衆來說,你不需要額外的東西就可以完成整個系列。其實那些是爲了測試。 我現在將測試您的片段和反饋! – Hanynowsky 2011-06-10 22:51:40

+0

與您的代碼片段一起測試,它沒有區別!我修改了監聽器,並且CSV文件被正確添加。另外,在創建或銷燬會話時(這兩種方法被有效地調用),使用System.out會給我一個正確的跟蹤。 實際上,當用戶註銷時,會話未經驗證,但當faces-config在註銷時重定向到登錄頁面時,會自動創建一個新會話,並且我發現會話超時和時間創建與自動創建的第一個會話有關重定向到登錄頁面發生。 – Hanynowsky 2011-06-12 19:17:32

+0

此外,我正在使用Apache JK模式,以便能夠在網絡'(http:// someip/mywebapp)'中使用Web應用程序而不是(http:// localhost:myport/mywebapp)。這可能是因爲我不斷從監聽器中獲得Apache生成的'NullPointerException',這是因爲('FaceContext ........ getRemoteUser()')在用戶登錄之前返回null! 即使會話被破壞,getCount()仍然越來越多地增加! 那麼我必須在沒有Apache的簡單網絡應用程序中進行分析並檢查! – Hanynowsky 2011-06-12 19:17:41

1

是您的public void sessionDestroyed(HttpSessionEvent se) {叫?我不明白爲什麼它不會增加。用戶通過註銷呼叫session.invalidate()後,會話被銷燬,併爲下一個請求創建一個新的請求。這是正常的行爲。

+0

是的,它是在會話被銷燬時追加csv文件而被調用的。我會根據@BalusC的建議來調整Listener並查看結果。 – Hanynowsky 2011-06-10 22:46:59

3

東西在完全不同的方向 - tomcat支持JMX。有一個JMX MBean會告訴你活動會話的數量。 (如果你的容器不是tomcat,它應該仍然支持JMX並提供一些方法來跟蹤它)

+0

My Container是Glassfish 3.1,我將研究如何使用JMX檢索信息!感謝那有用的提示。 – Hanynowsky 2011-06-10 22:33:14