前回は、フォームからデータをサーブレットに渡すところまでをやりました。

今回は、今までの知識を応用してログイン処理を作ってみます。

前回学んだリクエスト属性を使えば、入力画面に入力した内容をもとにJSPの出力画面に情報を表示できました。しかし、実はリクエスト属性は複数ページを跨いで情報の保持ができません。ステートレスといって1対のリクエストとレスポンスで終了してしまうのです。

そこで必要となるのがセッション属性です。セッション属性を使うことで複数ページを跨いで情報の保持ができます。そしてログイン処理は複数ページを跨いで情報を保持する必要のある典型的な処理です。この章ではそんなセッション属性の特徴をログイン処理を実装することにより体験的に学びます。

1. ログイン処理とは

まずは一般的なログイン処理についてまとめておきましょう。皆さんも是非、普段お使いのWebアプリケーションで実験してみてください。(あるいは講師の実演をご覧ください)

突然ですがログインに関する質問です。

  • ①一般にWebシステムにログインするにはどのような情報が必要ですか?
あなたの答え:
  • ②ログイン前と後では何が違いますか?
あなたの答え:
  • ③あるブラウザでログイン中に同じブラウザで他のタブを開いたら新しい方のタブでログインは継続されますか?
あなたの答え:
  • ④あるブラウザ(例えばクローム)でログイン中に新しいブラウザ(例えばエッジ)を起動したら新しいブラウザでログインは継続されますか?
あなたの答え:
  • ⑤どんなときにWebアプリからログアウトしますか?
あなたの答え:
  • ⑥ログアウトしてからブラウザの戻るボタンを押すと元のログイン状態に戻りますか?
あなたの答え:

上記の実験からも明らかなように一般的にはログインとは以下のような処理を指します。


①ユーザーはブラウザからIDとパスワードといった自分だけが知る情報を使ってログインする

②ログイン後はそのユーザーだけが見られるページに遷移できるようになる

③ログイン中は同じブラウザで他のタブを開いてもログインされたままである

④しかし、同じユーザーが別のブラウザで同じページにアクセスしても再度ログイン処理が必要である

⑤ログアウト処理をする、ブラウザを終了するまたは一定時間(大抵は30分間だが銀行のように5分程度と短い場合も)が経過するとログアウトする

⑥ログアウトしてからブラウザの戻るボタンを押すと元のログイン状態に戻らないセキュリティを強化したサイトが存在する


上記結果④から考えるとログイン処理はブラウザごとに固有の情報を利用していると推測できます。

また、結果⑤から考えるとログアウトのタイミングは技術者が個々に設定していることが分かります。

本章では、ログイン処理を実現するにはセッションという仕組みを理解することが必要になるということ、さらに同一セッションで有効なセッション属性を使うことでリクエスト属性では実現できなかった複数リクエストを跨いだデータ保持が可能になるということを解説していきたいと思います。例えば、オンラインショッピングで買い物かごの仕組みが実現できるのは、かごの中身をこのセッション属性に入れているから複数ページに渡ってデータを保持できるのです。次の商品を見に行くたびに買い物かごの中身がクリアされてしまっては使い物になりませんからね。

セッション属性とは開始してから破棄されるまで同一ブラウザで有効なスコープです。

セッションの破棄は、「ログアウト処理」、「ブラウザを終了する」または「セッションタイムアウト」により実行されます

実は、前章までの知識で実現できるのは上記「①ユーザーはブラウザからIDとパスワードといった自分だけが知る情報を使ってログインする」だけです。

1.1. IDとパスワードでログインする

以下の図5.1が処理の概要です。

ユーザーがブラウザからユーザーIDとパスワードを入力してログインボタンを押下します。

サーブレットはIdとpasswordが正しいことをチェックします。

①IDとパスワードが正しければ、messageをmember-only.jspにフォワードします。

②IDとパスワードが正しくなければ、エラー画面を表示します。

セッション属性
図5.1 ログイン処理の概要

2. ログイン処理の実装

下図5.2のようなログイン画面を作ります。

セッション属性
図5.2 ログイン画面

ログイン画面

以下のlogin.jspはユーザーIDとパスワードの入力を求める画面です。

ソースコードを読み込んで質問に答えてください。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>login.jsp</title>
        <style>
            #center {
                display:flex;
                justify-content: center;
                align-items: center;
                text-align: center;
                height: 100vh;
            }
        </style>
    </head>
    <body>
        <div id="center">
            <form action="${pageContext.request.contextPath}/Login1" method="post">
                ユーザーID:<input type="text" name="id" required><br>
                パスワード:<input type="password" name="pass" required><br>
                <button type="submit">ログイン</button>
            </form>
        </div>
    </body>
</html>
  • <style>タグで囲まれた部分を英字3文字で何といいましたか?
あなたの答え:
  • 「method="post"」このメソッドの特徴は何でしたか?
あなたの答え:

サーブレットのソースコード

以下のLogin1Servlet.javaはIDとパスワードを認証するサーブレットです。

プログラムを読み込んで質問に答えてください。

package controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns = { "/Login1" })
public class Login1Servlet extends HttpServlet {

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		String id = request.getParameter("id");
		String pass = request.getParameter("pass");

		if ("imai".equals(id) && "p".equals(pass)) {
			request.setAttribute("message", "ようこそ" + id + "さん。");
			request.getRequestDispatcher("/view/member-only.jsp").forward(request, response);
		} else {
			response.sendRedirect("view/login-error.jsp");
		}
	}
}
  • 上記のif文でtrueの場合はどうなりますか?
あなたの答え:
  • 「request.setAttribute…」ではどんな属性に対してどんな名前でどんなデータを格納していますか?
あなたの答え:

次に、if文でfalseの場合、すなわちIDまたはパスワードが間違った場合を見てみましょう。

ここでは、フォワードを使っていませんね。フォワードを使ってもよいのですが、フォワードですとアドレスバーの表記が変わらないため “ログインできていない” ことが伝わりづらいため、リダイレクト処理というものを行っています。

3. フォワードとリダイレクト

画面遷移の方法にはフォワードとリダイレクトがあります

英語の【redirect】には「re=再び」「direct=方向づける」という意味があります。データの出力先などを変更するという意味でIT業界では広く使われる言葉です。

その特徴をまとめると以下の図5.3の通りです。

セッション属性
図5.3 forwardとredirectの違い

特に注目いただきたいのは以下の4点です。

「2.ソースコード」のところでフォワードがrequestのメソッドであるのに対して、リダイレクトはresponseのメソッドであるという点

「3.遷移先のパス指定方式」のところで相対パス指定ができる点(混乱を避けるためこの後のパス指定は相対パスに統一します)

「4.典型的な処理の流れ」で、フォワードがリクエストとレスポンスを1往復交わすのに対して、リダイレクトは2往復であるという点

「5.リクエストスコープ」でリダイレクトはリクエスト属性を引き継がない

ちなみに、リダイレクトは「5.転送可能範囲」で外部サーバーOKとなっています。したがって上記の記述を以下のようにルートパスでも、絶対パスでも、同じ結果が得られるのです。フォワードと違ってパス指定のルールがそのまま適用できると考えれば理解しやすいでしょう。(上図5.3 の「3. 遷移先のパス指定方式」参照)

この研修中はリダイレクトには相対パスで指定することにします。なぜならそれが一番短く記述できるからです。

response.sendRedirect("view/login-error.jsp");

なお、リダイレクト先は外部サーバーも可能です。

response.sendRedirect("https://saycon.co.jp/");

例題1

以下の画面遷移はフォワードとリダイレクト、どちらを使うべきでしょうか?

  1. jspをレンダリングして画面表示させる場合
  2. サーブレットを呼び出して画面表示を任せる場合
  3. 外部のサイトのページを表示する場合
  4. ユーザーがログインに成功した後、ユーザー専用画面を表示したい場合

ログインエラー画面のソース

以下のlogin-error.jspはログインエラー時の画面、menber-only.jspはログイン成功時の画面です。

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>login-error.jsp</title>
        <style>
            #content1{
                color: red;
            }
        </style>
    </head>
    <body>
    <center>
        <div id="content1">
            <h2>ログインエラーが発生しました。</h2>
        </div>
    </center>
    <p style="text-align:center"><a href="login.jsp">ログイン画面へ戻る</a></p>
    </body>
</html>
<%@ page pageEncoding="UTF-8" %>
メンバーだけのページです。
${requestScope.message}

member-only.jspの3行目の以下の記述は、リクエスト属性を指定する書き方です。後で学ぶセッション属性を指定する書き方と比べてみてください。

${requestScope.message}

4. getメソッドとpostメソッドの違い

HTMLで学んだ図5.4にあるpostメソッドの特徴をログイン処理に応用しましょう。(ちなみにシステム開発演習中は無理にpostメソッドを使う必要はありません。とりあえず全てgetメソッドにしても大丈夫です。なぜなら、postメソッドには①サーブレットが単体で実行できなくなる。②リクエストパラメータが見えなくなる。という特徴があるためです。)

getPost
図5.4 getメソッドとpostメソッドの違い

実験1

もしも、postリクエストを使わずにgetリクエストを使ったらログイン処理としてどのような不都合があるでしょうか?

上記login.jspとLogin1Servlet.javaを書き換えて試してみましょう。

確かめた結果:

例題2

以下のactionはgetとpostのどちらを使うべきでしょうか?

  1. 検索の条件を送信し、結果を取得する場合
  2. ユーザーパスワードなどの機密情報を送信するなどURLにパラメータを表示させたくない場合
  3. ウェブフォームを介して大量のデータ(例:ファイルアップロード)を送信する場合

では、ここでもう少し踏み込んでgetメソッドとpostメソッドの違いについて見ていきましょう。

ブラウザには開発用のツール(ディベロッパーツール)があります。例えば、当社の新人エンジニア研修で使用しているChromeの場合はブラウザの画面を右クリックして「検証」を選びます。(ショートカットキーはF12)

当初は英語で表示されると思いますが、以下の設定画面で日本語にすることもできますので講師から説明を受けてください。

セッション属性
図5.5 Google Chromeのディベロッパーツールを日本語化する

図5.6にある「ネットワーク」のタブをクリックします。

セッション属性
図5.6 ネットワークタブ

F5キーを押してリクエストとレスポンスのやり取りをもう一度実行します。

次に、「名前」のところでサーブレットのURLパターン(例.Login1)を選択して、右の「ヘッダー」をクリックします。

図5.7の上がpostメソッド、下がgetメソッドの表示例です。

セッション属性
セッション属性
図5.7 postメソッドとgetメソッドの違い
  • postとgetでリクエストURLはどう違いますか?
あなたの答え:

ただし、postリクエストにするとリクエストパラメータがアドレスバーに表示されないというだけです。上図5.7の「Payload」というタブを開くとパラメータを見ることができてしまいます。httpsを使った暗号化などをしないとパケットを中継する機器からは丸見えです。くれぐれも誤解のないように。(https通信ですと「Payload」のタブ自体が無くなります)

ちなみにステータスコードが「200 OK」になっていますね。HTTPプロトコルにおいてステータスコードとは、Webサーバからのレスポンスの意味を表す3桁の数字です。

ここで当社の新人エンジニア研修で見かけるステータスコードを表5.1にまとめておきます。

ステータスコード意味
200正しく表示されている
403アクセスを禁止されている
404ページが見つからない
405このURLではサポートされていないメソッドでアクセスした
500サーバ内部エラー
表5.1 ステータスコード

調べてみましょう

余裕があれば、ジョークHTTPステータスコードの418を調べてみましょう。

次に図5.8のように「Cookie」をクリックしてください。

名前に「JSESSIONID」、値に32文字の16進数が入っていますね。

セッション属性
図5.8 JSESSIONID

Cookie とは、Webサイトの訪問者の情報を一時的にクライアントに保存するための仕組みです。Cookie の目的はユーザーの識別です。近年 Cookie を使った広告のトラッキングが問題になっていることをご存じの方もいるかと思います。

そして今回作りたいログイン処理もこの Cookie を使った仕組みなのです。


次に、 JSESSIONID とはJ2EEを使用したWebアプリケーションにおいてデフォルトで使用されるセッションIDを表す番号です。JSESSIONID の先頭のJはJavaのJなのですね。

セッション【session】とは、ブラウザとWebサーバの一連の複数のリクエストとレスポンスの活動期間のことです。(例えば、複数の質問に回答する時間をQ&Aセッションといいますね。英語のsessionには複数の送信と受信の一連の流れ、というような意味があるのです)このセッションごとにIDが付いているわけです。

実は一般的なログイン処理はこのセッションの仕組みを利用しているのです。(注:他にも方法はあります)

次はこのセッションの仕組みを使ってログイン処理を実装しましょう。

5. セッションIDの仕組み

下図5.9を使いセッションIDの仕組みを解説します。

  • クライアント(ブラウザ)からサーバにリクエストが送られます
  • サーバはセッションIDを生成します
  • サーバはレスポンスにセッションIDを入れてクライアントに返します
  • クライアントはセッションIDをCookieに保存します
  • 以降、クライアントは全てのリクエストにセッションIDを入れて送ります
  • サーバはクライアントから送られたセッションIDとサーバに保存されたセッションIDを照合することによりユーザーを認証します
  • それ以降は上記5,6の手順でリクエストとレスポンスを繰り返します
  • セッションIDのタイムアウト(デフォルトでは30分間)または破棄(大抵はログアウト)するまでセッションは有効です

パスワードとは異なりセッションIDは1回限りの意味のない16進数なので盗まれたとしても実害は少ないです。

(ただし、そのセッションIDを悪用する攻撃もありますので注意が必要です。もちろん現在皆さんがお使いのブラウザでは簡単には盗まれないようになっていますのでひとまずは安心して大丈夫ですが)

セッション属性
図5.9 セッションIDの仕組み

調べてみましょう

Cookieの保存場所を見てみましょう。

当社の新人研修で使用しているGoogle Chromeの場合のCookieは、C:\Users\Your_User_Name\AppData\Local\Google\Chrome\User Data\Default\Network
にある単一のファイルに保存されています(Your_User_Nameをあなたの実際のユーザーアカウント名に置き換えてください)。

なお、このファイルはユーザーが読むことや編集することはできませんので試してみましょう。

調べたことのメモ:

5.1. セッションを使ったログイン処理を実装する

セッションを使って次のログイン処理(再掲)を実現することにしましょう。以下の②~⑥に対応した処理を作っていきます。

ユーザーはブラウザからIDとパスワードといった自分だけが知る情報を使ってログインする(対応済み)

②ログイン後はそのユーザーだけが見られるページに遷移できるようになる

③ログイン中は同じブラウザで他のタブを開いてもログインされたままである

④しかし、同じユーザーが別のブラウザで同じページにアクセスしても再度ログイン処理が必要である

⑤ログアウト処理をする、ブラウザを終了するまたは一定時間(大抵は30分間だが銀行のように5分程度と短い場合も)が経過するとログアウトする

⑥ログアウトしてからブラウザの戻るボタンを押すと元のログイン状態に戻らないセキュリティを強化したサイトが存在する


セッションIDに紐づく形でセッション属性という記憶領域が用意されています。

セッション属性の概要は下図5.10のとおりです。

リクエスト属性に似ていますが、リクエスト属性は1つのリクエストだけがスコープでした。しかし、セッション属性は複数のリクエストにまたがって有効なスコープです。セッション属性は同一ブラウザであれば全てのページで有効なスコープであるともいえます。したがってセッションを使ったWebアプリケーションをテストする際には注意が必要です。例えばWebブラウザのタブを全て閉じてからテストしないと、セッション属性にデータが残っていて意図しない動作をすることがあります。

セッション属性
図5.10 セッション属性に入れたデータは複数リクエストをまたいで利用できる

<login.jsp>はコピーして <login2.jsp> として使用します。

飛び先だけ次のurlPatterns<Login2>に変更しておいてください。

package controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebServlet(urlPatterns = { "/Login2" })
public class Login2Servlet extends HttpServlet {

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		String id = request.getParameter("id");
		String pass = request.getParameter("pass");

		if ("imai".equals(id) && "p".equals(pass)) {

			HttpSession session = request.getSession();

			session.setAttribute("id", id);
			session.setAttribute("message", "ようこそ" + id + "さん。");
			response.sendRedirect("view/member-only2.jsp");
		} else {
			response.sendRedirect("view/login-error.jsp");
		}
	}
}
  • <Login1Servlet.java> からの変更点はなんですか?
あなたの答え:

HttpSession session = request.getSession();

このように記述することでセッションを取得しますこの記述はセッション属性を扱うすべてのServletで必要となります。

リクエスト属性はdoPostやdoGetメソッドの引数だったため宣言が不要でしたね。対して、セッション属性はHttpSessionクラスの宣言が必要なのですね。

session.setAttribute("id", id);
session.setAttribute("message", "こんにちは" + id + "さん。");

このように記述することでセッション属性にオブジェクトを名前をつけて保存することができます。メソッド名(setAttribute)は全くリクエスト属性のときと同じと覚えましょう。

  • セッション属性から属性を取得するメソッドの書き方を予測してみてください。
あなたの答え:

ログインしないと見られないページは次のmember-only2.jspに記述されています。

menber-only2.jspの以下の記述

${sessionScope.message}

は、セッション属性を指定する書き方です。以前のリクエスト属性を指定する書き方と比べてみてください。

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>member-only2.jsp</title>
    </head>
    <body>
        <br>メンバーだけのページです。
        ${sessionScope.message}<br>

        <a href="video.jsp"  target="_blank">別のタブでビデオを見る</a><br>
    </body>
</html>
  • 一旦ブラウザを閉じたあと、この <member-only2.jsp>を単体で実行したらどうなりますか?
あなたの答え:

<c:redirect url="login3.jsp"/>というタグは文字通り指定のURLにリダイレクトするという意味です。(なお、このようにjspからjspに遷移することはMVCモデルの原則から外れるためこの研修では推奨しません)

以下のvideo.jspはログイン後にメンバー専用でビデオが見られるページです。

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>video.jsp</title>
    </head>
    <body>
        ${sessionScope.message}ビデオを楽しんでください。<br>

        <iframe width="560" height="315" src="https://www.youtube.com/embed/LA95vAwTn-M" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

    </body>
</html>

5.2 セッション属性とリクエスト属性の使い分け

セッション属性は有効範囲が広いため、新人エンジニアの中にはリクエスト属性ではなくセッション属性に何でも入れようとする人がいます。しかし、それは良くないことです。なぜなら、アプリケーションサーバのメモリを圧迫してしまうからです。

リクエスト属性は一つのリクエスト間だけ有効

セッション属性は複数のリクエスト間でも有効

ということは、「リクエスト属性はすぐにサーバーのメモリから消えるが、セッション属性は残ってしまう」のです。この性質を理解して適切に使い分けましょう。「使い捨て」の方が都合の良いことも多いものです。特にITの世界では「使い捨て」といってもデータですから環境問題は生じないので積極的に使い捨てましょう。

下図5.11はセッション属性とリクエスト属性の比較です。

セッション属性とリクエスト属性の比較
図5.11 セッション属性とリクエスト属性の比較

例題3

以下の情報はリクエスト属性、セッション属性どちらに保存すべきでしょうか?

  1. ユーザーがログインしている間は常に必要となる登録ユーザーの個人情報
  2. ユーザーが買い物かごに入れた商品情報
  3. データベースから取得した画面表示のための商品情報

6. メニューをインクルードする

ここで、下図5.12のようにWebアプリケーションらしくログイン後の各ページにはメニューがある状態にしたいと思います。

セッション属性
図5.12 メインメニューのあるアプリケーション

メニューとして以下のmenu.jspをご用意ください。

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<a href="${pageContext.request.contextPath}/login3.jsp">ログイン</a>
<a href="${pageContext.request.contextPath}/Logout">ログアウト</a>
<a href="#">商品検索</a>
<a href="#">買い物かご</a>

        <%
            response.setHeader("Cache-Control", "no-cache,no-store, must-revalidate");//HTTP1.1をサポートしているブラウザ向けの記述
            response.setHeader("Pragma", "no-cache");//HTTP1.0をサポートしているブラウザ向けの記述
            response.setHeader("Expires", "0");//プロキシサーバー対策として、過去の日時を入力して強制的にキャッシュを無効化する
        %>
    </body>
</html>

商品検索や買い物かごのリンク先は今はダミー(#)です。また、7行目~11行目のスクリプトレットの記述はすべてブラウザバック対策のための記述です。コメントにその詳細を記述しておきました。

ブラウザバックとは、Webブラウザの「戻る」操作で直前に開いていたページに遷移することです。ログアウトしたにも関わらず、ブラウザバックでログイン中の画面に戻れる、とすると例えば、ネットカフェなどの共用のパソコンではセキュリティの問題があることは言うまでもありません。


ログインのリンク先のJSPはこれから以下のlogin3.jspを作ります。

  • Login3Servlet.javaはLogin2Servlet.javaを参考に各自作成すること
□作成できました
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<title>login3.jsp</title>
<style>
    #center {
        height: 200px;
        width: 300px;
        position: absolute;
        left: 50%;
        top: 50%;
        margin-top: -100px;
        margin-left: -150px;
        text-align: center;
    }
</style>
</head>
<body>
<%@ include file="view/menu.jsp" %>
    <div id="center">
        <form action="${pageContext.request.contextPath}/Login3" method="post">
            ユーザーID:<input type="text" name="id" required><br>
            パスワード:<input type="password" name="pass" required><br>
            <button type="submit">ログイン</button>
        </form>
    </div>
</body>
</html>
  • 「<%@ include file="view/menu.jsp" %>」この記述は何をしていると推測されますか?
あなたの答え:

7. ログアウト処理の実装

次にログアウト処理を考えてみましょう。

私達はこれまでセッションを発行することによって同一セッションであるかどうかを判断し、ログイン状態を保ってきました。したがって、ログアウト処理はセッションを終了することによって実現できそうです。

以下のLogout.javaはセッションを無効にした上で、ログイン画面にリダイレクト処理をするサーブレットです。このプログラムを読んで質問に答えてください。

package controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebServlet(urlPatterns = { "/Logout" })
public class LogoutServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		HttpSession session = request.getSession();
		if (session != null) {
			session.invalidate();
		}

		// キャッシュを無効にするヘッダーを設定
		response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1
		response.setHeader("Pragma", "no-cache"); // HTTP 1.0
		response.setDateHeader("Expires", 0); // Proxies

		// ログインページなどにリダイレクト
		response.sendRedirect("login3.jsp");
	}
}
  • 「HttpSession session = request.getSession();」という記述は、なぜ必要なのでしたか?
あなたの答え:
  • 「session.invalidate();」という記述では何をしていると推測されますか?
あなたの答え:

セッション属性を扱うすべてのServletでセッションの宣言が必要になることを銘記してください。

セッションを無効にすることで、セッションに保存されているユーザー情報やその他の機密情報が保護され、不正なアクセスから守られます。また、不要になったセッションデータをクリーンアップすることで、サーバーのメモリを圧迫しません。

例題6

ログイン後のページ全てにmenu.jspを組み込みなさい。

また、ログアウト後のブラウザバック対策ができていることを確認しなさい。

※なお、開発中はブラウザバック対策を外した方が楽かもしれません。

例題7

各社でプロジェクト名を決めて0からログインの仕組みを作りなさい。可能な限りこのテキストでやったことを再現すること。(できるだけテキストを見ないように)

例題8

これまで作成してきた数当てゲームを改良して複数回のチャレンジが可能なようにしなさい。

また、「もう一度プレイする」のリンクをクリックすることで再度プレイできるようにしなさい。

各チームで新プロジェクトの名前を決めて作成すること。

セッション属性を使った数当てゲーム
図5.13 セッション属性を使った数当てゲーム

使用ファイル:index.jsp, result.jsp, result2.jsp, GameServlet.java, Kazuate.java

なお、エラー処理は後回しにしてよい。

また、複数のブラウザから同時に実行して以下のようにそれぞれ違った答えになることを確認すること。

セッション属性
図5.14 複数のブラウザで結果の検証

例題9

7章を学んだあとで上記例題5から<c:if>タグを使い、不要なHTML要素を削除しなさい。

不要な要素を消した数当てゲーム
図5.15 不要な要素を消した数当てゲーム


今回はログイン処理の実装方法を通じてセッションについて学びました。

Webページというものは本来1ページ、1ページが独立していて、ページをまたいでデータを引き継ぐ仕組みがありません。このようにhttp通信のリクエストとレスポンスがそれぞれ独立していて他の http通信にデータを引き継がないことをステートレス【stateless】といいます。【state】= 状態 が【less】=(引き継げ)ないというわけでしたね。

本来http通信はステートレスであり、一対のリクエストとレスポンスで通信は終了します。しかし、複数のリクエストとレスポンスを同じものとして扱うことができなければ、ログイン処理や買い物かごの処理は実現できません。ページをまたぐごとにユーザーを忘れてしまったり、買物かごの中身が消えてしまったら使い物になりませんね。

そこで必要となるのがセッションです

Webアプリケーションは、本来ステートレスとして作られたhttp通信を使って擬似的にステートフルにしてオンライン商取引などに使っているわけです。そのため、かなり無理をしている(?)感じは否めないかと思います。

ブラウザの表示がおかしいときは?

Webシステムを開発しているとキャッシュが邪魔をして想定外の動きになることがあります。そんな時は以下の対策を試してみてください。

  • ブラウザのスーパーリロード(Ctrl + F5)を試す
  • ブラウザを再起動する(すべてのタブを閉じる)
  • サーバーのタブからTomcatを「停止」して「クリーン」してから再度実行する
  • 別のブラウザで実行する(例えば普段Edgeを使って開発している場合はChromeで実行する)
  • ブラウザのゲストモードで実行する(設定方法は以下のとおりですが、詳しくは講師がお話しします)
セッション属性
図5.16 ゲストモードで実行する場合の設定方法

Eclipseのクリーン起動

Eclipseのクリーン起動(Clean Start)は、Eclipse統合開発環境(IDE)を特定の状態で起動するための方法です。通常、Eclipseは前回のセッションの状態を記憶しており、起動時に前回の状態を復元します。しかし、クリーン起動を行うと、前回の状態やキャッシュを無視して、新しい状態でEclipseを起動することができます。

クリーン起動は通常eclipse.exeと同じフォルダに入っています。「eclipse.exe -clean.cmd」アイコンをダブルクリックします。

セッション属性
図5.17 Eclipseのクリーン起動

「ポート番号を変更する必要があります」となったときは?

これは、何らかの原因でtomcatが終了していない間に新しくtomcatを起動したことが原因です。

セッション属性
図5.18 サーバーが2重で起動する場合の問題

tomcatが入っているフォルダの中に「kill-8080-port.cmd」というツールがありませんか?

セッション属性
図5.19 kill-8080-port.cmd

これをダブルクリックすることでサーバーをkillすることができ、問題解決につながります。

「Tomcatxxに問題が発生しました。Tomcatxxは始動に失敗しました。」となったときは?

サーバーを削除して作り直すことも有効です。

具体的な方法は講師にお尋ねください。

<まとめ:隣の人に正しく説明できたらチェックを付けましょう>

□ ログイン処理を実現するにはセッションという仕組みを理解することが必要

□ セッション属性は同一ブラウザで開始してから破棄されるまで、同一ユーザー(ブラウザ)であれば全てのページで有効なスコープである

□ 画面遷移の方法にはフォワードとリダイレクトがある

□ フォワードはリクエスト属性を引き継ぐがリダイレクトは引き継がない(ただし、リクエストパラメータを付加することは可能)

□ クライアントはセッションIDをCookieに保存する

□ サーバはクライアントから送られたセッションIDとサーバに保存されたセッションIDを照合することによりユーザーを認証する

□ HttpSession session = request.getSession() と記述することでセッションを取得する。この記述はセッション属性を扱うすべてのServletで必要となる

□ セッション属性へのオブジェクトの出し入れのメソッド名はリクエスト属性のときと同じgetAttribute/setAttributeである

□ http通信はステートレスなためページをまたいでデータを保持するにはセッションが必要である

次回は、JavaBeansを学んでいきます。

JavaBeansを使うことで今回のセッション属性にオブジェクトをまるごと入れて複数ページをまたいだ処理が可能になります。例えば、買物かごのような仕組みも実現できるようになります。

「セッション属性を使いログインや買い物かごの仕組みを実装する」 最後までお読みいただきありがとうございます。