Ajadで非遷移リンク

そんな訳で、今回はaタグで表示したリンクをクリックした際に、遷移させずにリンク先のHTMLを同一HTMLのdivタグ内に読込む、いわゆる非遷移な部分更新をAjadでやってみたいと思います。これができれば、非遷移なタブやメニューバーなどいろいろなものに応用できる・・・はず。ただの.htmlのリンクを読込んでみても別にいいのですが、今回はあえてstrutsと連動させて以下のような処理を行ってみたいと思います。

  • リンク先は以下のように、.doなstrutsのアクションを指定
 <a href="<%= request.getContextPath() %>/nonTransitionLink.do" />
  • strutsでは、以下のようにnonTransitionLink.doを受ける。
 <action path="/nonTransitionLink" type="org.ajad.sample.web.action.ForwardAction">
 	<forward name="success" path="/pages/nonTransitionLink.jsp" />
 </action>
  • ForwardActionはその名の通り、forwardタグに指定された遷移先への遷移のみ行うアクション。
  • よって、事実上
 <a href="<%= request.getContextPath() %>/nonTransitionLink.do" />
  • は、
 <a href="<%= request.getContextPath() %>/pages/nonTransitionLink.jsp" />
  • と同義なのであるが、一応アクションを通しているところに価値がある。多分。


そんな訳で、今回用意するHTMLはこんな感じになります。

<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib uri="http://struts.apache.org/tags-logic"  prefix="logic"  %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
	<head>
		<meta http-equiv="Content-Style-Type" content="text/css" />
		<meta http-equiv="Content-Script-Type" content="text/javascript" />
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<script type="text/javascript">
			function getApplet() {
				return document.getElementById("applet");
			}
		</script>
		<title>トップ</title>
	</head>
	<body>
		<!-- アプレット読込み -->
		<applet id="applet" mayscript code="org/ajad/sample/web/applet/TopApplet" width="0" height="0"></applet>
		
		<!-- 文書 -->
		<ul>
			<li>
				非遷移リンク<br />
				<a id="nonTransitionLink" href="<%= request.getContextPath() %>/nonTransitionLink.do" onclick="getApplet().onClickNonTransitionLink(); return false;">
					非遷移リンク
				</a>
				<br />
				以下にリンク先のHTMLを読込みます。
				<div id="nonTransitionLinkTarget"></div>
			</li>
		</ul>
	</body>
</html>

onclickにJavaScriptを仕込んでリンククリック時にアプレットのメソッドを呼び出しているのは前回同様ですね。さりげにreturn false;が入っていたりもしますが。.doのフォワード先のHTML(JSP)は今回別に何でもいいのでとりあえず紙面の都合上(?)省略します。

で、アプレットの方は今回こんなコードになります。

package org.ajad.sample.web.applet;

import java.applet.Applet;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;

import netscape.javascript.JSObject;

public class TopApplet extends Applet {
	private static final long serialVersionUID = 3871816411119859125L;

	@Override
	public void init() {
		// NOP.
	}
	
	public void onClickNonTransitionLink() {
		// Windowオブジェクト取得
		JSObject win = JSObject.getWindow(this);
		
		// Documentオブジェクト取得
		JSObject document = (JSObject)win.getMember("document");
		
		// リンク先のURLを取得
		JSObject link = (JSObject)document.call("getElementById", new Object[] {"nonTransitionLink"});
		String linkUrl = (String)link.getMember("href");
		System.out.println("value = " + linkUrl);
		
		// リンク先のHTMLを取得
		StringBuilder builder = new StringBuilder();
		InputStream stream = null;
		BufferedReader reader = null;
		try {
			// ストリームオープン
			URL url = new URL(linkUrl);
			stream = url.openStream();
			reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
			
			// HTML読込み
			while (true) {
				String line = reader.readLine();
				if (line == null) {
					break;
				}
				builder.append(line);
			}
		} catch (Exception e) {
			throw new IllegalStateException(e);
		} finally {
			// BufferedReaderのクローズ
			if (reader != null) {
				try {
					reader.close();					
				} catch (IOException e) {
					e.printStackTrace();
				}				
			}
			
			// 入力ストリームのクローズ
			if (stream != null) {
				try {
					stream.close();					
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
		// 取得したHTMLの出力
		JSObject div = (JSObject)document.call("getElementById", new Object[] {"nonTransitionLinkTarget"});
		div.setMember("innerHTML", builder.toString());
	}
}

ベタにtry〜catch処理を書いているので若干煩雑に感じるかもしれませんが、ほとんど汎用化できる部分ばっかりなので大した手間ではないでしょう。linkUrlを渡してbuilder.toString()を返すようなメソッドでも定義しとけばぐっと記述を簡略化できるはずです。ポイントは、URLオブジェクトを使ってアプレットの配信元のサーバと通信できることはもちろんそうなのですが、さりげに未熟な私はここで一回文字化けしました。

 reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));

くだんの

この記事には、当該個所は

 reader = new BufferedReader(new InputStreamReader(stream));

こう書いてあるのですが、きちんとリンク先のHTML(JSP)にあわせた文字コードを指定してあげる方が無難ぽいです。