Astuces JSP pour faciliter les modèles?

305

Au travail, j'ai été chargé de transformer un tas de HTMLfichiers en un JSPprojet simple . C'est vraiment tout statique, aucune logique côté serveur à programmer. Je dois mentionner que je suis complètement nouveau pour Java. Les fichiers JSP semblent faciliter le travail avec des inclusions et des variables communes, tout comme PHP, mais j'aimerais connaître un moyen simple d'obtenir quelque chose comme l'héritage de modèle ( Djangostyle) ou au moins pouvoir avoir un fichier base.jsp contenant l'en-tête et le pied de page, afin que je puisse insérer du contenu plus tard.

Ben Lings semble offrir un peu d'espoir dans sa réponse ici: Héritage du modèle JSP Quelqu'un peut-il expliquer comment y parvenir?

Étant donné que je n'ai pas beaucoup de temps, je pense que le routage dynamique est un peu trop, donc je suis heureux de simplement avoir des URL mappées directement sur des .jspfichiers, mais je suis ouvert à toute suggestion.

Merci.

edit: Je ne veux pas utiliser de bibliothèques externes, car cela augmenterait la courbe d'apprentissage pour moi-même et les autres personnes qui travaillent sur le projet, et l'entreprise pour laquelle je travaille a été chargée de le faire.

Une autre modification: je ne sais pas si JSP tagscela 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 le faire:

base.html:

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

somepage.html

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

la sortie étant:

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

Je pense que cela me donnerait suffisamment de polyvalence pour faire tout ce dont j'ai besoin. Cela pourrait être réalisé avec includesmais j'aurais besoin d'un haut et d'un bas pour chaque emballage, ce qui est un peu désordonné.

Scott
la source

Réponses:

682

Comme l'a suggéré skaffman , les fichiers de balises JSP 2.0 sont les genoux de l'abeille.

Prenons votre 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.jsppage:

<%@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 qu'il fait.


Donc, élargissons cela à 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 cela vous rapporte? Beaucoup, mais ça va 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 avons une variable utilisateur dans la demande)

<%@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 utilisateur à d'autres endroits. Donc, nous allons le refactoriser. 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>

La beauté des fichiers JSP Tag est qu'ils vous permettent essentiellement de baliser un balisage générique, puis de le refactoriser selon le contenu de votre cœur.

JSP Tag Filesont à peu près usurpé des choses comme Tilesetc., du moins pour moi. Je les trouve beaucoup plus faciles à utiliser car la seule structure est ce que vous lui donnez, rien de préconçu. De plus, vous pouvez utiliser des fichiers de balises JSP pour d'autres choses (comme le fragment de détails utilisateur ci-dessus).

Voici un exemple similaire à DisplayTag que j'ai fait, mais tout cela est fait avec des fichiers de balises (et le Stripescadre, c'est le s: tags ..). Il en résulte un tableau de lignes, des couleurs alternées, la navigation dans les pages, 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>

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 de balises est d'ajouter du code de scriptlet Java, mais ce n'est pas autant une limitation que vous pourriez le penser. Si j'ai besoin de trucs de scriptlet, je viens de mettre la logique dans une balise et de la déposer. Facile.

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

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

Will Hartung
la source
34
Merci pour cela. C'est le meilleur tutoriel que j'ai pu trouver sur les fichiers de balises JSP, qui étaient super pour moi venant de JSF. J'aimerais pouvoir donner plus d'un vote positif.
digitaljoel
66
+ 40 millions. Merci de l'expliquer 50 000 fois mieux que n'importe quel tutoriel merdique que j'ai trouvé. Venant du monde Rails et manquant ERB, c'est exactement ce dont j'ai besoin. Vous devriez écrire un blog.
cbmeeks le
2
Tutoriel vraiment sympa. Pourriez-vous partager avec nous le code de la balise de table que vous avez créée? J'en ai créé un moi-même il y a quelque temps mais votre approche est meilleure.
Thiago Duarte
4
Si vous créez une balise de fichier de balises, le contenu de cette balise dans le fichier JSP ne peut pas avoir de code de scriptlet: <t: mytag> pas de code de scriptlet ici </ t: mytag>. Mais dans le fichier de balises implémentant la balise elle-même, cela peut avoir tout le code de scriptlet que vous voulez, comme n'importe quel JSP.
Will Hartung
4
Remarque - il semble que l'ordre des balises soit important; L'attribut jsp: doit précéder jsp: body, sinon vous obtiendrez une erreur. J'ai également dû définir une balise @attribute correspondante pour correspondre à jsp: invoke pour éviter une autre erreur. Utilisation de GlassFish 3.2.2
Ryan
21

J'ai créé une bibliothèque de balises d'héritage de modèle JSP assez simple. https://github.com/kwon37xi/jsp-template-inheritance

Je pense que cela facilite la gestion des 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>
KwonNam
la source
10

Basé sur la même idée de base que dans la réponse de @Will Hartung , voici mon moteur de modèle extensible à une balise magique. Il comprend même de la 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);
    }
%>
amichair
la source
4

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

Mais si vous ne le pouvez pas, il y a la balise include , ce qui la rend similaire à php.

La balise body pourrait ne pas faire ce dont vous avez besoin, sauf si vous avez un contenu super simple. La balise body est utilisée pour définir le corps d'un élément spécifié. Jetez un œ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, tous les attributs que l'élément pourrait avoir ("lang" dans ce cas), puis le texte qui y est contenu - le corps. Donc si

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

Ensuite, la sortie serait

<h1 lang="fr">Heading in French</h1>
geowa4
la source
0

ajouter des dépendances à utiliser <% @ tag description = "Modèle de page utilisateur" 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>
Juan Silupú Maza
la source
-1

Je sais que cette réponse vient des années après le fait et il y a déjà une excellente réponse JSP par Will Hartung, mais il y a des Facelets, ils sont même mentionnés dans les réponses de la question liée dans la question d'origine.

Description de la balise SO des facettes

Facelets est une technologie de vue basée sur XML pour le framework JavaServer Faces. Conçu spécifiquement pour JSF, Facelets se veut une alternative plus simple et plus puissante aux vues basées sur JSP. Initialement un projet distinct, la technologie a été normalisée dans le cadre de JSF 2.0 et Java-EE 6 et a abandonné JSP. Presque toutes les bibliothèques de composants ciblés JSF 2.0 ne prennent plus en charge JSP, mais seulement les Facelets.

Malheureusement, la meilleure description de tutoriel simple que j'ai trouvée était sur Wikipédia et non sur un site de tutoriel. En fait, la section décrivant les modèles va même dans le sens de ce que la question initiale demandait.

En raison du fait que Java-EE 6 a rendu JSP obsolète, je recommanderais d'utiliser Facelets malgré le fait qu'il semble qu'il pourrait y en avoir plus pour peu ou pas de gain sur JSP.

Fering
la source
Java EE 6 n'a pas déprécié JSP, juste déprécié en utilisant JSP comme technologie d'affichage pour JSF.
Ryan
@Ryan Étant donné que dans ce cas, les deux parlaient de la technologie de la vue, qu'y a-t-il de mal à dire qu'elle l'a dépréciée?
Fering
La question n'a rien à voir avec JSF. Il s'agit de JSP pur. Votre réponse est d'utiliser Facelets, qui est pour JSF.
Ryan