JSFアクティブセッションカウンター。方法?
-
26-10-2019 - |
質問
こんばんは、
JSF 2.0 Webアプリのテストでは、アクティブなセッションの数を取得しようとしていますが、httpsessionlistenerのセッションdestroyedメソッドに問題があります。実際、ユーザーがログインすると、アクティブなセッションの数が1増加しますが、ユーザーがログオフすると、同じ数がそのまま残ります(解除は発生しません)。彼がセッションを検証しなかったとしても)、同じ数が増加します。それを別の言葉で言えば:
1-ログイン、アクティブセッション番号は1で増加します。操作、およびセッション番号は増加し続けますが、ログインしているユーザーは1人だけです。
したがって、メソッドセッションデストロエドは適切に呼び出されていないか、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
?それは意味がありません、それを削除してください。 Java EE 6で使用します @WebListener
代わりは。
BufferedWriter output = null;
これはすべきです 絶対 インスタンス変数ではありません。それはスレッドセーフではありません。 MethodLocalを宣言します。すべてのための HttpSessionListener
実装しかありません 1 アプリケーションの生涯を通してインスタンス。同時セッションの作成/破壊がある場合、あなたの output
忙しい間、別の人にオーバーライドされ、ファイルが破損します。
public static long creationTime = 0;
public static int remTime = 0;
また、それらはインスタンス変数であってはなりません。すべての新しいセッション作成はそれをオーバーライドし、他のすべてのユーザーのプレゼンテーションに反映されます。つまり、threadsafeではありません。それらを取り除き、利用してください #{session.creationTime}
と #{session.maxInactiveInterval}
何らかの理由でそこにそれを手に入れる必要があるならば、エルで。または、からまっすぐに入手してください HttpSession
HTTP要求内のインスタンス。
if (hse.getSession().isNew()) {
これは いつも 内部は真です sessionCreated()
方法。これは意味がありません。それを除く。
JsfUtil.addErrorMessage(ex, "Cannot append session Info to File");
その方法が正確に何をしているのかわかりませんが、私はただあることを警告したいだけです 保証なし それ FacesContext
セッションが作成または破壊されようとしているときに、スレッドに存在します。 JSF以外のリクエストで行われる場合があります。または、HTTPリクエストの手段がまったくない場合があります。したがって、NPEのリスクがあります FacesContext
は null
それから。
それにもかかわらず、私は次のテストスニペットを作成しましたが、私にとっては正常に機能します。 @SessionScoped
Beanは暗黙的にセッションを作成します。 CommandButtonはセッションを無効にします。すべてのメソッドは、期待どおりに呼び出されます。同じブラウザタブでボタンを押す回数、カウントは常に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>
上記の例があなたのために機能する場合、あなたの問題はおそらくどこか別の場所にあります。おそらくあなたはそれを登録しなかったでしょう <listener>
の web.xml
まったく、ログイン方法内に毎回リスナーの新しいインスタンスを手動で作成するだけです。とにかく、少なくともさらに構築するための最小キックオフの例があります。
他のヒント
まったく異なる方向にあるもの-TomcatはJMXをサポートしています。アクティブセッションの数を示すJMX MBeanがあります。 (コンテナがTomcatでない場合でも、JMXをサポートし、それを追跡する方法を提供する必要があります)
あなたの public void sessionDestroyed(HttpSessionEvent se) {
呼ばれましたか?なぜそれが増えないのかわかりません。ユーザーが電話をかけた後 session.invalidate()
ログアウトを通じて、セッションは破壊され、次のリクエストのために新しいリクエストが作成されます。これは通常の動作です。