このページでは、サーブレットから他のリソース(サーブレット、JSP、HTMLなど)にリクエストを転送する機能である「ディスパッチ」について紹介する。
目次
リクエストのディスパッチ
Webアプリケーションを作るときに、サーブレットから別のサーブレットへリクエストをフォワード(forward:転送)することや、レスポンスに別のサーブレットの出力をインクルード(include:含める)することはよく使われる技術である。
ディスパッチャー(RequestDispatcher)インターフェイスがこれらの要求を実現している。このインターフェイスを通して、ディスパッチャーがサーブレットからのリクエストをディスパッチ(受け渡し)してくれる。
インクルード
インクルードの処理の流れを見てみよう。クライアントから来たリクエストを最初のサーブレットが受ける。このサーブレットが別のサーブレットを呼び出す。そして、別のサーブレットが処理した後、また処理が最初のサーブレットに戻る。
このサンプルプログラムは、サーブレットServletIncludeクラスがサーブレットServletIncludedにインクルード処理をさせる。
インクルードのコードの書き方は次のようになる。RequestDispatcherオブジェクトを取得して、そのincludeメソッドを呼び出している。
1 2 3 4 5 |
RequestDispatcher dispatcher = ServletContext().getRequestDispatcher("/ServletIncluded"); if (dispatcher != null) { dispatcher.include(request, response); } |
include メソッドAPI仕様
RequestDispatcher クラスのinclude メソッドAPI仕様は次の通りである。
include(ServletRequest request, ServletResponse response)
戻り値の型 |
void |
内容 |
レスポンスの中にリソース(servlet, JSP page, HTML file) のコンテンツを含ませる。ServletResponseオブジェクトはそのパス要素とパラメータを呼び出し側から変更なしで保持する。 インクルードされたサーブレットは、レスポンスのステータスコードを変更したりやヘッダーに設定したりすることはできない。どんな変更の試みも無視される。 リクエストとレスポンスパラメータは、いずれも呼び出し側のサーブレットのサービスメソッドに渡されたオブジェクトと同じか、ServletRequestWrapperかServletResponseWrapperのサブクラスでなければならない。
引数: request – クライアントのリクエストを含むServletRequetオブジェクト。 response – サーブレットのレスポンスを含むServletResponseオブジェクト。
例外: ServletException – もし、インクルードされたリソースがこの例外を発生させたら。 java.io.IOException - もし、インクルードされたリソースがこの例外を発生させたら。 |
では、実際のプログラムを見てみよう。
サンプルプログラム
このサーブレットは、インクルード処理を行うサーブレットを途中で起動している。その様子は「start」と「end」の間にIncludedServletの「[[[ IncludedServlet ]]]」という文字列が表示されることから確認できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import java.io.IOException; import java.io.PrintWriter; import javax.servlet.RequestDispatcher; 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("/ServletInclude")//[1] public class ServletInclude extends HttpServlet {//[2] @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//[3] response.setContentType("text/html");//[4] PrintWriter out=response.getWriter();//[5] out.println("<html><head></head><body>");//[6] out.println("<p>Main servlet - start</p>");//[7] RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/ServletIncluded");//[8] if (dispatcher != null) {//[9] dispatcher.include(request, response);//[10] } out.println("<p>Main servlet - end</p>");//[11]] out.println("</body></html>");//[12] } } |
サンプルプログラムの説明
それでは簡単にプログラムの解説をしてゆこう。
- [1] アノテーションの宣言をする。
- [2] HttpServletを継承して、ServletIncludeクラスを定義する。
- [3] doGet()メソッドをオーバーライドして定義する。
- [4] Content Typeにtext/html"を設定する。
- [5] 文字列をレスポンスへ出力するためのoutオブジェクトを取得する。
- [6]-[7] outオブジェクトに「Main servlet – start」をHTMLで出力する。
- [8]-[10] getRequestDispatcherの引数に/ ServletIncludedを指定して、サーブレット処理をインクルードする。
- [11] outオブジェクトに「Main servlet – end」をHTMLで出力する。
- [12] </body></html>"をoutオブジェクトに出力して、HTMLを完了させる。
インクルードされるサーブレットのサンプルプログラム
次のサーブレットは、インクルード処理を行う。どんな処理かというと、MainServletが「start」と「end」の文字列を表示する間にIncludedServletが「[[[ IncludedServlet ]]]」という文字列を挟んでクライアントに返信する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import java.io.IOException; import java.io.PrintWriter; 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("/ServletIncluded")//[1] public class ServletIncluded extends HttpServlet {//[2] @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//[3] PrintWriter out = response.getWriter();//[4] out.println("<p>[[[ ServletIncluded ]]]</p>");//[5] } } |
サンプルプログラムの説明
それでは簡単にプログラムの解説をしてゆこう。
- [1] アノテーションの宣言をする。
- [2] HttpServletを継承して、ServletIncludedクラスを定義する。
- [3] doGet()メソッドをオーバーライドして定義する。
- [4] 文字列をレスポンスへ出力するためのoutオブジェクトを取得する。
- [5] 文字列「[[[ServletIncluded]]]」をoutオブジェクトに出力する。
実行結果
ブラウザにURL:http://localhost:8080/Servlet/ServletIncludeを入力し、Enterを押す。インクルード処理によりstartとendの間に「[[[ IncludedServlet ]]]」がインクルード(含まれる)されている。
表示されるブラウザ画面:
フォワード
フォワードの処理の流れを見てみよう。クライアントから来たリクエストを最初のサーブレットが受ける。このサーブレットが別のサーブレットを呼び出す。そして、別のサーブレットがレスポンスをクライアントに返す。この時、最初のサーブレットはレスポンスバッファーに何か書き込んではいけない。もし、レスポンスバッファーに何か書き込んでいたならば、このメソッドを呼び出す前に書き込んだこのバッファーをクリアしなければならない。
このサンプルプログラムは、サーブレットServletIncludeクラスがサーブレットServletIncludedにインクルード処理をさせる。
フォワードのコードの書き方は次のようになる。RequestDispatcherオブジェクトを取得して、そのforwardメッソッドを呼び出している。
1 2 3 4 5 |
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/ServletForwarded"); if (dispatcher != null) { dispatcher.forward(request, response); } |
forward メソッドAPI仕様
RequestDispatcher クラスのforwardメソッドAPI仕様は次の通りである。
forward(ServletRequest request, ServletResponse response)
戻り値の型 |
void |
内容 |
サーブレットからのリクエストをサーバー上の別のリソースへ(servlet, JSP file, or HTML file)転送する。このメソッドはひとつのサーブレットにリクエストの予備処理か、別のリソースにレスポンスを生成することを許す。 getRequestDispatcher()を介して得られるRequestDispatcherのために、ServletRequestオブジェクトは、ターゲットリソースのパスに一致するように調整したパス要素とパラメータを持つ。 forwardはレスポンスがクライアントにコミットされる前に呼び出されるべきである(レスポンスのボディ出力が送信される前)。もし、既にレスポンスがコミットされていたならば、このメソッドはIllegalStateExceptionを発生させる。もしレスポンスバッファーの中にコミットされていない出力があれば、フォワードの前に自動的にクリアされる。 リクエストとレスポンスパラメータは、いずれも呼び出し側のサーブレットのサービスメソッドに渡されたオブジェクトと同じか、ServletRequestWrapperかServletResponseWrapperのサブクラスでなければならない。
引数: request –クライアントがサーブレットに渡すリクエストを表す ServletRequestオブジェクト。 response – サーブレットがクライアントに返すレスポンスを表すServletResponseオブジェクト。
例外: ServletException – もしターゲットのリソースがこの例外を発生させたら。 java.io.IOException – もしターゲットのリソースがこの例外を発生させたら。 java.lang.IllegalStateException – もしレスポンスが既にコミットされていたら。 |
では、実際のプログラムを見てみよう。
サンプルプログラム
このサーブレットは、別のサーブレットをフォワードする。その様子は、ServletForwardedの出力する文字列が「[[[ServletForwarded]]]」だけであるということから確認できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import java.io.IOException; import javax.servlet.RequestDispatcher; 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("/ServletForward")//[1] public class ServletForward extends HttpServlet {//[2] @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//[3] RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/ServletForwarded");//[4] if (dispatcher != null) {//[5] dispatcher.forward(request, response);//[6] } } } |
サンプルプログラムの説明
それでは簡単にプログラムの解説をしてゆこう。
- [1] アノテーションの宣言をする。
- [2] HttpServletを継承して、ServletForwardクラスを定義する。
- [3] doGet()メソッドをオーバーライドして定義する。
- [4]-[6] getRequestDispatcherの引数に/ ServletForwardedを指定して、サーブレット処理をフォワードする。
フォワードされるサーブレットのサンプルプログラム
次のサーブレットは、単純に「[[[ IncludedServlet ]]]」という文字列をHTMLでレスポンスに出力する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import java.io.IOException; import java.io.PrintWriter; 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("/ServletForwarded")//[1] public class ServletForwarded extends HttpServlet {//[2] @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//[3] response.setContentType("text/html");//[4] PrintWriter out=response.getWriter();//[5] out.println("<html><head></head><body>");//[6] out.println("<p>[[[ ServletForwarded ]]]</p>");//[7] out.println("</body></html>");//[8] } } |
サンプルプログラムの説明
それでは簡単にプログラムの解説をしてゆこう。
- [1] アノテーションの宣言をする。
- [2] HttpServletを継承して、ServletForwardedクラスを定義する。
- [3] doGet()メソッドをオーバーライドして定義する。
- [4] Content Typeにtext/html"を設定する。
- [5] 文字列をレスポンスへ出力するためのoutオブジェクトを取得する。
- [6]-[8] 文字列「[[[ServletForwarded]]]」をoutオブジェクトにHTMLで出力する。
実行結果
ブラウザにURL:http://localhost:8080/Servlet/ServletForwardを入力し、Enterを押す。フォワードにより「[[[ServletForwarded]]]」だけが表示される。
表示されるブラウザ画面:
リダイレクト
リダイレクトについては、別の記事「リダイレクトの設定(sendRedirect)」を参照のこと。
まとめ
ディスパッチを使う事でクライアント側への最終的な出力結果に複数のサーブレットの処理結果を反映することが出来る。2つ、3つとサーブレットを増やして出力結果を変化させてみよう。