Прощай, спагетти-код: как вычистить Java из JSP раз и навсегда
Если вы когда-нибудь открывали старый JSP-файл и видели мешанину из HTML, <% %> скриптлетов и логики на Java, вы знаете это чувство. Смесь презентации и бизнес-логики превращает поддержку проекта в ад. Вопрос "How can I avoid Java code in JSP files, using JSP 2?" на Stack Overflow набрал тысячи просмотров — и не зря.
Хорошая новость: JSP 2 (Java Server Pages версии 2) дал нам инструменты, чтобы навсегда забыть о скриптлетах. В этой статье я покажу три реальных подхода, которые превратят ваши JSP в чистые, читаемые шаблоны. Никакой воды — только код и практика.
Почему скриптлеты — зло? Взгляд разработчика
Скриптлеты (эти самые <% ... %>) нарушают главный принцип MVC: разделение логики и представления. Вот три причины, почему от них нужно избавляться:
- Сложность поддержки. Когда в JSP есть SQL-запросы и условные операторы, дизайнер не может безопасно править верстку.
- Трудное тестирование. Логику внутри JSP невозможно протестировать unit-тестами.
- Плохая читаемость. Код превращается в "спагетти", где Java мешается с HTML.
JSP 2 предлагает элегантные альтернативы. Давайте разберем их на примере реальной задачи: вывод списка пользователей из базы данных.
Подход 1: Expression Language (EL) — ваш новый друг
Expression Language (EL) позволяет обращаться к Java-объектам прямо в JSP без единой строчки Java-кода. Синтаксис ${...} интуитивно понятен.
Было (с Java-кодом):
<%
User user = (User) request.getAttribute("user");
out.println("Привет, " + user.getName());
%>
Стало (с EL):
<p>Привет, ${user.name}</p>
EL автоматически вызывает геттеры. Если user.getName() возвращает строку — она подставится в HTML. Если объект равен null — EL просто ничего не выведет (без NullPointerException).
Где использовать: для вывода данных из request, session, application scope или параметров запроса.
Подход 2: JSTL (JSP Standard Tag Library) — циклы и условия без Java
JSTL — это набор готовых тегов, которые покрывают 90% типовых задач: циклы, условия, форматирование, работа с URL. Для подключения достаточно добавить зависимость в pom.xml (Maven) или скачать JAR.
Пример: выводим список пользователей в таблицу.
До (скриптлеты):
<table>
<%
List<User> users = (List<User>) request.getAttribute("users");
for (User u : users) {
%>
<tr><td><%= u.getName() %></td><td><%= u.getEmail() %></td></tr>
<%
}
%>
</table>
После (JSTL + EL):
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<table>
<c:forEach var="u" items="${users}">
<tr>
<td>${u.name}</td>
<td>${u.email}</td>
</tr>
</c:forEach>
</table>
Обратите внимание: ни одной строчки Java! Тег <c:forEach> работает как foreach-цикл, а ${u.name} — это EL-выражение. Код стал читаемым и безопасным.
Другие полезные теги JSTL:
<c:if test="${condition}">— условный вывод<c:choose>— аналог switch<c:set var="x" value="..." />— создание переменной<fmt:formatDate>— форматирование дат
Подход 3: Custom Tags (пользовательские теги) — для сложной логики
Если JSTL не хватает, можно создать собственный тег. Это мощный инструмент, когда нужно вынести повторяющуюся логику в отдельный компонент.
Пример: тег, который выводит "Hello, имя!" с проверкой на null.
Шаг 1. Создаем класс тега (Java):
package com.example.tags;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import javax.servlet.jsp.JspException;
import java.io.IOException;
public class HelloTag extends SimpleTagSupport {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public void doTag() throws JspException, IOException {
String output = (name != null) ? "Hello, " + name + "!" : "Hello, Guest!";
getJspContext().getOut().write(output);
}
}
Шаг 2. Описываем тег в TLD-файле (например, /WEB-INF/tags.tld):
<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
version="2.1">
<tlib-version>1.0</tlib-version>
<short-name>mytags</short-name>
<tag>
<name>hello</name>
<tag-class>com.example.tags.HelloTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>name</name>
<required>false</required>
</attribute>
</tag>
</taglib>
Шаг 3. Используем в JSP:
<%@ taglib uri="/WEB-INF/tags.tld" prefix="mytags" %>
<p><mytags:hello name="${user.name}" /></p>
Результат: в JSP нет Java, вся логика — в отдельном классе. Это идеальный пример соблюдения