Question Comment éviter le code Java dans les fichiers JSP?


Je suis nouveau à Java EE et je sais que quelque chose comme les trois lignes suivantes

<%= x+1 %>
<%= request.getParameter("name") %>
<%! counter++; %>

est une méthode de codage à l'ancienne et dans la version 2 de JSP il existe une méthode pour éviter le code Java dans les fichiers JSP. Quelqu'un peut-il me dire s'il vous plaît les lignes alternatives JSP 2, et ce que cette technique est appelée?


1522
2017-07-05 07:24


origine


Réponses:


L'utilisation de scriptlets (ceux <% %> choses) dans JSP est en effet fortement découragé depuis la naissance de taglibs (comme JSTL) et EL (Expression Language, ceux ${} choses) en 2001.

Les principaux inconvénients de scriptlets sont:

  1. Réutilisabilité: vous ne pouvez pas réutiliser les scriptlets.
  2. Remplaçabilité: vous ne pouvez pas rendre les scriptlets abstraits.
  3. OO-capacité: vous ne pouvez pas utiliser l'héritage / la composition.
  4. Débogage: Si le scriptlet lève une exception à mi-chemin, tout ce que vous obtenez est une page blanche.
  5. Testabilité: les scriptlets ne sont pas testables à l'unité.
  6. Maintenabilité par saldo il faut plus de temps pour maintenir une logique de code mêlée / encombrée / dupliquée.

Soleil Oracle lui-même recommande également dans le Conventions de codage JSP pour éviter l'utilisation de scriptlets chaque fois que la même fonctionnalité est possible avec des classes (tag). Voici plusieurs cités de pertinence:

A partir de la spécification JSP 1.2, il est fortement recommandé d'utiliser la bibliothèque JST Standard Tag Library (JSTL) dans votre application Web pour réduire le besoin de scriptlets JSP dans vos pages. Les pages qui utilisent JSTL sont, en général, plus faciles à lire et à maintenir.

...

Lorsque c'est possible, éviter les scriptlets JSP chaque fois que les bibliothèques de balises fournissent des fonctionnalités équivalentes. Cela facilite la lecture et la maintenance des pages, aide à séparer la logique métier de la logique de présentation et rendra vos pages plus faciles à évoluer vers des pages de style JSP 2.0 (la spécification JSP 2.0 prend en charge mais désaccentue l'utilisation de scriptlets).

...

Dans l'esprit d'adopter le modèle de conception MVC (Model-View-Controller) pour réduire le couplage entre le niveau de présentation et la logique métier, Les scriptlets JSP ne doivent pas être utilisés pour l'écriture de la logique métier. Au lieu de cela, les scriptlets JSP sont utilisés si nécessaire pour transformer les données (également appelées "objets de valeur") renvoyées à partir du traitement des requêtes du client dans un format adapté au client. Même alors, cela serait mieux fait avec une servlet de contrôleur frontal ou une étiquette personnalisée.


Comment remplacer scriptlets dépend entièrement du seul but du code / de la logique. Plus souvent, ce code doit être placé dans une classe Java complète:

  • Si vous voulez invoquer le même Code Java sur chaque demande, moins ou plus, quelle que soit la page demandée, par ex. vérifier si un utilisateur est connecté, puis implémenter un filtre et écrire le code en conséquence doFilter() méthode. Par exemple.:

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        if (((HttpServletRequest) request).getSession().getAttribute("user") == null) {
            ((HttpServletResponse) response).sendRedirect("login"); // Not logged in, redirect to login page.
        } else {
            chain.doFilter(request, response); // Logged in, just continue request.
        }
    }
    

    Lorsque mappé sur un approprié <url-pattern>couvrant les pages JSP d'intérêt, vous n'avez pas besoin de copier le même morceau de code sur toutes les pages JSP.


  • Si vous voulez appeler du code Java pré-traitement une requête, par ex. préchargement d'une liste d'une base de données à afficher dans une table, si nécessaire en fonction de certains paramètres de requête, puis mettre en œuvre un servlet et écrire le code en conséquence doGet() méthode. Par exemple.:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            List<Product> products = productService.list(); // Obtain all products.
            request.setAttribute("products", products); // Store products in request scope.
            request.getRequestDispatcher("/WEB-INF/products.jsp").forward(request, response); // Forward to JSP page to display them in a HTML table.
        } catch (SQLException e) {
            throw new ServletException("Retrieving products failed!", e);
        }
    }
    

    Cette façon de traiter les exceptions est plus facile. La base de données n'est pas accessible au milieu du rendu JSP, mais bien avant que la JSP ne soit affichée. Vous avez toujours la possibilité de modifier la réponse chaque fois que l'accès à la base de données génère une exception. Dans l'exemple ci-dessus, la page d'erreur par défaut 500 s'affichera, que vous pouvez personnaliser de toute façon par un <error-page> dans web.xml.


  • Si vous voulez appeler du code Java post-traitement une requête, par ex. traiter un formulaire de soumission, puis mettre en œuvre un servlet et écrire le code en conséquence doPost() méthode. Par exemple.:

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        User user = userService.find(username, password);
    
        if (user != null) {
            request.getSession().setAttribute("user", user); // Login user.
            response.sendRedirect("home"); // Redirect to home page.
        } else {
            request.setAttribute("message", "Unknown username/password. Please retry."); // Store error message in request scope.
            request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response); // Forward to JSP page to redisplay login form with error.
        }
    }
    

    Cette manière de traiter différentes destinations de pages de résultats est plus facile: réafficher le formulaire avec des erreurs de validation en cas d'erreur (dans cet exemple particulier, vous pouvez le réafficher en utilisant ${message} dans EL), ou tout simplement en prenant la page cible souhaitée en cas de succès.


  • Si vous voulez appeler du code Java contrôle le plan d'exécution et / ou la destination de la demande et de la réponse, puis mettre en œuvre un servlet selon le Le modèle de contrôleur frontal de MVC. Par exemple.:

    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            Action action = ActionFactory.getAction(request);
            String view = action.execute(request, response);
    
            if (view.equals(request.getPathInfo().substring(1)) {
                request.getRequestDispatcher("/WEB-INF/" + view + ".jsp").forward(request, response);
            } else {
                response.sendRedirect(view);
            }
        } catch (Exception e) {
            throw new ServletException("Executing action failed.", e);
        }
    }
    

    Ou simplement adopter un cadre MVC comme JSF, Spring MVC, Guichet, etc, de sorte que vous finissez avec juste une page JSP / Facelets et une classe Javabean sans avoir besoin d'une servlet personnalisée.


  • Si vous voulez appeler du code Java contrôler le flux à l'intérieur d'une page JSP, alors vous devez saisir un taglib de contrôle de flux (existant) comme Noyau JSTL. Par exemple. affichage List<Product> dans une table:

    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    ...
    <table>
        <c:forEach items="${products}" var="product">
            <tr>
                <td>${product.name}</td>
                <td>${product.description}</td>
                <td>${product.price}</td>
            </tr>
        </c:forEach>
    </table>
    

    Avec des balises de style XML qui s'intègrent parfaitement à tout ce HTML, le code est plus lisible (et donc plus facile à maintenir) qu'un tas de scriptlets avec différentes accolades d'ouverture et de fermeture ("Où diable cette cale de fermeture appartient-elle?"). Une aide facile est de configurer votre application web pour lancer une exception à chaque fois scriptlets sont encore utilisés en ajoutant la pièce suivante à web.xml:

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

    Dans Facelets, le successeur de JSP, qui fait partie du framework MVC fourni par Java EE JSF, c'est déjà ne pas possible d'utiliser scriptlets. De cette façon, vous êtes automatiquement obligé de faire les choses "dans le bon sens".


  • Si vous voulez appeler du code Java accès et affichage données "backend" dans une page JSP, alors vous devez utiliser EL (Expression Language), ceux ${} des choses. Par exemple. redisplaying les valeurs d'entrée soumises:

    <input type="text" name="foo" value="${param.foo}" />
    

    le ${param.foo} affiche le résultat de request.getParameter("foo").


  • Si vous voulez en appeler utilitaire Code Java directement dans la page JSP (généralement public static méthodes), vous devez les définir comme des fonctions EL. Il y a une norme fonctions taglib en JSTL, mais vous pouvez également créer facilement des fonctions. Voici un exemple comment JSTL fn:escapeXml est utile pour prévenir XSS  attaques.

    <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
    ...
    <input type="text" name="foo" value="${fn:escapeXml(param.foo)}" />
    

    Notez que la sensibilité XSS n'est en aucun cas spécifiquement liée à Java / JSP / JSTL / EL / quoi que ce soit, ce problème doit être pris en compte dans chaqueapplication Web que vous développez. Le problème de scriptlets est qu'il ne fournit aucun moyen de prévention intégrée, du moins en utilisant l'API Java standard. Le successeur de JSP Facelets a déjà un échappement HTML implicite, donc vous n'avez pas besoin de vous inquiéter des trous XSS dans Facelets.

Voir également:


1852
2017-07-05 14:19



En tant que sauvegarde: Désactiver les scriptlets pour le bien

Comme une autre question discute, vous pouvez et devez toujours désactiver les scriptlets dans votre web.xml descripteur d'application Web.

Je ferais toujours cela afin d'empêcher tout développeur d'ajouter des scriptlets, en particulier dans les grandes entreprises où vous perdrez la vue d'ensemble tôt ou tard. le web.xml les paramètres ressemblent à ceci:

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

207
2017-08-14 21:59



JSTL propose des tags pour les conditionnels, les boucles, les sets, les get, etc. Par exemple:

<c:if test="${someAttribute == 'something'}">
   ...
</c:if>

JSTL fonctionne avec les attributs de requête - ils sont le plus souvent définis dans la requête par une servlet, qui avant à la JSP.


102
2017-07-05 07:28



Je ne suis pas sûr si je comprends bien.

Vous devriez lire quelque chose à propos de MVC. Spring MVC & Struts 2 sont les deux solutions les plus courantes.


56
2017-07-05 07:29



Vous pouvez utiliser des balises JSTL avec des expressions EL pour éviter le mélange de code Java et HTML:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<html>
    <head>
    </head>
    <body>

        <c:out value="${x + 1}" />
        <c:out value="${param.name}" />
    // and so on

    </body>
</html>

48
2017-07-05 08:45



Il existe également des cadres basés sur des composants tels que Guichet cela génère beaucoup de HTML pour vous. Les balises qui se retrouvent dans le code HTML sont extrêmement basiques et il n'y a virtuellement aucune logique qui se mélange. Le résultat est presque vide - comme les pages HTML avec des éléments HTML typiques. L'inconvénient est qu'il y a beaucoup de composants dans le Guichet API à apprendre et certaines choses peuvent être difficiles à réaliser sous ces contraintes.


32
2018-03-22 18:24



Dans le canevas MVC Architectural, les JSP représentent la couche View. L'incorporation de code java dans les JSP est considérée comme une mauvaise pratique. Vous pouvez utiliser JSTL, freeMarker, rapidité avec JSP comme "moteur de template". Le fournisseur de données à ces balises dépend de cadres que vous traitez. Struts 2 et webwork en tant que mise en œuvre pour MVC Pattern utilise OGNL "technique très intéressante pour exposer les propriétés des beans à JSP".


28
2018-02-04 10:41



L'expérience a montré que les JSP présentent certaines lacunes, l'une d'entre elles étant difficile à éviter en combinant le balisage avec le code réel.

Si vous le pouvez, pensez à utiliser une technologie spécialisée pour ce que vous devez faire. En Java EE 6, il y a JSF 2.0, qui fournit beaucoup de fonctionnalités intéressantes, y compris le collage de Java beans avec des pages JSF à travers le #{bean.method(argument)} approche.


25
2017-07-05 08:30



Wicket est également une alternative qui sépare complètement java de html, de sorte qu'un concepteur et un programmeur peuvent travailler ensemble et sur différents ensembles de code avec peu de compréhension les uns des autres.

Regardez Wicket.


23
2018-05-20 20:42



Si vous voulez simplement éviter les inconvénients du codage Java dans JSP, vous pouvez le faire même avec des scriplets. Il suffit de suivre une certaine discipline pour avoir un minimum de Java dans JSP et presque pas de calcul et de logique dans la page JSP.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%//instantiate a JSP controller
MyController clr = new MyController(request, response);

//process action if any
clr.process(request);

//process page forwaring if necessary

//do all variable assignment here
String showMe = clr.getShowMe();%>

<html>
    <head>
    </head>
    <body>
        <form name="frm1">
            <p><%= showMe %>
            <p><% for(String str : clr.listOfStrings()) { %>
            <p><%= str %><% } %>

            // and so on   
        </form>
    </body>
</html>

23
2018-05-11 16:45