ページ間の移動
ここまでは1つのJSPファイルですべて処理してきましたが、今度は複数のページの間でやりとりをしてみることにします。ある程度複雑なWebになると、処理をフロントエンドとバックヤードに分けて作成するようになります。ユーザーが操作する部分と、送られてきたデータを処理する部分を分けることで、システムの設計もしやすくなりますし、メンテナンスもやりやすくなります。
このような「複数のページ間でのやり取り」を考えた場合、必要となる機能にはどのようなものがあるでしょうか。1つは、「ページの移動」があるでしょう。そしてもう1つ、「ページ間でのデータの受け渡し」が考えられるでしょう。
では、まず「ページの移動」について行ってみましょう。サンプルとして、既に作成してある「index.jsp」と、新たに「back.jsp」というファイルを用意することにします。Eclipseのメニューから[ファイル]-[新規]-[JSP]を選択し、作成しておきましょう。ファイルを用意したら、それぞれ次のように記述します。
<%@ page language="java" contentType="text/html; charset=Shift_JIS" pageEncoding="windows-31j"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <title>JSP SAMPLE</title> </head> <body> ※送信元ページ<br><br> <form method="post" action="./back.jsp"> <input name="submit" type="submit" value="送信"> </form> </body> </html>
<%@ page language="java" contentType="text/html; charset=Shift_JIS" pageEncoding="Shift_JIS"%> <% request.setCharacterEncoding("Shift_JIS"); if (request.getParameter("submit") != null) pageContext.forward("./index.jsp"); %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <title>Insert title here</title> </head> <body> ※このページは、直接開いても動きません。 </body> </html>

「index.jsp」にアクセスし、ボタンを押すと、再び「index.jsp」に戻ります。ブラウザのアドレスバーには「back.jsp」と表示されていますが、表示は「index.jsp」になるのです。それを確認したら、今度はアドレスを記述して直接「back.jsp」にアクセスしてみましょう。すると、「※このページは、直接開いても動きません」と表示されるはずです。
この「back.jsp」は、直接アクセスするとこのようにメッセージを表示し、「index.jsp」から送信すると「index.jspに戻る」という働きをします。どうアクセスするかによって挙動が違うのです。
「back.jsp」で行っているのは、submitの値が送られているかどうかをチェックし、nullでなければ「index.jsp」にジャンプする、という処理です。以下の部分です。
if (request.getParameter("submit") != null) pageContext.forward("./index.jsp");
ここで使っているpageContextというのは、requestやoutと同じ「暗黙オブジェクト」です。これは、PageContextというクラスのインスタンスで、JSPのさまざまな暗黙オブジェクトや属性などを利用するための機能がまとめられたものです。ここで利用しているforwardは、引数に指定したページにリダイレクトする(ページを移動する)働きをします。ページの移動は、とりあえずこのメソッドだけ覚えておけば十分でしょう。
ページ間のデータの受け渡し
続いて、ページ間でのデータの受け渡しについて考えてみましょう。ページ間でさまざまな値を受け渡す場合には、「アトリビュート」(属性)と呼ばれるものを利用します。データを送る側でアトリビュートに値を設定し、受け取る側でそのアトリビュートの値を取り出す、といった形で値のやり取りを行うわけです。
問題は、このアトリビュートの保管先が複数ある、という点でしょう。アトリビュートを保管するメソッドは、以下の暗黙オブジェクトにそれぞれ用意されています。
- request
- session
requestは、複数ページ間で値をやり取りする際に最もよく使われるオブジェクトです。クライアントからサーバにリクエストが送られると、その後の一連の処理が完了するまで値は保持され続けますから、複数のページ間で値を受け渡すにはもってこいでしょう。リクエストが完了すると値は消えてしまいますが、逆にいえば「使い終わったらきれいに消えて後に残らない」という方が便利かも知れません。
sessionは、サーバとのセッションがつながっている間、常に値が保持され続けます。これは、複数のページ間で値を受け渡すためよりも、「接続中、常に保ち続ける必要がある値」の保管場所として利用されることが多いでしょう。単純な値の受け渡しではなく、そのWebアプリケーションで常に必要とされる値を置く場所、と考えるべきでしょう。
requestとsesionによる値の受け渡し
では、実際にrequestとsesionを使った値の受け渡しのサンプルをあげておきましょう。これも「index.jsp」と「back.jsp」の間でやり取りする形にしてあります。
<%@ page language="java" contentType="text/html; charset=Shift_JIS" pageEncoding="windows-31j"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <title>JSP SAMPLE</title> </head> <body> <% request.setCharacterEncoding("Shift_JIS"); String msg1 = (String)request.getAttribute("message"); if (msg1 == null) msg1 = "(REQUEST:未送信)"; out.println("REQUEST:" + msg1); out.println("<br>"); String msg2 = (String)session.getAttribute("defaultMsg"); if (msg2 == null) msg2 = "(SESSION:未送信)"; out.println("SESSION:" + msg2); %> <form method="post" action="./back.jsp"> <input type="text" name="text1"> <input type="submit"> </form> </body> </html>
<%@ page language="java" contentType="text/html; charset=Shift_JIS" pageEncoding="Shift_JIS"%> <% request.setCharacterEncoding("Shift_JIS"); String msg = request.getParameter("text1"); String result = "Hello, " + msg + "!"; request.setAttribute("message",result); if (session.getAttribute("defaultMsg") == null) session.setAttribute("defaultMsg",result); if (msg != null) pageContext.forward("./index.jsp"); %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <title>Insert title here</title> </head> <body> ※このページは、直接開いても動きません。 </body> </html>

最初に適当なテキストを書いて送信すると、それを元に「Hello,○○!」といったテキストを作成し、sessionとrequestにそれぞれ値を保管します。2回目以降は、requestのみ値を設定し、sessionには値を設定しません。
実際に送信をしてみると、requestの値は毎回送信する度に送られた値が表示されますが、sessionの値は最初に送信したメッセージがその後もずっと保ち続けられていることが分かります。
値のアトリビュートへの設定と、アトリビュートからの値の取り出しを行うために用意されているのは、次のようなメソッドです。これは、request、sessionそれぞれにまったく同じものが用意されています。
[request/session].setAttribute(String name, Object object);
Object 変数 = [request/session].getAttribute(String name);
引数のString nameは属性名を、Object objectは設定する値をそれぞれ示します。このように、アトリビュートは、setAttributeで指定した名前を使って値を管理します。
注意が必要なのは、設定される値はStringではなくObjectである、という点です。従って、Stringの値を設定したような場合には、取り出した値を再びStringにキャストして利用しなければいけません。
実際にアトリビュートを操作している部分を見てみましょう。「back.jsp」では、getParameterで送信されたテキストを取り出し、それを元にmsgを作成してから、requestとsessionにそれぞれ値を設定しています。sessionについては、値がnullである場合(すなわち、まだ値が設定されていない)にのみ設定をしています。
request.setAttribute("message",result); if (session.getAttribute("defaultMsg") == null) session.setAttribute("defaultMsg",result);
「index.jsp」側では、requestとsessionからそれぞれアトリビュートの値を取り出し、それを表示しています。request部分を見ると、このように値を取り出しているのが分かりますね。
String msg1 = (String)request.getAttribute("message");
保存される値はObjectインスタンスになっていますから、取り出す際にはStringにキャストします。sessionのgetAttributeも扱いは同じです。
