
サーブレット&JSPの基本|ひとこと広場のメイン画面とログアウト機能を作成する
ログイン中の利用者だけがメイン画面へ進める。セッション確認とログアウト処理で画面遷移を完成させよう
前回の記事では、ひとこと広場のログイン機能を作成しました。
トップ画面index.jspにログインフォームを追加し、Login.javaで利用者名とパスワードを受け取り、LoginLogic.javaでログイン判定を行いました。そして、ログインに成功した場合は、UserインスタンスをloginUserという属性名でセッションスコープに保存しました。
今回の記事では、ログイン結果画面からメイン画面へ進めるようにします。
メイン画面は、ログインした利用者がひとことを投稿したり、ほかの利用者の投稿を閲覧したりする中心画面です。ただし、今回の記事では、投稿フォームや投稿一覧の表示はまだ作成しません。まずは、ログイン中の利用者名をメイン画面に表示できるところまで作ります。
さらに、メイン画面からログアウトできる機能も追加します。
ログアウトでは、セッションスコープを破棄します。セッションスコープにはログイン中のUserインスタンスが保存されているため、セッションスコープを破棄することで、ログイン状態を終了できます。
この記事では、Main.java、main.jsp、Logout.java、logout.jspを作成し、ログイン済みの場合はメイン画面を表示し、未ログインの場合はトップ画面へ戻す流れを確認します。
今回作成する機能
今回作成する内容は、大きく分けると2つです。
作成する機能
| 機能 | 内容 |
|---|---|
| メイン画面表示機能 | ログイン済みの利用者だけがメイン画面を表示できる |
| ログアウト機能 | セッションスコープを破棄してログイン状態を終了する |
メイン画面表示機能では、セッションスコープからloginUserを取得します。
loginUserが取得できた場合は、ログイン済みと判断してmain.jspへフォワードします。
loginUserが取得できなかった場合は、未ログインと判断してトップ画面index.jspへリダイレクトします。
ログアウト機能では、Logout.javaでセッションスコープを破棄し、logout.jspへフォワードします。
今回作成・修正するファイル
今回の記事では、次のファイルを作成または修正します。
ファイル一覧
| ファイル | 種類 | 役割 |
|---|---|---|
| Main.java | コントローラ | メイン画面表示に関するリクエストを処理する |
| main.jsp | ビュー | ログイン中の利用者名を表示する |
| Logout.java | コントローラ | ログアウト処理を行う |
| main.jsp | ビュー 修正 | ログアウトリンクを追加する |
| logout.jsp | ビュー | ログアウト完了画面を表示する |
main.jspは、最初にログイン中の利用者名を表示する画面として作成します。
その後、ログアウト機能を追加するときに、同じmain.jspへログアウトリンクを追加します。
メイン画面表示の流れ
ログイン結果画面loginResult.jspには、前回の記事で次のリンクを作成しました。
ひとこと投稿・閲覧へ
このリンクをクリックすると、MainというURLパターンへGETリクエストが送られます。
今回作成するMain.javaは、このGETリクエストを受け取り、メイン画面を表示するか、トップ画面へ戻すかを判断します。
メイン画面表示で確認すること
| 確認する内容 | 処理 |
|---|---|
| ひとことリストがあるか | アプリケーションスコープから取得し、なければ新規作成する |
| ログインしているか | セッションスコープからloginUserを取得する |
| ログイン済みの場合 | main.jspへフォワードする |
| 未ログインの場合 | index.jspへリダイレクトする |
メイン画面を表示するだけなら、セッションスコープの確認だけでもよさそうに見えます。
しかし、ひとこと広場では、後の記事で投稿一覧を表示します。その投稿一覧は、アプリケーションスコープに保存する予定です。
そのため、Main.javaでは、メイン画面を表示する前に、アプリケーションスコープにひとことリストが存在するかを確認します。まだ存在しない場合は、空のリストを作成して保存しておきます。
図1:メイン画面表示の流れ

この図から分かること
ログイン結果画面からひとこと投稿・閲覧へリンクをクリックすると、Main.javaへGETリクエストが送られます。
Main.javaでは、まずアプリケーションスコープからmessageListを取得します。messageListがまだ存在しない場合は、新しいArrayListを作成してアプリケーションスコープに保存します。
その後、セッションスコープからloginUserを取得します。loginUserが取得できればログイン済みと判断し、main.jspへフォワードします。
main.jspでは、セッションスコープからloginUserを取得し、ログイン中の利用者名を表示します。
ひとことリストを先に用意する理由
今回の記事では、まだひとこと投稿機能は作成しません。
それでも、Main.javaではアプリケーションスコープにmessageListがあるかを確認します。
これは、後の記事で投稿一覧を表示するときに、必ずmessageListが存在する状態にしておくためです。
messageListを用意する理由
| 理由 | 内容 |
|---|---|
| 投稿一覧で使うため | 投稿されたひとことをリストで管理する |
| 全ユーザーで共有するため | アプリケーションスコープに保存する |
| 初回アクセスでも安全にするため | まだ存在しない場合は空のリストを作成する |
| 次の記事につなげるため | 投稿機能を追加しやすくする |
ひとこと広場では、すべての利用者の投稿を同じ一覧に表示します。
そのため、投稿リストはユーザーごとのセッションスコープではなく、Webアプリケーション全体で共有できるアプリケーションスコープに保存します。
Main.javaで行う処理
Main.javaは、メイン画面に関するリクエストを処理するコントローラです。
今回のMain.javaでは、GETリクエストを受け取るdoGetメソッドを作成します。
Main.javaの処理
| 順番 | 処理 | 内容 |
|---|---|---|
| 1 | ServletContextを取得する | アプリケーションスコープを操作する準備をする |
| 2 | messageListを取得する | アプリケーションスコープからひとことリストを取り出す |
| 3 | messageListがnullなら作成する | 初回アクセス時に空のArrayListを用意する |
| 4 | sessionを取得する | セッションスコープを操作する準備をする |
| 5 | loginUserを取得する | ログイン中の利用者情報を確認する |
| 6 | loginUserがnullならリダイレクト | 未ログインとしてトップ画面へ戻す |
| 7 | loginUserがあるならフォワード | ログイン済みとしてmain.jspを表示する |
Main.javaでは、アプリケーションスコープとセッションスコープの両方を使います。
アプリケーションスコープは投稿リストの準備に使い、セッションスコープはログイン状態の確認に使います。
ひとことに関するリクエストを処理するコントローラを作成する
Main.javaは、servletパッケージに作成します。
URLパターンは/Mainです。
ひとことに関するリクエストを処理するコントローラの例
ファイル名: Main.java
package servlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import model.ShortMessage;
import model.User;
@WebServlet("/Main")
public class Main extends HttpServlet {
private static final long serialVersionUID = 1L;
@SuppressWarnings("unchecked")
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// ひとことリストをアプリケーションスコープから取得
ServletContext application = this.getServletContext();
List<ShortMessage> messageList =
(List<ShortMessage>) application.getAttribute("messageList");
// 取得できなかった場合は、ひとことリストを新規作成して
// アプリケーションスコープに保存
if (messageList == null) {
messageList = new ArrayList<>();
application.setAttribute("messageList", messageList);
}
// ログインしているか確認するため、
// セッションスコープからユーザー情報を取得
HttpSession session = request.getSession();
User loginUser =
(User) session.getAttribute("loginUser");
if (loginUser == null) {
// ログインしていない場合はトップ画面へリダイレクト
response.sendRedirect("index.jsp");
return;
} else {
// ログイン済みの場合はメイン画面へフォワード
RequestDispatcher dispatcher =
request.getRequestDispatcher(
"WEB-INF/jsp/main.jsp");
dispatcher.forward(request, response);
}
}
}このサーブレットでは、doGetメソッドを使っています。
loginResult.jspのひとこと投稿・閲覧へリンクをクリックすると、GETリクエストでMain.javaが呼び出されるためです。
Main.javaのポイント
Main.javaでは、アプリケーションスコープとセッションスコープを使い分けています。
使っているスコープ
| スコープ | 保存・取得するもの | 目的 |
|---|---|---|
| アプリケーションスコープ | messageList | 全ユーザーのひとことを共有するため |
| セッションスコープ | loginUser | ログイン中の利用者を確認するため |
messageListは、全ユーザーで共有する投稿一覧です。
loginUserは、現在ログインしている利用者の情報です。
この2つは性質が違います。全ユーザーで共有したいmessageListはアプリケーションスコープ、ユーザーごとに管理したいloginUserはセッションスコープに保存します。
messageListがnullだった場合の処理
アプリケーションサーバを起動して最初にMain.javaへアクセスしたとき、アプリケーションスコープにはまだmessageListが保存されていません。
その状態でapplication.getAttribute("messageList")を実行すると、nullが返されます。
そこで、Main.javaでは次のように、messageListがnullかどうかを確認しています。
if (messageList == null) {
messageList = new ArrayList<>();
application.setAttribute("messageList", messageList);
}
nullの場合に行うこと
| 状態 | 処理 |
|---|---|
| messageListが取得できた | 既存のリストを使う |
| messageListがnull | 新しいArrayListを作成して保存する |
この処理により、メイン画面を表示する時点で、必ずアプリケーションスコープ内にmessageListが用意された状態になります。
次の記事で投稿機能を追加するとき、このmessageListにShortMessageインスタンスを追加していきます。
未ログインの場合はトップ画面へリダイレクトする
Main.javaでは、セッションスコープからloginUserを取得します。
User loginUser =
(User) session.getAttribute("loginUser");
loginUserがnullの場合は、ログインしていないと判断します。
未ログインの状態でメイン画面を表示してしまうと、誰が投稿しているのか分からなくなります。また、ログインしていない利用者にメイン画面を見せることにもなってしまいます。
そのため、loginUserがnullの場合は、トップ画面index.jspへリダイレクトします。
未ログイン時の処理
| 状態 | 処理 |
|---|---|
| loginUserが取得できる | main.jspへフォワードする |
| loginUserがnull | index.jspへリダイレクトする |
ここではフォワードではなくリダイレクトを使います。
リダイレクトを使うと、ブラウザのアドレスバーも転送先のURLに変わります。
図2:未ログインでMainへアクセスしたときの流れ

この図から分かること
未ログインの状態でMainへ直接アクセスすると、Main.javaはセッションスコープからloginUserを取得しようとします。
しかし、ログインしていないため、loginUserは取得できません。
その場合、Main.javaは未ログインと判断し、index.jspへリダイレクトします。
リダイレクトを使うことで、ブラウザのアドレスバーもトップ画面のURLに変わります。表示されている画面とURLが一致するため、利用者にとって自然な画面遷移になります。
フォワードではなくリダイレクトを使う理由
未ログイン時にトップ画面へ戻すだけなら、フォワードでも表示自体はできます。
しかし、フォワードを使うと、表示される画面はトップ画面なのに、ブラウザのアドレスバーにはMainのURLが残ります。
たとえば、次のような状態になります。
フォワードを使った場合の問題
| 項目 | 状態 |
|---|---|
| アドレスバー | http://localhost:8080/Hiroba/Main |
| 表示される画面 | トップ画面 |
| 問題点 | URLはメイン画面なのに、画面はトップ画面になる |
このように、URLと表示内容にズレが生じます。
一方、リダイレクトではブラウザが改めてindex.jspへリクエストします。そのため、アドレスバーもトップ画面のURLになります。
リダイレクトを使った場合
| 項目 | 状態 |
|---|---|
| アドレスバー | http://localhost:8080/Hiroba/index.jsp |
| 表示される画面 | トップ画面 |
| よい点 | URLと画面が一致する |
未ログインでメイン画面へ直接アクセスされた場合は、トップ画面からログインし直してもらう流れが自然です。
そのため、ここではリダイレクトを使います。
メイン画面を作成する
次に、メイン画面を表示するmain.jspを作成します。
現時点では、まだ投稿フォームや投稿一覧は表示しません。
まずは、セッションスコープに保存されたloginUserを取得し、利用者名を画面に表示します。
メイン画面に表示する内容
| 表示項目 | 内容 |
|---|---|
| 見出し | ひとこと広場メイン |
| ログイン中の表示 | 利用者名さん、ログイン中 |
main.jspは、WEB-INF/jspディレクトリに作成します。
WEB-INF内のJSPは、ブラウザから直接アクセスできません。Main.javaからフォワードして表示します。
メイン画面を出力するビューを作成する
main.jspは、src/main/webapp/WEB-INF/jspディレクトリに作成します。
メイン画面を出力するビューの例
ファイル名: main.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<%@ page import="model.User" %>
<%
// セッションスコープに保存されたユーザー情報を取得
User loginUser =
(User) session.getAttribute("loginUser");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ひとこと広場</title>
</head>
<body>
<h1>ひとこと広場メイン</h1>
<p>
<%= loginUser.getName() %>さん、ログイン中
</p>
</body>
</html>main.jspでは、session.getAttribute("loginUser")を使って、セッションスコープからUserインスタンスを取得しています。
取得したUserインスタンスを使い、loginUser.getNameで利用者名を表示します。
main.jspのポイント
main.jspでは、JSPの暗黙オブジェクトsessionを使っています。
サーブレットではrequest.getSessionでHttpSessionインスタンスを取得しましたが、JSPではsessionをそのまま使えます。
main.jspで行っていること
| 処理 | 内容 |
|---|---|
| page import="model.User" | JSPでUser型を使えるようにする |
| session.getAttribute("loginUser") | セッションスコープからUserインスタンスを取得する |
| (User) | Object型からUser型へキャストする |
| loginUser.getName | 利用者名を取得して表示する |
Main.javaでログイン済みかどうかを確認してからmain.jspへフォワードしているため、main.jspではloginUserが取得できる前提で画面を作成しています。
メイン画面表示の動作確認
ここまで作成できたら、ログイン時と未ログイン時の動作を確認します。
ログイン時の確認手順
| 手順 | 内容 |
|---|---|
| 1 | ブラウザでhttp://localhost:8080/Hiroba/へアクセスする |
| 2 | 任意の利用者名とパスワード1234でログインする |
| 3 | ログイン結果画面でひとこと投稿・閲覧へをクリックする |
| 4 | メイン画面が表示される |
| 5 | 利用者名さん、ログイン中と表示されることを確認する |
ログインに成功している場合は、セッションスコープにloginUserが保存されています。
そのため、Main.javaはログイン済みと判断し、main.jspへフォワードします。
ブラウザの表示例
ログイン結果画面でひとこと投稿・閲覧へをクリックします。

利用者名さん、ログイン中と表示されます。

未ログイン時の確認手順
| 手順 | 内容 |
|---|---|
| 1 | ブラウザをすべて閉じる |
| 2 | ブラウザでhttp://localhost:8080/Hiroba/Mainへ直接アクセスする |
| 3 | トップ画面が表示されることを確認する |
未ログインの場合は、セッションスコープにloginUserがありません。
そのため、Main.javaはindex.jspへリダイレクトします。
セッションスコープの状態が残っていると確認しづらいので、未ログイン時の動作を確認するときは、ブラウザをすべて閉じてから行うと分かりやすくなります。
ブラウザの表示例

ログアウト機能の流れ
メイン画面が表示できるようになったら、次にログアウト機能を作成します。
ログアウトは、ログイン状態を終了するための機能です。
ひとこと広場では、ログイン中の利用者情報をセッションスコープに保存しています。そのため、ログアウト時にはセッションスコープを破棄します。
ログアウトで行うこと
| 項目 | 内容 |
|---|---|
| ログアウトリンク | main.jspからLogout.javaへGETリクエストを送る |
| セッション破棄 | session.invalidateでセッションスコープを破棄する |
| 画面表示 | logout.jspへフォワードする |
| 結果 | ログアウトしましたと表示する |
セッションスコープを破棄すると、その中に保存されていたloginUserも利用できなくなります。
つまり、ログイン状態が解除されます。
図3:ログアウト機能の流れ

この図から分かること
メイン画面のログアウトリンクをクリックすると、Logout.javaへGETリクエストが送られます。
Logout.javaでは、session.invalidateを実行してセッションスコープを破棄します。
セッションスコープが破棄されると、その中に保存されていたloginUserも使えなくなります。これにより、ログイン状態が終了します。
その後、logout.jspへフォワードし、ログアウトしましたという画面を表示します。
ログアウトに関するリクエストを処理するコントローラを作成する
Logout.javaは、ログアウト処理を担当するサーブレットです。
servletパッケージに作成します。
URLパターンは/Logoutです。
ログアウトに関するリクエストを処理するコントローラの例
ファイル名: Logout.java
package servlet;
import java.io.IOException;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
@WebServlet("/Logout")
public class Logout extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// セッションスコープを破棄
HttpSession session = request.getSession();
session.invalidate();
// ログアウト画面にフォワード
RequestDispatcher dispatcher =
request.getRequestDispatcher(
"WEB-INF/jsp/logout.jsp");
dispatcher.forward(request, response);
}
}Logout.javaでは、request.getSessionでHttpSessionインスタンスを取得し、session.invalidateでセッションスコープを破棄しています。
その後、logout.jspへフォワードします。
session.invalidateの役割
session.invalidateは、セッションスコープそのものを破棄するための処理です。
セッションスコープを破棄すると、その中に保存されていたインスタンスも利用できなくなります。
session.invalidateで起こること
| 処理 | 内容 |
|---|---|
| セッションスコープを破棄する | 現在のHttpSessionを無効にする |
| loginUserが消える | ログイン中のUserインスタンスが利用できなくなる |
| ログイン状態が終わる | 次にMainへアクセスしても未ログイン扱いになる |
ログアウト処理では、ログイン中の利用者情報を残しておく必要がありません。
そのため、セッションスコープ全体を破棄して、ログイン状態を終了します。
メイン画面にログアウトリンクを追加する
次に、main.jspにログアウト用のリンクを追加します。
ログアウトリンクのリンク先はLogoutです。
このリンクをクリックすると、Logout.javaへGETリクエストが送られます。
追加するリンク
| リンク文字 | href属性 | 呼び出されるサーブレット |
|---|---|---|
| ログアウト | Logout | Logout.java |
main.jspを次のように修正します。
メイン画面を出力するビューを修正する
ここでは、先ほど作成したmain.jspにログアウトリンクを追加します。
メイン画面を出力するビューを修正した例
ファイル名: main.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<%@ page import="model.User" %>
<%
// セッションスコープに保存されたユーザー情報を取得
User loginUser =
(User) session.getAttribute("loginUser");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ひとこと広場</title>
</head>
<body>
<h1>ひとこと広場メイン</h1>
<p>
<%= loginUser.getName() %>さん、ログイン中
<a href="Logout">ログアウト</a>
</p>
</body>
</html>ログアウトリンクをクリックすると、Logout.javaへリクエストが送られます。
Logout.javaでセッションスコープが破棄され、logout.jspへフォワードされます。
ログアウト画面を作成する
最後に、ログアウト完了を表示するlogout.jspを作成します。
logout.jspでは、ログアウトしましたというメッセージと、トップ画面へ戻るリンクを表示します。
ログアウト画面に表示する内容
| 表示項目 | 内容 |
|---|---|
| 見出し | ひとこと広場ログアウト |
| メッセージ | ログアウトしました |
| リンク | トップへ |
logout.jspも、src/main/webapp/WEB-INF/jspディレクトリに作成します。
ブラウザから直接アクセスする画面ではなく、Logout.javaからフォワードして表示する画面です。
ログアウト画面を出力するビューを作成する
logout.jspを次のように作成します。
ログアウト画面を出力するビューの例
ファイル名: logout.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ひとこと広場</title>
</head>
<body>
<h1>ひとこと広場ログアウト</h1>
<p>ログアウトしました</p>
<a href="index.jsp">トップへ</a>
</body>
</html>このJSPでは、ログアウト完了のメッセージを表示し、トップ画面へ戻るためのリンクを用意しています。
トップへリンクをクリックすると、index.jspへ移動します。
ログアウト機能の動作確認
ここまで作成できたら、ログアウト機能を確認します。
ログアウト時の確認手順
| 手順 | 内容 |
|---|---|
| 1 | ブラウザでhttp://localhost:8080/Hiroba/へアクセスする |
| 2 | 任意の利用者名とパスワード1234でログインする |
| 3 | ログイン結果画面からひとこと投稿・閲覧へをクリックする |
| 4 | メイン画面が表示される |
| 5 | ログアウトリンクをクリックする |
| 6 | ログアウト画面が表示される |
| 7 | ログアウトしましたと表示される |
| 8 | トップへリンクをクリックしてトップ画面へ戻る |
ログアウト後は、セッションスコープが破棄されています。
そのため、再度Mainへ直接アクセスすると、loginUserを取得できず、トップ画面へリダイレクトされます。
ブラウザの表示例:ログアウト画面
ログアウトリンクをクリックします。

ログアウト画面が表示されます。

ログアウト後の確認
ログアウトが正しく動作しているかを確認するには、ログアウト後にMainへ直接アクセスしてみると分かりやすいです。
ログアウト後の確認手順
| 手順 | 内容 |
|---|---|
| 1 | ログアウト画面を表示する |
| 2 | ブラウザでhttp://localhost:8080/Hiroba/Mainへアクセスする |
| 3 | トップ画面へ戻されることを確認する |
ログアウトによってセッションスコープが破棄されていれば、Main.javaでloginUserを取得できません。
その結果、未ログインと判断され、index.jspへリダイレクトされます。
ブラウザの表示例:index.jspへリダイレクトされる

今回作成したファイル
今回の記事では、メイン画面表示とログアウト機能を作成しました。
作成・修正したファイル
| ファイル | 保存場所 | 内容 |
|---|---|---|
| Main.java | src/main/java/servlet | メイン画面表示とログイン確認を行う |
| main.jsp | src/main/webapp/WEB-INF/jsp | ログイン中の利用者名を表示する |
| Logout.java | src/main/java/servlet | セッションスコープを破棄する |
| main.jsp | src/main/webapp/WEB-INF/jsp | ログアウトリンクを追加する |
| logout.jsp | src/main/webapp/WEB-INF/jsp | ログアウト完了画面を表示する |
今回のポイントは、Main.javaでログイン状態を確認することです。
セッションスコープからloginUserを取得できる場合だけ、メイン画面を表示します。取得できない場合は、未ログインと判断してトップ画面へリダイレクトします。
また、Logout.javaではsession.invalidateを使い、セッションスコープを破棄しました。これにより、ログイン状態を終了できます。
次の記事では、メイン画面にひとこと投稿フォームと投稿一覧を追加します。投稿されたひとことは、アプリケーションスコープに保存したmessageListへ追加し、全ユーザーで閲覧できるようにします。
