サーブレット&JSPの基本|ひとこと広場のログイン機能を作成する

入力された利用者情報をサーブレットで受け取り、セッションスコープに保存する。ひとこと広場のログイン機能を作ろう

前回の記事では、ひとこと広場の全体像を確認し、開発準備として動的WebプロジェクトHiroba、User.java、ShortMessage.java、index.jspを作成しました。

今回の記事では、いよいよログイン機能を作成します。

ログイン機能は、Webアプリケーションでよく使われる基本的な機能です。利用者がトップ画面で利用者名とパスワードを入力し、ログインボタンをクリックすると、その情報がサーブレットへ送信されます。

サーブレットでは、送信された利用者名とパスワードを受け取り、Userインスタンスを作成します。その後、ログイン処理を行うモデルに判定を依頼します。

今回の学習用アプリケーションでは、パスワードが1234であればログイン成功とします。利用者名は自由に入力できます。

ログインに成功した場合は、Userインスタンスをセッションスコープに保存します。セッションスコープに保存しておくことで、次の画面でもログイン中の利用者情報を利用できます。

ログイン結果画面では、セッションスコープからUserインスタンスを取得します。取得できた場合はログイン成功、取得できない場合はログイン失敗として画面を表示します。

この記事では、ログイン処理を行うLoginLogic.java、ログインリクエストを受け取るLogin.java、ログインフォームを追加したindex.jsp、ログイン結果を表示するloginResult.jspを作成します。

今回作成するログイン機能

ひとこと広場のログイン機能では、トップ画面から利用者名とパスワードを送信します。

入力されたパスワードが1234であればログイン成功です。ログインに成功した場合は、利用者情報をセッションスコープに保存します。

ログイン機能の動き

項目内容
入力する情報利用者名、パスワード
認証に使う値パスワード
ログイン成功条件パスワードが1234と一致する
ログイン成功時Userインスタンスをセッションスコープに保存する
ログイン失敗時セッションスコープにUserインスタンスを保存しない
結果表示loginResult.jspで成功または失敗を表示する

今回は、データベースを使った本格的なユーザー管理は行いません。

ServletとJSPの基本を確認するため、全ユーザー共通のパスワード1234で判定します。

ログイン機能で作成するファイル

今回作成するファイルは、次の4つです。

作成するファイル一覧

ファイル種類役割
LoginLogic.javaモデルパスワードを確認し、ログインできるか判定する
Login.javaコントローラログインフォームから送信されたリクエストを処理する
index.jspビュートップ画面にログインフォームを表示する
loginResult.jspビューログイン成功または失敗の結果を表示する

User.javaは、前回の記事で作成済みです。

今回のログイン機能では、そのUser.javaを利用して、利用者名とパスワードを1つのインスタンスとして扱います。

図1:ひとこと広場のログイン機能の流れ

この図から分かること

ログイン機能では、トップ画面のフォームからLogin.javaへPOSTリクエストを送ります。

Login.javaは、送信された利用者名とパスワードを取得し、Userインスタンスを作成します。そのUserインスタンスをLoginLogic.javaに渡して、ログインできるかを判定します。

ログインに成功した場合は、Userインスタンスをセッションスコープに保存します。loginResult.jspでは、セッションスコープからUserインスタンスを取得し、成功または失敗の表示を切り替えます。

ログイン処理をモデルに分ける

ログイン判定は、Login.javaの中に直接書くこともできます。

しかし、MVCモデルを意識すると、ログイン判定のような処理はモデルに分けたほうが整理しやすくなります。

今回作成するLoginLogic.javaは、ログインできるかどうかを判定するモデルです。

LoginLogic.javaの役割

項目内容
受け取るものUserインスタンス
確認するものUserインスタンスが持つパスワード
成功条件パスワードが1234と一致する
戻り値成功ならtrue、失敗ならfalse

LoginLogic.javaは、画面表示を行いません。

また、リクエストパラメータを直接取得することもありません。

あくまで、Userインスタンスを受け取り、その中のパスワードを確認して、ログイン成功か失敗かを返す役割です。

ログインに関する処理を行うモデルを作成する

まず、ログイン判定を行うLoginLogic.javaを作成します。

ログインに関する処理を行うモデルの例

ファイル名: LoginLogic.java

package model;

public class LoginLogic {
    public boolean execute(User user) {
        if (user.getPass().equals("1234")) {
            return true;
        }
        return false;
    }
}

LoginLogic.javaは、modelパッケージに作成します。

executeメソッドは、Userインスタンスを受け取ります。そして、user.getPassでパスワードを取得し、その値が1234と一致するかどうかを確認します。

一致する場合はtrueを返します。一致しない場合はfalseを返します。

LoginLogic.javaのポイント

LoginLogic.javaでは、ログイン判定だけを担当しています。

処理の流れ

順番処理内容
1Userインスタンスを受け取るフォーム入力をもとに作成された利用者情報を受け取る
2user.getPassを実行するUserインスタンスからパスワードを取得する
31234と比較する入力されたパスワードが正しいか判定する
4trueまたはfalseを返すログイン結果をLogin.javaへ返す

今回は学習用のため、パスワードを1234に固定しています。

実際のアプリケーションでは、データベースに保存されたユーザー情報を確認するような処理になりますが、ここではServletとJSPの流れを理解することを優先します。

コントローラでログインリクエストを処理する

次に、ログインに関するリクエストを処理するサーブレットを作成します。

Login.javaは、トップ画面のフォームから送信されたPOSTリクエストを受け取ります。

フォームから送信される利用者名とパスワードを取得し、Userインスタンスを作成します。

その後、LoginLogic.javaを使ってログイン判定を行います。

Login.javaの主な役割

処理内容
リクエストパラメータの取得nameとpassを取得する
Userインスタンスの生成入力された利用者名とパスワードをまとめる
ログイン判定LoginLogic.javaに処理を依頼する
セッションスコープへの保存ログイン成功時だけloginUserとして保存する
フォワードloginResult.jspへ処理を渡す

Login.javaは、ログイン機能の中心になるコントローラです。

トップ画面とモデル、ログイン結果画面をつなぐ役割を持っています。

ログインに関するリクエストを処理するコントローラを作成する

Login.javaは、servletパッケージに作成します。

URLパターンは/Loginです。

ログインに関するリクエストを処理するコントローラの例

ファイル名: Login.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;
import model.LoginLogic;
import model.User;

@WebServlet("/Login")
public class Login extends HttpServlet {
    private static final long serialVersionUID = 1L;

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

        // リクエストパラメータの取得
        request.setCharacterEncoding("UTF-8");
        String name = request.getParameter("name");
        String pass = request.getParameter("pass");

        // Userインスタンスの生成
        User user = new User(name, pass);

        // ログイン処理
        LoginLogic loginLogic = new LoginLogic();
        boolean isLogin = loginLogic.execute(user);

        // ログイン成功時の処理
        if (isLogin) {
            // ユーザー情報をセッションスコープに保存
            HttpSession session = request.getSession();
            session.setAttribute("loginUser", user);
        }

        // ログイン結果画面にフォワード
        RequestDispatcher dispatcher =
                request.getRequestDispatcher(
                        "WEB-INF/jsp/loginResult.jsp");
        dispatcher.forward(request, response);
    }
}

このサーブレットでは、doPostメソッドを使っています。

トップ画面のログインフォームからPOSTで送信されるため、Login.javaではdoPostメソッドが実行されます。

Login.javaでリクエストパラメータを取得する

Login.javaでは、最初にフォームから送信された値を取得します。

取得しているのは、利用者名とパスワードです。

フォームのname属性と取得処理

フォーム側のname属性サーブレット側の取得
namerequest.getParameter("name")
passrequest.getParameter("pass")

フォーム側のname属性と、getParameterの引数は一致している必要があります。

一致していない場合、サーブレット側で値を正しく取得できません。

また、日本語の利用者名を扱うために、request.setCharacterEncoding("UTF-8")を実行しています。これにより、POSTで送られてきた文字列をUTF-8として扱えるようにします。

Userインスタンスを生成する

取得した利用者名とパスワードは、Userインスタンスにまとめます。

Login.javaでは、次のようにUserインスタンスを作成しています。

User user = new User(name, pass);

Userインスタンスにまとめることで、ログイン判定を行うLoginLogic.javaへ渡しやすくなります。

Userインスタンスに入る情報

プロパティ内容
nameフォームで入力された利用者名
passフォームで入力されたパスワード

User.javaは、前回の記事で作成したJavaBeansです。

ログイン処理では、このUserインスタンスを使って、利用者名とパスワードをひとまとまりの情報として扱います。

ログイン成功時だけセッションスコープに保存する

LoginLogic.javaによる判定結果は、boolean型のisLoginに入ります。

isLoginがtrueの場合、ログイン成功です。

ログインに成功した場合だけ、Userインスタンスをセッションスコープに保存します。

セッションスコープへの保存

処理内容
request.getSessionHttpSessionインスタンスを取得する
session.setAttribute("loginUser", user)loginUserという属性名でUserインスタンスを保存する

セッションスコープに保存しておくことで、次の画面でもログイン中の利用者情報を取得できます。

今回の例では、loginUserという属性名で保存しています。

ログインに失敗した場合は、セッションスコープにUserインスタンスを保存しません。そのため、loginResult.jspでloginUserを取得しようとしてもnullになります。

図2:ログイン成功時にUserインスタンスをセッションスコープへ保存する

この図から分かること

Login.javaでは、ログイン判定の結果によってセッションスコープへの保存を行うかどうかが変わります。

パスワードが1234でログイン成功になった場合だけ、UserインスタンスをloginUserという属性名でセッションスコープに保存します。

ログインに失敗した場合は、Userインスタンスを保存しません。そのため、loginResult.jspでloginUserを取得したときにnullになります。

この違いを利用して、ログイン結果画面では成功と失敗の表示を切り替えます。

トップ画面にログインフォームを追加する

前回作成したindex.jspは、ひとこと広場へようこそという見出しだけの画面でした。

今回は、このindex.jspにログインフォームを追加します。

ログインフォームでは、利用者名とパスワードを入力できるようにします。

フォームで指定する内容

項目指定内容
formタグのaction属性Login
formタグのmethod属性post
利用者名のname属性name
パスワードのname属性pass
送信ボタンログイン

action属性にLoginを指定することで、フォーム送信時にLogin.javaへリクエストが送られます。

method属性にpostを指定しているため、Login.javaではdoPostメソッドが実行されます。

トップ画面を出力するビューを修正する

index.jspを次のように修正します。

トップ画面を出力するビューを修正した例

ファイル名: index.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>

<form action="Login" method="post">
利用者名:<input type="text" name="name"><br>
パスワード:<input type="password" name="pass"><br>
<input type="submit" value="ログイン">
</form>

</body>
</html>

index.jspは、src/main/webappディレクトリの直下に保存します。

ブラウザからhttp://localhost:8080/Hiroba/へアクセスすると、デフォルトページとしてindex.jspが表示されます。

ブラウザの表示例

index.jspのポイント

index.jspでは、ログイン用のフォームを追加しています。

フォーム部品の対応

画面の入力欄inputタグのtype属性name属性サーブレットでの取得
利用者名textnamerequest.getParameter("name")
パスワードpasswordpassrequest.getParameter("pass")

パスワード欄では、inputタグのtype属性にpasswordを指定しています。

これにより、画面上では入力した文字が伏せ字で表示されます。

ただし、伏せ字で表示されるだけで、暗号化されるわけではありません。この段階では、フォームの基本動作として、パスワード用の入力欄を作成していると考えましょう。

ログイン結果画面を作成する

次に、ログイン結果を表示するloginResult.jspを作成します。

loginResult.jspでは、セッションスコープからloginUserを取得します。

取得できた場合は、ログインに成功したと判断して、成功メッセージと利用者名を表示します。

取得できなかった場合は、ログインに失敗したと判断して、失敗メッセージとトップ画面へのリンクを表示します。

ログイン結果画面の表示内容

状態表示内容
ログイン成功ログインに成功しました、ようこそ利用者名さん、ひとこと投稿・閲覧へ
ログイン失敗ログインに失敗しました、トップへ

ログイン成功時には、次の記事で作成するメイン画面へのリンクも表示します。

ログイン結果画面を出力するビューを作成する

loginResult.jspは、src/main/webapp/WEB-INF/jspディレクトリに作成します。

ログイン結果画面を出力するビューの例

ファイル名: loginResult.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>

<% if (loginUser != null) { %>
<p>ログインに成功しました</p>
<p>ようこそ<%= loginUser.getName() %>さん</p>
<a href="Main">ひとこと投稿・閲覧へ</a>
<% } else { %>
<p>ログインに失敗しました</p>
<a href="index.jsp">トップへ</a>
<% } %>

</body>
</html>

loginResult.jspでは、JSPの暗黙オブジェクトsessionを使っています。

サーブレットのようにrequest.getSessionを実行しなくても、JSPではsessionをそのまま利用できます。

loginResult.jspのポイント

loginResult.jspでは、セッションスコープにUserインスタンスが保存されているかどうかで表示を切り替えています。

JSPで行っていること

処理内容
page import="model.User"JSPでUser型を使えるようにする
session.getAttribute("loginUser")セッションスコープからUserインスタンスを取得する
(User)Object型からUser型へキャストする
loginUser != nullログイン成功として表示する
loginUser == nullログイン失敗として表示する

ログイン成功時だけLogin.javaでUserインスタンスをセッションスコープに保存しています。

そのため、loginResult.jspではloginUserが取得できるかどうかによって、ログイン結果を判断できます。

図3:loginResult.jspでログイン結果を表示する

この図から分かること

loginResult.jspでは、セッションスコープからloginUserを取得します。

loginUserがnullでなければ、ログイン成功として成功メッセージを表示します。さらに、loginUser.getNameを使って、利用者名を画面に表示します。

loginUserがnullの場合は、ログイン失敗として失敗メッセージを表示します。

ログイン成功時に表示するひとこと投稿・閲覧へのリンクは、次の記事で作成するMain.javaへアクセスするためのリンクです。

メイン画面へのリンクについて

loginResult.jspには、次のリンクがあります。

ひとこと投稿・閲覧へ

このリンクをクリックすると、MainというURLパターンへGETリクエストが送られます。

ただし、この時点ではまだMain.javaを作成していません。

そのため、今回の記事の段階でこのリンクをクリックすると、404ページが表示されます。

現時点での注意点

リンク現在の状態
Main次の記事で作成する
クリックした場合今回の段階では404ページになる
完成後メイン画面へ進めるようになる

今回の記事では、ログイン結果画面まで表示できれば十分です。

Main.javaとメイン画面は、次の記事で作成します。

ログイン成功時の動作確認

ここまでのファイルを作成したら、ログイン成功時の動作を確認します。

ログイン成功時の確認手順

手順内容
1ブラウザでhttp://localhost:8080/Hiroba/へアクセスする
2利用者名にuserAと入力する
3パスワードに1234と入力する
4ログインボタンをクリックする
5ログイン結果画面が表示される
6ログインに成功しましたと表示される
7ようこそuserAさんと表示される

パスワードが1234なので、LoginLogic.javaはtrueを返します。

その結果、Login.javaはUserインスタンスをセッションスコープに保存します。

loginResult.jspでは、セッションスコープからloginUserを取得できるため、ログイン成功の画面を表示します。

ブラウザの表示例

ログイン失敗時の動作確認

次に、ログイン失敗時の動作を確認します。

ログイン失敗時の確認手順

手順内容
1ブラウザでhttp://localhost:8080/Hiroba/へアクセスする
2利用者名にuserAと入力する
3パスワードに12345と入力する
4ログインボタンをクリックする
5ログイン結果画面が表示される
6ログインに失敗しましたと表示される
7トップへリンクが表示される

パスワードが1234ではないため、LoginLogic.javaはfalseを返します。

その場合、Login.javaはUserインスタンスをセッションスコープに保存しません。

loginResult.jspではloginUserを取得できないため、ログイン失敗の画面を表示します。

ブラウザの表示例

セッションスコープを使うときの動作確認の注意

ログイン機能では、セッションスコープを使います。

セッションスコープにUserインスタンスが残っていると、前回のログイン状態が影響して、思った通りに確認できない場合があります。

特に、ログイン成功を確認したあとにログイン失敗を確認する場合、以前のセッションが残っていると結果が分かりにくくなることがあります。

確認時の注意点

状況対応
動作結果が想定と違うブラウザをすべて閉じてから再実行する
前回のログイン情報が残っているように見えるセッションスコープの状態を疑う
ログイン成功と失敗を続けて確認するできればブラウザを閉じてから確認し直す

セッションスコープは、リクエストをまたいで情報を保持できる便利な仕組みです。

その一方で、開発中は前回の実行結果が残っているように見えることがあります。動作確認で迷ったときは、ブラウザをすべて閉じてから確認し直すと、状態を整理しやすくなります。

今回作成したファイル

今回の記事では、ログイン機能に必要な4つのファイルを作成しました。

作成・修正したファイル

ファイル保存場所内容
LoginLogic.javasrc/main/java/modelパスワードを確認してログイン判定を行う
Login.javasrc/main/java/servletログインリクエストを受け取り、セッションスコープにUserを保存する
index.jspsrc/main/webappログインフォームを追加する
loginResult.jspsrc/main/webapp/WEB-INF/jspログイン結果画面を表示する

前回作成したUser.javaを利用して、ログイン処理を行えるようになりました。

次の記事では、ログイン結果画面から進むメイン画面を作成します。メイン画面では、ログイン中の利用者名を表示し、未ログインで直接アクセスされた場合はトップ画面へ戻す処理を作成します。