JSP/Servlet | セッションとCookie | セッションの基本操作と使い方

Cookieは小さな値を保存するのに役立つが、それ以上のことはできない。複雑な値や大きなデータを保存しておく用途には向いていない。しかし、アクセスしてきた各ユーザーに対して何らかの値を保存しておきたい場合は多い。たとえばショッピングカートのようなものであれば、カートに入れた商品情報を保存しておけると非常に便利である。

このように「各ユーザーごとにCookieより複雑で大きなデータを保存する」場合に使われるのがセッションである。セッションとは、サーバーとクライアント、つまりブラウザーの接続が続いている間、維持される機能である。このセッションに値を保存しておくことで、各クライアントのデータを保存して管理できる。

セッションはHttpSessionというクラスとして用意されている。実際にはインスタンスを作成する必要はない。最初からsessionという暗黙オブジェクトが含まれており、これを利用してセッションを操作できる。

セッション値の保存と取得

このセッションには値を保存したり取得したりするメソッドが用意されている。

値を保存する

session.setAttribute(名前, 値);

値を取得する

Object 変数 = session.getAttribute(名前);

セッション値は属性、つまりアトリビュートという形で構成される。setAttributeで属性を設定し、getAttributeで指定された属性を取得する。ただし、この「属性」という概念がどうもピンとこない人も多いだろう。そこで、より単純に「値を設定して取得する」形のメソッドも用意されている。

値を保存する

session.putValue(名前, 値);

値を取得する

Object 変数 = session.getValue(名前);

この2つの方法は実は完全に同じものである。setAttributeとputValueは同じ動作をし、getAttributeとgetValueも同様である。setAttributeで設定した値をgetValueで取り出すことももちろん可能で、その逆も同じである。したがって、好みのものを使えばよい。

セッション接続時間と解除

このセッションは接続を開始したときに始まり、接続している間は維持される。一定時間以上アクセスしないとセッションも終了し、セッションに保存されていた情報もすべて削除される。ブラウザーを終了した場合はサーバーへ別途通知されないため、実際にはセッションはしばらく生きている。これは一定時間後に消える。

セッションの開始時間や経過時間、またはセッション終了に関するメソッドもHttpSessionに用意されている。次に整理しておく。

セッション開始時刻を取得する

long 変数 = session.getCreationTime();

最終アクセス時刻を取得する

long 変数 = session.getLastAccessedTime();

セッションを解除する

session.invalidate();

getCreationTimeとgetLastAccessedTimeは、PCの基準となる日時、1970年1月1日午前0時からの経過ミリ秒単位で取得する。またinvalidateはセッションを無効化するためのもので、呼び出した後はsessionメソッドなどをすべて使用できなくなる。

セッション保持時間を指定する

セッションの保持時間はWASのデフォルト設定値で指定される。任意の値でセッション保持時間を延ばす方法を見てみよう。

コード上で保持時間を指定する

session.setMaxInactiveInterval(秒単位);
  • セッション保持時間が1時間の場合は「3600」を入力する。

WEB-INF/web.xmlで保持時間を指定する

<session-config>
    <session-timeout>分単位</session-timeout>
</session-config>
  • セッション保持時間が1時間の場合は「60」を入力する。

上の2つの方法は、どちらもセッションの保持時間を指定する同じ方式である。保持時間を指定せず継続させたい場合は0を入力する。セッション保持時間は、そのセッションを生成したユーザーのブラウザーからリクエストがあるたびに新しく更新される。セッション保持時間を長くするのはセキュリティ上よくないため、適切に利用しよう。

セッションを使ってみる

それでは実際にセッションを使ってみよう。前の例と同じにするとセッションを理解しにくいため、今回は送信したメッセージをどんどん蓄積していくものを作ってみる。

次のような例を作成する。

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%@ page import="java.util.*"%>
<%
    request.setCharacterEncoding("utf-8");
    response.setCharacterEncoding("utf-8");

    String flg = request.getParameter("check");
    if (flg != null) {
        session.invalidate();
        session = request.getSession();
    }

    long create = session.getCreationTime();
    long last = session.getLastAccessedTime();
    long time = (last - create) / 1000;
    if (time < 0)
        time = 0;

    String input = request.getParameter("input");
    if (input == null)
        input = "";

    ArrayList<String> msgs = (ArrayList<String>) session.getValue("messages");
    if (msgs == null)
        msgs = new ArrayList<String>();

    if (!input.equals(""))
        msgs.add(0, input);

    session.putValue("messages", msgs);
%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Sample jsp</title>
<style>
h1 {
    font-size: 16pt;
    background: #AAFFAA;
    padding: 5px;
}
</style>
</head>
<body>
    <h1>Sample jsp page</h1>
    <p>このページはサンプルです。</p>
    <table>
        <form method="post" action="helo.jsp">
            <tr>
                <td>入力</td>
                <td><input type="text" id="input" name="input"></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="checkbox" id="check" name="check"> <label for="check">初期化</label></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="submit" value="送信"></td>
            </tr>
        </form>
    </table>
    <hr>
    <p>(<%=time%> sec.)</p>
    <ol>
        <%
            for (int i = 0; i < msgs.size(); i++) {
        %>
        <li><%=msgs.get(i)%></li>
        <%
            }
        %>
    </ol>
</body>
</html>

アクセスすると入力フィールドのある画面が表示される。そこに何かを書いて送信すると、それが下に表示される。送信するたびに、それが一覧の一番上に追加される。送信時に「初期化」チェックボックスをONにしておくと、セッションを初期化して新しいメッセージを追加する。

GAEでセッションを使う際の注意

このセッション利用サンプルをGoogle App Engineで動作させる場合、注意すべきなのは「GAEでセッションを使うには別途ONに設定する必要がある」という点である。プロジェクトのappengine-web.xmlファイルを開く。これはGAEの各種設定を含むXMLファイルである。この中に<appengine-web-app>タグがある。このタグに初期設定が書かれている。このタグ内に次のタグを書く。

<sessions-enabled>true</sessions-enabled>

これでセッションを使用できるようになる。これを忘れるとセッション機能は動作しないので注意しよう。

今回はArrayListをセッションに保存している。メッセージが送信されるたびに、このArrayListに追加される。

ArrayList<String> msgs = (ArrayList<String>)session.getValue("messages");
if (msgs == null)
    msgs = new ArrayList<String>();

まずgetValueで「messages」として保存しておいたArrayListを取得する。これがnullの場合、新しいArrayListインスタンスを作成する。

このようにArrayListが準備できたら、送信されたテキストを先頭にaddし、再びセッションに保存する。

session.putValue("messages", msgs);

サンプルでは、セッション開始後の経過時間を秒で表示している。これはあらかじめ経過時間を計算して変数に入れ、それを<%= %>タグで表示しているだけである。

long create = session.getCreationTime();
long last = session.getLastAccessedTime();
long time = (last - create) / 1000;
if (time < 0)
    time = 0;

getCreationTimeとgetLastAccessedTimeをそれぞれ変数として取得し、最終アクセス時間から開始時間を引いて1000で割れば、経過秒数がわかる。意外と簡単である。最後に、「初期化」チェックがONの場合の処理も見てみよう。

String flg = request.getParameter("check");
if (flg != null) {
    session.invalidate();
    session = request.getSession();
}

チェックボックスはチェックがONなら値が送信されるが、OFFなら値自体が送られない。したがって、request.getParameter("check")で取得した値がnullならOFF、nullでなければONと判断できる。

ONの場合はinvalidateでセッションを削除する。その後は再びセッションを開始し、送信された値を保存しておかなければならない。そこでrequest.getSession()によってHttpSessionを再取得している。暗黙オブジェクトであるsessionは、requestのgetSessionで取得できる。

これで、セッション値の保存や、セッションを終了した後の再開始など、基本操作ができるようになった。