Вопрос: Как избежать Java-кода в JSP-файлах?


Я новичок в Java EE, и я знаю, что что-то вроде следующих трех строк

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

является старым школьным способом кодирования, а в JSP версии 2 существует способ избежать Java-кода в JSP-файлах. Может кто-нибудь, пожалуйста, скажите мне альтернативные линии JSP 2 и что называется этой техникой?


1516


источник


Ответы:


Использование скриптлеты (те <% %>вещи) в JSP действительно сильно обескуражен с момента рождения библиотеки тегов (как JSTL ) а также EL ( Язык выражений , те ${}вещи) еще в 2001 году.

Основные недостатки скриптлеты находятся:

  1. Повторное использование: вы не можете повторно использовать скрипты.
  2. Заменяемость: вы не можете сделать абстрактные скриптлеты.
  3. OO-способность: вы не можете использовать наследование / состав.
  4. Debuggability: если скриптлет порождает исключение наполовину, все, что вы получаете, - это пустая страница.
  5. Тестируемость: скриптлеты не проверяются на единицу.
  6. Ремонтопригодность: для каждого сальдо требуется больше времени для поддержания смешанной / загроможденной / дублированной логики кода.

солнце Сам Oracle также рекомендует в Правила кодирования JSP во избежание использования скриптлеты всякий раз, когда одинаковые функциональные возможности могут выполняться классами (тегами). Вот несколько ссылок, релевантных:

Из спецификации JSP 1.2 рекомендуется, чтобы в вашем веб-приложении была использована Библиотека стандартных тегов JSP (JSTL), чтобы помочь уменьшить потребность в сценариях JSP на ваших страницах. Страницы, которые используют JSTL, в общем, легче читать и поддерживать.

...

Где возможно, избегать сценариев JSP когда библиотеки тегов предоставляют эквивалентную функциональность. Это упрощает чтение и обслуживание страниц, помогает отделить бизнес-логику от логики представления и облегчит перевод ваших страниц на страницы в стиле JSP 2.0 (спецификация JSP 2.0 поддерживает, но не позволяет использовать скриптлеты).

...

В духе принятия шаблона проектирования модели-представления (MVC) для уменьшения связи между уровнем представления из бизнес-логики, Нельзя использовать сценарии JSP для написания бизнес-логики. Скорее, сценарии сценариев JSP используются, если необходимо, для преобразования данных (также называемых «объектами значений»), возвращаемых при обработке запросов клиента в надлежащий готовый к клиенту формат. Даже тогда это было бы лучше сделать с сервлетом переднего контроллера или специальным тегом.


Как заменить скриптлеты полностью зависит от единственной цели кода / логики. Более часто этот код должен быть помещен в полноценный Java-класс:

  • Если вы хотите вызвать одна и та же Java-код на каждый запрос, меньше или больше, независимо от запрашиваемой страницы, например. проверяя, зарегистрирован ли пользователь, затем выполните фильтр и писать код соответственно в doFilter()метод. Например.:

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

    При сопоставлении с соответствующим <url-pattern>охватывая страницы JSP, представляющие интерес, тогда вам не нужно копировать одну и ту же часть кода на все страницы JSP.


  • Если вы хотите вызвать некоторый Java-код для предобработки запрос, например. предварительно загрузить некоторый список из базы данных для отображения в некоторой таблице, если необходимо, на основе некоторых параметров запроса, затем реализовать сервлет и писать код соответственно в doGet()метод. Например.:

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

    Этот способ справиться с исключениями проще. БД недоступен в середине рендеринга JSP, но намного раньше, чем отображается JSP. У вас все еще есть возможность изменять ответ, когда доступ к БД вызывает исключение. В приведенном выше примере будет отображаться страница с ошибкой по умолчанию 500, которую вы можете в любой момент настроить <error-page>в web.xml,


  • Если вы хотите вызвать некоторый Java-код для постобработки запрос, например. обрабатывать форму submit, а затем реализовать сервлет и писать код соответственно в doPost()метод. Например.:

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

    Этот способ работы с разными целевыми страницами результатов проще: повторное отображение формы с ошибками проверки в случае ошибки (в этом конкретном примере вы можете повторно отобразить ее, используя ${message}в EL ), либо просто перейдя на желаемую целевую страницу в случае успеха.


  • Если вы хотите вызвать некоторый Java-код для контроль плана выполнения и / или адресата запроса и ответа, а затем реализовать сервлет согласно Шаблон переднего контроллера MVC , Например.:

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

    Или просто примените структуру MVC, например JSF , Spring MVC , калитка , и т. д., чтобы вы получили только страницу JSP / Facelets и класс Javabean без необходимости использования специального сервлета.


  • Если вы хотите вызвать некоторый Java-код для контролировать поток внутри страницы JSP, тогда вам нужно захватить (существующий) теглиб управления потоком, например Ядро JSTL , Например. отображение List<Product>в таблице:

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

    С тегами XML-стиля, которые хорошо подходят для всего HTML, код лучше читается (и, следовательно, лучше обслуживается), чем куча скриптлетов с различными открывающимися и закрывающимися фигурными скобками ( «Где, черт возьми, эта закрывающая фигурная скобка?» ). Легкая помощь заключается в том, чтобы настроить веб-приложение для исключения исключений скриптлеты все еще используются, добавляя следующий фрагмент к web.xml:

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

    В Facelets , преемник JSP, который является частью Java EE, предоставляемой инфраструктурой MVC JSF , уже не возможно использовать скриптлеты , Таким образом, вы автоматически вынуждены делать что-то «правильно».


  • Если вы хотите вызвать некоторый Java-код для доступ и отображение «backend» на странице JSP, тогда вам нужно использовать EL (язык выражений), те ${}вещи. Например. повторное отображение представленных входных значений:

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

    ${param.foo}отображает результат request.getParameter("foo"),


  • Если вы хотите вызвать некоторые утилита Java-код непосредственно на странице JSP (обычно public staticметоды), то вам нужно определить их как функции EL. Есть стандартный функции taglib в JSTL, но вы также можете легко создавать функции самостоятельно , Вот пример того, как JSTL fn:escapeXmlполезно для предотвращения XSS нападки ,

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

    Обратите внимание, что чувствительность XSS никак не связана с Java / JSP / JSTL / EL / независимо от того, эта проблема должна быть учтена в каждый веб-приложение, которое вы разрабатываете. Проблема скриптлеты заключается в том, что он не предоставляет никаких встроенных предупреждений, по крайней мере, не использует стандартный Java API. Преемник JSP's Facelets уже неявный HTML-экранирование, поэтому вам не нужно беспокоиться о дырах XSS в Facelets.

Смотрите также:


1843



Как защитник: отключить скрипты для хорошего

В виде Другой вопрос обсуждает, вы можете и всегда должны отключать скрипты в вашем web.xmlдескриптор веб-приложения.

Я всегда делал это, чтобы любой разработчик не добавлял сценарии, особенно в крупных компаниях, где рано или поздно вы потеряете обзор. web.xmlнастройки выглядят следующим образом:

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

206



JSTL предлагает теги для условных выражений, циклов, наборов, наборов и т. д. Например:

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

JSTL работает с атрибутами запроса - они чаще всего задаются в запросе сервлетом, который вперед к JSP.


101



Я не уверен, правильно ли я это понял.

Вы должны прочитать что-то о MVC. Spring MVC & Struts 2 являются двумя наиболее распространенными решениями.


55



Вы можете использовать теги JSTL вместе с выражениями EL, чтобы избежать смешения Java и 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>

47



There are also component-based frameworks such as Wicket that generate a lot of the HTML for you. The tags that end up in the HTML are extremely basic and there is virtually no logic that gets mixed in. The result is almost empty-like HTML pages with typical HTML elements. The downside is that there are a lot of components in the Wicket API to learn and some things can be difficult to achieve under those constraints.


31



In the MVC Architectural pattern, JSPs represent the View layer. Embedding java code in JSPs is considered a bad practice. You can use JSTL, freeMarker, velocity with JSP as "template engine". The data provider to those tags depends on frameworks that you are dealing with. Struts 2 and webwork as an implementation for MVC Pattern uses OGNL "very interesting technique to expose Beans Properties to JSP ".


27



Experience has shown that JSP's have some shortcomings, one of them being hard to avoid mixing markup with actual code.

If you can, then consider using a specialized technology for what you need to do. In Java EE 6 there is JSF 2.0, which provides a lot of nice features including gluing Java beans together with JSF pages through the #{bean.method(argument)} approach.


24