サーブレットにページを読み込む
ここではリダイレクトして別のページに移動することでサーブレットの処理結果を表示させていましたが、別のアプローチもあります。それは、サーブレットの中に表示用のJSPを読み込んでしまうというものです。これも試してみましょう。
送信するフォーム「index.jsp」と結果表示の「page.jsp」はそのままでいいでしょう。送信先のMyServletの中で、結果表示のための「page.jsp」を読み込んで表示させるようにdoPostを修正します。
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("Shift_JIS"); response.setContentType("text/html;charset=Shift_JIS"); PrintWriter out = response.getWriter(); String str = request.getParameter("text1"); str = this.getSanitizedString(str); str = "[JSP-to-SERVLET:\"" + str + "\"]"; request.setAttribute("msg", str); ServletContext context = this.getServletContext(); out.println("※include↓<hr>"); RequestDispatcher dispatcher = context.getRequestDispatcher("/page.jsp"); dispatcher.include(request, response); // includeに変更 out.println("<hr>※include↑"); }

分かりやすくするためにいくつかoutにテキストを出力するコードを追加しましたが、基本的には修正部分はわずか1箇所です。一番最後のdispatcher.forwardを、dispatcher.includeに変更しただけです。このようにすると、MyServletの中にJSPを組み込んで表示します。実質的な表示はJSPにまかせておき、出力する値などを変数としてアトリビュートに入れておけばいいわけです。
forwardと異なり、これはあくまで「サーブレットの出力の中にJSPがはめ込まれる」という形になりますから、サーブレットで表示を作成し、表示の一部分として他のページを埋め込むこともできます。
JSPにサーブレットを埋め込む
では、逆にJSPの中にサーブレットの表示を埋め込むことはできるのでしょうか。これも、もちろん可能です。どちらかと言うと、表示用のJSPの中に、必要に応じてサーブレットを埋め込む方が使い勝手はよいでしょう。
これも実際にサンプルを挙げて説明しましょう。先ほどまでの例で、「index.jsp」から「page.jsp」にフォームを送信し、この「page.jsp」内からMyServletを読み込んで表示させてみることにします。「index.jsp」にあるフォームの送信先を、action="./page.jsp"というように変更し、「page.jsp」に送信するようにしてください。
では、「page.jsp」から修正を行いましょう。これは、単純にサーブレットを埋め込んで表示するだけのものにしておきます。
<%@ page language="java" contentType="text/html; charset=Shift_JIS"
pageEncoding="Shift_JIS"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html; Shift_JIS">
<title>PAGE</title>
</head>
<body>
※includeした内容<br>
<hr>
<jsp:include flush="true" page="/myserv"/>
<hr>
ここまで。
</body>
</html>

ここでは、<jsp:include>というタグを使っています。これは「アクションタグ」と呼ばれるもので、JSPに用意されている特別なタグです。この<jsp:include>タグを用意することで、その場所に指定のページの内容を読み込んで表示することができます。このタグには、以下の2つの属性を指定します。
- flush
- page
ここではpage="/myserv"とすることで、この部分にMyServletを読み込むようにしているのです。MyServlet側は、ここではPOSTでの送信先であるページにincludeされますから、doPostに必要な処理を用意しておきます。
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("Shift_JIS"); response.setContentType("text/html;charset=Shift_JIS"); PrintWriter out = response.getWriter(); String str = request.getParameter("text1"); // str = this.getSanitizedString(str); // サニタイズ str = "[JSP-to-SERVLET:\"" + str + "\"]"; out.println(str); }
ざっとこのように出力を用意しておけば、「page.jsp」内にこのMyServletのdoPostの出力が埋め込まれた状態で表示されます。include元の「page.jsp」がPOSTで呼び出された場合には、includeされるサーブレットもdoPostが呼ばれるということは重要ですのでよく覚えておきましょう。
<%@ page>でcontentTypeとpageEncodingを指定し、サーブレットでrequest.setCharacterEncoding/response.setContentTypeするといった基本的な処理をきちんと行っても、includeした場合に限り、パラメータがISO-8859-1のデフォルトエンコーディングで認識されてしまうという現象が確認できました。request.setCharacterEncodingしても、なぜかrequest.getParameterで得られるテキストが化けてしまう、というものです。もし同様の現象に遭遇した場合には、とりあえず取得したStringのエンコーディングを強制的に変換させることで対処できます。
str = new String(str.getBytes("iso-8859-1"), "Shift_JIS");

リクエスト・セッション・アプリケーションの値
サーブレットから他のページに値を受け渡すのにrequest.setParameterを利用していましたが、この他にもJSPではセッションを使った値の受け渡しができました。これもサーブレットから行ってみましょう。併せて、「Webアプリケーション全体」での値の保持も行ってみます。
まず、MyServletのdoPostに、値をそれぞれの場所に保管するための処理を用意しましょう。保管後、「page.jsp」にリダイレクトさせることにします。「index.jsp」のフォーム送信先をMyServletに変更し、それからMyServletの修正を行います。ここでは、doPostメソッドだけを次のように変更します。
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("Shift_JIS"); response.setContentType("text/html;charset=Shift_JIS"); String str = request.getParameter("text1"); request.setAttribute("msg", str); HttpSession session = request.getSession(); session.setAttribute("msg", str); ServletContext context = this.getServletContext(); context.setAttribute("msg", str); RequestDispatcher dispatcher = context.getRequestDispatcher("/page.jsp"); dispatcher.forward(request, response); }
続いて、「page.jsp」です。ここでは送られてきた値をそれぞれ表示させます。
<%@ page language="java" contentType="text/html; charset=Shift_JIS"
pageEncoding="Shift_JIS"%>
<%
String msg1 = (String)request.getAttribute("msg");
// msg1 = getSanitizedString(msg1); // サニタイズ
String msg2 = (String)session.getAttribute("msg");
// msg2 = getSanitizedString(msg2); // サニタイズ
String msg3 = (String)application.getAttribute("msg");
// msg3 = getSanitizedString(msg3); // サニタイズ
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html; Shift_JIS">
<title>PAGE</title>
</head>
<body>
REQUEST:<%=msg1 %><br>
SESSION:<%=msg2 %><br>
APPLICATION:<%=msg3 %>
</body>
</html>


「index.jsp」からMyServletに送信し、リダイレクトして「page.jsp」に表示された段階では、REQUEST、SESSION、APPLICATIONのすべてに値が表示されています。その後、直接「page.jsp」にアクセスしてみましょう。今度はREQUESTがnullになり、他の2つの値だけが表示されます。


これを確認したら、今度は別のブラウザを起動し、そこから「page.jsp」にアクセスをしてみてください。REQUEST、SESSIONはnullになりますが、APPLICATIONは値が保持されていることが分かります。REQUESTとSESSIONの値は、アクセスしたクライアントごとに個別の値が保持されますが、APPLICATIONの値は、Webアプリケーション全体に値が保持されており、誰がアクセスしても同じ値が表示されるのです。
ここでは、サーブレット側で次のようにしてそれぞれの値を設定しています。
- リクエストへの設定
- セッションへの設定
- Webアプリケーションへの設定
request.setAttribute("msg", str);
HttpSession session = request.getSession();
session.setAttribute("msg", str);
ServletContext context = this.getServletContext(); context.setAttribute("msg", str);
リクエストは基本的に同じですから分かりますね。セッションは、HttpServletRequestの「getSession」でHttpSessionというクラスのインスタンスとして取得します。この取り出したsessionが、JSPの「session」暗黙オブジェクトに相当するわけです。
もう一つ、Webアプリケーションへの保管は、this.getServletContextを使ってServletContextインスタンスを取得し、そこに保管をしています。ServletContextは、リダイレクトのときにも利用しましたね。これは、Webアプリケーションに関する機能が用意されており、この中のsetAttribute/getAttributeを使うことでWebアプリケーションに値を保管できるのです。この機能は、実はJSPにもありました。「application」という暗黙オブジェクトを使うことで同様のことが行えます。
こうして設定された値は、リダイレクトされたJSPによって取り出され利用されるわけです。通常、値を他のページに受け渡す際にはrequestの利用ばかりを考えてしまいますが、サーブレットによりGUIと処理部分を分けるようになってくると、複数のページで値を受け渡すような作業が多くなってきます。値の性質によっては、HttpSessionやServletContextを利用することも考えておきましょう。
