319 votes

Des astuces JSP pour faciliter le templating ?

Au travail, j'ai été chargé de transformer un tas de HTML dans un simple JSP projet. C'est vraiment tout statique, pas de logique de serveur à programmer. Je dois préciser que je suis complètement novice en Java. Les fichiers JSP semblent faciliter le travail avec les inclusions et les variables communes, un peu comme les fichiers PHP mais j'aimerais connaître un moyen simple d'obtenir quelque chose comme l'héritage de modèles ( Django ) ou au moins pouvoir disposer d'un fichier base.jsp contenant l'en-tête et le pied de page, afin de pouvoir insérer du contenu ultérieurement.

Ben Lings semble offrir un certain espoir dans sa réponse ici : Héritage des modèles JSP Quelqu'un peut-il m'expliquer comment y parvenir ?

Etant donné que je n'ai pas beaucoup de temps, je pense que le routage dynamique est un peu excessif, donc je suis content que les URLs se connectent directement à l'adresse suivante .jsp mais je suis ouvert à toute suggestion.

Merci.

éditer : Je ne veux pas utiliser de bibliothèques externes, car cela augmenterait la courbe d'apprentissage pour moi et les autres personnes qui travaillent sur le projet, et la société pour laquelle je travaille a été engagée pour le faire.

Un autre montage : Je ne suis pas sûr que JSP tags sera utile car mon contenu n'a pas vraiment de variables de modèle. Ce dont j'ai besoin, c'est d'un moyen de pouvoir le faire :

base.html:

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

somepage.html

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

avec comme résultat :

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

Je pense que cela me donnerait assez de polyvalence pour faire tout ce dont j'ai besoin. Cela pourrait être réalisé avec includes mais alors j'aurais besoin d'un include supérieur et d'un include inférieur pour chaque wrapper, ce qui est un peu désordonné.

715voto

Will Hartung Points 57465

Comme skaffman a suggéré , Fichiers de balises JSP 2.0 sont les abeilles à genoux.

Prenons un exemple simple.

Mettez ce qui suit dans WEB-INF/tags/wrapper.tag

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

Maintenant, dans votre example.jsp page :

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

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

Cela fait exactement ce que vous pensez que cela fait.


Alors, élargissons le propos à quelque chose d'un peu plus général. 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>

Pour l'utiliser :

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

Qu'est-ce que ça vous rapporte ? Beaucoup de choses, mais il y a encore mieux...


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>

Pour l'utiliser : (supposons que nous ayons une variable utilisateur dans la requête)

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

Mais il s'avère que vous aimez utiliser ce bloc de détails de l'utilisateur à d'autres endroits. Donc, nous allons le remanier. 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/>

Maintenant, l'exemple précédent devient :

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

L'intérêt des fichiers de balises JSP est qu'ils vous permettent de baliser des balises génériques et de les remanier à votre guise.

JSP Tag Files ont plutôt usurpé des choses comme Tiles etc., du moins pour moi. Je les trouve beaucoup plus faciles à utiliser car la seule structure est celle que vous lui donnez, rien de préconçu. De plus, vous pouvez utiliser les fichiers de balises JSP pour d'autres choses (comme le fragment de détails sur l'utilisateur ci-dessus).

Voici un exemple similaire à celui de DisplayTag que j'ai réalisé, mais tout est fait avec les fichiers de balises (et la fonction Stripes c'est le cadre s : tags..). Il en résulte un tableau de lignes, des couleurs alternées, une navigation dans la page, 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="http://stackoverflow.com/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>

Bien sûr, les balises fonctionnent avec le JSTL tags (comme c:if etc.). La seule chose que vous ne pouvez pas faire dans le corps d'une balise de fichier est d'ajouter du code de scriptlet Java, mais ce n'est pas une limitation aussi importante que vous pourriez le penser. Si j'ai besoin d'un script, je mets simplement la logique dans une balise et j'insère la balise. C'est facile.

Ainsi, les fichiers de balises peuvent être à peu près ce que vous voulez qu'ils soient. Au niveau le plus élémentaire, il s'agit d'un simple copier-coller de refactoring. Prenez une partie de la mise en page, découpez-la, effectuez un paramétrage simple et remplacez-la par une invocation de balise.

À un niveau plus élevé, vous pouvez faire des choses sophistiquées comme cette balise de table que j'ai ici.

38 votes

Merci pour ceci. C'est le meilleur tutoriel que j'ai pu trouver sur les fichiers de balises JSP, qui m'ont été d'un grand secours en venant de JSF. J'aimerais pouvoir donner plus d'un vote positif.

68 votes

+40millions. Merci de l'avoir expliqué 50 000 fois mieux que tous les tutoriels merdiques que j'ai trouvés. Venant du monde de Rails et manquant ERB, c'est exactement ce dont j'ai besoin. Vous devriez écrire un blog.

3 votes

Très beau tutoriel. Pourriez-vous partager avec nous le code de la balise table que vous avez créée ? J'en ai créé une moi-même il y a quelque temps mais votre approche est meilleure.

21voto

KwonNam Points 111

J'ai fait une bibliothèque de balises d'héritage de modèles JSP assez facile, à la manière de Django. https://github.com/kwon37xi/jsp-template-inheritance

Je pense qu'il permet de gérer facilement les mises en page sans courbe d'apprentissage.

exemple de code :

base.jsp : mise en page

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

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

11voto

amichair Points 1149

Basé sur la même idée de base que dans @Will Hartung Voici mon moteur magique de modèles extensibles à une balise. Il comprend même une documentation et un exemple :-)

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);
    }
%>

5voto

geowa4 Points 17712

Utilisez tuiles . Cela m'a sauvé la vie.

Mais si vous ne pouvez pas, il y a le inclure l'étiquette ce qui le rend similaire à php.

La balise body peut ne pas faire ce dont vous avez besoin, à moins que votre contenu soit très simple. La balise body est utilisée pour définir le corps d'un élément spécifique. Jetez un coup d'œil à cet exemple :

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

Vous spécifiez le nom de l'élément, les attributs éventuels de cet élément ("lang" dans ce cas), puis le texte qu'il contient - le corps. Ainsi, si

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

La sortie serait alors

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

2voto

Vous devez savoir que l'utilisation de JSP avec beaucoup de <%...%> partout, a généralement montré pour créer des applications qui sont difficiles à maintenir (d'une taille non-triviale).

Vous devez donc vous préparer dès à présent à devoir apprendre une couche supplémentaire, que ce soit pour ce projet ou pour le suivant. Personnellement, j'ai choisi JSF pour un projet qui permettait des pages jsp purement XML invoquant des taglibs, ce qui était raisonnablement bien, mais avait une courbe d'apprentissage abrupte, donc je ne le recommanderai pas à moins que vous ne l'ayez d'abord considéré attentivement :)

Quelle que soit la technologie que vous choisissez, prenez-en une qui vous permette de séparer la présentation du code réel. Vous l'apprécierez un jour.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X