連載
» 2002年01月10日 00時00分 公開

JSPとどう連携して使うのかJava Servlet徹底解説(改訂)(3/4 ページ)

[米持幸寿,日本アイ・ビー・エム]

サーブレットにおけるセッション管理

 では、実際に構築の話に移ろう。Webアプリケーションで、まず始めに考えなければならないことは、セッションの管理である。本稿では、サーブレットのみでの構築と、JSPと連携した構築の両方について説明する。

セッション管理はセッション・オブジェクトを使う

 HTTPリクエストがセッションレスであるため、サーブレットにはセッション管理という機構がある。サーブレットは基本的に1つのURLに対して1つのインスタンスで稼働するため、そのインスタンスは複数のWebブラウザで共有される。Webブラウザごとに違う状態やデータを管理するには、セッション・オブジェクトを利用する必要がある。セッション・オブジェクトは、接続しているWebブラウザの数だけインスタンスが作られ、セッションIDと呼ばれるストリングをWebブラウザ上にクッキーなどの方法で保管することによってWebブラウザとセッション・オブジェクトを1対1で管理してくれる。この管理は、サーブレット・エンジンが行う。セッション・オブジェクトはリクエストがサーブレットに送られるたびにRequestオブジェクトに貼り付けてスレッドが呼び出されるので、サーブレットからいつでも利用可能である。

図3 サーブレット・エンジンの役割 図3 サーブレット・エンジンの役割

 セッション・オブジェクトは、一度作られると、どのサーブレットを呼び出しても、常にブラウザと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> 
リスト1 atmarkit.htm

 URLとしてhttp://localhost/atmarkit.htmを開くと次の画面が現れる。

画面4 画面4

 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」を指定したとする。

画面5 画面5

 すると次のような画面が表示される。

画面6 画面6

 このとき、サーバ側のセッション・オブジェクトには、ユーザーIDとパスワードのそれぞれに「userid」「password」という名前が付けられて保存されている。ユーザー情報のリンクをクリックしてみよう。

画面7 画面7

 入力した内容が表示された。これは保存されていた文字列が使われたものである。

 再表示を行うと、同じ画面が表示される。Webブラウザを再起動して同じアドレスを表示すると、値として「null」が表示される。これは、セッションが新しくなったことを示す。さらに、一通り操作して表示されるようになってから、1時間ほど放っておいてから再表示してもnullが表示されるだろう。いろいろなことをしてセッション・オブジェクトの動きを確認してほしい。

 このアプリケーションの動きを、図で説明すると次のようになる。

図4 アプリケーションの動作 図4 アプリケーションの動作

 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)。そしてそのデータを使って画面を生成して送信する。

 セッション・オブジェクトは、不揮発のメモリのように見えるが、実際には期限つきである。通常、セッション・オブジェクトが生成されてからある一定期間たつと、リストから除去され、ガベージ・コレクタによって削除される。貼り付けたデータもこのとき(ほかのところから参照されていなければ)削除される。

 WebSphereでは、デフォルトで30分が設定されており、これは管理コンソールから変更可能である。

画面8 画面8

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。