連載
» 2001年10月13日 00時00分 公開

Tomcatを使う「JSPプログラミング」(9):JSPから別のファイルにアクセスする

[三谷純,タイムインターメディア]

JSPではforwardアクションを用いて、アクセス先を転送する処理が行えます。この仕組みを用いることで、特定の処理の前、または処理の途中で条件に応じたアクセス先の振り分けを行うことができます。今回は、このforwardアクションの使用方法について説明します。


forwardアクションの用途

 forwardアクションを使用することで、特定のJSPのページから別のページへアクセス先を転送することができます。転送先のページには別のJSPのページはもちろん、ほかのHTMLやCGIのページも指定できます。

 この仕組みを使用する代表的な例として、User Agent(ユーザーエージェント:クライアントのブラウザの種類)によるページの振り分けなどがあります。この例では、PCのブラウザでアクセスしてきたクライアントに対してはPC用のページへ転送し、携帯電話でアクセスしてきたクライアントに対しては携帯電話用のページへ転送する処理を行います。

 転送処理の仕組みを使用しない場合は、下図(左)のように、1つのJSPファイル内に異なるブラウザ用のHTML文を準備しなければなりませんが、転送処理を行う場合には、下図(右)のように、最初にアクセスされるページの記述は簡潔にまとめ上げることができます。また、それぞれのブラウザに対応したページは個別に用意しておけばよいので、メンテナンス性も上がります。

図1 転送処理を使用する場合と使用しない場合 図1 転送処理を使用する場合と使用しない場合

forwardアクションを使用するJSPプログラム

 さて、具体的なforwardアクションの記述は次のように行います。

<jsp:forward page="転送先ローカルURL">

 それでは、実際にforwardアクションを使用する例を見てみましょう。次の9-1.jspでは、HTTPヘッダからUser Agentを取得し、その文字列がDoCoMo***形式の場合に携帯電話用のページである9-1-mobile.jspへ転送する処理を行っています。

・9-1.jsp
<%@ page contentType="text/html; charset=euc-jp" %>
<%
// 内容: forward アクションを使用する
 
 // User Agent を取得
String user_agent = request.getHeader("user-agent");
 
// User Agent が "DoCoMo****" のタイプだったら携帯電話用のページへ転送
if(user_agent.startsWith("DoCoMo")) {
%><jsp:forward page="9-1-mobile.jsp" /><%
}
// 以下でPC用のページの内容を出力
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head><title>forward アクションを使用する</title></head>
<body>
<p>PC 用のページです<br>
User Agent = <b><%= user_agent %></b>
</p>
</body>
</html>

 まず、6行目でHTTPヘッダからUser Agent(ブラウザの種類)を表す文字列を取得しています。このHTTPヘッダ情報の取得に関しては、本連載の第4回で説明したとおりです。

 9行目ではStringクラスのstartsWithメソッドを使用して、取得したUser Agentの文字列がDoCoMoの6文字で始まっているかをチェックしています。もちろん、J-PHONEやauなど、ほかの携帯にも対応するためには、J-PHONEUP.Browserなどの文字列を含むかをチェックし、それぞれのページへ転送させる必要もありますが、ここでは簡単のために、DoCoMoという文字列で始まる場合にのみ、iモード用のページに転送するようにしています。

 実際の転送の記述は10行目で行っています。アクションタグの記述を行うために、一度%>タグによってスクリプトレットの記述を閉じていることに注意しましょう。アクションタグの記述後、再度<%タグによって、プログラムの記述を再開します。

10: %><jsp:forward page="9-1-mobile.jsp" /><%

 ここでは、User Agentの文字列がDoCoMo****の形式であった場合に、9-1-mobile.jspページへ転送されるようにしています。

 この転送処理が実行されると、9-1.jspページのそれ以降の記述はすべて無視されるので、この後にはそのまま、PC用のページの出力を記述することができます。

 次は、転送先の9-1-mobile.jspのプログラムコードです。

・9-1-mobile.jsp
<%@ page contentType="text/html; charset=Shift_JIS" %>
<%
// 内容: forward アクションを使用する(携帯電話用のページ)
 
// 確認用に再度 User Agent を取得
String user_agent = request.getHeader("user-agent");
%>
<html>
<body>
携帯用のページです<br>
User Agent = <br>
<%= user_agent %>
</body>
</html>

 これは、携帯電話(iモード)用のページです。iモードはシフトJISにのみ対応しているので、1行目のpageディレクティブで、

charset=Shift_JIS

と記述し、出力される文字コードをシフトJISに指定しています。ページ内では、再度確認用にUser Agentの文字列を表示します。さて、9-1.jspのページへPCと携帯電話の両方からアクセスしてみた結果は次のようになりました。

PCから 9-1.jsp にアクセスした様子 PCから 9-1.jsp にアクセスした様子
携帯電話(SO503i)から 9-1.jsp にアクセスした様子 携帯電話(SO503i)から 9-1.jsp にアクセスした様子


 それぞれ、PC用のページ、携帯電話用のページが表示されていることが分かります。携帯電話でアクセスした場合には、9-1.jspから9-1-mobile.jspへの転送が行われています。

転送元と転送先での変数の共有

 転送処理を行うと便利なケースのもう1つの例としてエラー処理があります。例えば、ユーザーから情報を入力してもらうような場合、必ずしもその入力が完全であるとは限りません。入力内容をチェックし、正しければそのまま処理を続け、問題がある場合にはエラーページへ転送することで効率の良いプログラムが行えます。

 さて、このような場合、転送先のエラーページでは、エラーの内容を表示するのが一般的です。このためには、エラーの情報が転送元のページからエラーページへ渡される必要があります。

 forwardアクションによる転送では転送元と転送先で、sessionオブジェクトrequestオブジェクトが共有されます。従って、これらのオブジェクトに変数を格納することで情報を持ちまわることができます。

転送元と転送先がどちらも同じアプリケーションに属する場合は、applicationオブジェクトも共有されるため、このオブジェクトに変数を格納することもできます。


 以下は、requestオブジェクトに変数を格納することで、入力内容に対するエラーの表示を行うプログラムの例です。

・9-2.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head><title>forward アクションを使用する(入力ページ)</title></head>
<body>
<p>-- 入力ページ --</p>
<p><form action="9-2.jsp" method="POST">
お名前: <input type="text" name="name" size=32><br>
生年月日: <input type="text" name="birthday" size=20><br>
<br>
<input type="submit" value="OK">
</form></p>
</body>
</html>

 9-2.htmlでは、名前と生年月日を入力するフォームを表示し、入力内容を9-2.jspに送ります。ごく一般的なHTML文ですので、特に問題はないでしょう。

・9-2.jsp
<%@ page contentType="text/html; charset=euc-jp" %>
<%
// 内容: forward アクションを使用する
 
// ユーザから入力されたパラメータを取得
String name = request.getParameter("name");
String birthday = request.getParameter("birthday");
 
// エラーメッセージを格納する文字列
String errorMessage = "";
 
// 名前が入力されなかった場合
if(name.equals("")) {
    errorMessage += "・名前が入力されていません<br>";
}
 
// 生年月日が入力されなかった場合
if(birthday.equals("")) {
    errorMessage += "・生年月日が入力されていません<br>";
}
 
// エラーメッセージが設定されている場合はエラーページへ転送
if(!errorMessage.equals("")) {
    request.setAttribute("errorMessage", errorMessage);
    %><jsp:forward page="9-2-error.jsp" /><%
}
 
// 文字コードの変換を行う
name = new String(name.getBytes("8859_1"), "EUC_JP");
birthday = new String(birthday.getBytes("8859_1"), "EUC_JP");
 
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head><title>forward アクションを使用する</title></head>
<body>
<p>-- 入力された値 --</p>
<p><ul>
<li>お名前: <%= name %>
<li>生年月日: <%= birthday %>
</ul></p>
</body>
</html>

 9-2.jspでは、9-2.htmlで入力された文字列を取得します。名前と生年月日をそれぞれ文字列nameとbirthdayに格納し、その内容が空でないかどうかをチェックしています。

 もし変数が空であった場合には、エラーの内容を示す文字列errorMessageに、エラーの内容を追加しています。

 23〜26行目で、エラーメッセージが設定されているかチェックし、設定されていた場合には9-2-error.jspへ転送を行います。その際、エラーメッセージの内容を転送先のページに送るために、requestオブジェクトに対して、setAttributeメソッドを用いてエラーメッセージを表す文字列を格納しています。

22: // エラーメッセージが設定されている場合はエラーページへ転送
23: if(!errorMessage.equals("")) {
24:     request.setAttribute("errorMessage", errorMessage);
25:     %><jsp:forward page="9-2-error.jsp" /><%
26: }

 エラーがなかった場合には、そのまま処理を続け、9-2.htmlで入力された文字列を表示します。

・9-2-error.jsp
<%@ page contentType="text/html; charset=euc-jp" %>
<%
// 内容: forward アクションを使用する
 
// エラーメッセージの取得
String errorMessage = (String)request.getAttribute("errorMessage");
 
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head><title>forward アクションを使用する(入力エラー)</title></head>
<body>
<p>-- 入力エラー --</p>
<p><%= errorMessage %></p>
<p><a href="9-2.html">入力ページへ戻る</a></p>
</body>
</html>

 9-2-error.jspでは、エラーの内容を表示します。エラーの内容は、requestオブジェクトに格納されているので、6行目でgetAttributeメソッドを使用して取得しています。

 5: // エラーメッセージの取得
 6: String errorMessage = (String)request.getAttribute("errorMessage");

プログラムの実行結果

 それでは、実際に上記のプログラムを実行してみましょう。実行した結果は次のようになります。

9-2.htmlで表示されるフォームに名前を入力します 9-2.htmlで表示されるフォームに名前を入力します

生年月日を入力しなかったため、9-2.jspから9-2-error.jspへ転送され、エラーメッセージが表示されました。9-2-error.jspへ転送されたもののブラウザのURLの表示は9-2.jspのままであることに注意しましょう。転送処理はサーバ側で行われるため、クライアント側からは転送先のURLは見えません 生年月日を入力しなかったため、9-2.jspから9-2-error.jspへ転送され、エラーメッセージが表示されました。9-2-error.jspへ転送されたもののブラウザのURLの表示は9-2.jspのままであることに注意しましょう。転送処理はサーバ側で行われるため、クライアント側からは転送先のURLは見えません

再度、入力フォームで必要な情報を入れたところです。エラーページではなく、9-2.jspの処理が正しく行われました 再度、入力フォームで必要な情報を入れたところです。エラーページではなく、9-2.jspの処理が正しく行われました

そのほかの転送方法

 今回紹介した例では、転送元と転送先の情報共有にrequestオブジェクトを使用しましたが、代わりにsessionオブジェクトを使用することもできます。requestオブジェクトは1回のリクエストごとに破棄されますが、さらに別のページでも使用する情報など、継続時間の長い情報を保持したい場合には、sessionオブジェクトを使用するとよいでしょう。requestとsessionの、変数を格納・取得するメソッドは共通ですので、例えば今回の例では、requestsessionに置き換えるだけで実現します。

 また、このほかにも、転送元から転送先への情報をリクエストパラメータとして渡すこともできます。この場合の構文は次のようになります。

<jsp:forward page="転送先ローカルURL" />
    <jsp:param name="パラメータ名A" value="パラメータ値A" />
    <jsp:param name="パラメータ名B" value="パラメータ値B" />
</jsp:forward>

 このようにして渡されたパラメータは、転送先のページで、

request.getParameter("パラメータ名A");

のように、通常のパラメータと同様の方法で受け取ることができます。

 ところで、forwardアクションでは、転送先をローカルのURLについてしか指定できませんでした。ほかのサイトへ転送させたい場合には、responseオブジェクトのメソッド、

sendRedirect(java.lang.String location)

を使用します。例えば、http://www.atmarkit.co.jp/fjava/へ転送させるには、次のように記述します。

response.sendRedirect("http://www.atmarkit.co.jp/fjava/");

 さて、いままではJSPを単独で用いる簡単なプログラムについて説明をしてきました。しかし、クライアント・サーバ型のWebアプリケーションでは、サービスを提供するためにデータベースを使用する必要がある場合が多いでしょう。次回以降では、JSPとデータベースを連携させたプログラムを紹介していきます。

著者プロフィール

三谷純

タイムインターメディア



Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。