Sztuczki JSP ułatwiające tworzenie szablonów?

W pracy miałem za zadanie zamienić kilka HTML plików w prosty JSP Projekt. To naprawdę wszystko statyczne, bez logiki serwera do programowania. Powinienem wspomnieć, że jestem zupełnie nowy w Javie. Pliki JSP wydają się ułatwiać pracę ze wspólnymi includes i zmiennymi, podobnie jak PHP, ale chciałbym znać prosty sposób na uzyskanie czegoś takiego jak dziedziczenie szablonów (stylDjango) lub przynajmniej mieć bazę.plik JSP zawierający nagłówek i stopkę, dzięki czemu mogę wstawić zawartość później.

Ben Lings wydaje się dawać nadzieję w swojej odpowiedzi tutaj: dziedziczenie szablonów JSP Czy ktoś może wyjaśnić jak to osiągnąć?

Biorąc pod uwagę, że nie mam dużo czasu, myślę, że dynamiczne routing to trochę za dużo, więc cieszę się, że mam mapowanie adresów URL bezpośrednio na plikach .jsp, ale jestem otwarty na sugestie.

Dzięki.

Edit: nie chcę używać żadnych zewnętrznych bibliotek, ponieważ zwiększyłoby to uczenie się curve dla mnie i innych, którzy pracują nad projektem, a firma, dla której pracuję, została do tego zatrudniona.

Kolejna edycja: nie jestem pewien, czy JSP tags będzie przydatna, ponieważ moja treść tak naprawdę nie ma żadnych Zmiennych Szablonu. To, czego potrzebuję, to sposób, aby móc to zrobić: {]}

base.html:

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

somepage.html

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

Z wyjściem:

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

Myślę, że to da mi wystarczającą wszechstronność, aby zrobić wszystko, czego potrzebuję. Można to osiągnąć z includes ale wtedy potrzebowałbym góry i dołu do każdego opakowania, co jest trochę niechlujne.

Author: Community, 2009-08-19

4 answers

Jako skaffman zasugerował, pliki znaczników JSP 2.0 są kolanami pszczół.

Weźmy Twój prosty przykład.

Wpisz w WEB-INF/tags/wrapper.tag

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

Teraz w Twojej example.jsp stronie:

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

<t:wrapper>
    <h1>Welcome</h1>
</t:wrapper>
To robi dokładnie to, co myślisz.

Więc rozszerzmy to na coś bardziej ogólnego. 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>

Aby użyć tego:

<%@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>
Co ci to da? Naprawdę dużo, ale staje się nawet lepiej...

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>

Aby użyć tego: (Załóżmy, że mamy zmienną użytkownika w żądaniu)

<%@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>

Ale okazuje się, że lubisz używać tego bloku szczegółów użytkownika w innych miejscach. Więc zmienimy to. 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/>

Teraz poprzedni przykład staje się:

<%@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>

Piękno plików znaczników JSP polega na tym, że pozwala on zasadniczo oznaczać ogólne znaczniki, a następnie zmieniać je na zawartość serca.

JSP Tag Files uzurpowali sobie rzeczy typu Tiles itp. przynajmniej dla mnie. Uważam, że są znacznie łatwiejsze w użyciu, ponieważ jedyna struktura jest taka, jaką mu podajesz, nic z góry założonego. Dodatkowo możesz używać plików znaczników JSP do innych rzeczy(jak powyższy fragment szczegółów użytkownika).

Oto przykład podobny do DisplayTag, który zrobiłem, ale wszystko odbywa się z plikami znaczników (i frameworkiem Stripes, czyli znacznikami s:..). W rezultacie powstaje tabela wierszy, przemiennych kolorów, nawigacji strony itp.]}

<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>

Oczywiście tagi działają z JSTL tags (Jak c:if, itp.). Jedyną rzeczą, której nie możesz zrobić w treści znacznika pliku tagu, jest dodanie kodu Java scriptlet, ale nie jest to tak duże ograniczenie, jak mogłoby się wydawać. Jeśli potrzebuję scriptleta, po prostu wkładam logikę do znacznika i upuszczam znacznik. Spokojnie.

tak więc pliki znaczników mogą być praktycznie tym, czym chcesz, aby były. Na najbardziej podstawowym poziomie, to proste cięcie i wklejanie refaktoryzacji. Chwyć kawałek układu, wytnij go, wykonaj prostą parametryzację, i zastąp go wywołaniem znacznika.

Na wyższym poziomie, możesz robić wyrafinowane rzeczy, takie jak ten znacznik tabeli, który mam tutaj.

 649
Author: Will Hartung,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:07

Zrobiłem całkiem prostą bibliotekę znaczników dziedziczenia szablonów JSP w stylu Django. https://github.com/kwon37xi/jsp-template-inheritance

Myślę, że ułatwia zarządzanie layoutami bez uczenia się krzywej.

Przykładowy kod:

Baza.jsp: layout

<%@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>

Widok.jsp: spis treści

<%@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
Author: KwonNam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-13 17:57:33

Bazując na tej samej podstawowej idei, co w odpowiedzi @Will Hartung, Oto Mój magiczny silnik szablonów z jednym znacznikiem. Zawiera nawet dokumentację i przykład: -)

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);
    }
%>
 8
Author: amichair,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:29

Użyj płytek . To uratowało mi życie.

Ale jeśli nie możesz, jest include tag, co czyni go podobnym do php.

Body tag może nie robić tego, czego potrzebujesz, chyba że masz bardzo prostą treść. Znacznik body jest używany do definiowania ciała określonego elementu. Spójrz na ten przykład :

<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>

Podajesz nazwę elementu, wszelkie atrybuty, które element może mieć (w tym przypadku" lang"), a następnie tekst, który się w nim znajduje-- ciało. Więc jeśli

  • content.headerName = h1,
  • content.lang = fr, oraz
  • content.body = Heading in French

Wtedy wyjście będzie

<h1 lang="fr">Heading in French</h1>
 4
Author: geowa4,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-20 12:28:10