2009-08-18 8 views
276

W pracy miałem za zadanie przekształcić kilka plików HTML w prosty projekt JSP. To naprawdę wszystko jest statyczne, bez logiki serwera do programowania. Powinienem wspomnieć, że jestem zupełnie nowy w Javie. Pliki JSP wydają się ułatwiać pracę z typowymi włączeniami i zmiennymi, podobnie jak PHP, ale chciałbym poznać prosty sposób na uzyskanie czegoś takiego jak dziedziczenie szablonów (styl Django) lub przynajmniej móc mieć plik base.jsp plik zawierający nagłówek i stopkę, więc mogę wstawić zawartość później.Sztuczki JSP ułatwiające tworzenie szablonów?

Ben Lings wydaje się oferować pewne nadzieje w jego odpowiedź tutaj: JSP template inheritance Może ktoś wyjaśnić jak to osiągnąć?

Biorąc pod uwagę, że nie mam zbyt wiele czasu, myślę, że dynamiczne wyznaczanie trasy to niewiele, więc cieszę się, że adresy URL są mapowane bezpośrednio na pliki .jsp, ale jestem otwarty na sugestie.

Dzięki.

edit: Nie chcę używać żadnych zewnętrznych bibliotek, ponieważ zwiększyłoby to krzywa uczenia się dla siebie i innych, którzy pracują nad projektem, a firma pracuję zostało zakontraktowane, aby to zrobić.

Kolejny edit: Nie jestem pewien, czy JSP tags będzie przydatna, ponieważ mój zawartość tak naprawdę nie ma żadnych zmiennych szablonu. Co potrzebne jest sposobem, aby móc to zrobić:

base.html:

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

somepage.html

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

z istoty wyjściowa:

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

myślę, że dałoby wystarczająca wszechstronność, aby zrobić wszystko, czego potrzebuję. Można to osiągnąć za pomocą includes, ale wtedy potrzebowałbym górnej i dolnej części dla każdej owijki, która jest trochę nieporządna.

Odpowiedz

628

Jak skaffman suggested, JSP 2.0 Tag Files są za kolana pszczoły.

Weźmy Twój prosty przykład.

umieścić następujące w WEB-INF/tags/wrapper.tag

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

Teraz na stronie example.jsp:

<%@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, że to robi.


Rozwińmy więc 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 to kupić ci? Wiele naprawdę, ale to staje się jeszcze lepszy ...


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 tego używać: (zakładamy, ż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 to sprawia, że ​​lubisz używać tego bloku szczegółów użytkownika w innych miejscach. Tak więc, będziemy go refaktoryzować. 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 postać:

<%@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 Tag JSP jest to, że pozwala w zasadzie oznakować rodzajowy znaczników i wtedy byłaby to do syta.

JSP Tag Files w dużym stopniu uzurpowałeś sobie takie rzeczy jak itd., Przynajmniej dla mnie. Uważam, że są znacznie łatwiejsze w użyciu, ponieważ jedyną strukturą jest to, co dajesz, nic z góry nie z góry. Dodatkowo możesz użyć plików znaczników JSP do innych rzeczy (takich jak fragment szczegółów użytkownika powyżej).

Oto przykład, który jest podobny do DisplayTag, który zrobiłem, ale to wszystko jest zrobione z plikami znaczników (i ze strukturą Stripes, to s: tagi ..). Wynika to w tabeli wierszy, na przemian kolorami, strona nawigacji, etc:

<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 współpracować z JSTL tags (jak c:if, itd.). Jedyne, czego nie możesz zrobić w treści znacznika pliku, to dodać kod skryptu Java, ale to nie jest tak duże ograniczenie, jak mogłoby się wydawać. Jeśli potrzebuję skryptletów, po prostu umieszczam logikę w tagu i upuszczam tag. Łatwo.

Tak więc pliki znaczników mogą być dowolne. Na najbardziej podstawowym poziomie jest to proste refaktoryzowanie. Chwyć fragment układu, wytnij go, przeprowadź prostą parametryzację i zastąp go za pomocą wywołania znacznika.

Na wyższym poziomie możesz wykonywać zaawansowane funkcje, takie jak ten tag tabeli, który mam tutaj.

+32

Dzięki za to.To najlepszy samouczek, jaki udało mi się znaleźć w plikach znaczników JSP, które były świetne dla mnie z JSF. Chciałbym dać więcej niż jeden głos. – digitaljoel

+59

+ 40 milionów. Dziękuję za wyjaśnienie tego 50 000 razy lepiej niż jakikolwiek paskudny tutorial, który znalazłem. Pochodzę ze świata Railsów i brakuje ERB, to jest dokładnie to, czego potrzebuję. Powinieneś napisać blog. – cbmeeks

+2

Naprawdę ładny tutorial. Czy możesz podzielić się z nami kodem tagu tabeli, który zrobiłeś? Stworzyłem go jakiś czas temu, ale twoje podejście jest lepsze. –

3

Użyj tiles. Uratowało mi to życie.

Ale jeśli nie możesz, jest include tag, dzięki czemu jest podobny do php.

Znacznik body może nie być w rzeczywistości tym, czego potrzebujesz, chyba że masz super proste treści. Znacznik body służy do definiowania treści określonego elementu. Spójrz na this example:

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

podać nazwę elementu, wszelkie atrybuty tego elementu może mieć („lang” w tym przypadku), a następnie tekst, który idzie w nim - ciało.Więc jeśli

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

Następnie wyjście byłoby

<h1 lang="fr">Heading in French</h1> 
1

Trzeba mieć świadomość, że za pomocą JSP z dużą ilością <% ...%> na całym, ogólnie pokazał, aby tworzyć aplikacje, które są ha rd utrzymać (o niebanalnym rozmiarze).

W związku z tym należy już teraz przygotować się do nauki dodatkowej warstwy dla tego lub następnego projektu. Osobiście wybrałem JSF dla projektu, który pozwolił na czyste strony XML jsp wywołujące taglibs, co było dość przyjemne, ale miał stromą krzywą uczenia się, więc nie polecę go, chyba że rozważnie go najpierw :)

Niezależnie od jaką technologię wybierzesz, wybierz taką, która pozwala oddzielić prezentację od rzeczywistego kodu. Z pewnością docenisz to pewnego dnia.

+6

Jest to naprawdę ogromna luka między <% %> obejmuje, i JSF, i że luka jest pełne dziesiątki coraz bardziej złożone rozwiązania. – skaffman

+0

Tak. Jest to stroma krzywa uczenia się :( –

+5

Zauważyłem, że używanie "ulepszeń" JSP przez <%...%> powoduje, że aplikacje są jeszcze trudniejsze w utrzymaniu – Magnus

19

Zrobiłem dość łatwe, znacznik dziedziczenia szablonów JSP w stylu Django. https://github.com/kwon37xi/jsp-template-inheritance

Myślę, że to łatwe do zarządzania układami bez krzywej uczenia się.

przykładowy kod:

base.jsp: układ

<%@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: zawartość

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

Bazując na tej samej podstawowej idei, jak w odpowiedzi @Will Hartung „s, tutaj jest mój magiczny, rozszerzalny silnik szablonowy. To nawet zawiera dokumentację i przykładowe :-)

WEB-INF/tagów/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); 
    } 
%> 
Powiązane problemy