matsukaz's blog

Agile, node.js, ruby, AWS, cocos2d-xなどなどいろいろやってます

JSPでページをテンプレート化

JSPでページをテンプレート化する方法として、の利用があります。Slim3: JSPでテンプレートを使う | 自転車で通勤しましょ♪ブログ で紹介されてる方法ですね。この方法を利用すれば、全体のレイアウトやヘッダー、フッターをテンプレート化することで、各ページはコンテンツ部分だけ作成すれば良い、という流れになります。
ただこの方法だとまずい問題が発生したので、今はを利用しています。ここではその問題と、どんな対応したかをご紹介。

Slim3の話ではないけど、Slim3のサンプルも問題のある書き方をしているので、タグは関連付けときます。

発生した問題

以下のようなlayout.jspを用意した場合、

<%@page pageEncoding="UTF-8" isELIgnored="false"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<title>${param.title}</title>
</head>
<body>
<jsp:include page="/layout/header.jsp"/>
<div id="main">
  ${param.content}
</div>
<jsp:include page="/layout/footer.jsp"/>
</body>
</html>

それを利用するindex.jspは以下のようになります。

<%@page pageEncoding="UTF-8" contentType="text/html" isELIgnored="false"%>
<jsp:include page="/layout/layout.jsp">
  <jsp:param name="title" value="Index"/>
  <jsp:param name="content">
    <jsp:attribute name="value">
      <p>Hello Index</p>
    </jsp:attribute>
  </jsp:param>
</jsp:include>

layout.jspに渡すデータは

  • のvalue属性
  • の子要素の要素のボディ部

のいずれかに記述します。

これだけなら正しく動作するんですが、問題になったのは内で「&」を利用するケース。例えば、

<%@page pageEncoding="UTF-8" contentType="text/html" isELIgnored="false"%>
<jsp:include page="/layout/layout.jsp">
  <jsp:param name="title" value="Index"/>
  <jsp:param name="content">
    <jsp:attribute name="value">
      Please <a href="http://hogehoge?param1=value1&param2=value2">Sign in</a>
    </jsp:attribute>
  </jsp:param>
</jsp:include>

とか書くと、&が正しく処理できないらしくて

Please <a href="http://hogehoge?param1=value1

と出力されてしまいます。最初はGAEの問題かと思ったけど、通常のWebアプリでも発生したので、JavaEEコンテナのJSPのアクションタグの実装の問題?GAE上とTomcat6.0.26で確認できました。久しくJSPを触ってなかったけどこんな問題あったかな・・・。コンテンツを作り込むと「&」を使わないなんてことはないと思うので、かなり問題になるんじゃないかと。

解決策

JSTLを利用すればこの問題は起こらなかったです。上記を書き直すと、layout.jsp

<%@page pageEncoding="UTF-8" isELIgnored="false"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<title>${param.title}</title>
</head>
<body>
<c:import url="/layout/header.jsp"/>
<div id="main">
  ${param.content}
</div>
<c:import url="/layout/footer.jsp"/>
</body>
</html>

となって、それを利用するindex.jspは以下のようになります。

<%@page pageEncoding="UTF-8" contentType="text/html" isELIgnored="false"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:import url="/layout/layout.jsp">
  <c:param name="title" value="Index"/>
  <c:param name="content">
    Please <a href="http://hogehoge?param1=value1&param2=value2">Sign in</a>
  </c:param>
</c:import>

layout.jspに渡すデータは

  • のvalue属性
  • のボディ部

のいずれかに記述します。

これなら「&」も問題なく出力されます。