S-JIS[2007-06-10/2007-09-02] 変更履歴

JavaサーブレットのHTTPセッション

HTTPにはセッションという仕様は無いが、J2EEサーブレット)ではセッション管理機能をサポートしている。


セッションの使用例

	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse res)
		throws ServletException, IOException {

		HttpSession session = req.getSession(true);

		//タイムアウト時間[秒]
		session.setMaxInactiveInterval(10 * 60);

		//値の取得
		String value = (String)session.getAttribute("名前");

		//値の保存
		session.setAttribule("名前", "値");
	}

getSession()で、HttpServletRequestからセッションのインスタンスを取得する。
getSession(true)は、セッションがまだ作られていない場合は新規にセッションを作る。
getSession(false)は、セッションが存在しない場合はnullを返す。
セッションを開始する画面ならtrue、セッション途中の画面ならfalseにして戻り値nullのエラーチェックをすべき。

セッションを破棄するには以下の様にする。

		session.invalidate();

セッション情報の制限

HttpSession#setAttribute()で、オブジェクトをセッションに保存できる。
指定できる値はObjectクラスなのでどんなクラスでも入れられる訳だが、シリアライズ可能にしておく必要がある。

セッションは破棄されない限りメモリ上に残り続けるので、多量のデータを保持するのは慎むべき。
(エンドユーザーがログアウトせずにブラウザーを閉じてしまったら、サーバー側でタイムアウトして破棄されるまでセッションは生きている。ユーザーとしての自分の行動を省みても、こんなケースは多いはず(苦笑) これを全てとっておく必要があるのだから、かなりの量になるのが分かるだろう)
また、レプリケーションで共有される(共有の為のデータ転送 や保持容量にコストがかかる)ことを考えれば、やはりデータ量は少ない方がよい。


セッションの実現方法

「クライアントからの要求が同一セッションであるかどうか」を識別する具体的な方法は、たぶんJavaEEサーバーの実装(TomcatやWebLogic)に任されている 。
が、ほとんどはクライアントとセッションIDをやりとりすることでセッションを認識している と思われる。

その実現方法は、URLリライティングとクッキーの併用。実行時にリクエスト毎にどちらかの方式が使用されるが、どちらを使うのかはサーブレットによって隠蔽されている。
つまりHttpServletRequestやHttpServletResponseを使っていれば、勝手にやってくれる。

が、URLリライティングに関しては、プログラマーも気をつける必要がある
つまり、生成するHTML内のリンク(URL)にセッションIDを埋め込むので、セッションを継続するURLかどうかを区別し、必要とするURLにはセッションIDを付加してやらなければならない。これは人間(プログラマー)にしか出来ない。
セッションIDを付与する方法に関しては、サーブレットでは専用のメソッドが用意されている。

	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

		PrintWriter out = res.getWriter();
		out.println("<html>");
		out.println("<head>");
		out.println("<title>サンプル</title>");
		out.println("</head>");
		out.println("<body>");

		out.print("<a href=\"");
		out.print(res.encodeURL("/session_sample.jsp"));
		out.println("\">リンク</a>");

		out.println("</body>");
		out.println("</html>");
	}

encodeURL()(リダイレクトの場合はencodeRedirectURL())を使うと、サーブレットが「URLリライティングが必要」と判断したときにはエンコードされる(URLが書き換えられる)し、「クッキーのみでいける」と判断したときにはURLはそのままとなる。
ちなみに、クッキーが扱えるかどうかはHttpServletRequest#isRequestedSessionIdFromCookie()で判断できる。


セッションIDはクライアントとサーバー間でやりとりされるが、実際にセッションデータを保持しているのはサーバー側。[2007-09-02]
データ(Javaのオブジェクト)自体はメモリやDB・ファイルに書き込まれて保存される。(具体的にどこに保存されるかは、APサーバーの設定による)
保持方法

	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

		HttpSession session = req.getSession(true);
	}
メソッド 状況 結果
HttpServletRequest#
getSession(true)
セッションが無いとき 新しくセッションが作られ、そのオブジェクトが返る。
セッションが有るとき そのオブジェクトが返る。
HttpServletRequest#
getSession(false)
セッションが無いとき nullが返る。
セッションが有るとき そのオブジェクトが返る。
HttpSession#
isNew()
セッションが初めて作られたとき
(まだクライアントへセッションIDを送っていないとき?)
trueが返る。
クライアントがセッションを使えるとき
(クライアントがセッションIDを返したとき?)
falseが返る。

セッションを使う場合は、セッションレプリケーションの有無に気を配らなければならない。
たいてい、開発時はローカルのサーバー1台で動いていて上手く動作するが、本番環境の複数台構成(レプリケーションが行われてない)で初めて不具合が表面化することになる。しかも再現性は不安定…!


参考


サーブレットへ戻る / J2EEへ戻る / Java目次へ戻る
メールの送信先:ひしだま