JavaのWebアプリで一覧を表示するには?JSPでデータからHTMLを作る仕組み

本記事は、Schooの「Java入門 中級【2026年版】」第4回「Webアプリケーションの動作原理と画面連携」に関連する補足記事です。商品などのデータが、Web画面の一覧になる仕組みを整理します。
商品が3件あれば3行、10件あれば10行。件数に合わせてHTMLを手書きする代わりに、JSPのfor文で1件ずつデータを取り出し、行のHTMLを作ります。さらにif文を使うと、在庫数に応じて「在庫あり」「売り切れ」のように表示内容を変えられます。
この記事ではServletが商品データを用意し、JSPが一覧のHTMLを作ります。授業資料と同じく、JSP内の <% ... %> と <%= ... %> を使って処理を追います。
Schoo コースページ:Java入門 中級【2026年版】
まず、完成する一覧と元のデータを対応させる
今回は「ノートが8個、ペンが0個、ファイルが3個」という3件の商品を表示します。0個なら「売り切れ」、1個以上なら「在庫あり」とする要件です。
ノート / 在庫8個
ペン / 在庫0個
ファイル / 在庫3個
<tr>…</tr> を1つ作る<tr> … ノート … 8 … 在庫あり … </tr>
2周目<tr> … ペン … 0 … 売り切れ … </tr>
3周目<tr> … ファイル … 3 … 在庫あり … </tr>
行の色は、データ・生成された行・画面の対応を示しています。ブラウザへJavaのfor文やif文が送られるわけではありません。
ServletとJSPはどちらもサーバー側で動きます。JSPの処理で作ったHTMLを受け取って、見える表にするのがブラウザです。図の色や枠は対応を示すためのもので、後のサンプルは装飾のないHTMLの表を返します。
JSPに書いたJavaは、どこで実行されるのか
まず、商品名を1つだけ出す小さな例で確認します。次はサーバーに置くJSPの一部分です。
<% String productName = "ノート"; %>
<p>商品名:<%= productName %></p>
<% ... %> の中ではJavaの処理を実行します。<%= ... %> は式の値をレスポンスへ出力する書き方です。この場合、サーバーで productName に「ノート」が入り、その値がHTMLの中に出力されます。
<p>商品名:ノート</p>
これがブラウザへ送られるHTMLです。ブラウザに String productName や <%= productName %> が届いて、それをブラウザがJavaとして実行するわけではありません。
商品名と在庫数をProductクラスにまとめる
商品一覧の1行には、1件の商品に属する名前と在庫数を表示します。そのため、商品名と在庫数を1つのProductオブジェクトにまとめます。example パッケージに Product.java を作ります。
package example;
public class Product {
private final String name;
private final int stockCount;
public Product(String name, int stockCount) {
this.name = name;
this.stockCount = stockCount;
}
public String getName() {
return name;
}
public int getStockCount() {
return stockCount;
}
}
new Product("ノート", 8) は、「名前はノート、在庫数は8」という1件の商品を作ります。getName() と getStockCount() を呼ぶと、その商品の名前と在庫数を取り出せます。
複数の商品は List<Product> に入れます。Productが商品1件、List<Product>が商品の一覧です。商品を追加したり並べ替えたりしても、名前と在庫数は同じオブジェクトの中で対応したまま扱えます。
Servletで商品のリストを用意し、JSPへ渡す
前の記事のServletはJavaの out.println() でHTMLを返していました。今回は表示部分を product-list.jsp に置き、Servletからデータを渡します。
example パッケージの ProductListServlet.java です。リストにProductを3件追加し、products という名前でJSPへ渡します。
package example;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@WebServlet("/products")
public class ProductListServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
List<Product> products = new ArrayList<>();
products.add(new Product("ノート", 8));
products.add(new Product("ペン", 0));
products.add(new Product("ファイル", 3));
request.setAttribute("products", products);
request.getRequestDispatcher("/product-list.jsp")
.forward(request, response);
}
}
List<Product> は変数の型で、「Productを要素として持つリスト」を表します。new ArrayList<>() で実際のリストを作り、add() で商品を1件ずつ追加しています。ここでは画面表示の流れに集中するため、データベースを使わずServletでデータを用意します。
setAttribute():Javaのデータに名前を付けて、同じリクエストの中で使えるようにする。forward():サーバー内で処理をJSPへ引き継ぐ。JSPは渡されたデータを使ってHTMLを作る。
ブラウザがアクセスするURLは /lesson04/products です。/lesson04 はこの例のアプリの配置先です。JSPは src/main/webapp/product-list.jsp に置き、Servletから /product-list.jsp へ転送します。forward() はブラウザへ移動先を通知する処理ではないため、アドレス欄のURLは変わりません。
この配置ではJSPのURLも公開されますが、このサンプルの確認はServletのURLから行います。/lesson04/product-list.jsp を直接開いてもServletが実行されず、表示に必要な products が渡されないためです。
JSPで商品のリストを受け取る:getParameter()との違い
<%@ page import="java.util.List, example.Product" %>
<%
List<Product> products =
(List<Product>) request.getAttribute("products");
%>
ここで使うのは getAttribute() です。Servletの setAttribute() に指定した名前と合わせて、商品のリストを取り出しています。戻り値の型は Object なので、List<Product> にキャストして受け取ります。先頭の page import は、このJSPで使うListとProductを指定しています。
このキャストでは、リストの各要素がProductであることまでは実行時に検査されないため、コンパイル時に「未チェックのキャスト」の警告が出ることがあります。Servlet側でProductのリストを渡し、JSP側で同じ型として受け取る約束を揃える必要があります。
| 用途 | 取得するメソッド | 今回の値 |
|---|---|---|
| ブラウザから送られたフォームなどの値を読む | getParameter() | String 型の入力値 |
| Servletがサーバー内で渡したデータを読む | getAttribute() | 商品のリスト List<Product> |
前の記事の「リクエストの入力値は基本的に文字列として取得する」は、getParameter() の話です。今回はブラウザから商品のリストが送られてくるのではなく、ServletがJavaで作ったリストをJSPに渡しています。
JSP全体:1周につき商品の行を1つ作る
src/main/webapp/product-list.jsp に置くコードです。表の外枠と見出しは1回だけ出力し、データの行をfor文の中に置きます。
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page import="java.util.List, example.Product" %>
<%
List<Product> products =
(List<Product>) request.getAttribute("products");
%>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>商品一覧</title>
</head>
<body>
<h1>商品一覧</h1>
<p>全<%= products.size() %>件</p>
<table>
<thead>
<tr><th>商品名</th><th>在庫数</th><th>状態</th></tr>
</thead>
<tbody>
<% for (Product product : products) { %>
<%
// 商品名をHTMLの文字として表示するための変換
String displayName = product.getName()
.replace("&", "&")
.replace("<", "<")
.replace(">", ">");
%>
<tr>
<td><%= displayName %></td>
<td><%= product.getStockCount() %></td>
<td>
<% if (product.getStockCount() > 0) { %>
在庫あり
<% } else { %>
売り切れ
<% } %>
</td>
</tr>
<% } %>
</tbody>
</table>
<% if (products.isEmpty()) { %>
<p>表示する商品がありません。</p>
<% } %>
</body>
</html>
このJSPは、上のServletから products という名前でProductのリストを受け取ることを前提にしています。products.size() は商品数です。for (Product product : products) で1件ずつ取り出し、各周回の product から名前と在庫数を読みます。3件なら <tr> から </tr> までが3回出力されます。
<table><% for (Product product : products) { %><tr>
<td>商品の値</td>
<td>在庫数</td>
</tr><% } %></table>3件なら表が3つできるのではなく、1つの表にデータの行が3つできます。図では見出し行などを省略しています。
%> が出てきても、for文そのものが終わるわけではありません。%> はJavaを書く区間の終わり、} はfor文やif文のブロックの終わりです。Javaの波括弧の対応で、どのHTMLが繰り返されるかを読んでください。
if文で、各商品の表示を分ける
<% if (product.getStockCount() > 0) { %>
在庫あり
<% } else { %>
売り切れ
<% } %>
if文は拡張for文の中にあるため、取り出した商品ごとに判定します。ペンのProductでは product.getStockCount() が0なので、HTMLへ出力されるのは「売り切れ」です。この行に「在庫あり」は出力されません。
| 拡張for文の周回 | productの商品名 | 在庫数 | 出力する状態 |
|---|---|---|---|
| 1周目 | ノート | 8 | 在庫あり |
| 2周目 | ペン | 0 | 売り切れ |
| 3周目 | ファイル | 3 | 在庫あり |
ブラウザへ届くHTMLを見比べる
生成される表の部分は次のようになります。読みやすいように空白と改行を整えています。JSPにあったfor文やif文がなくなり、処理結果の値とHTMLだけになっている点に注目してください。
<table>
<thead>
<tr><th>商品名</th><th>在庫数</th><th>状態</th></tr>
</thead>
<tbody>
<tr>
<td>ノート</td><td>8</td><td>在庫あり</td>
</tr>
<tr>
<td>ペン</td><td>0</td><td>売り切れ</td>
</tr>
<tr>
<td>ファイル</td><td>3</td><td>在庫あり</td>
</tr>
</tbody>
</table>
ブラウザは、このHTMLの <table>、<tr>、<td> を読み、表として表示します。Javaの繰り返し処理が完了した結果を表示しているので、通信がないままブラウザ上でJavaのfor文が回り続けることはありません。
データを増やすと、JSPを書き足さなくても行が増える
Servletの3件目の追加処理の後、setAttribute() より前に次の1行を追加して再実行します。JSPのfor文は変更しません。
products.add(new Product("ふせん", 12));
products.size() が4になるので、「ふせん・12・在庫あり」の行が追加されます。商品名と在庫数はProductとして一緒に追加します。一覧の各行を同じ書式で出すため、件数が変わるたびにHTMLを書き足す必要がありません。
new ArrayList<>() で作ったリストに何も追加せず渡した場合は、拡張for文が0回となり、商品の行は出力されません。products.isEmpty() がtrueになり、表の下に「表示する商品がありません。」と表示します。データを変えた結果を確認するには、アプリに変更を反映してページを再読み込みします。
商品名を出力する前にHTML用の変換をする理由
サンプルの displayName は、商品名に含まれる &、<、> をHTML用に変換した値です。例えば「A&Bノート」はHTML上では A&Bノート と出力し、画面では元の「A&Bノート」と表示します。
<%= ... %> はHTML用の変換を自動では行いません。データベースや入力フォームの文字列を表示する場合にも、HTMLのタグではなく文字として表示する処理が必要です。ここでの3文字の変換は <td> の中などの通常のテキスト表示用で、URL・HTML属性・JavaScriptへの埋め込みにそのまま使うものではありません。
確認問題
本文のServletの商品データを、次の内容に変更したとします。JSPはそのまま使い、在庫数は0以上とします。
List<Product> products = new ArrayList<>();
products.add(new Product("ノート", 2));
products.add(new Product("ペン", 0));
products.add(new Product("ふせん", 1));
- ブラウザに表示される3行の「商品名・在庫数・状態」を書いてください。
- ペンの行について、ブラウザへ送られる
<tr>から</tr>までのHTMLを書いてください。 - 「0個なら売り切れ、1〜2個なら残りわずか、3個以上なら在庫あり」と表示を変えます。JSPのif文を書き換えてください。
- 空の商品のリストを渡した場合、商品の行は何行になり、このサンプルでは何と表示されますか。
演習後の確認:こちらのページを使って、自分で考えた内容を見直せます。
まとめ
- Servletが用意したデータをJSPへ渡し、JSPがブラウザに送るHTMLを作る。
- JSPのfor文の中に1件分の行を書くと、件数に応じて行が出力される。
- if文を行の中に置くと、データごとに表示内容を分けられる。
- ブラウザが受け取るのは、Javaのコードではなく処理結果のHTML。