サーブレット&JSPの基本|アプリケーションスコープを使ったWebアプリ作成

全ユーザーで共有するカウントを保存する。アプリケーションスコープで評価ボタン付きWebアプリを作ろう

アプリケーションスコープは、Webアプリケーション全体で共有できるスコープです。

リクエストスコープは1回のリクエスト内で使うスコープ、セッションスコープはユーザーごとに使うスコープでした。それに対して、アプリケーションスコープは1つのWebアプリケーションにつき1つだけ用意され、すべてのユーザーで共通して利用できます。

この特徴を使うと、サイト全体で共有したい情報を保存できます。

ここでは、教材ページに対する評価ボタン機能を作成します。利用者が役に立ったまたはもう少しをクリックすると、それぞれの人数をカウントし、その結果を画面に表示します。

この評価数は、特定のユーザーだけが使う情報ではありません。サイトを利用するすべてのユーザーで共有したい情報です。そのため、セッションスコープではなく、アプリケーションスコープに保存します。

この記事では、評価情報を持つJavaBeans、評価数を増やすモデル、リクエストを処理するサーブレット、評価結果を表示するJSPを作成しながら、アプリケーションスコープの使い方を確認します。

教材ページ評価ボタン機能で作るもの

今回作成するのは、教材ページに評価ボタンを付けるWebアプリケーションです。

画面には、役に立ったともう少しの2つのリンクを表示します。利用者がどちらかをクリックすると、その評価数が1つ増えます。

画面に表示する内容

表示項目内容
ページタイトルJava入門教材ページへようこそ
評価リンク役に立った、もう少し
評価人数それぞれのクリック数
本文教材ページの紹介文

最初にアクセスしたときは、評価数がまだ保存されていません。そのため、評価情報を表すインスタンスを新しく作成し、役に立ったともう少しの数を0として表示します。

その後、役に立ったをクリックすると、役に立ったの人数が増えます。もう少しをクリックすると、もう少しの人数が増えます。

図1:教材ページ評価ボタン機能の画面遷移

この図から分かること

教材ページ評価ボタン機能では、最初に教材ページを表示します。

初回表示時は、評価情報がまだアプリケーションスコープに保存されていないため、新しい評価情報を作成します。その後、利用者が役に立ったまたはもう少しをクリックすると、リクエストパラメータactionの値によって、どちらの評価がクリックされたかを判断します。

評価数はアプリケーションスコープに保存されるため、同じWebアプリケーションを利用するすべてのユーザーで共有できます。

作成するファイル

このアプリケーションでは、MVCモデルに合わせて4つのファイルを作成します。

作成するファイル一覧

ファイル種類役割
PageFeedback.javaモデル JavaBeans役に立ったともう少しの数を持つ
PageFeedbackLogic.javaモデル 処理クラス評価数を増やす処理を行う
LessonIndex.javaコントローラ サーブレットリクエストを受け取り、評価処理と画面表示を制御する
lessonIndex.jspビュー JSP教材ページのトップ画面を表示する

PageFeedback.javaは、教材ページの評価情報を持つJavaBeansです。

PageFeedbackLogic.javaは、役に立ったまたはもう少しの数を増やす処理を担当します。

LessonIndex.javaは、ブラウザからのリクエストを受け取り、アプリケーションスコープから評価情報を取得します。必要に応じて評価数を増やし、JSPへフォワードします。

lessonIndex.jspは、アプリケーションスコープから評価情報を取得し、教材ページとして画面に表示します。

アプリケーションスコープに保存する理由

評価ボタンの人数は、特定のユーザーだけが見る情報ではありません。

すべてのユーザーで共通して見たい情報です。

たとえば、青山さんが役に立ったをクリックして人数が1人になったあと、山田さんが同じ教材ページを開いた場合にも、役に立った 1人と表示されるのが自然です。

このような全ユーザー共通の情報は、アプリケーションスコープに保存します。

評価情報とスコープの関係

保存したい情報適したスコープ理由
1回の結果表示だけで使う情報リクエストスコープレスポンス後に残す必要がない
ログイン中のユーザー情報セッションスコープユーザーごとに分ける必要がある
教材ページ全体の評価数アプリケーションスコープ全ユーザーで共有したい

アプリケーションスコープに保存した評価情報は、ブラウザを閉じても、Webアプリケーションが動いている間は残ります。

ただし、サーバを停止したり再起動したりすると、アプリケーションスコープに保存されていたインスタンスは消滅します。

図2:教材ページ評価ボタン機能のしくみ

この図から分かること

LessonIndex.javaは、教材ページのトップ画面に関するリクエストを処理するコントローラです。

最初に、ServletContextを使ってアプリケーションスコープからPageFeedbackインスタンスを取得します。まだ保存されていない場合は、新しくPageFeedbackインスタンスを作成します。

評価リンクがクリックされた場合は、actionの値を確認します。action=helpfulなら役に立ったの数を増やし、action=notHelpfulならもう少しの数を増やします。

更新されたPageFeedbackインスタンスはアプリケーションスコープに保存され、lessonIndex.jspで取得されて画面に表示されます。

処理全体の流れ

教材ページ評価ボタン機能は、同じLessonIndex.javaにアクセスしながら、actionの値によって動きを変えます。

初回表示の流れ

順番内容
1ブラウザからLessonIndexへGETリクエストを送る
2LessonIndexのdoGetメソッドが実行される
3アプリケーションスコープからPageFeedbackを取得する
4取得結果がnullならPageFeedbackを新しく作成する
5アプリケーションスコープにPageFeedbackを保存する
6lessonIndex.jspへフォワードする
7教材ページのトップ画面が表示される

初回アクセス時は、まだアプリケーションスコープに評価情報が保存されていません。

そのため、getAttributeの戻り値はnullになります。この場合は、PageFeedbackインスタンスを新しく作成します。

評価リンクをクリックしたときの流れ

順番内容
1役に立ったまたはもう少しのリンクをクリックする
2action付きでLessonIndexへGETリクエストを送る
3アプリケーションスコープからPageFeedbackを取得する
4actionの値を確認する
5PageFeedbackLogicで該当する評価数を増やす
6更新後のPageFeedbackをアプリケーションスコープに保存する
7lessonIndex.jspへフォワードする
8更新後の評価数が表示される

評価情報はアプリケーションスコープに保存されるため、別のユーザーがアクセスした場合でも、更新後の人数が表示されます。

リクエストパラメータactionで評価を判断する

このアプリケーションでは、どの評価リンクがクリックされたかをactionというリクエストパラメータで判断します。

役に立ったをクリックした場合はaction=helpful、もう少しをクリックした場合はaction=notHelpfulを送信します。

LessonIndex.javaでは、request.getParameter("action")でactionの値を取得します。

actionの値と処理

actionの値判断する内容実行する処理
null初回表示または通常表示評価数を増やさずに画面を表示する
helpful役に立ったがクリックされた役に立ったの数を1増やす
notHelpfulもう少しがクリックされたもう少しの数を1増やす

初回表示ではactionを送信しないため、actionの値はnullになります。

この場合、評価処理は行わず、現在の評価数を表示します。

JavaBeansを作成する

まず、教材ページの評価情報を持つJavaBeansを作成します。

PageFeedback.javaには、役に立ったの数と、もう少しの数をフィールドとして用意します。

教材ページ評価に関する情報を持つJavaBeansの例

ファイル名: PageFeedback.java

package model;

import java.io.Serializable;

public class PageFeedback implements Serializable {
    private int helpful;
    private int notHelpful;

    public PageFeedback() {
        helpful = 0;
        notHelpful = 0;
    }

    public int getHelpful() {
        return helpful;
    }

    public void setHelpful(int helpful) {
        this.helpful = helpful;
    }

    public int getNotHelpful() {
        return notHelpful;
    }

    public void setNotHelpful(int notHelpful) {
        this.notHelpful = notHelpful;
    }
}

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

このクラスは、教材ページの評価数をまとめて保持するJavaBeansです。

PageFeedback.javaのポイント

PageFeedback.javaでは、helpfulとnotHelpfulという2つのフィールドを用意しています。

PageFeedbackが持つ情報

フィールド内容
helpful役に立ったの数
notHelpfulもう少しの数

コンストラクタでは、helpfulとnotHelpfulに0を設定しています。

そのため、初めてPageFeedbackインスタンスを作成したときは、どちらの評価数も0から始まります。

アプリケーションスコープに保存するインスタンスとして扱うため、Serializableを実装し、フィールドはprivateにしています。値の取得や設定はgetterとsetterを通して行います。

評価処理を行うモデルを作成する

次に、教材ページ評価に関する処理を行うモデルを作成します。

PageFeedbackLogic.javaでは、役に立ったの数を増やす処理と、もう少しの数を増やす処理を用意します。

教材ページ評価に関する処理を行うモデルの例

ファイル名: PageFeedbackLogic.java

package model;

public class PageFeedbackLogic {

    public void helpful(PageFeedback feedback) {
        int count = feedback.getHelpful();
        feedback.setHelpful(count + 1);
    }

    public void notHelpful(PageFeedback feedback) {
        int count = feedback.getNotHelpful();
        feedback.setNotHelpful(count + 1);
    }
}

PageFeedbackLogic.javaもmodelパッケージに作成します。

このクラスは評価数を増やす処理だけを担当します。画面表示は行いません。また、アプリケーションスコープを直接操作することもありません。

PageFeedbackLogic.javaの役割

PageFeedbackLogic.javaは、PageFeedbackインスタンスを受け取り、評価数を変更します。

処理の内容

メソッド内容
helpful役に立ったの数を1増やす
notHelpfulもう少しの数を1増やす

LessonIndex.javaは、actionの値を見て、どちらのメソッドを呼び出すかを判断します。

action=helpfulならhelpfulメソッドを呼び出します。

action=notHelpfulならnotHelpfulメソッドを呼び出します。

PageFeedbackLogicが変更したPageFeedbackインスタンスは、その後アプリケーションスコープに保存され、JSPで表示されます。

コントローラを作成する

次に、教材ページのトップ画面に関するリクエストを処理するサーブレットを作成します。

LessonIndex.javaは、アプリケーションスコープからPageFeedbackインスタンスを取得し、必要に応じて評価数を増やします。

最後に、PageFeedbackをアプリケーションスコープに保存し、lessonIndex.jspへフォワードします。

教材ページのトップ画面に関するリクエストを処理するコントローラの例

ファイル名: LessonIndex.java

package servlet;

import java.io.IOException;

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 model.PageFeedback;
import model.PageFeedbackLogic;

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

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

        // アプリケーションスコープに保存された教材ページ評価を取得
        ServletContext application = this.getServletContext();

        PageFeedback pageFeedback =
                (PageFeedback) application.getAttribute("pageFeedback");

        // 教材ページ評価の初期化
        if (pageFeedback == null) {
            pageFeedback = new PageFeedback();
        }

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

        // 教材ページの評価処理
        PageFeedbackLogic pageFeedbackLogic =
                new PageFeedbackLogic();

        if (action != null && action.equals("helpful")) {
            pageFeedbackLogic.helpful(pageFeedback);

        } else if (action != null && action.equals("notHelpful")) {
            pageFeedbackLogic.notHelpful(pageFeedback);
        }

        // アプリケーションスコープに教材ページ評価を保存
        application.setAttribute("pageFeedback", pageFeedback);

        // フォワード
        RequestDispatcher dispatcher =
                request.getRequestDispatcher(
                        "WEB-INF/jsp/lessonIndex.jsp");
        dispatcher.forward(request, response);
    }
}

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

URLパターンは/LessonIndexです。ブラウザからhttp://localhost:8080/study/LessonIndexへアクセスすると、doGetメソッドが実行されます。

LessonIndex.javaのポイント

LessonIndex.javaでは、アプリケーションスコープの取得、評価情報の初期化、actionによる評価処理、アプリケーションスコープへの保存、JSPへのフォワードを行っています。

doGetメソッドの主な処理

順番内容
1getServletContextでServletContextを取得する
2application.getAttributeでPageFeedbackを取得する
3PageFeedbackがnullなら新しく作成する
4request.getParameterでactionを取得する
5actionに応じて評価数を増やす
6application.setAttributeでPageFeedbackを保存する
7lessonIndex.jspへフォワードする

アプリケーションスコープを使う場合、最初のアクセスではインスタンスがまだ保存されていないことがあります。

そのため、getAttributeの結果がnullだった場合は、新しいインスタンスを作成する処理が必要です。

初回表示時はgetAttributeがnullになる

初めてLessonIndexにアクセスしたとき、アプリケーションスコープにはまだpageFeedbackが保存されていません。

その状態でapplication.getAttribute("pageFeedback")を実行すると、nullが返されます。

このままJSPで表示しようとすると、PageFeedbackインスタンスが存在しないため、正しく表示できません。

そこで、nullの場合はnew PageFeedbackでインスタンスを作成します。

初回表示時の処理

状況処理
pageFeedbackが取得できた既存の評価情報を使う
pageFeedbackがnull新しいPageFeedbackを作成する

この初期化処理により、初回アクセス時でも役に立った 0人、もう少し 0人として画面を表示できます。

actionの値によって評価処理を分ける

LessonIndex.javaでは、actionの値によって処理を分けています。

初回表示ではactionが送信されないため、actionはnullです。この場合、評価数は増やしません。

役に立ったリンクをクリックした場合は、action=helpfulが送信されます。

もう少しリンクをクリックした場合は、action=notHelpfulが送信されます。

分岐処理

条件処理
actionがnull評価処理を行わない
actionがhelpful役に立ったの数を増やす
actionがnotHelpfulもう少しの数を増やす

リクエストパラメータを使うことで、同じLessonIndex.javaのdoGetメソッドでも、通常表示なのか評価ボタンのクリックなのかを判断できます。

アプリケーションスコープに保存し直す

評価数を変更したあと、PageFeedbackインスタンスをアプリケーションスコープへ保存します。

LessonIndex.javaでは、次の処理で保存しています。

application.setAttribute("pageFeedback", pageFeedback);

保存処理の意味

指定内容
pageFeedback属性名
pageFeedback変数保存するPageFeedbackインスタンス

同じ属性名で保存すると、アプリケーションスコープ内の値は上書きされます。

今回のように、評価数を更新したあとは、更新後のPageFeedbackインスタンスをアプリケーションスコープへ保存しておきます。

図3:初回表示と評価クリック時の処理分岐

この図から分かること

LessonIndex.javaでは、まずアプリケーションスコープからPageFeedbackを取得します。

初回表示ではPageFeedbackが保存されていないため、getAttributeの結果はnullになります。その場合は、新しいPageFeedbackインスタンスを作成します。

次に、actionの値を確認します。action=helpfulなら役に立ったの数を増やし、action=notHelpfulならもう少しの数を増やします。actionがnullなら、評価処理は行わず画面を表示します。

最後に、PageFeedbackをアプリケーションスコープへ保存し、lessonIndex.jspへフォワードします。

教材ページのトップ画面を作成する

最後に、教材ページのトップ画面を表示するJSPを作成します。

lessonIndex.jspでは、アプリケーションスコープからPageFeedbackインスタンスを取得し、評価数を表示します。

また、役に立ったともう少しのリンクには、それぞれactionパラメータを付けます。

教材ページのトップ画面を出力するビューの例

ファイル名: lessonIndex.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" %>
<%@ page import="model.PageFeedback" %>
<%
PageFeedback pageFeedback =
        (PageFeedback) application.getAttribute("pageFeedback");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Java入門教材ページ</title>
</head>
<body>

<h1>Java入門教材ページへようこそ</h1>

<p>
<a href="LessonIndex?action=helpful">役に立った</a>:
<%= pageFeedback.getHelpful() %>人

<a href="LessonIndex?action=notHelpful">もう少し</a>:
<%= pageFeedback.getNotHelpful() %>人
</p>

<h2>このページについて</h2>

<p>このページでは、JavaとWebアプリケーション開発の基礎を学習できます。</p>

</body>
</html>

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

WEB-INF内にあるJSPは、ブラウザから直接リクエストできません。LessonIndex.javaからフォワードして表示します。

lessonIndex.jspのポイント

lessonIndex.jspでは、application暗黙オブジェクトを使って、アプリケーションスコープからPageFeedbackを取得しています。

JSPで確認する点

処理内容
page import="model.PageFeedback"JSPでPageFeedback型を使えるようにする
application.getAttribute("pageFeedback")アプリケーションスコープから評価情報を取得する
(PageFeedback)Object型からPageFeedback型へキャストする
getHelpful役に立ったの数を表示する
getNotHelpfulもう少しの数を表示する

JSPでは、ServletContextを取得するためにgetServletContextを使う必要はありません。

暗黙オブジェクトapplicationをそのまま使って、アプリケーションスコープを操作できます。

評価リンクでactionを送信する

lessonIndex.jspでは、評価リンクにリクエストパラメータを付けています。

役に立ったリンクでは、LessonIndex?action=helpfulへアクセスします。

もう少しリンクでは、LessonIndex?action=notHelpfulへアクセスします。

評価リンクの対応

リンク送信されるaction増える評価
役に立ったhelpfulhelpfulの数
もう少しnotHelpfulnotHelpfulの数

リンクをクリックすると、LessonIndexへGETリクエストが送られます。

LessonIndex.javaでは、request.getParameter("action")でactionの値を取得し、どちらの評価数を増やすかを判断します。

実行方法

4つのファイルを作成したら、LessonIndex.javaを実行して動作を確認します。

ブラウザから実行する場合は、次のURLへアクセスします。

http://localhost:8080/study/LessonIndex

または、EclipseでLessonIndex.javaを選択し、サーバーで実行します。

ブラウザの表示例:初回表示時

ブラウザの表示例:「役に立った」「もう少し」をクリック後

動作確認の流れ

操作表示される内容
LessonIndexへアクセスする教材ページのトップ画面が表示される
役に立ったをクリックする役に立ったの人数が1増える
もう少しをクリックするもう少しの人数が1増える
ブラウザを閉じて再度アクセスするアプリケーションスコープに残っていれば人数が保持される

アプリケーションスコープの効果として、ブラウザを閉じたあとに再度アクセスしても、評価数が残っていることを確認できます。

これは、評価情報がユーザーごとのセッションスコープではなく、Webアプリケーション全体のアプリケーションスコープに保存されているためです。

サーバを再起動すると評価数は戻る

アプリケーションスコープに保存したインスタンスは、Webアプリケーションが動いている間だけ利用できます。

そのため、サーバを停止したり再起動したりすると、アプリケーションスコープに保存されていたPageFeedbackインスタンスは消滅します。

その後、再びLessonIndexへアクセスすると、pageFeedbackがnullになり、新しいPageFeedbackインスタンスが作成されます。

その結果、役に立ったともう少しの数は0に戻ります。

ブラウザの表示例:サーバ再起動直後

評価数が消えるタイミング

操作評価数
ブラウザを閉じる基本的には残る
別のブラウザからアクセスする同じアプリケーションスコープの値を表示する
サーバを停止する消える
サーバを再起動する消える
Webアプリケーションが再読み込みされる消えることがある

開発中に評価数が急に0に戻った場合は、サーバが再起動していないか、Webアプリケーションが再読み込みされていないかを確認しましょう。

アプリケーションスコープを使うときの注意

アプリケーションスコープは、すべてのユーザーで共有されます。

今回の評価数のように、全ユーザーで共通して扱いたい情報には向いています。

一方で、ユーザーごとに異なる情報を保存する場所としては向いていません。

アプリケーションスコープに向いている情報と向いていない情報

情報向き不向き理由
教材ページの評価数向いている全ユーザーで共有する情報だから
サイト全体のお知らせ向いているすべてのユーザーに同じ内容を表示するから
ログイン中のユーザー情報向いていないユーザーごとに分ける必要があるから
個人の入力途中データ向いていない他のユーザーと共有してはいけないから

アプリケーションスコープは、みんなで使う共有スペースのようなものです。

個人ごとの情報ではなく、Webアプリケーション全体で共通して扱いたい情報を保存します。

確認したいポイント

アプリケーションスコープを使ったWebアプリケーションでは、次の点を確認しましょう。

確認項目内容
URLパターン@WebServlet("/LessonIndex")になっているか
実行URLhttp://localhost:8080/study/LessonIndexになっているか
JSPの保存場所WEB-INF/jspに配置しているか
ServletContextの取得getServletContextでapplicationを取得しているか
初回表示の判定getAttributeの結果がnullならインスタンスを作成しているか
属性名pageFeedbackで保存と取得をそろえているか
actionの値helpfulとnotHelpfulで処理を分けているか
評価処理PageFeedbackLogicで人数を増やしているか
アプリケーションスコープへの保存application.setAttributeで保存しているか
JSPでの取得application.getAttributeで取得しているか

アプリケーションスコープを使うと、Webアプリケーション全体で共有する情報を扱えるようになります。

今回の評価ボタン機能では、PageFeedbackインスタンスをアプリケーションスコープに保存することで、すべてのユーザーで共通の評価数を表示できます。

ブラウザを閉じても評価数が残る一方で、サーバの停止や再起動によって消滅する点も、動作確認しながら押さえておきましょう。