web-dev-qa-db-ja.com

テンプレート作成を簡単にするJSPのトリック

仕事では、HTMLファイルの束を単純なJSPプロジェクトに変える作業をしました。実際にはすべて静的で、プログラムするサーバーサイドロジックはありません。私はJavaを初めて使用することに言及する必要があります。 JSPファイルはPHPによく似た一般的なインクルードと変数を簡単に操作できるように見えますが、テンプレートの継承(Djangoスタイル)のようなものを取得する、または少なくともbase.jspを持つことができる簡単な方法を知りたいヘッダーとフッターを含むファイルなので、後でコンテンツを挿入できます。

Ben Lingsは、彼の答えにいくつかの希望を与えているようです: JSPテンプレート継承 誰かがこれを達成する方法を説明できますか?

あまり時間がないので、動的ルーティングは少し多いと思うので、URLを.jspファイルに直接マップするだけでいいのですが、提案は受け付けています。

ありがとう。

edit:外部ライブラリを使用したくありません。なぜなら、それは自分自身やプロジェクトに携わる他の人たちの学習曲線を増やし、私が働いている会社はこれを行うために契約されています。

別の編集:私のコンテンツにはテンプレート変数がないため、JSP tagsが役立つかどうかはわかりません。私が必要なのはこれを行うことができる方法です:

base.html:

<html><body>
{ content.body }
</body></html>

somepage.html

<wrapper:base.html>
<h1>Welcome</h1>
</wrapper>

出力は次のとおりです。

<html><body>
<h1>Welcome</h1>
</body></html>

これにより、必要なすべてを行うのに十分な汎用性が得られると思います。 includesで実現できますが、各ラッパーにトップインクルードとボトムインクルードが必要になりますが、これはちょっと面倒です。

297
Scott

スカッフマンの提案JSP 2.0タグファイルはミツバチの膝です。

簡単な例を見てみましょう。

以下をWEB-INF/tags/wrapper.tagに入れます

<%@tag description="Simple Wrapper Tag" pageEncoding="UTF-8"%>
<html><body>
  <jsp:doBody/>
</body></html>

これでexample.jspページで:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>

<t:wrapper>
    <h1>Welcome</h1>
</t:wrapper>

それはあなたが思うようになります。


それで、それをもう少し一般的なものに拡張しましょう。 WEB-INF/tags/genericpage.tag

<%@tag description="Overall Page template" pageEncoding="UTF-8"%>
<%@attribute name="header" fragment="true" %>
<%@attribute name="footer" fragment="true" %>
<html>
  <body>
    <div id="pageheader">
      <jsp:invoke fragment="header"/>
    </div>
    <div id="body">
      <jsp:doBody/>
    </div>
    <div id="pagefooter">
      <jsp:invoke fragment="footer"/>
    </div>
  </body>
</html>

これを使用するには:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>

<t:genericpage>
    <jsp:attribute name="header">
      <h1>Welcome</h1>
    </jsp:attribute>
    <jsp:attribute name="footer">
      <p id="copyright">Copyright 1927, Future Bits When There Be Bits Inc.</p>
    </jsp:attribute>
    <jsp:body>
        <p>Hi I'm the heart of the message</p>
    </jsp:body>
</t:genericpage>

それは何を買うのですか?本当にたくさんありますが、さらに良くなります...


WEB-INF/tags/userpage.tag

<%@tag description="User Page template" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>
<%@attribute name="userName" required="true"%>

<t:genericpage>
    <jsp:attribute name="header">
      <h1>Welcome ${userName}</h1>
    </jsp:attribute>
    <jsp:attribute name="footer">
      <p id="copyright">Copyright 1927, Future Bits When There Be Bits Inc.</p>
    </jsp:attribute>
    <jsp:body>
        <jsp:doBody/>
    </jsp:body>
</t:genericpage>

これを使用するには:(リクエストにユーザー変数があると仮定します)

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>

<t:userpage userName="${user.fullName}">
  <p>
    First Name: ${user.firstName} <br/>
    Last Name: ${user.lastName} <br/>
    Phone: ${user.phone}<br/>
  </p>
</t:userpage>

しかし、他の場所でそのユーザー詳細ブロックを使用することが好きになります。したがって、リファクタリングします。 WEB-INF/tags/userdetail.tag

<%@tag description="User Page template" pageEncoding="UTF-8"%>
<%@tag import="com.example.User" %>
<%@attribute name="user" required="true" type="com.example.User"%>

First Name: ${user.firstName} <br/>
Last Name: ${user.lastName} <br/>
Phone: ${user.phone}<br/>

これで、前の例は次のようになります。

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>

<t:userpage userName="${user.fullName}">
  <p>
    <t:userdetail user="${user}"/>
  </p>
</t:userpage>

JSPタグファイルの優れた点は、一般的なマークアップに基本的にタグを付けてから、思いのままにリファクタリングできることです。

少なくとも私にとっては、JSP Tag FilesTilesなどのようなものをほとんど奪っています。唯一の構造はあなたがそれを与えるものであり、何も先入観がないので、私はそれらを使うのがはるかに簡単だと思います。さらに、JSPタグファイルを他の目的(上記のユーザー詳細フラグメントなど)に使用できます。

ここに私がやったDisplayTagに似た例がありますが、これはすべてタグファイル(およびStripesフレームワーク、つまりs:タグ)で行われます。これにより、行のテーブル、交互の色、ページナビゲーションなどが生成されます。

<t:table items="${actionBean.customerList}" var="obj" css_class="display">
  <t:col css_class="checkboxcol">
    <s:checkbox name="customerIds" value="${obj.customerId}"
                onclick="handleCheckboxRangeSelection(this, event);"/>
  </t:col>
  <t:col name="customerId" title="ID"/>
  <t:col name="firstName" title="First Name"/>
  <t:col name="lastName" title="Last Name"/>
  <t:col>
    <s:link href="/Customer.action" event="preEdit">
      Edit
      <s:param name="customer.customerId" value="${obj.customerId}"/>
      <s:param name="page" value="${actionBean.page}"/>
    </s:link>
  </t:col>
</t:table>

もちろん、タグはJSTL tagsで機能します(c:ifなど)。タグファイルタグの本文内でできないことは、Javaスクリプトレットコードを追加することだけですが、これはあなたが考えているほどの制限ではありません。スクリプトレットのものが必要な場合は、ロジックをタグに入れて、タグをドロップするだけです。簡単です。

だから、タグファイルはあなたが望むものなら何でもかまいません。最も基本的なレベルでは、単純な切り取りと貼り付けのリファクタリングです。レイアウトのチャンクを取得し、それを切り取り、簡単なパラメーター化を行い、タグ呼び出しに置き換えます。

より高いレベルでは、ここにあるこのテーブルタグのような洗練されたことができます。

665
Will Hartung

DjangoスタイルのJSPテンプレート継承タグライブラリを作成しました。 https://github.com/kwon37xi/jsp-template-inheritance

学習曲線なしでレイアウトを簡単に管理できると思います。

サンプルコード:

base.jsp:レイアウト

<%@page contentType="text/html; charset=UTF-8" %>
<%@ taglib uri="http://kwonnam.pe.kr/jsp/template-inheritance" prefix="layout"%>
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>JSP Template Inheritance</title>
    </head>

<h1>Head</h1>
<div>
    <layout:block name="header">
        header
    </layout:block>
</div>

<h1>Contents</h1>
<div>
    <p>
    <layout:block name="contents">
        <h2>Contents will be placed under this h2</h2>
    </layout:block>
    </p>
</div>

<div class="footer">
    <hr />
    <a href="https://github.com/kwon37xi/jsp-template-inheritance">jsp template inheritance example</a>
</div>
</html>

view.jsp:コンテンツ

<%@page contentType="text/html; charset=UTF-8" %>
<%@ taglib uri="http://kwonnam.pe.kr/jsp/template-inheritance" prefix="layout"%>
<layout:extends name="base.jsp">
    <layout:put name="header" type="REPLACE">
        <h2>This is an example about layout management with JSP Template Inheritance</h2>
    </layout:put>
    <layout:put name="contents">
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin porta,
        augue ut ornare sagittis, diam libero facilisis augue, quis accumsan enim velit a mauris.
    </layout:put>
</layout:extends>
21
KwonNam

@ Will Hartung の答えと同じ基本的な考えに基づいて、ここに私の魔法の1タグ拡張可能なテンプレートエンジンを示します。ドキュメントと例さえ含まれています:-)

WEB-INF/tags/block.tag:

<%--
    The block tag implements a basic but useful extensible template system.

    A base template consists of a block tag without a 'template' attribute.
    The template body is specified in a standard jsp:body tag, which can
    contain EL, JSTL tags, nested block tags and other custom tags, but
    cannot contain scriptlets (scriptlets are allowed in the template file,
    but only outside of the body and attribute tags). Templates can be
    full-page templates, or smaller blocks of markup included within a page.

    The template is customizable by referencing named attributes within
    the body (via EL). Attribute values can then be set either as attributes
    of the block tag element itself (convenient for short values), or by
    using nested jsp:attribute elements (better for entire blocks of markup).

    Rendering a template block or extending it in a child template is then
    just a matter of invoking the block tag with the 'template' attribute set
    to the desired template name, and overriding template-specific attributes
    as necessary to customize it.

    Attribute values set when rendering a tag override those set in the template
    definition, which override those set in its parent template definition, etc.
    The attributes that are set in the base template are thus effectively used
    as defaults. Attributes that are not set anywhere are treated as empty.

    Internally, attributes are passed from child to parent via request-scope
    attributes, which are removed when rendering is complete.

    Here's a contrived example:

    ====== WEB-INF/tags/block.tag (the template engine tag)

    <the file you're looking at right now>

    ====== WEB-INF/templates/base.jsp (base template)

    <%@ page trimDirectiveWhitespaces="true" %>
    <%@ taglib prefix="t" tagdir="/WEB-INF/tags" %>
    <t:block>
        <jsp:attribute name="title">Template Page</jsp:attribute>
        <jsp:attribute name="style">
            .footer { font-size: smaller; color: #aaa; }
            .content { margin: 2em; color: #009; }
            ${moreStyle}
        </jsp:attribute>
        <jsp:attribute name="footer">
            <div class="footer">
                Powered by the block tag
            </div>
        </jsp:attribute>
        <jsp:body>
            <html>
                <head>
                    <title>${title}</title>
                    <style>
                        ${style}
                    </style>
                </head>
                <body>
                    <h1>${title}</h1>
                    <div class="content">
                        ${content}
                    </div>
                    ${footer}
                </body>
            </html>
        </jsp:body>
    </t:block>

    ====== WEB-INF/templates/history.jsp (child template)

    <%@ page trimDirectiveWhitespaces="true" %>
    <%@ taglib prefix="t" tagdir="/WEB-INF/tags" %>
    <t:block template="base" title="History Lesson">
        <jsp:attribute name="content" trim="false">
            <p>${shooter} shot first!</p>
        </jsp:attribute>
    </t:block>

    ====== history-1977.jsp (a page using child template)

    <%@ page trimDirectiveWhitespaces="true" %>
    <%@ taglib prefix="t" tagdir="/WEB-INF/tags" %>
    <t:block template="history" shooter="Han" />

    ====== history-1997.jsp (a page using child template)

    <%@ page trimDirectiveWhitespaces="true" %>
    <%@ taglib prefix="t" tagdir="/WEB-INF/tags" %>
    <t:block template="history" title="Revised History Lesson">
        <jsp:attribute name="moreStyle">.revised { font-style: italic; }</jsp:attribute>
        <jsp:attribute name="shooter"><span class="revised">Greedo</span></jsp:attribute>
    </t:block>

--%>

<%@ tag trimDirectiveWhitespaces="true" %>
<%@ tag import="Java.util.HashSet, Java.util.Map, Java.util.Map.Entry" %>
<%@ tag dynamic-attributes="dynattributes" %>
<%@ attribute name="template" %>
<%
    // get template name (adding default .jsp extension if it does not contain
    // any '.', and /WEB-INF/templates/ prefix if it does not start with a '/')
    String template = (String)jspContext.getAttribute("template");
    if (template != null) {
        if (!template.contains("."))
            template += ".jsp";
        if (!template.startsWith("/"))
            template = "/WEB-INF/templates/" + template;
    }
    // copy dynamic attributes into request scope so they can be accessed from included template page
    // (child is processed before parent template, so only set previously undefined attributes)
    Map<String, String> dynattributes = (Map<String, String>)jspContext.getAttribute("dynattributes");
    HashSet<String> addedAttributes = new HashSet<String>();
    for (Map.Entry<String, String> e : dynattributes.entrySet()) {
        if (jspContext.getAttribute(e.getKey(), PageContext.REQUEST_SCOPE) == null) {
            jspContext.setAttribute(e.getKey(), e.getValue(), PageContext.REQUEST_SCOPE);
            addedAttributes.add(e.getKey());
        }
    }
%>

<% if (template == null) { // this is the base template itself, so render it %>
    <jsp:doBody/>
<% } else { // this is a page using the template, so include the template instead %>
    <jsp:include page="<%= template %>" />
<% } %>

<%
    // clean up the added attributes to prevent side effect outside the current tag
    for (String key : addedAttributes) {
        jspContext.removeAttribute(key, PageContext.REQUEST_SCOPE);
    }
%>
9
amichair

tiles を使用します。それは私の命を救った。

しかし、できない場合は includeタグ があり、phpに似ています。

Bodyタグは、非常にシンプルなコンテンツがない限り、実際に必要なことをしない場合があります。 bodyタグは、指定された要素の本文を定義するために使用されます。 この例 を見てください:

<jsp:element name="${content.headerName}"   
   xmlns:jsp="http://Java.Sun.com/JSP/Page">    
   <jsp:attribute name="lang">${content.lang}</jsp:attribute>   
   <jsp:body>${content.body}</jsp:body> 
</jsp:element>

要素名、要素が持つ可能性のある属性(この場合は「lang」)、およびそこに入るテキスト(本文)を指定します。だから

  • content.headerName = h1
  • content.lang = fr、および
  • content.body = Heading in French

次に、出力は次のようになります

<h1 lang="fr">Heading in French</h1>
4
geowa4

使用するディペンデンシーを追加<%@ tag description = "ユーザーページテンプレート" pageEncoding = "UTF-8"%>

<dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2</version>
        <scope>provided</scope>
    </dependency>
        <dependency>
            <groupId>javax.servlet.jsp.jstl</groupId>
            <artifactId>javax.servlet.jsp.jstl-api</artifactId>
            <version>1.2.1</version>
        </dependency>
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
    </dependencies>
0

この回答は事実から数年後になっており、Will HartungによるすばらしいJSP回答がすでにあることは知っていますが、Faceletsがあり、元の質問のリンクされた質問の回答にも記載されています。

Facelets SOタグの説明

Faceletsは、JavaServer Facesフレームワーク用のXMLベースのビューテクノロジーです。 JSF専用に設計されたFaceletsは、JSPベースのビューに対するよりシンプルで強力な代替手段となることを目的としています。当初は別個のプロジェクトでしたが、この技術はJSF 2.0およびJava-EE 6の一部として標準化され、JSPが非推奨になりました。ほとんどすべてのJSF 2.0ターゲットコンポーネントライブラリは、JSPをサポートしていませんが、Faceletsのみをサポートしています。

悲しいことに、私が見つけた最高のわかりやすいチュートリアルの説明は、チュートリアルサイトではなく Wikipedia にありました。実際、 templates を説明するセクションは、元の質問が求めていたものの線に沿ってさえも行います。

Java-EE 6はJSPを非推奨にしているという事実により、JSPをほとんどまたはまったく得られない場合には、より多くの要件が必要になる可能性があるにもかかわらず、Faceletsを使用することをお勧めします。

0
Fering