SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

WTPではじめるサーバサイドJava入門

サーバサイドJava入門 JSP~サーブレット~Beanを相互利用する

第6回 サーブレットとJSPの連携

サーブレットにページを読み込む

 ここではリダイレクトして別のページに移動することでサーブレットの処理結果を表示させていましたが、別のアプローチもあります。それは、サーブレットの中に表示用のJSPを読み込んでしまうというものです。これも試してみましょう。

 送信するフォーム「index.jsp」と結果表示の「page.jsp」はそのままでいいでしょう。送信先のMyServletの中で、結果表示のための「page.jsp」を読み込んで表示させるようにdoPostを修正します。

MyServletの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↑");
}
includeにより、サーブレット内にJSPのページを埋め込むことができる。
includeにより、サーブレット内にJSPのページを埋め込むことができる。

 分かりやすくするためにいくつか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.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の中にサーブレットをインクルードする。<jsp:include>タグを利用するのが一番簡単。
JSPの中にサーブレットをインクルードする。<jsp:include>タグを利用するのが一番簡単。

 ここでは、<jsp:include>というタグを使っています。これは「アクションタグ」と呼ばれるもので、JSPに用意されている特別なタグです。この<jsp:include>タグを用意することで、その場所に指定のページの内容を読み込んで表示することができます。このタグには、以下の2つの属性を指定します。

  • flush
  • 読み込み時に出力を強制的にフラッシュする
  • page
  • 読み込むページのURL

 ここでは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が呼ばれるということは重要ですのでよく覚えておきましょう。

パラメータの文字化けについて
 実際にJSP内にサーブレットを埋め込んだものをPOSTで送信し表示させてみると、送信されたテキストをサーブレット内で利用する際に文字化けを起こす現象に遭遇するかもしれません。これは、おそらくTomcat5特有の現象です。JSPで<%@ 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");
includeした内容のうち、getParameterしたテキストだけが文字化けする。
includeした内容のうち、getParameterしたテキストだけが文字化けする。

リクエスト・セッション・アプリケーションの値

 サーブレットから他のページに値を受け渡すのにrequest.setParameterを利用していましたが、この他にもJSPではセッションを使った値の受け渡しができました。これもサーブレットから行ってみましょう。併せて、「Webアプリケーション全体」での値の保持も行ってみます。

 まず、MyServletのdoPostに、値をそれぞれの場所に保管するための処理を用意しましょう。保管後、「page.jsp」にリダイレクトさせることにします。「index.jsp」のフォーム送信先をMyServletに変更し、それからMyServletの修正を行います。ここでは、doPostメソッドだけを次のように変更します。

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からテキストをサーブレットに送信する。
index.jspからテキストをサーブレットに送信する。
送信直後はすべての値が保管されている。
送信直後はすべての値が保管されている。

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

直接page.jspにアクセスすると、REQUESTはnullになる。
直接page.jspにアクセスすると、REQUESTはnullになる。
ブラウザを新たに起動してアクセスすると、APPLICATIONだけ値が残っている。
ブラウザを新たに起動してアクセスすると、APPLICATIONだけ値が残っている。

 これを確認したら、今度は別のブラウザを起動し、そこから「page.jsp」にアクセスをしてみてください。REQUEST、SESSIONはnullになりますが、APPLICATIONは値が保持されていることが分かります。REQUESTとSESSIONの値は、アクセスしたクライアントごとに個別の値が保持されますが、APPLICATIONの値は、Webアプリケーション全体に値が保持されており、誰がアクセスしても同じ値が表示されるのです。

 ここでは、サーブレット側で次のようにしてそれぞれの値を設定しています。

  • リクエストへの設定
  • request.setAttribute("msg", str);
    
  • セッションへの設定
  • HttpSession session = request.getSession();
    session.setAttribute("msg", str);
    
  • Webアプリケーションへの設定
  • 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を利用することも考えておきましょう。

次のページ
WEB-INF内のファイルをBeanからアクセスする

この記事は参考になりましたか?

WTPではじめるサーバサイドJava入門連載記事一覧

もっと読む

この記事の著者

掌田 津耶乃(ショウダ ツヤノ)

三文ライター&三流プログラマ。主にビギナーに向けたプログラミング関連の執筆を中心に活動している。※現在、入門ドキュメントサイト「libro」、カード型学習サイト「CARD.tuyano.com」を公開...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/1481 2007/07/20 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー