web-dev-qa-db-fra.com

Comment éviter d'utiliser des scriptlets dans ma page JSP?

On m'a dit que l'utilisation de scriptlets (<% = ...%>) dans mes pages JSP n'est pas une si bonne idée.

Quelqu'un avec un peu plus d'expérience Java/jsp peut-il me donner quelques conseils sur la façon de changer ce code afin qu'il soit plus "meilleure pratique", quel qu'il soit?

Ce JSP est en fait ma page décoratrice principale de Sitemesh. Fondamentalement, ma conception Web a une bande d'onglets et un sous-menu, et je souhaite en quelque sorte mettre en surbrillance l'onglet actuel et afficher le sous-menu correct en regardant l'URI de la demande actuelle.

<%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator" %>

<html>
<head>
  <title>My Events - <decorator:title /></title>
  <link href="<%= request.getContextPath() %>/assets/styles.css" rel="stylesheet" type="text/css" />
</head>
<body>

<div class="tabs">
  <a 
    <%= request.getRequestURI().contains("/events/") ? "class='selected'" : "" %>
    href='<%= request.getContextPath() %>/events/Listing.action'>Events</a>
  <a 
    <%= request.getRequestURI().contains("/people/") ? "class='selected'" : "" %>
    href='<%= request.getContextPath() %>/people/Listing.action'>People</a>
</div>

<div class="submenu">
  <% if(request.getRequestURI().contains("/events/")) { %>
    <a href="Listing.action">List of Events</a>
    |<a href="New.action">New Event</a>
  <% } %>
  <% if(request.getRequestURI().contains("/people/")) { %>
    <a href="Listing.action">List of People</a>
    |<a href="New.action">New Person</a>
  <% } %>  
  &nbsp;
</div>

<div class="body">
  <decorator:body />
</div>

</body>
</html>

Merci a tous

34
Chris

Je pense que cela aide plus si vous voyez de vos propres yeux que cela peut être fait entièrement sans scriptlets.

Voici une réécriture 1 sur 1 avec l'aide, entre autres JSTL (il suffit de laisser tomber jstl-1.2.jar dans /WEB-INF/lib) core et fonctions taglib:

<%@ taglib uri="http://Java.Sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://Java.Sun.com/jsp/jstl/functions" prefix="fn" %>

<html>
<head>
  <title>My Events - <decorator:title /></title>
  <link href="${pageContext.request.contextPath}/assets/styles.css" rel="stylesheet" type="text/css" />
</head>
<body>

<div class="tabs">
  <a 
    ${fn:contains(pageContext.request.requestURI, '/events/') ? 'class="selected"' : ''}
    href="${pageContext.request.contextPath}/events/Listing.action">Events</a>
  <a 
    ${fn:contains(pageContext.request.requestURI, '/people/') ? 'class="selected"' : ''}
    href="${pageContext.request.contextPath}/people/Listing.action">People</a>
</div>

<div class="submenu">
  <c:if test="${fn:contains(pageContext.request.requestURI, '/events/')}">
    <a href="Listing.action">List of Events</a>
    |<a href="New.action">New Event</a>
  </c:if>
  <c:if test="${fn:contains(pageContext.request.requestURI, '/people/')}">
    <a href="Listing.action">List of People</a>
    |<a href="New.action">New Person</a>
  </c:if>
  &nbsp;
</div>

Voici une réécriture plus optimisée, notez que j'ai utilisé c:set Pour "mettre en cache" les résultats d'expression à réutiliser et que j'utilise la balise HTML <base> Pour éviter de mettre le chemin du contexte dans chaque lien (il suffit de rendre tous les éléments relatifs URL de votre page Web par rapport à celle-ci - sans la barre oblique principale!):

<%@ taglib uri="http://Java.Sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://Java.Sun.com/jsp/jstl/functions" prefix="fn" %>

<c:set var="isEvents" value="${fn:contains(pageContext.request.requestURI, '/events/')}" />
<c:set var="isPeople" value="${fn:contains(pageContext.request.requestURI, '/people/')}" />

<html>
<head>
  <title>My Events - <decorator:title /></title>
  <base href="${pageContext.request.contextPath}">
  <link href="assets/styles.css" rel="stylesheet" type="text/css" />
</head>
<body>

<div class="tabs">
  <a ${isEvents ? 'class="selected"' : ''} href="events/Listing.action">Events</a>
  <a ${isPeople ? 'class="selected"' : ''} href="people/Listing.action">People</a>
</div>

<div class="submenu">
  <c:if test="${isEvents}">
    <a href="Listing.action">List of Events</a>|<a href="New.action">New Event</a>
  </c:if>
  <c:if test="${isPeople}">
    <a href="Listing.action">List of People</a>|<a href="New.action">New Person</a>
  </c:if>
  &nbsp;
</div>

Il peut en fait être optimisé davantage si vous collectez toutes ces valeurs "codées en dur" comme events et people et liez des textes dans un Map dans la portée de l'application et utilisez sous chaque JSTL <c:forEach> Pour afficher les onglets.

Quant à votre question réelle , vous pouvez désactiver scriptlets (et obtenir des erreurs d'exécution sur son utilisation) en ajoutant ce qui suit entrée dans web.xml de l'application Web. Il peut être utile de repérer des scriptlets supervisés.

<jsp-config>
    <jsp-property-group>
        <url-pattern>*.jsp</url-pattern>
        <scripting-invalid>true</scripting-invalid>
    </jsp-property-group>
</jsp-config>

Pour en savoir plus sur EL, consultez le Java EE tutorial part II chapter 5 . Les objets EL implicites, tels que ${pageContext} Sont décrits ici . Pour en savoir plus sur JSTL, consultez le Java EE tutorial part II chapter 7 . Notez que JSTL et EL sont deux choses distinctes. JSTL est un taglib standard et EL permet juste d'accéder aux données du backend par programmation. Bien qu'il soit normalement utilisé dans des balises comme JSTL, il peut également être utilisé de manière autonome dans le texte du modèle.

42
BalusC

En passant, <%= request.getContextPath() %> est-il une utilisation acceptable des scriptlets qui ne sont pas tellement mal vus?

C'est peut-être une opinion impopulaire, mais si vous ne faites que de simples conditionnelles et des insertions de texte, je ne trouve pas grand-chose à redire dans l'utilisation des scriptlets. (Notez le si)

J'utiliserais probablement JSTL et le langage d'expression, mais surtout parce qu'il peut être moins typé et que le support IDE peut être meilleur (mais un bon JSP IDE peut également trouver des crochets de fermeture manquants et des trucs comme ça).

Mais fondamentalement (comme dans "garder la logique hors des modèles"), je ne vois aucune différence entre

<% if(request.getRequestURI().contains("/events/")) { %>

et

${fn:contains(pageContext.request.requestURI, '/events/') 
9
Thilo

Les scriptlets ne sont pas la pire chose au monde. Une considération importante est de penser à qui va maintenir le code. Si ses concepteurs Web qui n'ont pas beaucoup d'expérience Java, il vaut probablement mieux utiliser des bibliothèques de balises. Cependant, si Java les développeurs font la maintenance) , il peut être plus facile pour eux d’utiliser des scriptlets.

Si vous finissez par utiliser une bibliothèque de balises et JSTL, vous vous attendez à ce que le responsable apprenne également la bibliothèque de balises et connaisse JSTL. Certains développeurs seront d'accord avec cela car c'est une compétence qu'ils veulent ou ont déjà, mais pour certains développeurs qui n'ont à traiter avec les JSP que tous les quelques mois, il peut être beaucoup moins pénible de travailler avec des scriptlets clairement écrits écrits à Nice. , Java familier.

6
Spike Williams

Ce n'est pas une réponse directe à votre question (et il y en a déjà plusieurs bonnes, donc je n'essaierai pas d'y ajouter), mais vous avez mentionné:

Quelqu'un avec un peu plus d'expérience Java/jsp peut-il me donner quelques conseils sur la façon de changer ce code pour sa plus "meilleure pratique", quelle qu'elle soit?

À mon avis, la meilleure pratique, en ce qui concerne JSP, est qu'il devrait être utilisé strictement comme un moteur de modélisation, et pas plus (c'est-à-dire, aucune logique métier là-dedans). L'utilisation de JSTL, comme beaucoup l'ont souligné, vous aide certainement à y arriver, mais même avec JSTL, il est facile de faire beaucoup dans une JSP.

Personnellement, j'aime suivre les règles énoncées dans Enforcing Strict Model-View Separation in Templating Engines par Terence Parr lors du développement dans JSP. L'article mentionne le but des modèles de moteur (séparation du modèle et de la vue) et les caractéristiques d'un bon moteur de modélisation. Il jette un bon coup d'œil à JSP et montre comment ce n'est pas un bon moteur de modélisation. Sans surprise, JSP est fondamentalement trop puissant et permet aux développeurs d'en faire trop. Je recommande fortement de lire cet article, et cela vous aidera à vous limiter aux "bonnes" parties de JSP.

Si vous ne lisez qu'une seule section de cet article, lisez le chapitre 7, qui comprend les règles suivantes:

  1. la vue ne peut pas modifier le modèle en modifiant directement les objets de données du modèle ou en appelant des méthodes sur le modèle qui provoquent des effets secondaires. Autrement dit, un modèle peut accéder aux données du modèle et appeler les méthodes, mais ces références doivent être sans effet secondaire. Cette règle se pose en partie parce que les références de données doivent être insensibles à l'ordre. Voir section 7.1.
  2. la vue ne peut pas effectuer de calculs sur des valeurs de données dépendantes car les calculs peuvent changer à l'avenir et ils doivent être soigneusement encapsulés dans le modèle dans tous les cas. Par exemple, la vue ne peut pas calculer les prix de vente des livres comme "prix $ * .90". Pour être indépendante du modèle, la vue ne peut pas faire d'hypothèses sur la signification des données.
  3. la vue ne peut pas comparer les valeurs de données dépendantes , mais peut tester les propriétés des données telles que la présence/absence ou la longueur d'une valeur de données à valeurs multiples. Des tests comme $ bloodPressure <120 doivent être déplacés vers le modèle car les médecins aiment continuer à réduire la pression systolique maximale sur nous. Les expressions dans la vue doivent être remplacées par un test de présence d'une valeur simulant un booléen tel que $ bloodPressureOk! = Null La sortie du modèle peut être conditionnée par les données et les calculs du modèle, le conditionnel doit simplement être calculé dans le modèle . Même les tests simples qui rendent les valeurs négatives rouges doivent être calculés dans le modèle; le bon niveau d'abstraction est généralement quelque chose de plus élevé, comme "le département x perd de l'argent".
  4. la vue ne peut pas faire d'hypothèses de type de données. Certaines hypothèses de type sont évidentes lorsque la vue suppose qu'une valeur de données est une date, par exemple, mais des hypothèses de type plus subtiles apparaît: Si un modèle suppose que $ userID est un entier, le programmeur ne peut pas changer cette valeur pour qu'elle soit non numérique dans le modèle sans casser le modèle. Cette règle interdit l'indexation de tableaux tels que colorCode [$ topic] et $ name [$ ID] La vue ne peut en outre pas appeler de méthodes avec des arguments car (statiquement ou dynamiquement) il existe un type d'argument supposé, à moins que l'on puisse garantir le modèle la méthode les traitait simplement comme des objets. En outre, les graphistes ne sont pas des programmeurs; il n'est pas réaliste de s'attendre à ce qu'ils invoquent des méthodes et sachent quoi passer.
  5. les données du modèle ne doivent pas contenir d'informations d'affichage ou de disposition. Le modèle ne peut transmettre aucune information d'affichage à la vue déguisée en valeurs de données. Cela inclut de ne pas transmettre le nom d'un modèle à appliquer à d'autres valeurs de données.

Soit dit en passant, Terence a créé son propre moteur de création de modèles appelé String Template qui fait censément un très bon travail d'application de ces règles. Je n'ai aucune expérience personnelle avec cela, mais j'aimerais le vérifier sur mon prochain projet.

6
Jack Leow

Vous pouvez commencer par utiliser des bibliothèques de balises. Vous pouvez utiliser la bibliothèque de balises standard JSTL pour faire la plupart des choses courantes pour lesquelles vous avez besoin de scriplets. Il existe de nombreuses autres bibliothèques de balises plus riches qui sont utilisées comme dans le cadre struts2 ou depuis Apache.

par exemple.

  <c:if test="${your condition}">
       Your Content
  </c:if>

remplacerait vos instructions if.

3
Vincent Ramdhanie

L'alternative préférée aux scriptlets est le langage d'expression JSTL; ici est un bon aperçu. Vous devrez ajouter le taglib comme ceci:

<%@ taglib uri='http://Java.Sun.com/jsp/jstl/core' prefix='c' %>

À titre d'exemple, JSTL fournit un tas d'objets implicites qui vous donnent ce dont vous avez besoin; celui que vous voulez est pageContext.request.

Vous pouvez donc remplacer <%request.getRequestURI%> avec ${pageContext.request.requestURI}.

Vous pouvez effectuer des conditions à l'aide de <c:if> Mots clés.

3
Jacob Mattison

Vous devrez utiliser un cadre Web. Ou au moins un taglib pratique. Ou un modèle comme FreeMarker .

Cadres publicitaires:

Si vous aimez le codage JSP, je vous suggère Struts 2.

<s:if test="%{false}">
    <div>Will Not Be Executed</div>
</s:if>
<s:elseif test="%{true}">
    <div>Will Be Executed</div>
</s:elseif>
<s:else>
    <div>Will Not Be Executed</div>
</s:else>

Ensuite, il y a les composants [~ # ~] jsf [~ # ~] .

Si vous aimez OOP et tout coder en Java, essayez Apache Wicket (mon préféré ) ou Google Web Toolkit .

2
Ondra Žižka