前回は、JavaBeansについて学びました。今回は、ELとJSTLについて学びます。ELではオブジェクトのプロパティが表示できるようになります。さらに、JSTLのCタグで制御文を書くと、条件分岐や繰り返しが書けます。さらに、JSTLのfmtタグを使えば日時や金額を書式を設定して表示できるようになります。 

この章の内容は覚える必要はありませんが、後のシステム開発演習で参照できるようにブックマークしておいてください。

1. なぜ、ELが必要なのか?

EL(Expression Language)はすでに見たように変数やJavaBeansクラスのプロパティ値など、指定された式の出力を行うための言語です。ELを使えば型をそれほど意識しなくても済むようになり、デザイナーの方にJSPを扱ってもらいやすくなります。

JSTLなどの拡張タグライブラリと用いれば、プログラムの知識が少ない人でも条件分岐や繰り返しを実現することができるようになります。

2. ELの基本

基本的なELはこれまでにも出てきましたので、ここでは簡単に振り返りたいと思います。

2.1 ELの記述方法

EL(Expression Language)とは、JSPの表示に関わる技術です。ELは、短いプログラムコードを記述することで式を評価したり、変数に値をセットしたり取り出したり、メソッドを実行できる技術でした。


JSP2.0より導入されています。
https://docs.oracle.com/javaee/6/tutorial/doc/bnahq.html


ELは以下の形で定義します。

ELの書式

${式}

この時、{}で囲まれた式を評価し、結果を表示します。

以下のel-basic.jspを読み込んで質問に答えてください。

${"Hello World"}
<br>
${'Hello World'}
<br>
${42 * 42}
<br>
I'm ${20 + 3} years old.
<br>
Hello World has ${"Hello World".length()} characters.
<br>
  • ELでは、文字列をシングルクォーテーション、ダブルクオーテーションどちらで囲みますか?
あなたの答え:
  • ELでは、数値を何で囲みますか?
あなたの答え:
  • ELを文字列の中に埋め込むことはできますか?
あなたの答え:
  • ELの中でメソッドを使うことはできますか?
あなたの答え:

ELで文字列をシングルクォーテーションでも囲むことができるのは、ダブルクォーテーションの中に入れられるようにするためのルールです。つまり、「"${bloodType == "A"}"」とすることはできませんが、「"${bloodType == 'A'}"」あるいは「'${bloodType == "A"}'」とすることはできるのです。このお話はまた後にもう一度出てきます。

3. ELの演算子

ここでは、ELで使う演算子を見ていきます。

ただし、JavaSEでも演算子は学びましたのでここではEL特有の部分だけを押さえてください。

3.1 ELの算術演算子

ELの算術演算子をまとめると下表7.1のとおりです。

ELの算術演算子は基本はJavaSEのときと同じと覚えてください。ただし、ELの場合は整数同士の割り算が浮動小数点数になります。

算術演算子演算内容式の例結果(値)
+足し算${1 + 2}3
-引き算${ 1 - 2 } -1
*掛け算${ 2 * 3 } 6
/割り算${ 5 / 2 } 2.5
%剰余(余りを求める)${ 5 % 2 } 1
表7.1 ELの算術演算子

以下の以下のel-arithmetic.jspはELの算術演算子の使用例です。

${1+2}
<br>
${1-2}
<br>
${2*3}
<br>
${5/2}
<br>
${5%2}
<br>
${"Hello"+=" World"}

3.2 ELの関係演算子

関係演算子もJavaSEと同様です。ただし、ELには別表記があります。

別表記がある理由はHTMLの中に入れたときにも関係演算子を見やすくするため、とお考えください。 「<」よりも「lt」の方がHTMLのタグの中に入ったときに見やすいです。

ELの関係演算子をまとめると下表7.2のとおりです。

関係演算子 別表記説明式の例 別表記を使った例結果(値)
== eq左辺と右辺が等しい${1 == 1} 1 eq 1true
!= ne左辺と右辺が等しくない${1 != 2 } 1 ne 1true
> gt左辺が右辺より大きい${ 1 > 2 } 1 gt 1false
< lt左辺が右辺より小さい${ 1 < 2 } 1 lt 1true
>= ge左辺が右辺以上である${ 1 >= 2 } 1 ge 1false
<= le左辺が右辺以下である${ 1 <= 2 } 1 le 1true
empty-nullまたは空文字である${empty ""}
${empty null}
-true
表7.2 ELの関係演算子

ここではELの場合は==で文字列の比較ができることを知っておきましょう。(JavaSEではequalsメソッドを使う必要がありましたね)また、Javaでは本来nullと空文字は全くの別物ですが、ELのemptyでは同じ扱いです。これも非エンジニアへの配慮です。

なお、別表記の英語の意味は以下のとおりです。

eq:equal
ne:negate
gt:greater than
lt:less than
ge:greater than or equal to
le:less than or equal to

余裕があれば、覚えましょう。他の言語でも使われる表現(例えばLinuxのシェルスクリプト)ですから覚えておいて損はありません。

以下のel-relational.jspはELにおける関係演算子の使用例です。

${1 == 1}
<br>
${1 eq 1}
<hr>
${1 != 2}
<br>
${1 ne 2}
<hr>
${1 > 2}
<br>
${1 gt 2}
<hr>
${1 < 2}
<br>
${1 lt 2}
<hr>
${1 >= 2}
<br>
${1 ge 2}
<hr>
${1 <= 2}
<br>
${1 le 2}
<hr>
${empty ""}
<br>
${empty null}
<br>
${empty "Hello"}

3.3 ELの論理演算子

論理演算子も基本はJavaSEと同じです。ただしここでも別表記があります。

ELの論理演算子をまとめると下表7.3のとおりです。

演算子 別表記読み方式がtrueになる条件使用例 別表記の例
&& andかつ AND左辺と右辺の両方がtrue${1 eq 1 && 2 eq 1} ${1 eq 1 and 2 eq 1}
|| orまたは ORすくなくとも左辺と右辺のどちらかがtrue${1 eq 1 || 2 eq 1} ${1 eq 1 or 2 eq 1}
! not否定 NOT条件式がfalse ${${!(1 eq 1)} ${not(1 eq 1)}
表7.3 ELの論理演算子

以下のel-logical.jspはELにおける論理演算子の使用例です。

${1 eq 1 && 2 eq 1}    
<br>
${1 eq 1 and 2 eq 1}
<hr>
${1 eq 1 || 2 eq 1}    
<br>
${1 eq 1 or 2 eq 1}
<hr>
${!(1 eq 1)}    
<br> 
${not(1 eq 1)}

4. ELとJavaBeans

前章のJavaBeansとELは相性がいいですELを使うと JavaBeansのプロパティを簡単に出力できます。ただし、その前に少し補足説明です。

このあとしばらくコード量を減らして見やすくするためにスクリプトレットを使います。

この章では、MVCパターンの原則を破ってスクリプトレットを使います。理由は、見易さのためです。

サーブレットとJSPを使った本来のWebアプリケーションの書き方ですと以下WasteServlet.java(無駄なサーブレットの意)とsample.jspのようにファイルが2つに別れるうえにコード量も全11行と多くなります。

${requestScope.message}

package p07;

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(name = "WasteServlet", urlPatterns = {"/WasteServlet"})
public class WasteServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setAttribute("message", "Hello World");
        
        request.getRequestDispatcher("07JSTL/sample.jsp").forward(request, response);
    }
}

しかし、スクリプトレットを使えば上記の2つのファイルの記述が以下expression1.jspのようになります。ファイルが1つにまとめられる上にコード量が4行に減って見易くなりました。

<%
 request.setAttribute("message", "Hello World");
%>

${requestScope.message}

よって、この章のみスクリプトレットを使うことをご了承ください。

リクエスト属性に入っているJavaBeansのデータをELで表示する

さて、JavaBeansをリクエスト属性に入れて、ELで取り出す方法を以下el-bean1.jspで見てみましょう。

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@page import="model.CustomerBean"%>
<%
CustomerBean cb1 = new CustomerBean();
cb1.setCustomerId(1);
cb1.setName("今井");

request.setAttribute("customer1", cb1);

CustomerBean cb2 = new CustomerBean();
request.setAttribute("customer2", cb2);
%>

${requestScope.customer1}
<br>
${requestScope.customer1.getName()}
<br>
${requestScope.customer1.name}
<hr>
${requestScope.customer2.name}
  • 「<%@page import="model.CustomerBean"%>」、この記述は何のために必要でしょうか?
あなたの答え:
  • 「${requestScope.customer1}」のようにリクエスト属性名を指定すると何が出力されますか?
あなたの答え:
  • 「${requestScope.customer1.getName()}」のように属性名に続けてメソッドを呼び出すとどうなりますか?
あなたの答え:
  • 「${requestScope.customer1.name}」のように属性名に続けてプロパティを呼び出すとどうなりますか?
あなたの答え:
  • 「${requestScope.customer2.name}」のようにnullのプロパティを呼び出すとどうなりますか?
あなたの答え:

このように、nullのプロパティを呼び出しても何も出力されません。また、${customer2.name.length()}と書いてもNullPointerExceptionは発生しません。JavaSEを学んできた皆さんのようなエンジニアには違和感の残る仕様かもしれません。しかし、エラーメッセージが表示されてもユーザーを困惑させるだけだということを考慮すると納得できる仕様です。うまく活用してください。

JavaBeansの入れ子の例

次にBeanの中にBeanが入っている例、Beanの入れ子の例を以下のel-bean2.jspで見てみましょう。

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@page import="model.CustomersBean"%>
<%@page import="model.CustomerBean"%>
<%
CustomerBean cb1 = new CustomerBean();
cb1.setCustomerId(1);
cb1.setName("今井");

CustomerBean cb2 = new CustomerBean();
cb2.setCustomerId(2);
cb2.setName("田渕");

CustomersBean csb = new CustomersBean();
csb.addCustomer(cb1);
csb.addCustomer(cb2);

request.setAttribute("customers", csb);
%>

${requestScope.customers}
<br>
${requestScope.customers.getCustomerArrayList()}
<br>
${requestScope.customers.customerArrayList}
<br>
${requestScope.customers.customerArrayList[0].name}
<br>
  • 「${customers}」のようにBeanの入ったBeanを指定すると何が出力されますか?
あなたの答え:
  • 「${requestScope.customers.getCustomerArrayList()}」のようにBeanのメソッドを呼び出すと何が出力されますか?
あなたの答え:
  • 「${requestScope.customers.customerArrayList}」のようにBeanのプロパティを呼び出すと何が出力されますか?
あなたの答え:
  • 「${requestScope.customers.customerArrayList[0].name}」のようにBeanのプロパティの0番目のプロパティを呼び出すことはできますか?
あなたの答え:

このようにしてBeanのプロパティのプロパティにアクセスすることも可能です。しかし、実際には Beanのプロパティのプロパティにアクセスする場合には次のJSTLの繰り返しを使います。この点はまたあとで詳述します。

実験1

ELとコメントの関係

コメントだけからなる以下のcomment.jsp を実行するとどうなるでしょうか?HTMLのソースまで見て確かめてみましょう。

<%@page contentType="text/html" pageEncoding="UTF-8"%>

        <!-- htmlのコメント  ${1 + 2 } -->
        <%-- JSPのコメント  ${1 + 2 } --%>
実験結果のメモ:

ユーザーに見せたくないコメントはJSPのコメントで、ユーザーに見せてもよいコメントはHTMLのコメントで書くようにしましょう。

5. ELを記述できる場所

ELは文字列として評価されますのでHTMLファイルで文字列が書けるところであれば、HTMLでもCSSでもJavaScriptでもどこでも書くことができます

例えば、以下el-and-html.jspのようにCSSにもHTMLのタグにもタグの属性値にも入れられます。

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%
    request.setAttribute("color", "pink");
    request.setAttribute("message", "Hello World");
    request.setAttribute("tag", "h1");
%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>el-and-html.jsp</title>
        <style>
            body{
                background-color: ${color};
            }
        </style>
    </head>
    <body>
        <input type="text" value="${message}">

        <${tag}>${message}</${tag}>

    </body>
</html>

また、例えば以下el-and-javascript.jspのようにJavaScriptの中にも書くことができます。

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>el-and-javascript.jsp</title>
    </head>
    <body>
        <button id="logout">logout?</button>
        <%
            request.setAttribute("name", "田渕");
        %>
        <script>
            const button = document.querySelector("#logout");
            button.addEventListener("click", function () {
                let logout = confirm("${name}さん本当にログアウトしますか?");
                if (logout) {
                    window.location.href = "https://saycon.co.jp";
                }
            });
        </script>
    </body>
</html>

例題1

上記のようにHTMLやCSS,JavsScriptとELを組み合わせて簡単なWebサイトを作成しなさい。

6. JSTLとは何か?

JSTL【JSP Standard Tag Library】はその名の通り、JSP内でよく使われる機能をライブラリ【Library】= 図書館としてまとめたものです。先のELと組み合わせることで、スクリプトレットが不要になり、可読性・保守性が向上します。

JSTLはカスタムタグといって自分でタグを作るのともできます。しかし、本新人研修では既に用意されているタグのみを使います。しかもJSTLのうち2つ、Coreタグという核となる基本のタグとi18nタグ【Internationalization】(面白いネーミングですね)という表示形式に関わるタグのみ紹介します。(本来 Internationalizationのタグは国際化に関するJSTLタグですが、本研修では表示形式を整える目的でのみ使用します。)

7. JSTLの使い方

7.1 JSTLライブラリの準備

JSTLのjarファイルをプロジェクトに追加する前に、ライブラリをダウンロードする必要があります。

講師の指示に従ってApacheの公式サイトからダウンロードしてください。

https://tomcat.apache.org/download-taglibs.cgi

ダウンロードしたjarファイルを対象プロジェクトの「WEB-INF\lib」配下にコピーします。

7.2 JSPファイルでのJSTLタグの使用

JSTLライブラリをプロジェクトに追加した後、JSPファイル内でJSTLタグを使用するためには、対応するタグライブラリの宣言をJSPファイルの先頭に追加する必要があります。以下は、Coreタグライブラリを使用する例です。

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

当社新人エンジニア研修の環境では、JSPの1行目に以下のようにしてPrefixとURIを指定するだけでJSTLが使えるようになります。

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

※Coreタグの例

7.3 JSTLのCoreタグの使い方

JSTLの Coreタグ を使って条件分岐と繰り返しができるようになりましょう。

以前出てきた以下の2つのタグとその他の使用頻度が低めのコアタグについては説明を割愛していますのでご了承ください。

<c:out> 値を安全に出力する
<c:redirect> リダイレクトする

なお、 Coreタグは全て <c:タグの種類> のように書きます。

7.4 条件分岐

<c:if>

JSTLで単純分岐を実現するには<c:if>タグを使います

<c:if>の書式

<c:if test = "判定条件">

真の場合の処理(例えば、HTMLを書けば出力がなされる:以降同様)

</c:if>

HTMLと同じように開始終了タグでifのブロックを表現します。

私達は当たり前のようにJavaSEでブロックを表現するのに{}を使ってきました。しかし、JSTLのようにブロックの開始と終了を何らかの単語で表現するプログラミング言語もたくさんあるのですね。今のうちに慣れておきましょう。

<c:if> のtest属性には判定条件をEL式を使って記述します。

JavaSEで書かれた以下JavaSESampleIf.javaのような処理があるとします。

package JavaSE;

public class JavaSESampleIf {

	public static void main(String[] args) {

		if (true) {
			System.out.println(true);
		}

		if (1 < 2) {
			System.out.println(true);
		}

		if (1 > 2) {
			System.out.println(true);
		}
	}
}

以下if1.jspは同じ処理をJSPで実現したものです。

読み込んで質問に答えてください。

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>if1</title>
    <body>
        <c:if test="${true}" >
            trueです。
        </c:if>
        <hr>
        <c:if test="${1 < 2}" >
            trueです。
        </c:if>
        <hr>
        <c:if test="${1 > 2}" >
            trueです。
        </c:if>
        <hr>
    </body>
</html>
  • 9~11行の出力結果を予想しなさい。
あなたの答え:
  • 13~15行の出力結果を予想しなさい。
あなたの答え:
  • 17~19行の出力結果を予想しなさい。
あなたの答え:


例題2

以下のif2.jspで20歳以上であれば「酒を飲む」と表示するJSTLをコメント(<%--(ここに書く)--%>)の位置に書き入れなさい。

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>if2</title>
    </head>
    <body>
        <%
            request.setAttribute("age", 20);
        %>
            <%--(ここに書く)--%>
    </body>
</html>

<c:if>タグではvar属性に変数名を指定すると、test属性に指定した条件式の判定結果のboolean値がその変数に格納されます。そのため以降の判定条件にその変数を使うことができます。

以下のif3.jspを読み込んで質問に答えてください。

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>if2</title>
    </head>
    <body>
        <%
            request.setAttribute("count", 10);
            request.setAttribute("name", "imai");
        %>
        <c:if test="${count >= 10}" >
            count:<c:out value="${count}" />
        </c:if>
        <hr>
        <c:if test="${name == 'imai'}" var="flag" />
        imai?:<c:out value="${flag}" />
        <hr>
        <c:if test="${flag}" >
            imai
        </c:if>
        <hr>
        <c:if test="${!flag}" >
            imaiではない
        </c:if>
    </body>
</html>
  • 14~16行の出力結果を予想しなさい。
あなたの答え:
  • 18~20行の出力結果を予想しなさい。
あなたの答え:
  • 21~23行の出力結果を予想しなさい。
あなたの答え:
  • 25~27行の出力結果を予想しなさい。
あなたの答え:

<c:choose>

JavaSEのif文はelse句を使って処理を分岐させることができました。

しかし、JSTLの<c:if>タグにはelseはありません。

JSTLで多岐分岐を実現する場合は<c:choose>タグを使います

<c:choose>タグ の中には複数の<c:when>タグと、ひとつの<c:otherwise>タグを含めることができます。なお、英語で【otherwise】には「そうでなければ」といった意味がありましたね。JavaSEのswitch文でいえばdefault句にあたります。

<c:choose>の書式

<c:choose>

<c:when test = 判定条件1> 判定条件1が真の場合の処理 </c:when>

<c:when test = 判定条件2> 判定条件2が真の場合の処理 </c:when>

<c:otherwise> 判定条件1,2がともに偽の場合の処理 </c:otherwise>

</c:choose>

JavaSEのときに作成したBMI「体重kg/(身長m * 身長m )」を判定するプログラムを作成してみます。

JavaSEの場合は以下JavaSESampleIfElse.javaのようになりました。

package JavaSE;

public class JavaSESampleIfElse {

	public static void main(String[] args) {

		double bmi = 70 / (1.7 * 1.7);

		if (bmi < 18.5) {
			System.out.println("低体重(やせ型)");
		} else if (bmi < 25) {
			System.out.println("普通体重");
		} else {
			System.out.println("肥満");
		}
	}
}

上記と同じことを以下choose1.jspではJSTLで実現しています。

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>choose1.jsp</title>
    </head>
    <body>
        <%
            request.setAttribute("bmi", 70/(1.7*1.7));
        %>
        <c:choose>
            <c:when test="${bmi < 18.5}">低体重(やせ型)</c:when>
            <c:when test="${bmi < 25}">普通体重</c:when>
            <c:otherwise>肥満</c:otherwise>
        </c:choose>
    </body>
</html>

例題3

次のJavaSE(Q2.java )のプログラムと同様のことをJSTLを使って実現しなさい。

package JavaSE;

public class Q2 {

	public static void main(String[] args) {

		int num = (int) (Math.random() * 101) % 9;

		if (num == 0) {
			System.out.println("大吉です");
		} else if (num == 1 || num == 2) {
			System.out.println("中吉です");
		} else if (num >= 3 && num <= 5) {
			System.out.println("小吉です");
		} else if (num == 6 || num == 7) {
			System.out.println("凶です");
		} else {
			System.out.println("大凶です");
		}
	}
}

switch文的な役割もこの<c:choose>タグが担います。

以下JavaSESampleSwitch.javaはJavaSEの血液型診断のプログラムです。(ちなみに筆者は血液型診断を信じません…AB型なので…)

package JavaSE;

public class JavaSESampleSwitch {

	public static void main(String[] args) {
		char bloodType = 'A';
		switch (bloodType) {
		case 'A':
			System.out.println("慎重な性格");
			break;
		case 'B':
			System.out.println("大胆な性格");
			break;
		case '0':
			System.out.println("おおらかな性格");
			break;
		default:
			System.out.println("不思議な性格");
		}
	}
}

上記と同じことをJSTLで実現するのが以下choose2.jspです。

ここでのポイントは、繰り返しになりますが、ELでは==で文字列が等しいかどうかの判定ができる点です。(JavaSEではequalsメソッドを使う必要がありました)さらに==をeqと書くこともできるのでしたね。(JavaSEではeqはありませんでした)

さらに、14、15行目をよく見てください。ELの場合は文字列をシングルクォーテーションでも囲むことができるのはダブルクォーテーションの中に入れられるようにするためでした。つまり、「"${bloodType == "A"}"」とすることはできませんが、「"${bloodType == 'A'}"」あるいは「'${bloodType == "A"}'」とすることはできるのです。

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>choose2.jsp</title>
    </head>
    <body>
        <%
            request.setAttribute("bloodType", "A");
        %>
        <c:choose>
            <%--シングルクートで文字列を使った例--%>
            <c:when test="${bloodType == 'A'}">慎重な性格</c:when>
            <%--ダブルクオートで文字列を囲んだ例--%>
            <c:when test='${bloodType == "B"}'>大胆な性格</c:when>
            <%--eqを使った例--%>
            <c:when test='${bloodType eq "O"}'>おおらかな性格</c:when>
            <c:otherwise>不思議な性格</c:otherwise>
        </c:choose>
    </body>
</html>

7.5 繰り返し

JSTLで繰り返しを実現するには<c:forEach>タグを使います

<c:forEach>の書式

<c:forEach>

繰り返したい処理

</c:forEach>

また、下表7.4の属性を指定できます。

属性意味
varvariableの略。繰り返し処理される値が代入される変数の名前(省略可)
itemsコレクションフレームワークを指定すれば、var属性で1つ1つの要素を取り出すことができるようになる
表7.4 <c:forEach>の属性

リストを使った繰り返し

<c:forEach> はJavaSEの拡張for文に似た使い方ができます

例えば、リストに入れた4人の名前を拡張for文を使って表示するには以下JavaSESampleFor.javaのように書きました。

package JavaSE;

import java.util.ArrayList;
import java.util.List;

public class JavaSESampleFor {

	public static void main(String[] args) {

		for (int i = 0; i < 6; i++) {
			System.out.println("Hello World");
		}

		List<String> names = new ArrayList<String>();
		names.add("今");
		names.add("國分");
		names.add("田渕");
		names.add("久保川");

		for (String name : names) {
			System.out.println(name);
		}
	}
}

同様のことをしているのが以下foreach1.jspのサンプルコードです。

このときitems属性に指定できるのはリストなどのコレクションフレームワーク(や配列)のみであることに注意が必要です。

<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>forEach1</title>
</head>
<body>

	<%
	List<String> names = new ArrayList<>();

	names.add("今");
	names.add("國分");
	names.add("田渕");
	names.add("久保川");

	request.setAttribute("names", names);
	%>

	<c:forEach var="name" items="${requestScope.names}">            
    ${name}<br>
	</c:forEach>

	<c:forEach var="name" items="${requestScope.names}">            
    ${name}:${name.length()}文字<br>
	</c:forEach>

</body>
</html>
  • 28~30行の出力結果を予想しなさい。
あなたの答え:

例題4

上記のプログラムをできるだけ何も見ないで書きなさい。

オブジェクトを使った繰り返し

items属性に指定できるのはリストなどのコレクションフレームワークのみでした。

逆に言えばコレクションフレームワークであれば、その中身がどのようなオブジェクトでも指定できるということです。

以下のforeach2.jspを読み込んで質問に答えてください。

<%@page import="model.CustomersBean"%>
<%@page import="model.CustomerBean"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>forEach2</title>
</head>
<body>

	<%
	CustomerBean c1 = new CustomerBean();

	c1.setCustomerId(1);
	c1.setName("今井");
	c1.setPrefectureId(23);
	c1.setAddress("愛知県一宮市一丁目");
	c1.setBirthday("1992-05-23");
	c1.setPoints(100);

	CustomerBean c2 = new CustomerBean();
	c2.setCustomerId(2);
	c2.setName("田渕");
	c2.setPrefectureId(23);
	c2.setAddress("三重県桑名市一丁目");
	c2.setBirthday("1995-04-27");
	c2.setPoints(100);

	CustomersBean csb = new CustomersBean();

	csb.addCustomer(c1);
	csb.addCustomer(c2);
	request.setAttribute("customers", csb);
	%>

	<c:forEach var="customer"
		items="${requestScope.customers.customerArrayList}">            
            ${customer}<br>
	</c:forEach>
	<hr>
	<c:forEach var="customer"
		items="${requestScope.customers.customerArrayList}">            
            ${customer.name}<br>
	</c:forEach>
	<hr>
	<table border="1">
		<thead>
			<tr>
				<th>顧客ID</th>
				<th>顧客名</th>
				<th>都道府県コード</th>
				<th>顧客住所</th>
				<th>顧客誕生日</th>
				<th>ポイント</th>
			</tr>
		</thead>

		<tbody>
			<c:forEach var="customer"
				items="${requestScope.customers.customerArrayList}">
				<tr>
					<td>${customer.customerId}</td>
					<td>${customer.name}</td>
					<td>${customer.prefectureId}</td>
					<td>${customer.address}</td>
					<td>${customer.birthday}</td>
					<td>${customer.points}</td>
				</tr>
			</c:forEach>
		</tbody>
	</table>
</body>
</html>
  • 「${customer}」の出力結果を予想しなさい。
あなたの答え:
  • 「${customer.name}」の出力結果を予想しなさい。
あなたの答え:
  • 「${customer.customerId}」以下6行の出力結果を予想しなさい。
あなたの答え:

今回はスクリプトレットで2名分の顧客オブジェクトを用意して、それぞれのデータを出力しました。

もう少し学習が進むとデータベースから取り出した全顧客の情報をオブジェクトに入れて一覧表にして出力することもできるようになります。それまであと一息ですので頑張りましょう。

例題5

以下の例を参考に顧客リストのテーブルにあなたのチームメンバーを加えなさい。

ただし、住所や誕生日はダミーでよい。

例題6

上記例題4を出力は変えずに、以下のようにコンストラクタ1行でインスタンスを生成するように書き換えなさい。(Customerクラスにも手を加える必要がある)

CustomerBean c1 = new CustomerBean(1, "今井", 23, "愛知県一宮市一丁目", "1992-01-16" ,100);

例題7

以前作成した以下のような数あてゲームのボタン版のフォームをforeachを使って作成しなさい。

なお、begin, end, varといったこのテキストに記述されていない属性を使う必要があるので「補講:JSTLをつかった単純な繰り返し」の記事を参考にすること。

7.6 カートの中身を取り出す

前回のJavaBeansのところで作成したCarBeanクラスとCartクラスを使ってカートに商品を追加して、個々の商品と合計金額を表示するJSPを作成してみます。

これまでの知識を組み合わせれば以下cartSample1.jspのとおりです。

<%@page import="model.Cart"%>
<%@page import="model.CarBean"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>cartSample1.jsp</title>
</head>
<body>
	<%
	CarBean c1 = new CarBean("セダン", 2590000);
	CarBean c2 = new CarBean("クーペ", 4990000);

	Cart cart = new Cart();

	cart.addCar(c1);
	cart.addCar(c2);

	request.setAttribute("cart", cart);
	%>
	<c:forEach var="car" items="${requestScope.cart.list}">            
            ${car.name}:${car.price}<br>
	</c:forEach>
	合計:${requestScope.cart.total}
</body>
</html>

単純な繰り返し

単純な繰り返しについては本研修では使用頻度が低いので以下の補講を見てください。

補講:JSTLをつかった単純な繰り返し

8. JSTLのi18nタグ

JSTLの i18nタグを使って金額や日付の表示フォーマットをコントロールできるようになりましょう。例えば金額に3桁のカンマを付けたり、日付を和暦で表示したりといったことができるようになります。当社が想定している最終課題をやり抜く上で特に重要なのが金額表示です。

8.1 金額の表示

金額の先頭に¥マークを付けて3桁カンマ付きで金額を表示するには以下fmt1.jspのようにします。

<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<fmt:formatNumber value="2590000" type="CURRENCY" currencySymbol="¥" maxFractionDigits="0" groupingUsed="true" />

<実行結果>

¥2,590,000
  • Coreタグを使用したときの表示(例:2590000)と何が同じで何が違いますか?
あなたの答え:

金額等の数値関連の属性としては下表7.5を押さえれば十分です。

属性説明
value数値データ
typeデータ型 CURRENCYは金額の意
currencySymbol="&yen;"をつけることで先頭に¥マークが付く、PERCENTは後ろに%が付く
groupingUsed3桁カンマの有無 trueは有り、falseは無し
maxFractionDigits小数部分の最大けた数(結果は四捨五入)
米ドルは小数点以下2桁まで表示するのが一般的だが日本円の場合は整数表示にするのが一般的なためmaxFractionDigits="0"とする
minFractionDigits小数部分の最小けた数 (結果は四捨五入)
表7.5 金額等の数値関連の属性

以下のfmt2.jspは金額等の数値関連の属性を使用したJSPです。

<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<fmt:formatNumber value="2590000" type="CURRENCY"  groupingUsed="true" /><br>

<fmt:formatNumber value="3.141592" maxFractionDigits="3"/><br>

<fmt:formatNumber value="0.12345" type="PERCENT" minFractionDigits="1"/><br>

<fmt:formatNumber value="0.23456" type="PERCENT" minFractionDigits="1"/><br>

<実行結果>

¥2,590,000
3.142
12.3%
23.5%

8.2 日付の表示

次に日付の表示をコントロールしてみます。

以下fmt3.jspを見てください。


<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<jsp:useBean id="date" class="java.util.Date"/>

<%
    java.util.Date theDay = new java.util.Date();
    request.setAttribute("theDay", theDay);
%>

<html>
    <body>
        <p><fmt:formatDate value="${theDay}" pattern="yyyy年MM月dd日(E)" /> </p>
        <p><fmt:formatDate value="${theDay}" pattern="yy年M月d日(E)" /></p>
        <p><fmt:formatDate value="${theDay}" pattern="yyyy年" /></p>
        <p><fmt:formatDate value="${theDay}" pattern="MM月" /></p>
        <p><fmt:formatDate value="${theDay}" pattern="dd日(E)" /></p>
    </body>
</html>

<実行結果>

2022年09月29日(木)
22年9月29日(木)
2022年
09月
29日(木)

日付関連の属性にpatternがあります。

本当はもっと多くのpatternがあるのですが、下表7.6を押さえれば当社の新人エンジニア研修では十分です。

なお、このpatternは多くのプログラミング言語やツール(例.EXCEL)でほぼ共通のものですから覚えて損はありません。

pattern意味(一般に文字数が桁数を意味する)
y西暦年(year)
M月(month)
d日(day)
E曜日
表7.6 日付関連のpattern属性

例題8

上記の例を参考に今日の日付をいろいろな表現で表示しなさい。

最後に今回紹介したCoreタグとi18nタグについて下表7.7にまとめておきます。

種類Prefix URI
Corechttp://java.sun.com/jsp/jstl/core
Internationalization(i18n)fmthttp://java.sun.com/jsp/jstl/fmt
表7.7 Coreタグとi18nタグのまとめ

まとめ

□ELで文字列をシングルクォーテーションでも囲むことができるのは、ダブルクォーテーションの中に入れられるようにするためのルール

□ ELは==で文字列の比較ができる

□ ELを使うと JavaBeansのプロパティを簡単に出力できる

□ nullのオブジェクトをELに入れると何も出力されない

□ JSTLで単純分岐を実現するには<c:if>タグを使う

□ JSTLで多岐分岐を実現する場合は<c:choose>タグを使う

□ JSTLで繰り返しを実現するには<c:forEach>タグを使う

□ <c:forEach>タグはJavaSEの拡張for文に似た使い方ができる。その際、items属性に指定できるのはリストなどのコレクションフレームワークのみ

□ JSTLの i18nタグを使うと金額や日付の表示フォーマットをコントロールできる

今回はELとJSTLについて学びました。

次回は、JDBCを学んでいきます。 JDBC を使えば、JSPやサーブレットとデータベースを組み合わせることができます。つまり、データベースから取り出したデータをBeansに入れて、<c:forEach>タグを使い拡張for文のような使い方をしてデータベースの内容を全てJSPに出力するということもできるようになります。

「ELとJSTLで豊かな表現ができるようになる」 最後までお読みいただきありがとうございます。