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

Webでは、すべてのデータはネットワークの向こう側にある。以前はローカル環境に多くのデータを置くことはできなかった。HTML5になってさまざまな保存ができるようになり、Webの姿も大きく変わってきた。HTML5が登場するまで、ブラウザーにデータなどを保存できる機能といえばCookieだけだった。

Cookieを利用すると、ブラウザーに少量のデータを保存しておける。Cookieの役割はそれだけである。しかし、「ブラウザーとサーバーの間でデータをやり取りする情報を交換できる」という点に意味がある。各クライアント、つまりWebブラウザーごとにデータを保存しておけるため、いろいろな用途に活用できる。たとえばIDを割り当てて各クライアントを識別したり、最後にアクセスした日時などの情報を保存したりできる。

最近はHTML5によってローカルに各種情報を保存できるようになってきたが、それらはJavaScriptを通じてしか必要な情報を取り出せないため、サーバーサイドで利用するには非常に面倒である。また、HTML5をサポートしないブラウザーもまだ存在する。クライアントとサーバーの間で円滑に交換できる「クライアント側に保存できるデータ」として、Cookieの必要性は今でも高い。

それではCookieの使い方を整理してみよう。CookieはCookieというクラスとして用意されている。これは次のようにインスタンスを作成する。

Cookie 変数 = new Cookie(名前, 値);

Cookieは保存する値と、それに付ける名前がセットになっている。このようにすることで、複数の値を名前で整理して保存できる。では、このCookieはどのように保存し、取り出せるのだろうか。

Cookieを保存する

response.addCookie(cookie);

Cookieを受け取る

Cookie[] 変数 = request.getCookies();

Cookieの保存はresponseというオブジェクトのメソッドを呼び出して行う。これはクライアントへのレスポンスに関する情報を管理するオブジェクトである。このaddCookieメソッドに、保存するCookieインスタンスを引数として指定して実行する。

Cookieを受け取るのは少し面倒である。JSPの機能には特定のCookieだけを取得する機能はない。用意されているのはrequestオブジェクトのgetCookiesメソッドだけである。これは該当サイトに保存されているすべてのCookieをCookie配列として取得する。取得したCookieから保存されている名前と値は次のように取り出せる。

Cookie名を取得する

String 変数 = cookie.getName();

Cookie値を取得する

String 変数 = cookie.getValue();

したがって少し複雑だが、getCookiesですべてのCookieを取得し、繰り返しで順番にCookieを取り出し、その名前をgetNameで確認する形で必要なCookieを探す必要がある。

有効期間を設定する

cookie.setMaxAge(秒);

最後にもう一つ覚えておきたいのがこれである。これはCookieが保存される期間を設定するものだ。これにより、そのCookieをいつまで保存するかを設定できる。これを設定しなければ、ブラウザーを終了した時点でCookieは消える。

Cookieを使ってみる

それでは実際にCookieを使って、データをクライアントに保存し、それを取り出す処理を試してみよう。

ここでは簡単なメッセージと読み込み回数をCookieに保存するサンプルを考える。次がそのJSPソースコードである。

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%@ page import="java.net.*"%>
<%
    request.setCharacterEncoding("utf-8");
    response.setCharacterEncoding("utf-8");
    req = request;
    String input = request.getParameter("input");
    if (input == null)
        input = "";
    Cookie msg = getCookie("message");
    Cookie count = getCookie("count");
    if (msg == null) {
        input = URLEncoder.encode(input, "utf-8");
        msg = new Cookie("message", input);
        response.addCookie(msg);
    }
    if (count == null) {
        count = new Cookie("count", "0");
        response.addCookie(count);
    } else {
        String num = count.getValue();
        int n = Integer.parseInt(num);
        n++;
        count = new Cookie("count", String.valueOf(n));
        response.addCookie(count);
    }
    if (!input.equals("")) {
        input = URLEncoder.encode(input, "utf-8");
        msg = new Cookie("message", input);
        response.addCookie(msg);
        count = new Cookie("count", "1");
        response.addCookie(count);
    }
%>
<%!HttpServletRequest req;

    Cookie getCookie(String s) {
        Cookie[] cookies = req.getCookies();
        Cookie res = null;
        if (cookies != null) {
            for (Cookie c : cookies) {
                if (s.equals(c.getName())) {
                    res = c;
                    break;
                }
            }
        }
        return res;
    }%>
<!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>
    <p><%=count.getValue() + ": " + URLDecoder.decode(msg.getValue(), "utf-8")%></p>
    <form method="post" action="hello8.jsp">
        <table>
            <tr>
                <td>入力</td>
                <td><input type="text" id="input" name="input"></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="submit" value="送信"></td>
            </tr>
        </table>
    </form>
</body>
</html>

このJSPページにアクセスすると、入力フィールドが1つあるフォームが表示される。ここにテキストを書いて送信すると、そのメッセージがCookieに保存され、アクセス時にページへ表示される。何度かリロードしてみると、送信したメッセージが正しく記憶され、ページに表示されることがわかる。

また、更新するたびにカウンターの数が増える。最後のカウンター数がCookieに保存されており、そこに1を足した値をCookieへ保存して再び更新するようになっている。メッセージを送信して変更すると初期化され、最初から数え直す。

ここでは名前を指定してCookieを取得するために、getCookieというメソッドを定義している。このメソッドはgetCookiesですべてのCookie配列を取得し、繰り返しで名前を確認している。ここで注意すべきなのは、暗黙オブジェクトであるHttpServletRequestの扱いである。

このgetCookieメソッドはreq.getCookies();でCookie配列を取得しているが、このreqは暗黙オブジェクトではない。実は、このようなメソッド定義では暗黙オブジェクトを使用できない。暗黙オブジェクトは<% %>に書かれたコード、一般に「スクリプト」と呼ばれる部分の中でしか使用できない。そのため、ここではあらかじめグローバル変数を用意し、そこにrequestを割り当てて使用している。

もう一つ注意すべき点は、Cookieに保存するテキストについてである。Cookieに保存できるのは通常のASCIIテキスト、つまり英数字だけである。日本語や韓国語などはそのまま保存できない。

では、そのような文字列はどう保存すればよいのか。ASCIIテキストで表現できる形にエンコードするのである。これはURLエンコードと呼ばれ、この形式にテキストを変換して保存し、取り出した後に再びデコードして元のテキストに戻す。

テキストをURLエンコードする

String 変数 = URLEncoder.encode(値, エンコーディング名);

テキストをURLデコードする

String 変数 = URLDecoder.decode(値, エンコーディング名);

URLEncoder.encodeはテキストをURLエンコードしたものを返す。そしてURLDecoder.decodeは、エンコードされたテキストを元のテキストに戻したものを返す。これを利用してテキストをエンコードしてCookieに保存し、Cookieから取り出した後に再びデコードして使うことで、日本語なども問題なくCookieに保存できる。

さらに、リクエストとレスポンスそれぞれのテキストエンコーディングを設定するため、最初に次の文を実行している。

request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");

エンコーディングを正しく設定しておくことで、日本語などの文字化けを防ぐのに役立つ。以前のフォーム送信などでは行わなかったが、日本語を使う場合はこのような設定をしておくほうがよい。ここで覚えておこう。