セッションとは

セッションはデータを一時的に保存する

セッション(session) は、ブラウザやスマホで入力したデータを、サーバー上にデータを一時的に保存する仕組みで、Webシステムでは必須な処理です。例えばログイン認証後に、他のページでもログイン状態を保持したいときに利用します。

セッションとデータベースの違い

Webシステムのデータの保存は大きく2つにわかれます。

  • 永続的にデータ保存(テキスト、データベース)
  • 一時的に保存(セッション、インメモリ)

データベースでログイン状態を管理すると、大量のユーザアクセスごとにデータベースに問い合わせるため、サーバ負荷の原因になってしまいます。 よって、Webシステムではログイン状態をセッションやメモリに保存することが多くあります。

セッションとCookie(クッキー)の違い

Cookie(クッキー) は、セッションと同じように状態をデータ保存しますが、セッションとCookie では保存される場所が違います。

  • セッション:サーバーに保存
  • Cookie:ブラウザに保存

Cookie の問題点

Cookie はブラウザにデータ保存するので、データが書き換える可能性が高くなり、情報の信頼性が比較的低い傾向にあります。 セッションはサーバにデータ保存するため、セッションデータ自体は Cookieより安全といえます。

ステートレスとステートフル

ステートレス(stateless)

セッションや Cookie などに状態を保存していないことをステートレス(stateless) といいます。

例えば、ショッピングサイトで商品をカートに入れたが、状態を保存せずに他のページにアクセスすると、当然ながらカート商品を表示できません。

ステートフル(stateful)

セッションやCookieなどにデータを一時保存し、他のページで利用できる状態を ステートフル(stateful) といいます。ステートフルだと他のページに移動して商品データ表示することができます。

セッションの基本

セッション管理

セッションはどのクライアント(ブラウザ)が接続しているか判別するために、セッションIDを生成して管理します。

DevToolsでセッションID確認

「セッションID」はブラウザのCookieに保存され、DevToolsなどで確認できます。

セッションの操作

セッション開始

HttpSessionはセッションを利用するクラスです。セッションデータを利用する前に、getSession() でセッションを開始します。引数はboolean型で、 「true」を指定すると新規セッションを作成します。

HttpSession session = request.getSession(新規作成フラグ);
セッション保存

セッションデータの保存は、setAttribute() で「キー」「値」を指定します。

session.setAttribute(キー, 値);

セッション取得

セッションデータの取得は、getAttribute() で「キー」を指定します。

session.getAttribute(キー);

セッション削除

セッションデータの削除は、removeAttribute() で「キー」を指定します。

session.removeAttribute(キー);

エラーメッセージ

セッション保存

セッション開始

「LoginAuth」の doPost() でセッションを開始します。

login.LoginAuth.java
	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
					throws IOException, ServletException {ServletException {
		//セッション開始
		HttpSession session = request.getSession(true);
		...
	}

認証処理でセッション保存

認証失敗時に「Email」と「エラーメッセージ」をセッションに保存します。 成功時には、セッションを空欄にします。

login.LoginAuth.java
		if (authUser != null && authUser.id > 0) {
			//セッション空欄
			session.setAttribute("email", "");
			session.setAttribute("errors", "");
			uri = request.getContextPath() + "/user/";
		} else {
			//セッション保存
			session.setAttribute("email", email);
			session.setAttribute("errors", "Emailまたはパスワードが間違っています。");
			uri = request.getContextPath() + "/login/";
		}

ログイン画面でセッション取得

ログイン画面でセッション「email」「errors」を取得します。既存のセッションを利用するので、getSession() は引数なし(false)で実行します。

login.LoginIndex.java
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //既存のセッション取得
		HttpSession session = request.getSession();
        //セッションデータ取得
		String email = (String) session.getAttribute("email");
		String errors = (String) session.getAttribute("errors");

		... 
	}

JSP受け渡し

取得したデータを、request.setAttribute() でJSPに受け渡します。「errros」はセッションを削除します(1度だけセッション保存)。

login.LoginIndex.java
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		HttpSession session = request.getSession();
		String email = (String) session.getAttribute("email");
		String errors = (String) session.getAttribute("errors");

		email = (email != null) ? email : "";
		errors = (errors != null) ? errors : "";
		
		request.setAttribute("email", email);
		request.setAttribute("errors", errors);
        //セッション削除
        session.removeAttribute("errors");
		request.getRequestDispatcher(jsp).forward(request, response); 
	}

JSPでデータ表示

ログイン画面のJSPで request.getAttribute() でデータ表示します。

Email

「Email」は「value」プロパティに設定します。

views/login/index.jsp
			<div class="form-floating">
				<input type="text" name="email" value="<%= request.getAttribute("email") %>"
					class="form-control border-0 border-bottom rounded-0"
					id="floatingInput" placeholder="[email protected]">
			</div>

エラーメッセージ

「errors」は、pタグなどで警告カラーで表示します。

views/login/index.jsp
<p class="text-danger p-2"><%= request.getAttribute("errors") %></p>

セッション確認

認証を失敗して、入力した「Email」と「エラーメッセージ」を確認してみましょう。

ログイン処理

ログインが成功したら、ユーザデータをセッションに保存してみましょう。

ユーザセッション保存

ログイン成功時にユーザデータを、セッションに保存します。キーは「auth_user」とします。

login.LoginAuth.java
		if (authUser != null && authUser.id > 0) {
			session.setAttribute("email", "");
			session.setAttribute("errors", "");
			//「auth_user」キーでセッション保存
			session.setAttribute("auth_user", authUser);
			uri = request.getContextPath() + "/user/";
		} else {
			session.setAttribute("email", email);
			session.setAttribute("errors", "Emailまたはパスワードが間違っています。");
			uri = request.getContextPath() + "/login/";
		}

セッション取得

ユーザセッション取得

「auth_user」キーのセッションデータを取得し、ユーザデータは「User」クラスでキャストします。

user.UserIndex.java
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//「auth_user」キーでセッション取得し、Userでキャスト 
		User user = (User) request.getSession().getAttribute("auth_user");

		System.out.println(user.id);
		System.out.println(user.name);

		request.getRequestDispatcher(jsp).forward(request, response);
	}

セッション確認

コンソールでセッションデータを確認してみましょう。

1
Alice

JSPでデータ表示

「jsp:useBean」タグを利用すると、サーブレットのJavaBeansデータにアクセスできます。

<jsp:useBean id="オブジェクト名" class="JavaBeansクラス" scope="スコープ範囲" />

Userクラス

「User」クラスはJavaBeansになっているので、setAttribute() でJSPに受け渡しできます。

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

		User user = (User) request.getSession().getAttribute("auth_user");
		request.setAttribute("user", user);
		request.getRequestDispatcher(jsp).forward(request, response);
	}

「user」オブジェクトにアクセス

「jsp:useBean」タグで「user」オブジェクトにアクセスできるようにします。

views/user/index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<jsp:useBean id="user" class="model.User" scope="request" />
  • オブジェクト:user
  • クラス:model.User
  • スコープ:request

ユーザ名表示

「user」オブジェクトからユーザ名を表示します。

views/user/index.jsp
	<div class="container">
		<h2 class="text-center">マイページ</h2>
		<p><%= user.name %>さん、ようこそ!</p>
	</div>

ユーザホーム確認

ユーザホームにアクセスして、セッションデータが表示できるか確認してみましょう。

例外処理

ユーザセッションがなくても場合、「/user/」が表示できてしまいます。

例外でログイン制御

ユーザデータが Nullのときに、例外処理でログイン画面にリダイレクトします。

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

		try {
			User user = (User) request.getSession().getAttribute("auth_user");
			if (user.id > 0) {
				request.setAttribute("user", user);
				request.getRequestDispatcher(jsp).forward(request, response);
			}
		} catch (Exception e) {
			response.sendRedirect(request.getContextPath() + "/login/");
		}
	}

演習

問題1

ログアウト機能を作成してみましょう。

  • サーブレットファイル:UserLogout.java
  • サーブレット名:UserLogout
  • URLパターン:/user/logout

ユーザページのナビゲーション

views/user/index.jsp
	<nav class="navbar navbar-expand-lg navbar-light bg-light">
		<ul class="navbar-nav ms-auto m-2">
			<li class="nav-item"><a class="nav-link" href="logtout">ログアウト</a></li>
		</ul>
	</nav>
	<div class="container">
		<h2 class="text-center">マイページ</h2>
		<p><%=user.name%>さん、ようこそ!
		</p>
	</div>

TomcatでつくるWebアプリ