前回は、フォームからデータをサーブレットに渡すところまでをやりました。
今回は、今までの知識を応用してログイン処理を作ってみます。
前回学んだリクエスト属性を使えば、入力画面に入力した内容をもとにJSPの出力画面に情報を表示できました。しかし、実はリクエスト属性は複数ページを跨いで情報の保持ができません。ステートレスといって1対のリクエストとレスポンスで終了してしまうのです。
そこで必要となるのがセッション属性です。セッション属性を使うことで複数ページを跨いで情報の保持ができます。そしてログイン処理は複数ページを跨いで情報を保持する必要のある典型的な処理です。この章ではそんなセッション属性の特徴をログイン処理を実装することにより体験的に学びます。
1. ログイン処理とは
まずは一般的なログイン処理についてまとめておきましょう。皆さんも是非、普段お使いのWebアプリケーションで実験してみてください。(あるいは講師の実演をご覧ください)
突然ですがログインに関する質問です。
- ①一般にWebシステムにログインするにはどのような情報が必要ですか?
あなたの答え: |
- ②ログイン前と後では何が違いますか?
あなたの答え: |
- ③あるブラウザでログイン中に同じブラウザで他のタブを開いたら新しい方のタブでログインは継続されますか?
あなたの答え: |
- ④あるブラウザ(例えばクローム)でログイン中に新しいブラウザ(例えばエッジ)を起動したら新しいブラウザでログインは継続されますか?
あなたの答え: |
- ⑤どんなときにWebアプリからログアウトしますか?
あなたの答え: |
上記の実験からも明らかなように一般的にはログインとは以下のような処理を指します。
①ユーザーはブラウザからIDとパスワードといった自分だけが知る情報を使ってログインする
②ログイン後はそのユーザーだけが見られるページに遷移できるようになる
③ログイン中は同じブラウザで他のタブを開いてもログインされたままである
④しかし、同じユーザーが別のブラウザで同じページにアクセスしても再度ログイン処理が必要である
⑤ログアウト処理をする、ブラウザを終了するまたは一定時間(大抵は30分間だが銀行のように5分程度と短い場合も)が経過するとログアウトする
上記結果④から考えるとログイン処理はブラウザごとに固有の情報を利用していると推測できます。
また、結果⑤から考えるとログアウトのタイミングは技術者が個々に設定していることが分かります。
本章では、ログイン処理を実現するにはセッションという仕組みを理解することが必要になるということ、さらに同一セッションで有効なセッション属性を使うことでリクエスト属性では実現できなかった複数リクエストを跨いだデータ保持が可能になるということを解説していきたいと思います。例えば、オンラインショッピングで買い物かごの仕組みが実現できるのは、かごの中身をこのセッション属性に入れているから複数ページに渡ってデータを保持できるのです。次の商品を見に行くたびに買い物かごの中身がクリアされてしまっては使い物になりませんからね。
セッション属性とは開始してから破棄されるまで同一ブラウザで有効なスコープです。
セッションの破棄は、「ログアウト処理」、「ブラウザを終了する」または「セッションタイムアウト」により実行されます。
実は、前章までの知識で実現できるのは上記「①ユーザーはブラウザからIDとパスワードといった自分だけが知る情報を使ってログインする」だけです。
1.1. IDとパスワードでログインする
以下の図が処理の概要です。
ユーザーがブラウザからユーザーIDとパスワードを入力してログインボタンを押下します。
サーブレットはIdとpasswordが正しいことをチェックします。
①IDとパスワードが正しければ、messageをmember-only.jspにフォワードします。
②IDとパスワードが正しくなければ、エラー画面を表示します。
2. ログイン処理の実装
下図のようなログイン画面を作ります。
ログイン画面
以下のlogin.jspはユーザーIDとパスワードの入力を求める画面です。
ソースコードを読み込んで質問に答えてください。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>login.jsp</title>
<style>
#center {
display:flex;
justify-content: center;
align-items: center;
text-align: center;
height: 100vh;
}
</style>
</head>
<body>
<div id="center">
<form action="${pageContext.request.contextPath}/Login1" method="post">
ユーザーID:<input type="text" name="id" required><br>
パスワード:<input type="password" name="pass" required><br>
<button type="submit">ログイン</button>
</form>
</div>
</body>
</html>
- ①<style>タグで囲まれた部分を英字3文字で何といいましたか?
あなたの答え: |
- ②「method="post"」このメソッドの特徴は何でしたか?
あなたの答え: |
サーブレットのソースコード
以下のLogin1Servlet.javaはIDとパスワードを認証するサーブレットです。
プログラムを読み込んで質問に答えてください。
package controller;
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(urlPatterns = { "/Login1" })
public class Login1Servlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String id = request.getParameter("id");
String pass = request.getParameter("pass");
if ("imai".equals(id) && "p".equals(pass)) {
request.setAttribute("id", id);
request.getRequestDispatcher("view/member-only.jsp").forward(request, response);
} else {
response.sendRedirect("view/login-error.jsp");
}
}
}
- ①上記のif文でtrueの場合はどうなりますか?
あなたの答え: |
- ②「request.setAttribute…」ではどんな属性に対してどんな名前でどんなデータを格納していますか?
あなたの答え: |
setAttribute()メソッドの引数は以下のようになっています。
setAttribute(String name, Object value)
第2引数はセッションに格納したいインスタンスです。Object型なのでJavaのインスタンスであれば何でも格納できます。
第1引数は名前です。変数名のようなもので JSPのEL式でこの名前で取り出すことができます。
次に、if文でfalseの場合、すなわちIDまたはパスワードが間違った場合を見てみましょう。
ここでは、フォワードを使っていませんね。フォワードを使ってもよいのですが、フォワードですとアドレスバーの表記が変わらないため “ログインできていない” ことが伝わりづらいため、リダイレクト処理というものを行っています。
3. フォワードとリダイレクト
画面遷移の方法にはフォワードとリダイレクトがあります。
英語の【redirect】には「re=再び」「direct=方向づける」という意味があります。データの出力先などを変更するという意味でIT業界では広く使われる言葉です。
その特徴をまとめると以下の図の通りです。
特に注目いただきたいのは以下の4点です。
「2.ソースコード」のところでフォワードがrequestのメソッドであるのに対して、リダイレクトはresponseのメソッドであるという点
「3.遷移先のパス指定方式」のところで相対パス指定ができる点(混乱を避けるためこの後のパス指定は相対パスに統一します)
「4.典型的な処理の流れ」で、フォワードがリクエストとレスポンスを1往復交わすのに対して、リダイレクトは2往復であるという点
「5.リクエストスコープ」でリダイレクトはリクエスト属性を引き継がない点
ちなみに、リダイレクトは「5.転送可能範囲」で外部サーバーOKとなっています。したがって上記の記述を以下のようにルートパスでも、絶対パスでも、同じ結果が得られるのです。フォワードと違ってパス指定のルールがそのまま適用できると考えれば理解しやすいでしょう。(上図の「3. 遷移先のパス指定方式」参照)
この研修中はリダイレクトには相対パスで指定することにします。なぜならそれが一番短く記述できるうえにフォワードと共通だからです。
response.sendRedirect("view/login-error.jsp");
なお、リダイレクト先は外部サーバーも可能です。
response.sendRedirect("https://saycon.co.jp/");
ひとまず、「リクエスト属性とフォワード」、「セッション属性とリダイレクト」はセットであるそう覚えていただいても研修期間中は問題ありません。
ログインエラー画面のソース
以下のlogin-error.jspはログインエラー時の画面、menber-only.jspはログイン成功時の画面です。
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>login-error.jsp</title>
<style>
#content1{
color: red;
}
</style>
</head>
<body>
<center>
<div id="content1">
<h2>ログインエラーが発生しました。</h2>
</div>
</center>
<p style="text-align:center"><a href="login.jsp">ログイン画面へ戻る</a></p>
</body>
</html>
<%@ page pageEncoding="UTF-8" %>
メンバーだけのページです。
ようこそ${requestScope.id}さん
member-only.jspの3行目の以下の記述は、リクエスト属性を指定する書き方です。後で学ぶセッション属性を指定する書き方と比べてみてください。
${requestScope.id}
4. getメソッドとpostメソッドの違い
HTMLでも学んだ下図にあるpostメソッドの特徴をログイン処理に応用しましょう。(ちなみにシステム開発演習中は無理にpostメソッドを使う必要はありません。とりあえず全てgetメソッドにしても大丈夫です。なぜなら、postメソッドには①サーブレットが単体で実行できなくなる。②リクエストパラメータが見えなくなる。という特徴があるためです。)
では、ここでもう少し踏み込んでgetメソッドとpostメソッドの違いについて見ていきましょう。
ブラウザには開発用のツール(ディベロッパーツール)があります。例えば、当社の新人エンジニア研修で使用しているChromeの場合はブラウザの画面を右クリックして「検証」を選びます。(ショートカットキーはF12)
当初は英語で表示されると思いますが、以下の設定画面で日本語にすることもできますので講師から説明を受けてください。
下図にある「ネットワーク」のタブをクリックします。
F5キーを押してリクエストとレスポンスのやり取りをもう一度実行します。
次に、「名前」のところでサーブレットのURLパターン(例.Login1)を選択して、右の「ヘッダー」をクリックします。
下図の上がpostメソッド、下がgetメソッドの表示例です。
- ①postとgetでリクエストURLはどう違いますか?
あなたの答え: |
ただし、postリクエストにするとリクエストパラメータがアドレスバーに表示されないというだけです。上図の「Payload」というタブを開くとパラメータを見ることができてしまいます。httpsを使った暗号化などをしないとパケットを中継する機器からは丸見えです。くれぐれも誤解のないように。(https通信ですと「Payload」のタブ自体が無くなります)
ちなみにステータスコードが「200 OK」になっていますね。HTTPプロトコルにおいてステータスコードとは、Webサーバからのレスポンスの意味を表す3桁の数字です。
ここで当社の新人エンジニア研修で見かけるステータスコードを表5.1にまとめておきます。
ステータスコード | 意味 |
---|---|
200 | 正しく表示されている |
403 | アクセスを禁止されている |
404 | ページが見つからない |
405 | このURLではサポートされていないメソッドでアクセスした |
500 | サーバ内部エラー |
次に下図のように「Cookie」をクリックしてください。
名前に「JSESSIONID」、値に32桁の16進数が入っていますね。
Cookie とは、Webサイトの訪問者の情報を一時的にクライアントに保存するための仕組みです。Cookie の目的はユーザーの識別です。近年 Cookie を使った広告のトラッキングが問題になっていることをご存じの方もいるかと思います。
そして今回作りたいログイン処理もこの Cookie を使った仕組みなのです。
次に、 JSESSIONID とはJ2EEを使用したWebアプリケーションにおいてデフォルトで使用されるセッションIDを表す番号です。JSESSIONID の先頭のJはJavaのJなのですね。
セッション【session】とは、ブラウザとWebサーバの一連の複数のリクエストとレスポンスの活動期間のことです。(例えば、複数の質問に回答する時間をQ&Aセッションといいますね。英語のsessionには複数の送信と受信の一連の流れ、というような意味があるのです)このセッションごとにIDが付いているわけです。
実は一般的なログイン処理はこのセッションの仕組みを利用しているのです。(注:他にも方法はあります)
次はこのセッションの仕組みを使ってログイン処理を実装しましょう。
5. セッションIDの仕組み
下図を使いセッションIDの仕組みを解説します。
- クライアント(ブラウザ)からサーバにリクエストが送られます
- サーバはセッションIDを生成します
- サーバはレスポンスにセッションIDを入れてクライアントに返します
- クライアントはセッションIDをCookieに保存します
- 以降、クライアントは全てのリクエストにセッションIDを入れて送ります
- サーバはクライアントから送られたセッションIDとサーバに保存されたセッションIDを照合することによりユーザーを認証します
- それ以降は上記5,6の手順でリクエストとレスポンスを繰り返します
- セッションIDのタイムアウト(デフォルトでは30分間)または破棄(大抵はログアウト)するまでセッションは有効です
パスワードとは異なりセッションIDは1回限りの意味のない16進数なので盗まれたとしても実害は少ないです。
(ただし、そのセッションIDを悪用する攻撃もありますので注意が必要です。もちろん現在皆さんがお使いのブラウザでは簡単には盗まれないようになっていますのでひとまずは安心して大丈夫ですが)
5.1. セッションを使ったログイン処理を実装する
セッションを使って次のログイン処理(再掲)を実現することにしましょう。以下の②~⑥に対応した処理を作っていきます。
①ユーザーはブラウザからIDとパスワードといった自分だけが知る情報を使ってログインする(対応済み)
②ログイン後はそのユーザーだけが見られるページに遷移できるようになる
③ログイン中は同じブラウザで他のタブを開いてもログインされたままである
④しかし、同じユーザーが別のブラウザで同じページにアクセスしても再度ログイン処理が必要である
⑤ログアウト処理をする、ブラウザを終了するまたは一定時間(大抵は30分間だが銀行のように5分程度と短い場合も)が経過するとログアウトする
⑥ログアウトしてからブラウザの戻るボタンを押すと元のログイン状態に戻らないセキュリティを強化したサイトが存在する
セッションIDに紐づく形でセッション属性という記憶領域が用意されています。
セッション属性の概要は下図のとおりです。
リクエスト属性に似ていますが、リクエスト属性は1つのリクエストだけがスコープでした。しかし、セッション属性は複数のリクエストにまたがって有効なスコープです。セッション属性は同一ブラウザであれば全てのページで有効なスコープであるともいえます。したがってセッションを使ったWebアプリケーションをテストする際には注意が必要です。例えばWebブラウザのタブを全て閉じてからテストしないと、セッション属性にデータが残っていて意図しない動作をすることがあります。
<login.jsp>はコピーして <login2.jsp> として使用します。
飛び先だけ次のurlPatterns<Login2>に変更しておいてください。
package controller;
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;
import javax.servlet.http.HttpSession;
@WebServlet(urlPatterns = { "/Login2" })
public class Login2Servlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String id = request.getParameter("id");
String pass = request.getParameter("pass");
if ("imai".equals(id) && "p".equals(pass)) {
HttpSession session = request.getSession(true);
session.setAttribute("id", id);
response.sendRedirect("view/member-only2.jsp");
} else {
response.sendRedirect("view/login-error.jsp");
}
}
}
- ①<Login1Servlet.java> からの変更点はなんですか?
あなたの答え: |
request.getSession(true);
このように記述することでセッションが存在する場合にはそのセッションを返し、存在しない場合には新しいセッションを作成します。この記述は初めてアクセスするサーブレットでセッションを作成する場合に使用すると考えてください。最初のアクセスやログインページなど、セッションがまだ存在しない可能性が高い場面です。
リクエスト属性はdoPost()やdoGet()メソッドの引数だったため宣言が不要でしたね。対して、セッション属性はHttpSessionクラスの宣言が必要なのですね。
session.setAttribute("id", id);
このように記述することでセッション属性にオブジェクトを名前をつけて保存することができます。メソッド名(setAttribute)
は全くリクエスト属性のときと同じと覚えましょう。
- ①セッション属性から属性を取得するメソッドの書き方を予測してみてください。
あなたの答え: |
ログインしないと見られないページは次のmember-only2.jspに記述されています。
menber-only2.jspの以下の記述
${sessionScope.id}
は、セッション属性を指定する書き方です。以前のリクエスト属性を指定する書き方と比べてみてください。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>member-only2.jsp</title>
</head>
<body>
<br>メンバーだけのページです。
ようこそ${sessionScope.id}さん<br>
<a href="video.jsp" target="_blank">別のタブでビデオを見る</a><br>
</body>
</html>
- ①一旦ブラウザを閉じたあと、この <member-only2.jsp>を単体で実行したらどうなりますか?
あなたの答え: |
以下のvideo.jspはログイン後にメンバー専用でビデオが見られるページです。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>video.jsp</title>
</head>
<body>
こんにちは${sessionScope.message}さんビデオを楽しんでください。<br>
<iframe width="560" height="315" src="https://www.youtube.com/embed/LA95vAwTn-M" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</body>
</html>
5.2 セッション属性とリクエスト属性の使い分け
セッション属性は有効範囲が広いため、新人エンジニアの中にはリクエスト属性ではなくセッション属性に何でも入れようとする人がいます。しかし、それは良くないことです。なぜなら、アプリケーションサーバのメモリを圧迫してしまうからです。
リクエスト属性は一つのリクエスト間だけ有効
セッション属性は複数のリクエスト間でも有効
ということは、「リクエスト属性はすぐにサーバーのメモリから消えるが、セッション属性は残ってしまう」のです。この性質を理解して適切に使い分けましょう。「使い捨て」の方が都合の良いことも多いものです。特にITの世界では「使い捨て」といってもデータですから環境問題は生じないので積極的に使い捨てましょう。
下図はセッション属性とリクエスト属性の比較です。
6. メニューをインクルードする
ここで、下図のようにWebアプリケーションらしくログイン後の各ページにはメニューがある状態にしたいと思います。
メニューとして以下のmenu.jspをご用意ください。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<a href="${pageContext.request.contextPath}/login3.jsp">ログイン</a>
<a href="${pageContext.request.contextPath}/Logout">ログアウト</a>
<a href="#">商品検索</a>
<a href="#">買い物かご</a>
リンクにpageContext.request.contextPath
を使用している理由は、各JSPページがどのコンテキストパスで提供されているかに関係なく、リンクが正しく動作するようにするためです。メニューが異なるJSPページに組み込まれる場合、それぞれのJSPページが異なるコンテキストパス(ディレクトリ構造)で提供される可能性があるからです。
また、商品検索や買い物かごのリンク先は今はダミー(#)です。
ログインのリンク先のJSPはこれから以下のlogin3.jspを作ります。
- ①Login3Servlet.javaはLogin2Servlet.javaを参考に各自作成すること
□作成できました |
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<title>login3.jsp</title>
<style>
#center {
height: 200px;
width: 300px;
position: absolute;
left: 50%;
top: 50%;
margin-top: -100px;
margin-left: -150px;
text-align: center;
}
</style>
</head>
<body>
<%@ include file="view/menu.jsp" %>
<div id="center">
<form action="${pageContext.request.contextPath}/Login3" method="post">
ユーザーID:<input type="text" name="id" required><br>
パスワード:<input type="password" name="pass" required><br>
<button type="submit">ログイン</button>
</form>
</div>
</body>
</html>
- ①「<%@ include file="view/menu.jsp" %>」この記述は何をしていると推測されますか?
あなたの答え: |
7. ログアウト処理の実装
次にログアウト処理を考えてみましょう。
私達はこれまでセッションを発行することによって同一セッションであるかどうかを判断し、ログイン状態を保ってきました。したがって、ログアウト処理はセッションを終了することによって実現できそうです。
以下のLogout.javaはセッションを無効にした上で、ログイン画面にリダイレクト処理をするサーブレットです。このプログラムを読んで質問に答えてください。
package controller;
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;
import javax.servlet.http.HttpSession;
@WebServlet(urlPatterns = { "/Logout" })
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
// ログインページなどにリダイレクト
response.sendRedirect("login3.jsp");
}
}
request.getSession(false);
このように記述することでセッションが存在する場合にはそのセッションを返し、存在しない場合にはnullを返します。引数にtrueを指定した場合と異なる挙動ですので気を付けてください。
この記述は既にセッションが存在することが前提の場合、例えばユーザーがログイン後に利用するページでは、request.getSession(false) を使用します。これにより、無駄なセッションが作成されず、セッションが存在しない場合は適切に処理できます。2回目以降にサーブレットにアクセスする場合に使います。
- ①「session.invalidate();」という記述では何をしていると推測されますか?
あなたの答え: |
セッションを無効にすることで、セッションに保存されているユーザー情報やその他の機密情報が保護され、不正なアクセスから守られます。また、不要になったセッションデータをクリーンアップすることで、サーバーのメモリを圧迫しません。
8. セッションのまとめ
最後にセッションの扱い方をサンプルコードにして、コメントを付けておきましたので確認してください。
package controller;
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;
import javax.servlet.http.HttpSession;
@WebServlet(urlPatterns = { "/SessionExample" })
public class SessionExampleServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// セッションを取得、セッションが存在しない場合は新規作成
HttpSession session = request.getSession(true);
// セッションIDを取得
System.out.println(session.getId());
// セッション属性の設定
session.setAttribute("username", "exampleUser");
// セッション属性の取得、セッション属性はObject型で設定されるためキャストが必要
String username = (String)session.getAttribute("username");
// 取得した文字列を表示
System.out.println(username);
// セッション属性の削除
session.removeAttribute("username");
// セッション属性の取得、ただし、削除されているために出力はnull
System.out.println(session.getAttribute("username"));
// しかし、セッション自体は存在しているためIDは取得できる
System.out.println(session.getId());
// セッションの無効化
session.invalidate();
// セッションを取得、セッションが存在しない場合はnull
System.out.println(request.getSession(false));
// セッションを取得、セッションが存在しない場合は新規作成
session = request.getSession(true);
// 新しいセッションIDが作られている
System.out.println(session.getId());
}
}
<コンソールの出力例>
5E5B0799298D6A98A56BFCBCAF4FAEFF exampleUser null 5E5B0799298D6A98A56BFCBCAF4FAEFF null DAF55E879825AFB4A3CEE6E712D1E7E2 |
今回はログイン処理の実装方法を通じてセッションについて学びました。
Webページというものは本来1ページ、1ページが独立していて、ページをまたいでデータを引き継ぐ仕組みがありません。このようにhttp通信のリクエストとレスポンスがそれぞれ独立していて他の http通信にデータを引き継がないことをステートレス【stateless】といいます。【state】= 状態 が【less】=(引き継げ)ないというわけでしたね。
本来http通信はステートレスであり、一対のリクエストとレスポンスで通信は終了します。しかし、複数のリクエストとレスポンスを同じものとして扱うことができなければ、ログイン処理や買い物かごの処理は実現できません。ページをまたぐごとにユーザーを忘れてしまったり、買物かごの中身が消えてしまったら使い物になりませんね。
そこで必要となるのがセッションです。
Webアプリケーションは、本来ステートレスとして作られたhttp通信を使って擬似的にステートフルにしてオンライン商取引などに使っているわけです。そのため、かなり無理をしている(?)感じは否めないかと思います。
次回は、JavaBeansを学んでいきます。
JavaBeansを使うことで今回のセッション属性にオブジェクトをまるごと入れて複数ページをまたいだ処理が可能になります。例えば、買物かごのような仕組みも実現できるようになります。
IT企業向け新人研修おすすめ資料 無料公開中 (saycon.co.jp)