JavaのServletからJSPへ値を渡すには?setAttributeとgetAttributeの使い方

ServletやJSPを使うWebアプリには、処理の間でデータを共有するための置き場所が用意されています。名前を付けてデータを保存できるこれらのオブジェクトを、一般に「スコープオブジェクト」と呼びます。「スコープ」は、保存したデータを共有できる範囲のことです。
今回は、その中のリクエストスコープを使います。Servlet側で求めた割引額を request に保存し、処理を引き継いだJSPで取り出して表示します。フォームから届くリクエストパラメータとは別のデータなので、取得に使うメソッドも区別して見ていきましょう。
Schoo「Java入門 中級」第5回「サーバーサイドアプリケーションの実装基礎」に対応しています。授業を受けていない方も、購入金額から割引額を表示する例を通して確認できます。
今回はリクエストスコープを使って、ServletとJSPで値を共有する
スコープオブジェクトには、リクエストごとの request、同じ利用者の複数のリクエストで共有できる session、アプリ全体で共有する ServletContext などがあります。どこまで共有し、いつまで使うデータなのかによって、置き場所を選びます。
今回の割引額は、送られてきた購入金額を処理して、その結果を表示するまで使えれば十分です。そこで、1回のリクエストの処理中に値を共有できるrequestの属性へ保存します。ここでいう「属性」は、名前と値を対応付けて保存したデータのことです。

Servletで setAttribute() を使って保存し、forward() でJSPへ処理を引き継ぎます。JSPでは getAttribute() で同じ名前の値を取り出せます。ServletからJSPへ進んでも、新しいリクエストにならないので、この置き場所を共有できます。
一方、リンクをクリックしたり、JSPのURLを直接開いたりすると、新しいリクエストになります。前のリクエストへ保存した属性は自動で引き継がれません。requestは、次の画面操作までデータを残しておくための保存場所ではありません。
注意:リクエストスコープの属性と、リクエストパラメータは別
- リクエストパラメータ:フォームやURLから届いた入力。今回なら購入金額の文字列
"12000"で、getParameter()で読みます。 - リクエストスコープの属性:サーバー側で名前を付けて保存するデータ。今回なら計算した割引額500で、
setAttribute()で保存し、getAttribute()で読みます。
どちらもrequestから扱えますが、同じものではありません。setAttributeで保存しても、getParameterでその値を取得できるようにはなりません。また、フォームの値が自動で同名の属性になるわけでもありません。
getParameterはServlet専用、getAttributeはJSP専用という区別でもありません。JSPからパラメータを読むことも、Servletから属性を読むこともできます。読みたいのが送信された入力なのか、サーバー側で保存した属性なのかで使い分けます。
Servletの変数は、JSPからそのまま使えるわけではない
int discount = 500;
これをServletのdoPost内に書いても、別のファイルであるJSPに discount という変数が自動的に作られるわけではありません。Servletのローカル変数が使える範囲は、その変数を宣言したメソッドやブロックの中です。
そこで、Servletの変数に入っている値を、先ほどのrequestの属性へ保存します。Servletコンテナが用意したrequestを使うため、共有用のオブジェクトを自分でnewする必要はありません。
int discount = 500;
request.setAttribute("discount", discount);
この1行で、"discount" という名前に500を対応付けます。setAttributeを書いただけでは画面は切り替わらず、HTMLも表示されません。保存したあと、JSPへ処理を引き継ぎます。
イラストで見る:保存した500が画面に出るまで

- Servletが
setAttribute("discount", discount)で、計算結果に名前を付けてrequestへ保存する。 forward(request, response)で、同じリクエストの処理をJSPへ引き継ぐ。- JSPが
getAttribute("discount")で、保存した値を取り出す。 - JSPが値をHTMLへ埋め込み、ブラウザには「割引額: 500円」と表示される。
ServletからJSPへの引き継ぎはサーバー内で行われます。属性の表がそのままブラウザへ送られるわけではありません。ブラウザが受け取るのは、JSPの実行によって作られたHTMLです。
入力を数値へ変換し、Modelの戻り値を保存する
入力欄が type="number" でも、getParameterで受け取る値は文字列です。Servletで整数へ変換し、Modelへ渡して割引額を求めます。受け取った戻り値をsetAttributeで保存するところまで、コードでつなげてみましょう。
String text = request.getParameter("amount");
int amount = Integer.parseInt(text);
DiscountModel model = new DiscountModel();
int discount = model.calculateDiscount(amount);
request.setAttribute("discount", discount);
これは正常な入力の流れだけを抜き出したコードです。未入力や整数でない値への対応は、後のServlet全体のコードに含めます。
購入金額もJSPに表示したい場合は、request.setAttribute("amount", amount); を追加します。フォームの入力名と同じ "amount" ですが、元のパラメータは書き換わりません。12000を送った場合、getParameterではStringの "12000"、getAttributeでは保存したIntegerの12000を取得します。
setAttributeの第1引数は保存名、第2引数は値
int discountAmount = 500;
request.setAttribute("discount", discountAmount);
| 部分 | 意味 |
|---|---|
"discount" | JSPから探すための保存名。文字列なのでダブルクォートで囲む。 |
discountAmount | 保存したい値が入っているServletの変数。今回の値は500。 |
保存名とJavaの変数名は一致させる必要がありません。この例でJSPが指定するのは "discountAmount" ではなく、"discount" です。揃えるのはsetAttributeとgetAttributeの第1引数です。大文字・小文字も区別されます。
同じ名前でsetAttributeを呼び直すと、その名前の値は後の値に置き換わります。複数の値を渡す場合は、"amount"、"discount" のように名前を分けます。
getAttributeでIntegerとして取り出す理由
Integer discount =
(Integer) request.getAttribute("discount");
getAttribute() はさまざまな種類の値を返せるように、戻り値の型がObjectになっています。今回は整数を保存したので、(Integer) と書いてInteger型として扱います。このキャストは、文字列を数値へ変換する処理ではありません。
setAttributeの値はオブジェクトとして保存されます。int型の500を渡すと、自動的にIntegerへ変換されます。この仕組みをオートボクシングと呼びます。Integer は整数をオブジェクトとして扱うためのクラスです。
名前に対応する属性がない場合、getAttributeは0ではなく null を返します。Integer ならnullを受け取り、「値が渡されていない」と確認できます。受け取ってすぐintへ代入すると、nullを整数へ変換しようとしてNullPointerExceptionになることがあります。
Integer discount =
(Integer) request.getAttribute("discount");
if (discount != null) {
// ここでは割引額を使える
}
setAttribute("discount", "500") のように文字列を保存したのにIntegerへキャストすると、ClassCastExceptionになります。保存名だけでなく、渡す値の型もServletとJSPで揃える必要があります。0円という結果と、値がないnullも区別しましょう。
forwardで、属性を持ったままJSPへ引き継ぐ
request.setAttribute("discount", discount);
request.getRequestDispatcher("/discount-result.jsp")
.forward(request, response);
getRequestDispatcher() で表示先を指定し、forward() で処理を引き継ぎます。先頭の / は、このWebアプリのルートを表します。アプリのURLが /lesson05 なら、そのアプリ内のdiscount-result.jspです。
この例ではブラウザへ別URLへのアクセスを指示せず、サーバー内でJSPを実行します。そのため、ブラウザのアドレス欄はServletへの送信先のままです。JSPのrequestから、Servletが保存した属性を取得できます。
値の保存はforwardより前に行います。また、forwardはJavaのreturnではなくメソッド呼び出しです。通常どおり戻ればServletの後続コードも実行されるため、このサンプルではdoPostの最後に置きます。画面の出力が始まってから転送する構成にもせず、表示はJSPへ任せます。
動くコードで確認する:割引額をJSPに表示する
購入金額が10,000円以上なら500円引き、それ未満なら0円とします。Java 17・Tomcat 10.1の jakarta.servlet を使う構成です。各ファイルはUTF-8で保存します。前の記事と同じ計算例ですが、ここではJSPへの受け渡しに注目します。
1.入力画面:src/main/webapp/discount-form.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>割引額の確認</title>
</head>
<body>
<h1>割引額の確認</h1>
<form action="discount" method="post"
accept-charset="UTF-8">
<label for="amount">購入金額(円)</label>
<input id="amount" name="amount" type="number"
min="0" max="2147483647" step="1" required>
<button type="submit">割引額を確認する</button>
</form>
</body>
</html>
2.計算するクラス:src/main/java/example/DiscountModel.java
package example;
public class DiscountModel {
public int calculateDiscount(int amount) {
if (amount < 0) {
throw new IllegalArgumentException(
"購入金額は0円以上にしてください。");
}
if (amount >= 10000) {
return 500;
}
return 0;
}
}
Modelは整数の購入金額を受け取り、割引額を返すだけです。requestへの保存やHTMLの出力は行いません。
3.値を用意して渡す:src/main/java/example/DiscountServlet.java
package example;
import java.io.IOException;
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("/discount")
public class DiscountServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String text = request.getParameter("amount");
if (text == null || text.isBlank()) {
request.setAttribute("error", "購入金額を入力してください。");
} else {
try {
int amount = Integer.parseInt(text.trim());
DiscountModel model = new DiscountModel();
int discount = model.calculateDiscount(amount);
request.setAttribute("amount", amount);
request.setAttribute("discount", discount);
} catch (NumberFormatException e) {
request.setAttribute("error",
"購入金額は0〜2147483647の整数で入力してください。");
} catch (IllegalArgumentException e) {
request.setAttribute("error",
"購入金額は0円以上にしてください。");
}
}
request.getRequestDispatcher("/discount-result.jsp")
.forward(request, response);
}
}
正常時には amount と discount、入力に問題があれば error を属性へ保存します。HTML側でrequiredやminを指定していても、それだけには頼らずServlet側でも確認します。
4.受け取って表示する:src/main/webapp/discount-result.jsp
<%@ page pageEncoding="UTF-8"
contentType="text/html; charset=UTF-8" %>
<%
String error = (String) request.getAttribute("error");
Integer amount = (Integer) request.getAttribute("amount");
Integer discount = (Integer) request.getAttribute("discount");
%>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>割引額の確認結果</title>
</head>
<body>
<h1>割引額の確認結果</h1>
<% if (error != null) { %>
<p><%= error %></p>
<% } else if (amount != null && discount != null) { %>
<p>購入金額: <%= amount %>円</p>
<p>割引額: <%= discount %>円</p>
<% } else { %>
<p>入力画面から割引額を確認してください。</p>
<% } %>
<a href="discount-form.html">入力画面に戻る</a>
</body>
</html>
JSPの <% ... %> の中では、サーバー側でJavaの処理を実行します。<%= discount %> はdiscountの値を出力する記述です。discountが500なら、<p>割引額: 500円</p> というHTMLが作られます。JSPのJavaコード自体をブラウザへ送るわけではありません。
この例でHTMLに埋め込むのは、整数とプログラム内で決めた固定のエラーメッセージだけです。フォームの入力文字列はそのまま表示しません。外部から届く商品名などの文字列を表示する場合、<%= ... %> は自動でHTMLエスケープしないため、別途適切なエスケープ処理が必要です。
実際の注文処理では、フォームで送られた金額をそのまま請求の根拠にせず、サーバー側の商品情報と数量から金額を確定します。今回は値の受け渡しを確認するサンプルです。
フォームから開く場合と、JSPを直接開く場合を比べる
アプリのコンテキストパスが /lesson05 なら、http://localhost:8080/lesson05/discount-form.html を開いて送信します。
| 操作・入力 | 結果 | 理由 |
|---|---|---|
| 12000を送信 | 購入金額12000円・割引額500円を表示 | ServletがModelから割引額を取得し、2つの属性を保存してからforwardする。 |
| 9999を送信 | 割引額0円を表示 | 0も有効な計算結果として属性へ保存される。 |
| 未入力やabcがサーバーへ届く | 入力エラーのメッセージを表示 | Servletがerror属性を保存し、JSPが取り出す。 |
| discount-result.jspを直接開く | 「入力画面から割引額を確認してください。」と表示 | 新しいリクエストでJSPへ直接アクセスするため、Servletによる属性の保存が行われていない。 |
フォームから結果を表示したあと、別のタブでJSPを直接開いてみてください。前の割引額ではなく案内文が表示されれば、リクエストごとに属性が別であることを確認できます。
リンクでJSPを開いたり、sendRedirectでブラウザにアクセスし直してもらったりする場合も、新しいリクエストになります。forwardと同じつもりで置き換えると、保存した属性を取得できません。なお、ServletのURLで画面を再読み込みしたときはPOSTが再送信される場合があり、単に「再読み込みしたら必ず値が消える」とは限りません。
表示されないときは、保存名・型・経路を確認する
| 症状 | 確認する場所 | 直し方 |
|---|---|---|
| getAttributeがnullになる | "discount" と "discountAmount" など、名前が食い違っていないか | 保存名と取得名を揃える。 |
| getParameterで結果が取れない | setAttributeで保存した値を読もうとしていないか | 属性はgetAttributeで読む。 |
| ClassCastException | 数値を保存したのにStringへキャストしていないか | 保存したオブジェクトに合う型で受け取る。 |
| NullPointerException | 属性がないのにintへ自動変換していないか | Integerで受け、nullを確認する。 |
| JSPの直接アクセスだけ値がない | Servletを通り、保存後にforwardしているか | 入力画面から送信し、想定した処理経路で確かめる。 |
JSP側で割引額をもう一度計算して埋め合わせるのではなく、Servletで保存した値が、同じ名前・型で届いているかを順に確認します。
確認問題
それぞれ独立した問題です。本文の割引額は10,000円以上で500円、それ未満で0円とします。
- Servletの変数
int discountAmount = 500;を、保存名"discount"でrequestに保存し、JSPの変数Integer resultへ取り出すコードを書いてください。 - フォームから
amount=12000が届き、Servletがrequest.setAttribute("amount", 12000);を実行しました。getParameter(“amount”)とgetAttribute(“amount”)で取得する値と型を答えてください。 - Servletが
request.setAttribute("discount", 500);と書き、JSPが(Integer) request.getAttribute("discountAmount")と書いています。結果が取得できない理由と修正方法を答えてください。 - 一度フォームから結果を表示したあと、新しいタブでdiscount-result.jspを直接開きました。本文のJSPでは何が表示されますか。同じ値を表示できない理由も説明してください。
演習後の確認:こちらのページを使って、自分で考えた内容を見直せます。
まとめ
- Servletの変数をJSPで使うには、setAttributeでrequestへ名前を付けて値を保存する。
- getParameterは送られてきたパラメータ、getAttributeはサーバー側で保存した属性を読む。
- JSPでは同じ保存名を指定し、保存した値に合う型で受け取る。属性がない場合はnullになる。
- forwardなら同じリクエストの処理をJSPへ引き継げる。JSPの直接アクセスは別のリクエスト。
- ブラウザへ返るのは、JSPが値を埋め込んで生成したHTML。