Avatar ·

Как избежать Java кода в JSP файлах при использовании JSP 2 (Servlet 2.4)?

Всем привет! Я начинающий Java-разработчик, и у меня возникла проблема с архитектурой моего веб-приложения. Я пишу простой интернет-магазин на Java EE, используя JSP для отображения страниц. Проблема в том, что мои JSP файлы превратились в "спагетти-код" из HTML и Java скриптлетов. Вот как выглядит мой типичный JSP файл для отображения списка товаров: ```jsp <%@ page import="java.util.List, com.myapp.Product" %>

Товары

<% List products = (List) request.getAttribute("products"); for (Product p : products) { %> <% } %>
<%= p.getName() %> <%= p.getPrice() %> Купить
``` Я слышал, что использование скриптлетов ( `<% %>` ) — это плохая практика, и в JSP 2 (Servlet 2.4) появились новые возможности, которые позволяют полностью отказаться от Java-кода в представлении. Но я не понимаю, как это сделать правильно. Подскажите, пожалуйста, как мне переписать этот пример, используя Expression Language (EL) и JSTL (JSP Standard Tag Library)? Нужен полный пример, включая сервлет и изменённый JSP. Заранее спасибо! <<>>

Правильный подход: разделение логики и представления

Вы совершенно правы, что скриптлеты в JSP — это устаревшая и вредная практика. Они смешивают бизнес-логику (Java) с представлением (HTML), что делает код нечитаемым, сложным в поддержке и тестировании. JSP 2 (Servlet 2.4) предлагает элегантное решение: Expression Language (EL) для доступа к данным и JSTL (JSP Standard Tag Library) для управления потоком (циклы, условия).

Вот как должен выглядеть ваш сервлет и JSP файл:

Шаг 1: Исправленный сервлет (Java)

Сервлет должен подготовить данные и передать их в JSP через атрибуты запроса. Никакой логики отображения в сервлете быть не должно.

package com.myapp.controller;

import com.myapp.Product;
import com.myapp.dao.ProductDAO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

@WebServlet("/products")
public class ProductListServlet extends HttpServlet {

    private ProductDAO productDAO = new ProductDAO(); // Допустим, у вас есть DAO

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        // 1. Получаем данные из модели (например, из базы данных)
        List<Product> allProducts = productDAO.getAllProducts();
        
        // 2. Помещаем данные в атрибут запроса
        request.setAttribute("products", allProducts);
        
        // 3. Перенаправляем запрос на JSP страницу
        request.getRequestDispatcher("/WEB-INF/jsp/product-list.jsp").forward(request, response);
    }
}

Шаг 2: JSP файл без скриптлетов (с использованием EL и JSTL)

Теперь ваш JSP файл будет содержать только HTML и теги JSTL. Для начала подключите библиотеки JSTL в начале файла (требуется добавить jstl.jar в проект).

<%@ 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>
    <title>Список товаров</title>
</head>
<body>
    <h1>Наши товары</h1>
    
    <table border="1">
        <tr>
            <th>Название</th>
            <th>Цена</th>
            <th>Действие</th>
        </tr>
        
        <!-- Цикл forEach вместо скриптлета -->
        <c:forEach items="${products}" var="product">
            <tr>
                <td><c:out value="${product.name}" /></td>
                <td>
                    <fmt:formatNumber value="${product.price}" type="currency" currencySymbol="₽" />
                </td>
                <td>
                    <a href="cart?add=${product.id}">Купить</a>
                </td>
            </tr>
        </c:forEach>
        
        <!-- Обработка пустого списка -->
        <c:if test="${empty products}">
            <tr><td colspan="3">Товаров пока нет.</td></tr>
        </c:if>
    </table>
</body>
</html>

Объяснение ключевых моментов:

  • Expression Language (EL): ${products} — это автоматический доступ к атрибуту запроса products. Вам не нужно явно вызывать request.getAttribute(). EL автоматически ищет атрибут в page, request, session и application scope.
  • : Заменяет классический Java-цикл for. Атрибут items указывает на коллекцию, var — на имя переменной для текущего элемента.
  • : Безопасный вывод данных. Он экранирует HTML-символы (например, < превращает в &lt;), предотвращая XSS-атаки. В вашем старом коде <%= p.getName() %> этого не делал.
  • и : Заменяют условные операторы Java (if, if-else).
  • : Позволяет форматировать числа, даты и валюты без Java-кода.

Главные преимущества такого подхода:

  1. Читаемость: JSP выглядит как HTML с вставками тегов, а не как перемешанный Java-код.
  2. Поддерживаемость: Дизайнер может править HTML, не боясь сломать Java-логику.
  3. Безопасность: EL и JSTL автоматически экранируют вывод (кроме случаев, когда вы используете ${...} в атрибутах href — там нужно быть осторожным).
  4. Тестируемость: Логика вынесена в сервлеты/контроллеры, которые легко тестировать без запуска веб-сервера.

Этот паттерн называется MVC (Model-View-Controller). Ваш сервлет — Controller, JSP — View, а Java-объекты (Product) — Model. Придерживайтесь его, и ваш код станет профессиональным.

<<>>

Альтернативный подход: Использование фреймворков (Spring MVC)

Хотя использование чистого JSP 2 с EL и JSTL — это огромный шаг вперёд по сравнению со скриптлетами, в современной Java-разработке принято использовать более мощные фреймворки, такие как Spring MVC или JSF.

Spring MVC предлагает ещё более чистый подход с помощью Thymeleaf или JSP + Spring Tag Library. Например, вместо JSTL вы можете использовать формы Spring MVC для автоматической валидации и биндинга данных. Вот как будет выглядеть ваш контроллер на Spring:

@Controller
public class ProductController {

    @Autowired
    private ProductService productService;

    @GetMapping("/products")
    public String listProducts(Model model) {
        List<Product> products = productService.getAll();
        model.addAttribute("products", products);
        return "product-list"; // Имя JSP без расширения
    }
}

А в JSP вы подключаете Spring-теги:

<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>

Преимущество Spring MVC в том, что он решает множество проблем "из коробки": валидация, интернационализация, управление транзакциями, безопасность (Spring Security). Если вы