Au travail, j'ai été chargé de transformer une série de fichiers HTML
en un simple projet JSP
. C'est vraiment tout statique, pas de logique serveur à programmer. Je devrais mentionner que je suis complètement nouveau en Java. Les fichiers JSP semblent faciliter le travail avec des inclusions et des variables communes, un peu comme PHP
, mais j'aimerais connaître un moyen simple d'obtenir quelque chose comme l'héritage de modèle (style Django
) ou au moins de pouvoir avoir une base.jsp fichier 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: Héritage du modèle JSP Quelqu'un peut-il expliquer comment y parvenir?
Etant donné que je dispose de peu de temps, je pense que le routage dynamique est un peu trop, alors je suis heureux de simplement mapper les URL directement sur les fichiers .jsp
, mais je suis ouvert à toute suggestion.
Merci.
edit: Je ne souhaite utiliser aucune bibliothèque externe, car cela augmenterait la courbe d'apprentissage pour moi-même et les autres personnes travaillant sur le projet, et l'entreprise pour laquelle je travaille a été chargée de le faire.
Une autre édition: Je ne sais pas si JSP tags
sera utile car mon contenu ne contient pas vraiment de variables de modèle. Ce dont j'ai besoin, c'est d'un moyen de pouvoir faire ceci:
base.html:
<html><body>
{ content.body }
</body></html>
somepage.html
<wrapper:base.html>
<h1>Welcome</h1>
</wrapper>
avec 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 includes
, mais il me faudrait alors un haut et un bas pour chaque enveloppe, ce qui est un peu désordonné.
Comme suggéré par skaffman , JSP 2.0 Les fichiers de balises 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 page example.jsp
:
<%@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.
Alors, développons cela pour 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 utiliser ceci:
<%@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 achète? Beaucoup vraiment, 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 utiliser ceci: (Supposons que nous avons 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 d'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 réside dans le fait qu’il vous permet de baliser le balisage générique, puis de le reformater au contenu qui vous convient.
JSP Tag Files
ont à peu près usurpé des choses comme Tiles
etc., 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 les fichiers de balise JSP pour d'autres tâches (comme le fragment de détail d'utilisateur ci-dessus).
Voici un exemple similaire à DisplayTag que j'ai déjà réalisé, mais tout cela est fait avec les fichiers de balises (et le framework Stripes
, c’est le s: tags ..). Cela se traduit par un tableau de lignes, de couleurs alternées, de navigation de 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="/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 balise est d'ajouter du code de scriptlet Java, mais cela ne représente pas une limitation aussi importante que vous pourriez le penser. Si j'ai besoin de scriptlet, je mets simplement la logique dans une balise et la laisse tomber. Facile.
Ainsi, les fichiers de balises peuvent être à peu près ce que vous voulez. Au niveau le plus élémentaire, c’est un simple refactoring couper/coller. une invocation de balise.
À un niveau supérieur, vous pouvez faire des choses sophistiquées comme cette balise de table que j'ai ici.
J'ai rendu assez facile, Django style bibliothèque de balises d'héritage de modèles JSP. https://github.com/kwon37xi/jsp-template-inheritance
Je pense qu'il est facile de gérer les mises en page sans courbe d'apprentissage.
exemple de code:
base.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>
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>
Sur la base de la même idée de base que dans la réponse de @Will Hartung , voici mon moteur de gabarit extensible magique à une étiquette. 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);
}
%>
Utilisez tiles . Cela m'a sauvé la vie.
Mais si vous ne pouvez pas, il y a la balise include , la rendant similaire à php.
La balise body ne fera peut-être pas ce dont vous avez besoin, à moins que vous n'ayez un contenu extrêmement simple. La balise body est utilisée pour définir le corps d'un élément spécifié. 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, tous les attributs que cet élément peut avoir ("lang" dans ce cas), puis le texte qui y figure - le corps. Donc si
content.headerName = h1
,content.lang = fr
, etcontent.body = Heading in French
Alors la sortie serait
<h1 lang="fr">Heading in French</h1>
add dependecys for use <% @ 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>
Je sais que cette réponse viendra des années après les faits et que Will Hartung a déjà répondu à une excellente question JSP, mais il y a Facelets, ils sont même mentionnés dans les réponses de la question liée à la question initiale.
Description de la balise Facelets SO
Facelets est une technologie d'affichage basée sur XML pour la structure 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 de Java-EE 6 et a rendu obsolète JSP. Presque toutes les bibliothèques de composants ciblées par JSF 2.0 ne prennent plus en charge JSP, mais uniquement Facelets.
Malheureusement, la meilleure description de tutoriel simple que j'ai trouvée était sur Wikipedia et non sur un site de tutoriel. En fait, la section décrivant templates correspond même à ce que la question initiale demandait.
En raison du fait que Java-EE 6 a obsolète JSP, je recommanderais d’utiliser Facelets, même s’il semble qu’il pourrait être plus nécessaire d’obtenir un gain minime voire nul par rapport à JSP.