サーブレットにおけるセッション管理
では、実際に構築の話に移ろう。Webアプリケーションで、まず始めに考えなければならないことは、セッションの管理である。本稿では、サーブレットのみでの構築と、JSPと連携した構築の両方について説明する。
セッション管理はセッション・オブジェクトを使う
HTTPリクエストがセッションレスであるため、サーブレットにはセッション管理という機構がある。サーブレットは基本的に1つのURLに対して1つのインスタンスで稼働するため、そのインスタンスは複数のWebブラウザで共有される。Webブラウザごとに違う状態やデータを管理するには、セッション・オブジェクトを利用する必要がある。セッション・オブジェクトは、接続しているWebブラウザの数だけインスタンスが作られ、セッションIDと呼ばれるストリングをWebブラウザ上にクッキーなどの方法で保管することによってWebブラウザとセッション・オブジェクトを1対1で管理してくれる。この管理は、サーブレット・エンジンが行う。セッション・オブジェクトはリクエストがサーブレットに送られるたびにRequestオブジェクトに貼り付けてスレッドが呼び出されるので、サーブレットからいつでも利用可能である。
セッション・オブジェクトは、一度作られると、どのサーブレットを呼び出しても、常にブラウザと1対1の関係で付いて回る。タイムアウトを起こしたり、サーバがダウンされたりして削除されるまでは、いつでも同じセッション・オブジェクトを使うことができる。こうして、複数の画面(サーブレット)にまたがって、Webブラウザ単位のデータの管理が可能になる。プログラム的に明示的にセッション・オブジェクトを削除するには、invalidateというメソッドを呼び出せばよい。WebSphereでは、サーバがダウンしたときにもセッション・オブジェクトが維持されたり、負荷分散時にプロセス間を移動したりできるように、パーシスタンスという機能も持っている。
では、セッションを具体的にどのように使うのか、その利用方法の例を挙げてみよう。セッション管理を利用するには、Webブラウザと1対1で対応付けられたセッション・オブジェクトにアクセスすることが必要である。まず、セッション・オブジェクトを使って簡単に、2つ以上の連続した画面を通して1つのデータを共有する手順を解説しよう。次のように、画面が全部で3つ存在するものとする。
画面1 | ログイン画面 | ユーザIDとパスワードを入力する |
---|---|---|
画面2 | 「ようこそ」の表示 | 次の画面へのリンクを持っている |
画面3 | ユーザー情報 | ユーザーの情報を表示する |
画面3はログインした後に新たに表示される画面なので、ログイン情報を得るためにセッション・オブジェクトを利用する。これらの画面を構成するため、次の3つのファイルを準備する。
ファイル名 | 種別 | 役割 |
---|---|---|
atmarkit.htm | HTML(ログイン画面を表示) | フォームを持ち、次の画面を呼び出す。フィールドとして「userid」「password」を持っている |
atmarkit\Welcome.java | JavaServlet(「ようこそ」を表示) | userid、passwordを受取り、セッション・オブジェクトに保管し、「ようこそ」を表示する |
atmarkit\Userinfo.java | JavaServlet(ユーザ情報) | セッション・オブジェクトからユーザIDを取り出し、ユーザ情報を表示する |
実際のプログラミングを見てみよう。理解しやすいように、必要以外のものは一切記述していないので、体裁は気にしないでいただきたい。
サーブレットのみでの構築
まず、入力用のHTMLファイル「atmarkit.htm」を準備する。テキストエディタで次のようなHTMLファイルを作成し、<コンテンツディレクトリ>に置く。
<HTML> <BODY> <FORM action="/servlet/atmarkit.Login" method="POST"> ユーザーID:<INPUT type="input" name="userid"><BR> パスワード:<INPUT type="password" name="password"><BR> <INPUT type="submit" value="ログイン"> </FORM> </BODY> </HTML>
URLとしてhttp://localhost/atmarkit.htmを開くと次の画面が現れる。
FORMタグによって入力フィールドが2つと送信ボタンが表示される。「type=password」とすると、入力した文字が表示されず「****」が表示される。
actionに「/servlet/atmarkit.Login」とやっている理由を説明しよう。サーブレットはLogin.javaというファイル名で作られ、コンパイルによってLogin.classになる。このファイルをatmarkitという名前のディレクトリに置きたい。Javaのクラスファイルなので、当然のことながら、パッケージ名が「atmarkit」となる。 サーブレットをアクセスするためのURLとして標準なのは次のURLである。
http://hostname/servlet/Classname
もしパッケージ「package」に入っていれば、
http://hostname/servlet/package.Classname
となる。
HTTPの設定ファイルや、アプリケーション・サーバの設定によって、まったく別のURLでサーブレットを呼び出すこともできるので、サーバのマニュアルによって調べていただきたい。また、J2EEでは、そういった設定もWARファイルにデプロイメント・ディスクリプタで入れることになっている。
さて次に、画面2、画面3を表示するためのサーブレットを見てみよう。ソースコードは次のようなものになる。
Login.java package atmarkit; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class Login extends HttpServlet { public void service( HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // Webブラウザからの情報の読み取り String userid = request.getParameter("userid"); String password = request.getParameter("password"); // セッション・オブジェクトに保管 HttpSession session = request.getSession(true); session.setAttribute("userid", userid); session.setAttribute("password", password); // Webブラウザに画面(HTML)を送信 PrintWriter out = response.getWriter(); out.println("<HTML><BODY> out.println("<H1>"+userid+"さん、ようこそ!</H1><BR>"); out.println("<A HREF='/servlet/atmarkit.Userinfo'>ユーザー情報</A>"); out.println("</BODY></HTML>"); } }
同様に、Userinfo.javaは次のようになる。
package atmarkit; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class Userinfo extends HttpServlet { public void service( HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // セッション・オブジェクトから復元 HttpSession session = request.getSession(true); String userid = (String)session.getAttribute("userid"); String password = (String)session.getAttribute("password"); // Webブラウザに画面(HTML)を送信 PrintWriter out = response.getWriter(); out.println("<HTML><BODY>"); out.println("<H1>パスワードの表示</H1><BR>"); out.println("<TABLE><TR><TD>ユーザーID</TD> out.println("<TD>"+userid+"</TD></TR>"); out.println("<TR><TD>パスワード</TD> out.println("<TD>"+password+"</TD></TR></TABLE>"); out.println("</BODY></HTML>"); } }
やはり、テキストエディタでこのファイルを作成し、コンパイルする。ソースコードを見て、取り出した文字列の参照を変数に代入するとき、次のようにStringにキャストしているのが分かるだろうか。
String userid = (String)session.getAttribute("userid");
セッション・オブジェクトに貼り付けられるのは、「Object」である。つまり、オブジェクトならなんでもよい。取り出すときもObjectが戻り値となっているので、キャストが必要である。裏を返せば、セッション・オブジェクトにはどんなオブジェクトでも貼り付けておける。自作のクラスやBean、DBのコネクションや分散オブジェクトの参照など、Webブラウザごとに管理したいものは何でもである。多くのものを同時に管理する必要があるようであれば、1つずつ貼り付けるのではなく、これらを管理するBeanを定義してそれを1つだけ貼り付けた方がよい場合もある。
WebSphereでは、<サーブレットディレクトリ>\atmarkitにこれらの2つのファイルをコンパイルしておく。コンパイルは次の手順でできる。
1.コマンドプロンプトを開く
2.WebSphere\AppServer\bin\setupCmdLineを実行するCLASSPATHに、サーブレットのディレクトリが入っていないので追加する
CLASSPATH=%CLASSPATH%;<サーブレットディレクトリ>
3.コンパイルする
CD <サーブレットディレクトリ>\atmarkit2 %JAVA_HOME%\bin\javac -extdirs %WAS_HOME%\libjavac Login.java %JAVA_HOME%\bin\javac -extdirs %WAS_HOME%\libjavac Userid.java
実際に動かしてみよう。URL「http://localhost/atmarkit.htm」を開き、適当にユーザーIDとパスワードを入れ、「ログイン」ボタンを押す。ここでは、ユーザーIDに「よねもち」、パスワードに「yukihisa」を指定したとする。
すると次のような画面が表示される。
このとき、サーバ側のセッション・オブジェクトには、ユーザーIDとパスワードのそれぞれに「userid」「password」という名前が付けられて保存されている。ユーザー情報のリンクをクリックしてみよう。
入力した内容が表示された。これは保存されていた文字列が使われたものである。
再表示を行うと、同じ画面が表示される。Webブラウザを再起動して同じアドレスを表示すると、値として「null」が表示される。これは、セッションが新しくなったことを示す。さらに、一通り操作して表示されるようになってから、1時間ほど放っておいてから再表示してもnullが表示されるだろう。いろいろなことをしてセッション・オブジェクトの動きを確認してほしい。
このアプリケーションの動きを、図で説明すると次のようになる。
Webブラウザの送信ボタンを押すと、FORMタグのaction属性で指定されたURLにリクエストが飛ぶ。このとき、FORMタグが持っているINPUT要素のデータがパラメータとしてリクエストに入れられて送信される。このHTTPリクエストは、サーブレット・エンジンに届けられると、Requestオブジェクトにコピーされ、同時に返信用のResponseオブジェクトも作られる。
サーブレット・エンジンは、ブラウザが持っているクッキー情報を読み出し、なければ、新しいSessionオブジェクトを作ってRequestオブジェクトに付ける。Sessionオブジェクトは、サーブレットが管理する。
このとき、Responseオブジェクトにsessionidが一緒に返信されるようにセットする。
Loginサーブレットは、サービス・メソッドの引数としてRequestオブジェクトを受け取ると、Sessionオブジェクトを取り出し(getSession)、RequestオブジェクトからgetParameterでuseridとpasswordを読み出して、Sessionオブジェクトに保管(setAttribute)する。そして、画面を生成して返信する。これがLoginサーブレットのロジックである。このとき、sessionidがHTTPレスポンスのヘッダに含まれて送信される。
ようこそ画面で「ユーザー情報」のリンクをクリックすると、これは単なるリンクなので、GETリクエストが飛ぶ。このとき、クッキーも一緒にHTTPヘッダに含まれて送信される。
サーブレット・エンジンは、送られてきたsessionidで、先ほどのSessionオブジェクトを見つけ出し、Requestオブジェクトに付ける。Userinfoサーブレットは、RequestオブジェクトからSessionオブジェクトを取り出し(getSession)、先ほど保管したuseridとpasswordを取り出す(getAttribute)。そしてそのデータを使って画面を生成して送信する。
セッション・オブジェクトは、不揮発のメモリのように見えるが、実際には期限つきである。通常、セッション・オブジェクトが生成されてからある一定期間たつと、リストから除去され、ガベージ・コレクタによって削除される。貼り付けたデータもこのとき(ほかのところから参照されていなければ)削除される。
Copyright © ITmedia, Inc. All Rights Reserved.