DWR: サーバーからHTMLファイルを取得する。
前回のログ(「Direct Web Remoting」)に引き続き、dwr.warにあるサンプルをみていく。
今回は、非同期に、ウェブ・アプリケーション・サーバー(以下、サーバー)からHTMLファイルを取得するサンプル(dwr.warにある「Resource Forwarding」Example)。
少しだけ画面を改造した。初期画面は以下。
上の画面で、「HTMLをインクルード」ボタンを押すと、サーバーにあるHTMLファイルを取得して、それをdiv要素に差し込む(下図)。
差し込むHTMLファイルは、dwr.warにあるもの(forward.html)そのままを利用した。
このHTMLから分かるように、HTMLをそのまま読み込んでいるが、IFrameでもないし、エスケープもされていないことがポイント。(DWR Utilで提供されているsetValue()は、クロスサイトスクリプティングを防止するために、デフォルトでは値をエスケープする)
(注意)日本語では文字化けが発生する。
<html> <body> <big> <span style="color: rgb(153, 153, 153);">An <code>import</code>ed</span> <span style="font-weight: bold; font-family: Helvetica,Arial,sans-serif;"> <span style="color: rgb(204, 102, 204);">JSP</span> Page </span> <span style="text-decoration: underline;">with </span> <span style="font-style: italic; text-decoration: underline;">lots</span> <span style="text-decoration: underline;"> of formatting</span> . </big> </body> </html>
以下が、これを行うためのJavaクラス(ServletContextDemo.java)。
package test; import java.io.IOException; import javax.servlet.ServletException; import org.directwebremoting.WebContext; import org.directwebremoting.WebContextFactory; /** * DWRのデモ * * ServletContextを取得し、相対参照でファイルを取得して * レスポンスする。 * */ public class ServletContextDemo { public String getInclude() throws ServletException, IOException { // ServletContextの取得 // WebContext(if)はServletContext(if)の拡張 WebContext wctx = WebContextFactory.get(); // forward先のurlからデータを取得する。 return wctx.forwardToString("/data/forward.html"); } }
コンテキストパス(ドキュメントルート)下にあるディレクトリを相対参照するには、ServletContextへのアクセスとServletConfigの取得が不可欠だが、そのために、DWRではWebContextというインターフェイスが用意されている。
WebContextFactory.get()
で、WebContextを取得(ちょっと語弊があるかな)することができる。
wctx.forwardToString("/data/forward.html")
は、コンテキストパス配下のdataディレクトリにあるforward.htmlというファイルにリクエストをforwardし、forward先からStringを取得するというメソッド。
DWRでは、見た目上、JavaScriptから直接このクラスを呼び出す格好になるので、(PHPなどで実装する場合と違い)このクラス上ではHTTPレスポンスを返す必要はない。
このように、このクラスが「サーバー上で閉じている」、つまり、「リクエスト/レスポンスに依存せず、サーバー上で完結している」というのは(テストを行う上などで)大きなメリットとなる。
以下は、画面表示のHtmlファイル(servlet_context_demo.html)。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>DWRのサンプリング</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <style type="text/css" id="defaultstyle"> body { margin:0; padding:0; } #container { margin: 2px; padding: 3px; line-height:1.5em; width: 500px; height: auto; border:1px dashed #999999; } </style> <!-- ServletContextDemo.jsはDWRによって自動生成される。 dwr/はドキュメントルートとの相対参照。 --> <script src='dwr/interface/ServletContextDemo.js'></script> <!-- engine.jsは必須 --> <script src='dwr/engine.js'></script> <!-- util.jsは必須 --> <script src='dwr/util.js'></script> <script type="text/javascript"> function forward() { // ServletContextDemoは、dwr.xmlで定義したPOJO名 ServletContextDemo.getInclude( // Callback関数 function(data) { dwr.util.setValue("forward", data, // escapeしないでセットする(オプション)。 { escapeHtml:false } ); }); } </script> </head> <body> <div id="container"> <p> 簡単なDWRのデモです。<br> 「HTMLをインクルード」ボタンを押すと、下にHTMLをインクルードします。 </p> <p> <input value="HTMLをインクルード" type="button" onclick="forward()"/> <br> <br> インクルードされたHTML: <br> <div id="forward"></div> </p> </div> </body> </html>
ここでは、
dwr.util.setValue("forward", data, // escapeしないでセットする(オプション)。 { escapeHtml:false } );
がポイント。DWR UtilのsetValue()に、オブジェクトリテラル型のオプション{ escapeHtml:false }をつけている。
このオプションをつけないと、setValue()によってこのHTML内にセットされる値がエスケープされてしまい、タグがそのまま表示されてしまう(HTML文書としてインクルードできない)。
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://directwebremoting.org/schema/dwr20.dtd"> <dwr> <allow> <!-- test.ServletContextDemoというクラスのオブジェクトが「new」によって生成され、 クライアントのJavaScriptプログラムでは「ServletContextDemo」という名前で 参照できることを意味 --> <create creator="new" javascript="ServletContextDemo"> <param name="class" value="test.ServletContextDemo"/> </create> </allow> </dwr>