- ベストアンサー
ブラウザの×(閉じる)ボタンのイベントを拾いたいのですが
現在servlet,JSPでwebサイトを作っていて(webserver:Apache2.x - Tomcat4.x)、 ユーザーの2重ログイン防止の為に (1)ユーザーが×(閉じる)ボタンを押した時 (2)セッションタイムアウトになった時 のイベントを拾ってDBへの書き込み処理をしたいのですが、 どのようにやればよいのかわかりません。 ((2)の場合SessionListenerというのがあると聞いたのですが、使い方がいまいち分からず・・・) servletプログラミングで上の2つのイベントの拾い方をご存知の方がいたら教えていただきたいです。 よろしくお願いします。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
- ベストアンサー
すみません。 見落としていました。 No.3 の補足で、 > HttpSessionBindingListenerを実装したクラスでgetAttribute()できました と記述されていますが、これ自体が問題です。 No.4 で記述したように > 2.アプリケーションでinvalidate()が呼ばれてセッション自体が消えた > 3.セッションタイムアウトでセッション自体が消えた という場合にも、valueUnBound()が呼ばれます。 そして、これらの場合、セッションが無効化されてから valueUnBound() が呼ばれてしまうので、今問題になっているような状況になります。 これについては、ログオフ処理で利用するHttpSessionの情報を 1つのクラスにまとめ、そのクラスに HttpSessionBindingListener を実装します。そして、valueUnBound() で自分自身のフィールドに アクセスして処理を行うようにします。 こうすることで、invalidate() でセッションが無効化されて valueUnBound() が呼ばれても、valueUnBound() を持つクラスのインスタンス自体は 破壊されていないので、情報が取得できます。 すなわち、 > valueUnBound()の中では > 1)セッション情報を取り出す > 2)取り出した値を使ってDBに書き込みする > 3)セッション情報を破棄する 2) で本来取り出されるクラスにvalueUnBound() を実装して、 そこでDBへの書き込みを行うようにします。 この場合、1) は特に不要(自分自身に情報が存在するから)ですし、 3) はログオフの処理を行っている場所で呼び出すようになります。
その他の回答 (5)
> ただ、現在「removeAttribute() メソッドを呼び出している場所(ログオフ処理)で、 > invalidate() メソッドを呼ぶようする」と、 > 1.removeAttribute()でvalueUnBound()が呼ばれ、 > 2.invalidate()でまたvalueUnBound()が呼ばれてしまうらしく、invalidate()で呼ばれた時の > valueUnBound()はgetAttribute()出来ずにExceptionで落ちてしまいます。 どうも、私の書き方に問題があったような、、、 > removeAttribute() でセッションオブジェクトから特定のオブジェクトを削除してから > セッションを無効化するのであれば、removeAttribute() メソッドを呼び出している場所で、 > invalidate() メソッドを呼ぶようするだけで構わないのでは? これは、現在ログオフ処理で行っている、removeAttribute()を invalidate()に置き換えては?という意味です。 invalidate()を実行すると既存のセッションオブジェクト自体が 削除されるわけですから、わざわざ直前でremoveAttribute()を呼び出す 意味がないように思えますが、どうでしょうか?
お礼
書き込みが遅くなってしまいすみません。 回答ありがとうございました。
補足
invalidate()に置き換えた場合なのですが、 invalidate()でvalueUnBound()が呼ばれた場合、セッション情報が破棄されているらしく、 getAttribute("xx")で自分で詰めたセッションの情報が取り出せません。 (質問が堂堂巡りのようになってしまいすみません。) 上記valueUnBound()の中では 1)セッション情報を取り出す 2)取り出した値を使ってDBに書き込みする 3)セッション情報を破棄する という処理をしたいのですが、invalidate()の場合、 3)の要件を先に満たしてしまうために1)の処理ができないようです。
> ちなみにremoveAttribute()でvalueUnBound()を呼び出した時に、 > セッション情報の破棄をしたいのですが、valueUnBound()メソッドの中 > でsession.invalidate()をすると「無効化されたセッションです」と > いうエラーで落ちてしまいます。 これは、例えば、セッションが削除(HttpSession#invalidate()や タイムアウト)されたときにvalueUnBound() が呼ばれたせいだと思います。 removeAttribute() でセッションオブジェクトから特定のオブジェクトを削除してから セッションを無効化するのであれば、removeAttribute() メソッドを呼び出している場所で、 invalidate() メソッドを呼ぶようするだけで構わないのでは? valueUnBound() メソッドは、 1.アプリケーションでremoveAttribute()が呼ばれてセッションから消された 2.アプリケーションでinvalidate()が呼ばれてセッション自体が消えた 3.セッションタイムアウトでセッション自体が消えた という全てのパターンで呼ばれてしまいます。 > removeAttribute()したらsession.invalidate()は必要ないのでしょうか? removeAttribute() はセッションオブジェクトから特定のオブジェクトを削除 するためのメソッドで、HttpSession#invalidate() はセッションオブジェクトを 破棄するメソッドですから、必要です。 ただし、明示的に破棄しなくても、一定時間後タイムアウトでなくなりますが。。。
補足
的確でわかりやすい回答をありがとうございます。 ただ、現在「removeAttribute() メソッドを呼び出している場所(ログオフ処理)で、 invalidate() メソッドを呼ぶようする」と、 1.removeAttribute()でvalueUnBound()が呼ばれ、 2.invalidate()でまたvalueUnBound()が呼ばれてしまうらしく、invalidate()で呼ばれた時の valueUnBound()はgetAttribute()出来ずにExceptionで落ちてしまいます。 そして、2.のinvalidate()で呼ばれた時のvalueUnBound()では、セッションオブジェクト自体は残っているらしく(getId()でセッションIDなどは取得できる)、 if(session==null)などでは判定できず、removeAttribute()のvalueUnBound()メソッドが呼ばれたのか、invalidate()のvalueUnBound()が呼ばれたのか判断できずにいます。 このような場合はremoveAttribute()で設定したセッション情報を1つ1つすべて削除していくしかないのでしょうか。 (ちなみにremoveAttribute()のvalueUnBound()の中でもinvalidate()してみましたが、やっぱりダメでした。これは当然ですかね(^_^;)) 分かりにくい説明ですみませんが、重ねて教えていただけたらありがたいです。よろしくお願いします。
> String str = (String)se.getSession().getAttribute("xx"); > ができませんでした。(se.getId()とかはできるのに・・・) > setAttribute()で詰め込んだ値を取り出す方法はないものでしょうか・・・。 これは、HttpSessionBindingListenerインタフェースを使います。 というのは、HttpSessionListener#sessionDestroyed() は、 「セッションが削除された」ときに呼ばれるため、セッションの情報には アクセスできません。 この代わりに、 public MyBindingClass implements HttpSessionBindingListener { private String foo; public void valueBound(HttpSessionEvent se) { } public void valueUnBound(HttpSessionEvent se) { // セッションからこのクラスが削除されるときに // 実行される。foo に合わせて処理したり、、、 } } というクラスを作成して、これをSessionにsetAttribute()してやります。
補足
HttpSessionBindingListenerを実装したクラスでgetAttribute()できました!!ありがとうございます。 ちなみにremoveAttribute()でvalueUnBound()を呼び出した時に、セッション情報の破棄をしたいのですが、valueUnBound()メソッドの中でsession.invalidate()をすると「無効化されたセッションです」というエラーで落ちてしまいます。 removeAttribute()したらsession.invalidate()は必要ないのでしょうか? 稚拙な質問で申し訳ないのですが、教えていただけるとありがたいです。よろしくお願いします。
- tajiri
- ベストアンサー率45% (5/11)
こんにちは >ユーザーの2重ログイン防止の為に これはよくやることなので大手のソフト開発の 現場では定石となっている場合が多いです。 >(1)ユーザーが×(閉じる)ボタンを押した時 これは残念ながら拾うことができません。 >(2)セッションタイムアウトになった時 1.HttpSessionBindingListenerという リスナーを設定することによって たとえば30分通信が無かったら接続をきるなどの 処理ができます。 (使い方はHttpSessionの中で通常の リスナーのようにaddListenerすればよかったと思います) たしか原田洋子さんの本に載っていたと思うのですが・・・ 2.web-xmlの中でも指定できるみたいです。 これはやってみたこと無いのでちょっとわからないですが・・・
お礼
回答ありがとうございます。
補足
HttpSessionBindingListenerの方はまだよくわからなくて試していません・・・。 ただ、HttpSessionListenerはgetAttribute()で値がとれなかったので、こちらの方法を頑張って試してみます。 ちなみに HttpSessionBindingListener と HttpSessionListener はどう違うのでしょうか?
(1) についてはServlet、JSPでは不可能です。 これはクライアント側の話なので、VBScriptとかであれば 実現可能です。 その場合は、IE限定になりますが。。。 (2) については、Servlet2.3以上をサポートするコンテナ上で HttpSessionListenerインタフェースを実装したクラスを用意して web.xml に設定を記述すれば実現できます。 public MyListener implements HttpSessionListener { public void sessionCreated(HttpSessionEvent se) { // ここにセッションが作られたときの処理 } public void sessionDestroyed(HttpSessionEvent se) { // ここにセッションが削除されるときの処理 } } -- web.xml -- <listener> <listener-class>MyListener</listener-class> </listener> -------------
お礼
回答ありがとうございます。
補足
HttpSessionListenerを実装したクラスを作って、やってみました。 (1)の×ボタンのイベントを拾うのやっぱり無理みたいですね。 (2)についてはこの方法だと、 String str = (String)se.getSession().getAttribute("xx"); ができませんでした。(se.getId()とかはできるのに・・・) setAttribute()で詰め込んだ値を取り出す方法はないものでしょうか・・・。
お礼
「ログオフ処理で利用するHttpSessionの情報を 1つのクラスにまとめ、そのクラスに HttpSessionBindingListener を実装し」たら、うまく処理できるようになりました。 丁寧な回答でとても分かりやすかったです。 本当に助かりました。ありがとうございました。