Java Server Pages (JSP) Оглавление Java Server Pages (JSP) ......................................................................................................................................... 1 Что такое JSP? ..............................................................................................................................................1 Пример JSP-страницы ..................................................................................................................................2 Типичный сценарий использования JSP ....................................................................................................4 Язык выражений (Expression Language) .....................................................................................................4 Предопределённые (predefined) теги и директивы JSP ............................................................................5 JSP Standard Tag Library (JSTL) ...................................................................................................................5 Библиотека тегов Core (избранное) ................................................................................................. 6 Библиотека тегов Fmt (избранное) ................................................................................................... 6 Функции (одна в качестве примера) ................................................................................................. 6 Custom Tag Libraries ......................................................................................................................................7 Что можно ещё почитать про JSP и JSTL ...................................................................................................7 Что такое JSP? Основная проблема сервлетов состоит в том, что их невозможно нормально использовать для web-разработки, как все привыкли со времён появления PHP, а может быть и ещё раньше. Что происходило в PHP? Брался уже почти готовый статический HTML документ, в него добавлялись вставки кода на PHP с помощью специальных тегов: <html> <head/> <body><h1><% some code here %></h1></body> </html> PHP предоставляет так же возможность включать содержимое одного PHP файла внутрь другого, и тем самым достигается некоторое повторное использование элементов страницы. Что в этом подходе хорошо – это то, что мы видим HTML-страницу практически в том виде, в котором она будет отдана браузеру. Что не хорошо – это то, что внутри PHP страницы можно написать произвольный код, и это приведёт к смешению визуализации (view) и логики приложения (business-logic). Через некоторое время это поняли, но дисциплину обрели не многие :) Сервлеты сами по себе не предоставляют возможность верстать неких шаблон страницы, который будет превращаться в итоговую HTML-страницу и заполняться при исполнении кода на сервере. Поэтому над сервлетами сделали надстройку, которую назвали JSP. JSP используется как view. Или другими словами, в JSP сосредоточена верстка документа и его отображение. JSP по сути дела практически полностью функционально аналогичен PHP. Разница в том, что написание кода производится не с помощью вставок непосредственно Javaкода (хотя и это возможно), а с помощью использования специальных JSP-тегов. После того, как JSP-страница оказывается в web-контейнере, специальный компилятор превращает её в сервлет. Этот сервлет распечатывает статическое содержимое страницы и исполняет код, который реализует JSP-теги. Сам сгенернированный в runtime сервлет нам не интересен, его класс появляется гдето в недрах контейнера, и нам он не понадобится. Пример JSP-страницы <%@ page language="java" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ include file="/WEB-INF/jsp/includes/loginhdr.jsp" %> <form action='<c:url value="/auth" />' method="POST" > <div align="center"> <c:if test="${invalidLoginOrPassword}"> <table width="30%"> <tr> <th colspan="2">Access Denied</th> </tr> <tr> <td align="right"> <img alt="Access denied" src='<c:url value="/images/lock.png"/>' /> </td> <td>Login or password invalid. Try again please.</td> </tr> </table> <br/> </c:if> <table width="30%"> <tr> <th colspan="2">Sign in</th> </tr> <tr> <td>Login:</td> <td><input type="text" name="__login"/></td> </tr> <tr> <td>Password:</td> <td><input type="password" name="__pass"/></td> </tr> <tr> <td colspan="2"><input type="submit" value="Enter"/></td> </tr> </table> </div> </form> <%@ include file="/WEB-INF/jsp/includes/footer.jsp" %> Небольшие пояснения. Серым выделены директивы JSP. Как правило используются три директивы: page (для задания таких параметров, как кодировка файла и content type, который будет возвращаться браузеру), taglib (подключение библиотеки тегов) и include (включение содержимого других файлов в текст JSP) Синим выделены теги JSP. В остальном мы видим обычный документ HTML, но специальные теги JSP позволяют генерировать на сервере динамическое содержимое. В этом примере сообщение «Access Denied» будет выдано браузеру только в том случае, если выставлен флаг invalidLoginOrPassword. Это достигается с помощью тега <c:if>, суть которого состоит в том, что его внутреннее содержимое интерпретируется и включается в ответ сервера только в том случае, если выражение атрибута test является истинным. Тег <c:url> предназначен в первую очередь для того, чтобы дописывать root context приложения в начало URL. Например, если корневым контекстом приложения является /hello, то такая конструкция <a href='<c:url value="/someAction"/>' >ссылка</a> превратится в <a href='/hello/someAction' >ссылка</a> Это очень удобно, т.к. JSP-страница не обязана знать, какой корневой контекст использует приложение. Зелёным выделены конструкции языка выражений (Expression Language). Об этом языке будет сказано ниже, но нужен он исключительно для того, чтобы извлекать данные из контекста страницы и передавать эти данные тегам для дальнейшей интерпретации. Выражения EL могут быть как просто строками, так и достаточно сложными конструкциями, которые записываются внутри такого вот маркера ${ }. EL позволяет извлекать данные из коллекций, массивов, автоматически конвертировать типы данных и т.п. Рекомендуется также выносить всю информацию о стилях элементов из JSP в CSS. Это уменьшает размер JSP и упрощает модификацию. Типичный сценарий использования JSP Пример того, как со всем этим взлететь будет следующим шагом, а пока приведём примерный сценарий использования JSP: 1. Браузер отправляет GET/POST запрос на определённый URL, обрабатываемый web-контейнером 2. Web-контейнер находит приложение и сервлет-диспетчер, который обрабатывает этот URL и передаёт ему управление 3. Сервлет-диспетчер передаёт управление нужному классу приложения, который извлекает данные из СУБД и кладёт их в контекст запроса или сессию. После чего переадресует дальнейшее управление сервлету, сгенерированному по JSP странице. 4. JSP-сервлет извлекает подготовлены данные, и встраивает их определённым образом в шаблон HTML-документа. HTML-документ возвращается браузеру. Язык выражений (Expression Language) Язык выражений нужен для того, чтобы манипулировать данными при их отображении в JSP. EL -- это язык с динамической типизацией, что позволяет добиться компактности. EL лучше всего подходит для работы с объектами, придерживающихся нотации JavaBean. Результат вызова метода getSomething() для объекта obj выполняется в языке выражений так: obj.something. Естественно, что можно пойти дальше и записывать следующие конструкции: obj.something.justAnotherSomething Что будет эквивалентно следующему вызову: obj.getSomething().getJustAnotherSomething() Все подобные конструкции нужно записывать внутри специального маркера ${ }, внутри которого могут быть также операторы, вызовы JSP-функций и т.п. Например: ${obj.something.justAnotherSomething eq 'hello'} Здесь мы сравниваем значение со строкой "hello". Обычные операторы типа >, <, +, -, *, / тоже работают. Для некоторых есть собственные аналоги в JSP: Оператор JSP Аналог в Java a eq b a.equals(b) (значения null корректно учитываются) a lt b a < b либо a.compareTo(b)<0 в зависимости от типа объектов a gt b a > b либо a.compareTo(b)>0 в зависимости от типа объектов le, ge Нестрогие неравенства (<=, >=) или конструкции с compareTo в зависимости от типа. and, or, not &&, ||, ! empty a Проверка a на null, на пустую строку, пустой массив, пустую коллекцию. Со списками, массивами в основном работают через <c:forEach>, но тем не менее есть специальные конструкции для извлечения данных из коллекций: Оператор [ ] используется как для доступа к элементам массива, так и для списков (List) и отображений (Map). Например: ${obj.arrayValue[0]+obj.arrayValue[1]} ${obj.mapValue["price"]+obj.mapValue["tax"]} Что будет соответственно эквивалентно следующим выражениям на Java: obj.getArrayValue()[0]+obj.getArrayValue()[1] obj.getMapValue().get("price")+obj.getMapValue().get("tax") Исчерпывающие сведения о языке выражений можно почерпнуть тут (я намеренно даю ссылку на Java2 EE 1.4, т.к. там проще изложение, хотя и не покрыты кое-какие новые фичи): http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JSPIntro.html#wp100465 На первых этапах приведённых сведений будет более чем достаточно. Предопределённые (predefined) теги и директивы JSP Почитать можно тут: http://java.sun.com/products/jsp/tags/tags.html Хотя маловероятно, что понадобится что-то кроме следующего: Настройка параметров ответа сервера (директива page). Подключение библиотеки тегов (директива taglib) Включение содержимого файла внутрь JSP на этапе компиляции (директива include) Директивы-комментарии в JSP: Открытый вариант (попадает в ответ сервера) Закрытый вариант (не попадает в ответ сервера) JSP Standard Tag Library (JSTL) Набор встроенных тегов JSP сам по себе крайне убог, но есть что-то типа стандартной библиотеки тегов, которую можно легко добавить в проект. Она так и называется JSTL. Полная документация по тегам JSTL (по крайней мере версии 1.1, которую я нашел достаточно легко) доступна тут (на самом деле это модифицированный JavaDoc): http://java.sun.com/products/jsp/jstl/1.1/docs/tlddocs/index.html А пока мы разберем только самое востребованное и приведём примеры. Итак, JSTL состоит из нескольких независимых библиотек: core, fmt, functions, xml, sql. На практике, JSTL используется не полностью, а используются практически только две библиотеки тегов – core и fmt и библиотека functions. Работа с XML и SQL в частях проекта, отвечающих за визуализацию редко оправдана, поэтому библиотеки тегов xml и sql не используются в реальной жизни. Поэтому важно знать что предлагают только часто используемые библиотеки. Библиотека тегов Core (избранное) Библиотека Core предоставляет базовые теги для управления процессом генерации страницы. <c:out> – печать значения выражения с HTML-эскейпингом или без него. <c:forEach> – тело тега выполняется для каждого значения из коллекции <c:if> – тело тега выполняется если выражение истинно - более продвинутая версия <c:if>. Может иметь несколько условий (<c:when>) как в switch и секцию <c:otherwise> <c:choose> – фактический аналог оператора присваивания. Устанавливает значение переменной или атрибута через вызов setter-метода. <c:set> <c:url> – <c:param> – Генерация URL с проставленными параметрами Библиотека тегов Fmt (избранное) Библиотека Fmt предоставляет теги для форматированного вывода и разбора чисел, дат, печати сообщений с учётом локали, установленной в браузере пользователя. – <fmt:param> – Вывод локализованного сообщения идентификатором и с подстановкой параметров в сообщение. <fmt:message> <fmt:formatNumber> <fmt:formatDate> с указанным – Форматированный вывод чисел. – Форматированный вывод даты и времени Функции (одна в качестве примера) Функции в JSP появились не сразу и связано это было с тем, что не всё покрывалось возможностями языка выражений. В частности, не было возможности узнать размер коллекции, т.к. метод List.size() не удовлетворял требованиям JavaBean и не мог быть вызван с помощью оператора '.' языка выражений. И тогда появились функции. Подробнее о них можно почитать тут: http://java.sun.com/javaee/5/docs/tutorial/doc/bnalg.html Из стандартных функций я использовал только функцию определения длины (хотя, вероятно, в библиотеке функций можно найти что-нибудь полезное): <c:choose> <c:when test="${fn:length(users) > limit}"> ... </c:when> <c:otherwise> Too may users! </c:otherwise> </c:choose> Длину она определяет практически у всего. У строки, у коллекции, у массива... Custom Tag Libraries Вообще говоря, можно написать свою библиотеку тегов. Это делают достаточно редко, т.к. как правило, используют стандартные библиотеки, либо библиотеки, идущие в комплекте с какими-то фреймворками. Единственное, что нужно знать – это то, что библиотека тегов, по большому счёту, представляет собой набор классов, реализующих интерфейс Tag http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/jsp/tagext/Tag.html И специальный компилятором. дескриптор (TLD-файл), по всей видимости, используемый Детали о библиотеках тегов можно почерпнуть здесь: http://java.sun.com/products/jsp/tutorial/TagLibrariesTOC.html но скорее всего это можно сделать при необходимости. Что можно ещё почитать про JSP и JSTL 1. JSTL Quick Reference (см. в директории с документацией) 2. JSP в JavaEE Tutorial http://java.sun.com/javaee/5/docs/tutorial/doc/bnagy.html 3. JSTL в JavaEE Tutorial http://java.sun.com/javaee/5/docs/tutorial/doc/bnakc.html 4. Вот вроде бы неплохой такой туториал по сервлетам и JSP: http://courses.coreservlets.com/Course-Materials/csajsp2.html 5. Полная спецификация JSTL (JSR-52), нужно выбрать ссылку для разработчиков, а не для тех, кто будет реализовывать спецификацию (есть в директории с документацией): http://jcp.org/aboutJava/communityprocess/mrel/jsr052/index2.html 6. Я изучал JSP по книге Сью Шпильман, но сейчас её хрен найдёшь (только на английском) и она достаточно старая: http://www.ozon.ru/context/detail/id/1826679/ 7. Может быть хорошая книга (Брюс У. Перри “Java сервлеты и JSP. Сборник рецептов”): http://www.ozon.ru/context/detail/id/4434287/