Смотреть что такое "JSP" в других словарях. Синтаксис страницы JSP

Страницы JSP имеют комбинированный синтаксис: объединение стандартного синтаксиса, соответствующего спецификации HTML, и синтаксиса JSP, определенного спецификацией Java Server Pages. Синтаксис JSP определяет правила записи страниц JSP, состоящих из стандартных тегов HTML и тегов JSP.

Страницы JSP, кроме HTML-тегов, содержат теги JSP следующих категорий:

JSP директивы

JSP директивы обеспечивают глобальную информацию, касающихся конкретных запросов, направляемых в сервер, и предоставляют информацию, необходимую на стадии трансляции. Директивы всегда помещаются в начале JSP-страницы до всех остальных тегов, чтобы parser (анализатор) JSP при разборе текста в самом начале выделил глобальные инструкции. Таким, образом, JSP Engine (среда исполнения JSP), анализируя код, создает из JSP сервлет. Директивы представляют собой сообщения контейнеру JSP.

Синтаксис JSP директив выглядит следующим образом:

<%@ директива имяАтрибута="значение" %>

Синтаксис задания директив на XML:

JSP директива может иметь несколько атрибутов. В этом случае директива может быть повторена для каждого из атрибутов. В то же время пары "имяАтрибута=значение" могут располагаться под одной директивой с пробелом в качестве разделителя.

Существует три типа директив:

  • page (страница)
  • taglib (библиотека тегов)
  • include (включить)

JSP директива page

JSP директива page определяет свойства страницы JSP, которые воздействуют на транслятор. Порядок следования атрибутов в директиве page не имеет значения. Нарушение синтаксиса или наличие нераспознанных атрибутов приводит к ошибке трансляции. Примером директивы page может служить следующий код:

<%@ page buffer="none" isThreadSafe="yes" errorPage="/error.jsp" %>

Директива page объявляет, что данная страница JSP не использует буферизацию, что возможно одновременное обращение к данной странице JSP многих пользователей, и что поддерживается страница ошибок с именем error.jsp .

JSP директива page может содержать информацию о странице:

<%@ page info = "JSP Sample 1" %>

Список возможных атрибутов директивы page представлен в таблице.

Наименование атрибута Значение Описание
language Строка Определяет язык, используемый в скриптлетах файла JSP, выражениях или любых включаемых файлах, в том числе, в теле оттранслированного кода. По умолчанию принимается значение "java"
extends Строка Задает суперкласс для генерируемого сервлета. Этот атрибут следует использовать с большой осторожностью, поскольку возможно что сервер уже использует какой-нибудь суперкласс
import Строка Определение импортируемых пакетов., например:
<%@ page import="java.util.* %>
Session true или false Значение true (принимается по умолчанию) свидетельствует о том, что заранее определенная переменная session (тип HttpSession) должна быть привязана к существующей сессии, если таковая имеется, в противном случае создается новая сессия, к которой осуществляется привязка. Значение false определяет что сессии не будут использоваться, и попытки обращения к переменной session приведут к возникновению ошибки при трансляции JSP страницы в сервлет
Buffer none или размер буфера в кБ. Задает размер буфера для JspWriter out. Значение принимаемое по умолчанию зависит от настроек сервера, и не должно превышать 8 кБ. Если значение равно none вывод происходит непосредственно в объект ServletResponse
autoFlush true или false Определяет, должен ли буфер освобождаться автоматически, когда он переполнен или произошла ошибка. По умолчанию значение true
isThreadSafe true или false Значение true (принимается по умолчанию) задает нормальный режим выполнения сервлета, когда множественные запросы обрабатываются одновременно с использованием одного экземпляра сервлета, исходя из соображения, что автор синхронизировал доступ к переменным этого экземпляра. Значение false ("ложь") сигнализирует о том, что сервлет должен наследовать SingleThreadModel (однопоточную модель), при которой последовательные или одновременные запросы обрабатываются отдельными экземплярами сервлета
info Строка Определяет строку информации о странице JSP, которая будет доступна с помощью метода Servlet.getServletInfo ()
errorPage Строка Значение атрибута представляет собой URL страницу, которая должна выводиться в случае возможных ошибок, вызывающих исключения
isErrorPage true или false Сигнализирует о том, может ли эта страница использоваться для обработки ошибок для других JSP страниц. По умолчанию принимается значение false
contentType Строка Определяет кодировку для страницы JSP и ответа, а также MIME-тип ответа JSP. Значение по умолчанию типа содержания - text/html , кодировки - ISO-8859-1. Например:
contentType="text/html;charset=ISO-8859-1"
pageEncoding Строка Определяет кодировку символов страницы JSP. По умолчанию используется charset из атрибута contentType , если оно там определено. Если значение charset в атрибуте contentType не определено, значение pageEncoding устанавливается равным ISO-8859-1

JSP директива taglib

JSP директива taglib объявляет, что данная страница JSP использует библиотеку тегов, уникальным образом идентифицируя ее с помощью URI, и ставит в соответствие префикс тега, с помощью которого возможны действия в библиотеке. Если контейнер не может найти библиотеку тегов, возникает фатальная ошибка трансляции.

Директива taglib имеет следующий синтаксис:

<%@ taglib uri="URI включаемой библиотеки тегов " prefix="имяПрефикса " %>

Префикс "имяПрефикса " используется при обращении к библиотеке. Пример использования библиотеки тегов mytags :

<%@ taglib uri="http://www.taglib/mytags" prefix="customs" %> . . .

В данном примере библиотека тегов имеет URI-адрес "http://www.taglib/mytags" , в качестве префикса назначена строка customs , которая используется в странице JSP при обращении к элементам библиотеки тегов.

JSP директива include

JSP Директива include позволяет вставлять текст или код в процессе трансляции страницы JSP в сервлет. Синтаксис директивы include имеет следующий вид:

<%@ include file="Относительный URI включаемой страницы " %>

Директива include имеет один атрибут - file . Она включает текст специфицированного ресурса в файл JSP. Эту директиву можно использовать для размещения стандартного заголовка об авторских правах на каждой странице JSP:

<%@ include file="copyright.html" %>

Контейнер JSP получает доступ к включаемому файлу. Если включаемый файл изменился, контейнер может перекомпилировать страницу JSP. Директива include рассматривает ресурс, например, страницу JSP, как статический объект.

Заданный URI обычно интерпретируется относительно JSP страницы, на которой расположена ссылка, но, как и при использовании любых других относительных URI, можно задать системе положение интересующего ресурса относительно домашнего каталога WEB-сервера добавлением в начало URI символа "/". Содержимое подключаемого файла обрабатывается как обычный текст JSP и поэтому может включать такие элементы, как статический HTML, элементы скриптов, директивы и действия.

Многие сайты используют небольшую панель навигации на каждой странице. В связи с проблемами использования фреймов HTML часто эта задача решается размещением небольшой таблицы сверху или в левой половине страницы, HTML код которой многократно повторяется для каждой страницы сайта. Директива include - это наиболее естественный способ решения данной задачи, избавляющий разработчика от кошмара рутины копирования HTML в каждый отдельный файл.

Поскольку директива include подключает файлы в ходе трансляции страницы, то после внесения изменений в панель навигации требуется повторная трансляция всех использующих ее JSP страниц. Если же подключенные файлы меняются довольно часто, можно использовать действие jsp:include , которое подключает файл в процессе обращения к JSP странице.

JSP директива declarations

JSP директива declarations предназначены для определения переменных и методов на языке скриптов, которые в дальнейшем используются на странице JSP. Синтаксис declarations имеет следующий вид:

<%! код Java %>

declarations располагаются в блоке объявлений, а вызываются в блоке выражений страницы JSP. Код в блоке объявлений обычно пишется на языке Java, однако серверы приложений могут использовать синтаксис и других скриптов. Объявления иногда используются для того, чтобы добавить дополнительную функциональность при работе с динамическими данными, получаемыми из свойств компонентов JavaBeans. Примеры объявлений представлены в таблице.

Declarations может содержать несколько строк, как например, в приведенном ниже коде вычисления значения функции fact (int n) , которая должна быть равна 1 при n меньше 2 и n! при положительном значении n;

<%! public static int fact (int n) { if (n <= 1) return 1; else return n * fact (n - 1); } %>

declarations не производят никакого вывода в стандартный выходной поток out . Переменные и методы, декларированные в объявлениях, инициализируются и становятся доступными для скриптлетов и других объявлений в момент инициализации страницы JSP.

Скриптлеты scriptlets

scriptlets включают различные фрагменты кода, написанного на языке скрипта, определенного в директиве language . Фрагменты кода должны соответствовать синтаксическим конструкциям языка скриптлетов , т.е., как правило, синтаксису языка Java. scriptlets имеют следующий синтаксис:

<% текст скриптлета %>

Эквивалентом синтаксиса скриптлета для XML является:

текст скриптлета

Если в тексте скриптлета необходимо использовать последовательность символов %> именно как сочетание символов, а не как тег - признак окончания скриптлета , вместо последовательности %> следует использовать следующее сочетание символов %\>.

В спецификации JSP приводится простой и понятный пример скриптлета , обеспечивающего динамическое изменение содержимого страницы JSP в течение дня.

<% if (Calendar.getInstance ().get (Calendar.AM_PM) == Calendar.AM) {%> Good Morning <% } else { %> Good Afternoon <% } %>

Необходимо отметить, что код внутри скриплета вставляется в том виде, как он записан, и весь статический HTML-текст (текст шаблона) до или после скриплета конвертируется при помощи оператора print . Это означает что скриплеты не обязательно должны содержать завершенные фрагменты на Java, и что оставленные открытыми блоки могут оказать влияние на статический HTML-текст вне скриплета .

Скриплеты имеют доступ к тем же автоматически определенным переменным, что и выражения. Поэтому, например, если есть необходимость вывести какую-либо информацию на страницу, необходимо воспользоваться переменной out .

<% String queryData = request.getQueryString (); out.println ("Дополнительные данные запроса: " + queryData); %>

Выражения expressions

Выражения expressions в странице JSP - это исполняемое выражение, написанное на языке скрипта, указанного в объявлении language (как правило Java). Результат выражения JSP, имеющий обязательный тип String, направляется в стандартный поток вывода out с помощью текущего объекта JspWriter . Если результат выражения не может быть приведен к типу String , возникает либо ошибка трансляции, если проблема была выявлена на этапе трансляции, либо возбуждается исключение ClassCastException , если несоответствие было выявлено в процессе выполнения запроса. Выражение имеет следующий синтаксис:

<%= текст выражения %>

альтернативный синтаксис для JSP expressions при использовании XML:

текст выражения

Порядок выполнения expressions на странице JSP слева-направо. Если выражение появляется более чем в одном атрибуте времени выполнения, то оно выполняется слева-направо в данном теге. Выражение должно быть полным выражением на определенном скрипте (как правило Java).

expressions выполняются во время работы протокола HTTP. Значение выражения преобразуется в строку и включается в соответствующую позицию файла JSP.

Выражения обычно используются для того, чтобы вычислить и вывести на экран строковое представление переменных и методов, определенных в блоке объявлений страницы JSP или полученных от компонентов JavaBeans, которые доступны из JSP. Следующий код expressions служит для отображения даты и времени запроса страницы:

Текущее время: <%= new java.util.Date () %>

Для того чтобы упростить expressions существует несколько заранее определенных переменных, которые можно использовать. Наиболее часто используемые переменные:

  • request, HttpServletRequest;
  • response, HttpServletResponse;
  • session, HttpSession - ассоциируется с запросом, если таковой имеется;
  • out, PrintWriter - буферизированный вариант типа JspWriter для отсылки данных клиенту.

1) NetBeans 7.3;
2) Maven;
3) Hibernate;
4) Spring MVC;
5) JSP+JSTL;
6) Знание про Сервлеты, Сессии, JavaBean, XML и т.д.;
7) HTML+CSS (немного красоты по Вашему вкусу, но лучше заплатить левым людям, - у Вас с серверной стороной итак хлопот хватит);
8) Java SE (знание коллекций, умение обрабатывать исключения… В общем, стандартный набор);
9) Знание паттернов проектирования (DAO, Factory);
10) JPA;
11) SVN;
12) SQL (для написания скриптов, заполняющих наши БД).

Начнем с того, где мы будем хранить наш код и как обмениваться им с друзьями. Думаю, не все начинающие знают про репозитории, и эта часть именно для них.

SVN

Есть такое понятие, как репозиторий - удаленный сервер хранения кода.
Если Вам дадут тестовое задание, и Вы пошлете его архивом, то Вас скорее всего тоже пошлют. Может, не пошлют, но точно разочаруются в Вас.
Существуют различные репозитории CVS, SVN, Git. Для начинающих я считаю оптимальным SVN. Ну а Вам главное не знать что это, а уметь применять. Пока достаточно будет и этого, остальное придет с опытом.

После всего этого у Вас будет ссылка на Ваше пространство. Чтобы понять, что это такое - нужно взять один из ваших проектов (или создайте какой нибудь пустой проект в NetBeans). Нажимаете на нем правой кнопочкой и у Вас в меню будет доступно «Управление версиями» -> «импортировать в репозиторий Subversion». После этого будет диалоговое окно, в котом будет путь к репозиторию - это ссылка которую Вы получили на сайте во вкладке «Исходный код».

Далее, полностью удалите проект, который вы закоммитили. Дальше зайдите в папку, где у вас проекты хранятся, и проверьте что реально все удалено. Потом возвращаетесь в NetBeans и ищете в панели меню вкладку Группа(на панели где Файл, Вид, Правка, Переход, Источник...) в нем есть наш Subversion. И в подменю на нем есть «Получить». Дальше в диалоговых окнах надо будет указать ссылку на репозиторий (это ссылка которую вы получили на сайте во вкладке «Исходный код».) И когда он предложит выкачивать папки, то по дереву репозитория нужно будет найти ваш проект и выбрать его, и по окончанию вы выкачаете свой проект. Вот так происходит обмен кодом.
Ваш проект будет постоянно синхронизироваться с репозиторием и помечать файлы, которые были изменены, или новые(то что отличается от версии на репозитории). Чтобы обновить, нужно вызвать контекстное меню, и в закладке «Управление Версиями» будет большой список того, что можно делать с проектом. «Обновлять» - это обновить свои файлы; «Фиксировать» - ложить код который Вы написали или изменили в репозиторий; «Сбрасывать» - возвращаться к версии на репозитории, и «Сравнивать» - отображение изменений строк которые отличаются от удаленных. Это способ командного обмена кодом, который используется всегда и нужно к нему привыкать.

Вы уже скачали NetBeans, поигрались с SVN - теперь перейдем к делу. Создаете проект. Нажимаете «Создать проект», там выбираете Maven-> Веб-приложение. Называете как хотите, это все Ваша фантазия. Итак, у нас есть веб-приложение, сборка нашего проекта идет мавеном, у нас есть цель и теперь наступило время подумать над тем, как ее осуществить. То есть Вы, как разработчик, должны подумать над тем, как будет выглядеть Ваше приложение, какую иметь архитектуру, дерево пакетов и так далее. Общее количество строк кода здесь около 4000 и лучше позаботиться о красивой архитектуре заранее, иначе потом Вы просто не будете понимать что где и как у Вас работает, каким чудом Вы, к примеру, выводите последнюю купленную вещь, как считаете общую сумму покупок. И если Вас потом попросят что-то доделать или добавить - Вы осознаете что проще написать все с нуля.

Ну и конечно нам нужно прикинуть наш план действий.

Итак: План действий
1) описываем entity(entities) - сущности. Это POJO - класс, связанный с БД с помощью аннотации (@Entity) или через XML. Использовать будем JPA, поэтому импортировать надо javax.persistence.* Почему не Hibernate Persistence API, т.к если использовать его и потом мы захотим сменить ORM библиотеку, то придется переписывать и наши классы, а JPA - это стандарт от Sun. По поводу того, что такое JPA - ну для Вас могу своими словами сказать так: это библиотека предоставляющая API для работы с *долго живущими* объектами, то есть позволяет нам удобно сохранять наши объекты в БД. Могу дать совет: создайте для этого отдельный пакет назовите его entity или domain - как хотите, главное чтобы Вам было понятно. В конечном итоге это может выглядеть так: edu.shop.model.domain.Customer.java edu.shop.model.domain.Notebook.java.
Подробнее буду описывать непосредственно при рассмотрении данного пункта. Сейчас задача стоит прикинуть план действий.

2) Создаем HibernateUtil (вообще суффикс или приставка Util подразумевает, что код в этом классе есть универсальный и используется множеством классов).
Итак, в HibernateUtil мы размещаем SessionFactory. Он тяжеловесный. Этот код, по идее, должен быть независим от всего приложения, так как он устанавливает соединение с базой данных при старте и должен нам давать только Сессии с базой данных. Еще мы в этом классе регистрируем наши классы-сущности. Подробнее про этот класс расскажу позже. Засунем его тоже в отдельный пакет, к примеру, edu.shop.model.hbutil.HibernateUtil.java

3) Пишем DAO.
Что в нем писать? Пишем то, что мы хотим получить от базы данных, но нам не нужно думать как получились эти данные, важен результат. К примеру, мы определяем интерфейс ProductDAO и пишем в нем методы
List> getAllProducts(); потом пишем его реализацию ProductDAOImpl.

В чем идея? Если бы это приложение писал я и Вы, Вы бы сказали: «Миха, мне нужны от БД следующие данные: все товары что у меня есть в БД». Я отвечаю: «не вопрос». И далее следующее развитие событий: вы в своем коде, везде где нужно делать запросы к базе пишете следующее%

*здесь обращение к методу*.getAllProducts(); - и видите, что компилятор не ругается, а реализацию этого интерфейса я мог еще не успеть написать. И какой итог? У Вас все скомпилилось, а рабочего кода даже нет. Здесь мы применим Enums и паттерн Factory, и еще кое-что, но всему свое время. Именно в DAO нужно уделить особое внимание обработке исключений, хотя бы генерировать страницы с ошибками. Чтобы Вы быстро находили кусок неработающего кода. Иначе, Вы просто замучаетесь с отладкой.

3)Здесь начнется наша работа с Spring MVC. Это долгая история и этому будет посвящена отдельная статья. Сразу скажу - это самое сложное в этом приложении. Но я Вам покажу и более простой вариант, как выводить все, не особо заботясь про паттерн MVC.
Затронем использование скриплетов.

4) Здесь у нас будут вспомогательные классы, добавляющие всякие вкусности в наш проект: подсчет общей суммы покупок; последняя купленная вещь; вспомогательные переменные, которые пригодятся нам для работы метода, который, к примеру, будет выводить нам с БД вещи не дороже 5000 грн, или не дешевле 500; вывод всех ноутбуков марки Асус. Этот пункт тесно взаимосвязан с предыдущим.

Пока остановимся на этом. С остальным разберемся чуть позже. Итак, у нас есть намеченный план, приступим к его реализации.

Entity

Мы создали наш проект и создали наш пакет с сущностями. Пусть это будет edu.shop.entity. Там мы создаем такие классы:

Примечание. Корзина, в которой будут храниться наши купленные товары, будет как таблица в БД, это я сделал т.к на ней покажу некоторые основы работы с БД. Для реального случая целесообразнее будет использовать коллекции для хранения наших товаров.

1) Product
2) Notebook
3) Camera
4) Book
5) Cable
6) Customer
7) Cart

Поговорим немного о том, что такое класс-сущность.
Entity (Сущность) - POJO-класс, связанный с БД с помощью аннотации (@Entity) или через XML. К такому классу предъявляются следующие требования:

Должен иметь пустой конструктор (public или protected);
- Не может быть вложенным, интерфейсом или enum;
- Не может быть final и не может содержать final-полей/свойств;
- Должен содержать хотя бы одно @Id-поле.

При этом entity может:

Entities могут быть связаны друг с другом: один-к-одному, один-ко-многим, многие-к-одному и многие-ко-многим.

Использовать мы будем аннотации. И тут сразу у нас появляется возможность описать двумя способами. Либо мы будем писать аннотации непосредственно над полями, либо над геттерами. Скажу одно: правильно писать над геттерами, а причину Вы спросите в гугле. Не могу я все темы абсолютно здесь описать.

Есть еще одно что хочу сказать. Для этого придется показать 2 примера описания класса сущности. Итак, первый пример:
Коментарии к нему я написал в самом коде:

Import java.io.Serializable; import javax.persistence.*; import javax.validation.constraints.Size; /** * * @author Mikhail Shumenko */ @Entity //Этой аннотацией мы указываем, что данный класс является сущностью. @Table(name = "CART")// Этой аннотацией мы указываем, что за эту сущность в БД отвечает таблица с именем CART //Хочу отметить, что регистр не важен, эту анотацию можно не указывать, тогда хибернейт создаст нам БД с //именем как у класса public class CartEntity implements Serializable { //Здесь мы пишем аннотации над полями. Правильно писать над геттерами //Описываем Id таблицы @Id //Указываем, что это поле класса отвечает за столбец в таблице с именем Id //Если мы его указывать не будем, хибернейт создаст столбец с именем как у поля. @Column(name = "ID") //Здесь написать можно много)) Почему я написал здесь так? В общем можно в //@GeneratedValue(strategy=GenerationType.вместо TABLE написать AUTO) тогда //при первой загрузке таблицы, Id сгенерируются автоматически от 1 до своего максимального значения. //Если у вас 20 вещей в таблице, то сгенерируется от 1 до 20. //Но при последующих добавлениях, id у добавленной вещи будет примерно таким - 345768. //Я написал все так, чтобы последний мой id хранился в таблице и генерировался потом адекватно при последующих добавлениях. //Также есть SEQUENCE, но он не поддерживается в Derby, а работать мы будем именно с ней. //В общем, это нюансы. Можете узнать про них самостоятельно @TableGenerator(name = "cartid", table = "cartpktb", pkColumnName = "idCart", pkColumnValue = "idCartValue",allocationSize = 1) @GeneratedValue (strategy = GenerationType.TABLE, generator = "cartid") private Integer id; //Указываем максимальный размер. Это строка из 25 символов. @Size(max = 25) @Column(name = "NAMEITEM") //Если тип нашего поля String, то и создаваться будет столбец с типом VARCHAR(в Derby) //Если Integer, то будет столбец, в который поместить можно только Integer //boolean в Derby - это столбец с типом SMALLINT private String nameItem; @Column(name = "PRICE") private Integer price; public CartEntity() { } public CartEntity(String nameItem, int price) { this.nameItem = nameItem; this.price = price; } public CartEntity(Integer id,String nameItem, int price) { this.id=id; this.nameItem = nameItem; this.price = price; } public CartEntity(Integer id) { this.id = id; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getNameItem() { return nameItem; } public void setNameItem(String nameItem) { this.nameItem = nameItem; } public Integer getPrice() { return price; } public void setPrice(Integer price) { this.price = price; } }

Второй способ: пишем над геттерами. Пояснения смотрим в коде.

import java.io.Serializable; import javax.persistence.*; /** * * @author miha */ @Entity //Видите, я не указывал аннотацию @Table //Hibernate все поймет за меня. public class Product implements Serializable { private Integer id; private String nameProduct; private Integer availableProduct; @Id @GeneratedValue(strategy = GenerationType.AUTO) //Я описал Id над геттером, значит, и с остальными полями работа будет идти через геттеры. public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getNameProduct() { return nameProduct; } public void setNameProduct(String nameProduct) { this.nameProduct = nameProduct; } public Integer getAvailableProduct() { return availableProduct; } public void setAvailableProduct(Integer availableProduct) { this.availableProduct = availableProduct; } }

Итак, у Вас есть два примера классов сущностей. Создайте остальные, используя эти примеры. Такие поля как: модель, год публикации, имя, стоимость - все на Вашу фантазию. Включите обязательно поле Available(в переводе наличие). Оно Вам потом пригодится. Можете сделать его булевым и добавить столбец с именем количество. Это все нам пригодится.

Теперь приведем пример нашего HibernateUtil

/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package edu.shumenko.hibernate; import edu.shumenko.entity.BookEntity; import edu.shumenko.entity.CableEntity; import edu.shumenko.entity.CameraEntity; import edu.shumenko.entity.CartEntity; import edu.shumenko.entity.CustomerEntity; import edu.shumenko.entity.NotebookEntity; import edu.shumenko.entity.ProductEntity; import org.hibernate.cfg.AnnotationConfiguration; import org.hibernate.SessionFactory; /** * Hibernate Utility class with a convenient method to get Session Factory * object. * * @author Mikhail Shumenko */ public class HibernateUtil { //Создаем нашу SessionFactory. private static final SessionFactory sessionFactory; static { try { //Создаем новый екземпляр AnnotationConfiguration AnnotationConfiguration ac = new AnnotationConfiguration(); //Это нам нужно для того, чтобы мы добавили все наши классы сущности. //каждый ваш Entity здесь нужно прописать, не пропишете - не будет работать. ac.addAnnotatedClass(ProductEntity.class).addAnnotatedClass(BookEntity.class).addAnnotatedClass(CableEntity.class) .addAnnotatedClass(CameraEntity.class).addAnnotatedClass(NotebookEntity.class). addAnnotatedClass(CartEntity.class).addAnnotatedClass(CustomerEntity.class); //Вот мы собственно и создали нашу Фабрику сессий. //Она нужна т.к с БД мы работаем через сессии //Подробности будут чуть позже, пока знайте, как ее сделать и как с ней работать. sessionFactory = ac.configure().buildSessionFactory(); } catch (Throwable ex) { // Log the exception. System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } }

DAO

Приступим к следующей части. Что такое DAO. Это шаблон проектирования.

Его смысл:
- Весь доступ к базе данных в системе производится через DAO для инкапсуляции.
- Каждый экземпляр DAO отвечает за один первичный доменный объект или сущность. Если доменный объект имеет независимый цикл жизни, он должен иметь свой собственный DAO.
- DAO отвечает за операции создания, чтения (по первичному ключу), обновления и удаления (то есть, CRUD (create, read, update, delete)) доменного объекта.
- DAO может разрешать запросы, основанные на критерии, отличном от первичного ключа. Я ссылаюсь на такие методы как finder или finders. Метод finder обычно возвращает коллекцию доменных объектов, за которые отвечает DAO.
- DAO не занимается обработкой транзакций, сессий или соединений. Это делается вне DAO для обеспечения гибкости.
Подробнее всегда расскажет гугл.

Мы пока напишем DAO для наших продуктов.
Итак, подумаем что нам вообще нужно. Таблица Product будет иметь 4 поля Id,nameProduct,available+amount+actionForServlet. Она нам будет нужна, чтобы создать на нашем сайте категории. Над последним полем пока не заморачиваемся. Единственное что нам нужно - это получение списка продуктов.

Пишем интерфейс
public interface ProductDAO { ProductDAO INSTANCE_PRODUCT= new ProductDAOImpl(); ListGetProducts(); //и метод с которым мы будем работать }

Реализация нашего интерфейса. Пояснения смотрим в коде
/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package edu.shop.model.dao; import java.util.List; import org.hibernate.Criteria; import org.hibernate.Session; /** * * @author Mikhail Shumenko */ public class ProductDAOImpl implements ProductDAO { @Override public ListGetProducts() { ListResult = null; //Создаем сессию, она нужна для использования транзакций //Грубо говоря, транзакция - это как точка восстановления, если не прошла до конца, то все изменения откатываются. Session session = HibernateUtil.getSessionFactory().openSession(); try { session.beginTransaction().begin(); //Criteria используется для запроса с целью получения данных из БД //Такой формулировки, думаю, Вам пока хватит //Параметром мы передаем тот класс-сущность, который используем. Если бы данные получали из таблицы Cart то передавать //надо было бы Cart.class Criteria criteria = session.createCriteria(Product.class); result = (List) criteria.list(); session.getTransaction().commit } catch (Exception e) { //Обработку исключений обязательно пишите. Но это я оставлю Вам на самостоятельную работу. e.printStackTrace(); }finally { if (session != null) session.close(); } return result; } }

Итак, теперь у нас есть возможность получать данные из БД. Вы можете, используя скриплеты, создать незамысловатый цикл for-each и вывести свою продукцию на вашу страницу index.jsp

Категории

//INSTANCE_PRODUCT что это такое? //В ProductDAO описана такая переменная, отвечает за создание ProductDAOImpl //Ну у нас все будет по-другому, можете особо не запоминать это. //ProductDAO INSTANCE_PRODUCT= new ProductDAOImpl(); <% for (Product product:ProductDAO.INSTANCE_PRODUCT.getProducts()) {%> <%}%> <% for (Product product: ProductDAO.INSTANCE_PRODUCT.getProducts()) {%> <%}%>
Категория"><%=product.getName()%>
Наличие<%=product.getAvailable()%>

Но это на первое время, а вообще так делать плохо. Это нарушает наш паттерн MVC. Как сделать правильно я объясню в следующем уроке, если мне дадут инвайт. Во втором уроке мы займемся Spring, в третьем коснемся паттерна Factory, и углубимся в хибернейт. Для особо нетерпеливых, покажу как нужно удалять из БД, сохранять в БД и удалять полностью все из БД. Ну, а как сделать, чтобы все это взаимодействовало в целом с нашим приложением и подробное рассмотрение оставим на потом.

Сохранить в БД

public void addItemToCart(CartEntity cart) { Session session = HibernateUtil.getSessionFactory().openSession(); try { session.beginTransaction().begin(); session.save(cart); session.getTransaction().commit(); } catch (Exception ex) { ex.printStackTrace(); } finally { if (session != null) { session.close(); } } }

Удалить из базы по id

public void deleteItemFromCart(Integer id) { Session session = HibernateUtil.getSessionFactory().openSession(); try { session.beginTransaction().begin(); CartEntity itemDelete = (CartEntity) session.get(CartEntity.class, id); session.delete(itemDelete); session.getTransaction().commit(); } catch (Exception ex) { ex.printStackTrace(); } finally { if (session != null) { session.close(); } } }

Удаление из базы группы id .

public void deleteAllItemToCart(List idAllItemsInCart) { Session session = HibernateUtil.getSessionFactory().openSession(); try { session.beginTransaction().begin(); for(Integer id:idAllItemsInCart){ CartEntity itemDelete = (CartEntity) session.get(CartEntity.class, id); session.delete(itemDelete); } session.getTransaction().commit(); } catch (Exception ex) { ex.printStackTrace(); } finally { if (session != null) { session.close(); } } }

Также Вам нужен будет файл настройки Hibernate. Создайте в Derby БД shop. Имя и пароль пользователя root и pass соответственно. Если не получится - не расстраивайтесь - я уделю еще этому время.

org.hibernate.dialect.DerbyDialect org.apache.derby.jdbc.ClientDriver jdbc:derby://localhost:1527/shop root pass UTF-8 update

О том, как заполнять наши БД поговорим позже. Можете заполнить их вручную. Либо дождаться следующего урока.

Продолжаю описывать процесс создания веб-приложения используя сервлеты, jsp, мавен и томкат. , если необходимо.

Создаем сущности.
Создадим в пакете entities класс User, в котором создадим две приватные строковые переменные name и password. Создадим конструкторы (по умолчанию и такой, который бы принимал оба значения), геттеры/сеттеры, переопределим метод toString() на всякий случай, а так же методы equals() и hashCode(). public class User { private String name; private String password; public User() { } public User(String name, String password) { this.name = name; this.password = password; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "name="" + name + "\"" + ", password="" + password + "\"" + "}"; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; if (name != null ? !name.equals(user.name) : user.name != null) return false; return password != null ? password.equals(user.password) : user.password == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (password != null ? password.hashCode() : 0); return result; } } Теперь можем приступить к созданию списка пользователей, куда мы будем наших пользователей добавлять, и откуда будем их забирать для отображения. Но есть проблема. Объекты наших сервлетов мы не создаем, их создает за нас томкат. Методы, которые мы переопределяем в них - тоже за нас уже определены и добавить параметр мы не можем. Как же тогда создать общий список, который бы виден был в обоих наших сервлетах? Если мы просто в каждом сервлете создадим свой объект списка - то получится, что добавлять пользователей мы будем в один список, а выводить список пользователей сервлетом ListServlet - совершенно другой. Получается, что нам нужен такой объект, который был бы общим для обоих сервлетов. Если говорить обобщенно, то нам нужен такой объект, который был бы общим для всех классов в нашей программе; единственный объект на всю программу. Надеюсь, вы что-то да слышали про шаблоны проектирования. И возможно для кого-то это первая реальная необходимость использования шаблона в своей программе. Можете поизвращаться и запилить какой-нибудь крутой синглтон, с двойными проверками и синхронизациями (да-да, у нас многопоточное приложение, так как сервлеты томкат запускает в разных потоках), но я буду использовать вариант с ранней инициализацией, так как в данном случае он вполне подходит.
Создание модели.
Создадим тогда класс (и реализуем в нем шаблон singleton) в пакете model, ну и назовем тоже вполне красочно Model. Создадим в нем приватный объект списка пользователей, и сделаем два метода: один для того, чтоб можно было добавить пользователя, а второй - пусть просто возвращает список строк (имен пользователей). Поскольку наш объект пользователя состоит из имени и пароля - то пароли пользователей мы "светить" не хотели бы, поэтому и возвращать будем только список их имен. public class Model { private static Model instance = new Model(); private List model; public static Model getInstance() { return instance; } private Model() { model = new ArrayList<>(); } public void add(User user) { model.add(user); } public List list() { return model.stream() .map(User::getName) .collect(Collectors.toList()); } }
Немного про mvc.
Раз уж вы слышали про singleton, значит возможно слышали и про другой шаблон проектирования - MVC (model-view-controller, или по-русски модель-представление-контроллер, или прям так как и на английском модель-вью-контроллер). Его суть в том, чтобы отделять бизнес-логику от представления. То-есть, отделять код, который определяет что делать от кода, который определяет как отображать . View (представление или просто вьюхи) как-раз и отвечает за то, в каком виде представлять какие-то данные. В нашем случае вьюхи - это наши jsp странички. Именно поэтому я их и положил в папочку с названием views. Модель - это собственно сами данные, с которыми работает программа. В нашем случае это пользователи (список пользователей). Ну а контроллеры - связующее звено между ними. Берут данные из модели и передают их во вьюхи, ну или получают от томката какие-то данные, обрабатывают их и передают модели. Бизнес-логика (то-есть что делать ) должна быть описана в них, а не в модели или во вьюхе. Таким образом, каждый занимается своим делом:
  • модель хранит данные
  • вьюхи рисуют красивое представление данных
  • контроллеры занимаются обработкой данных
Это позволяет всем им быть достаточно простыми и поддерживаемыми. А не монструозной свалкой всего кода в одном классе. MVC подходит не только для веб-программирования, но все-же в этой сфере он встречается очень часто (если не всегда). В нашем случае в качестве контроллеров будут выступать сервлеты. Да это очень поверхностное и даже грубое описание этого паттерна, но эта статья не о шаблонах проектирования, а о том, как сделать простенькое веб-приложение:) Кто хочет узнать больше - гугл знает все ! :) Вернемся к нашим вьюхам.
Создаем форму добавления пользователя.
Добавим в файл add.jsp форму, состоящую из двух текстовых инпутов (один обычный, другой типа пароль) и кнопки для отправки данных на сервер. Name: Password: Submit Здесь у формы указан атрибут method со значением post. Это говорит о том, что данные из этой формы полетят на сервер в виде POST-запроса. Атрибут action не указан, значит запрос этот полетит по тому же адресу, по которому мы перешли на эту страничку (/add). Таким образом наш сервлет, который привязан к этому адресу, при получении GET-запроса возвращает эту jsp с формой добавления пользователей, а если получит POST-запрос - значит эта форма отправила туда свои данные (которые мы в методе doPost() вытащим из объекта запроса, обработаем и передадим в модель на сохранение). Стоит обратить внимание, что у инпутов здесь указан параметр name (для поля с именем он имеет значение name, а для поля с паролем - pass). Это довольно важный момент. Так как чтобы получить из запроса (внутри сервлета уже) эти данные (имя и пароль которые будут введены) - мы будем использовать именно эти name и pass. Но об этом чуть позже. Сама кнопка отправки данных у меня сделана снова же в виде button, а не инпутом, как это обычно принято. Не знаю насколько такой вариант универсален, но у меня в хроме работает:)
Обработка POST-запроса сервлетом.
Вернемся к сервлету AddServlet. Мы уже знаем, что чтобы наш сервлет умел "ловить" GET-запросы - мы переопределили метод doGet() из класса HttpServlet. Чтобы научить наш сервлет ловить еще и POST-звапросы - мы переопределяем еще и метод doPost(). Он получает аналогичные объекты запроса и ответа от томката, с которыми мы и будем работать. Для начала вытащим из запроса параметры name и pass, которые отправила форма (если вы их в форме назвали по-другому - тогда именно те названия и пишете). После чего создадим объект нашего пользователя, используя полученные данные. Потом получим объект модели и добавим созданного пользователя в модель. @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String name = req.getParameter("name"); String password = req.getParameter("pass"); User user = new User(name, password); Model model = Model.getInstance(); model.add(user); }
Передача данных во вьюху.
Теперь перейдем к сервлету ListServlet. У нас тут уже реализован метод doGet(), который просто передает управление во вьюху list.jsp. Если у вас этого еще нет - сделайте по аналогии с таким же методом из сервлета AddServlet. Теперь было бы неплохо получить из модели список имен пользователей и передать их во вьюху, которая их там получит и красивенько отобразит. Для этого воспользуемся снова же объектом запроса, который мы получили от томката. К этому объекту мы можем добавить атрибут, дав ему какое-то имя ну и собственно сам объект, который бы мы хотели передать во вьюху. Благодаря тому, что при передаче процесса выполнения из сервлета во вьюху мы передаем туда эти же объекты запроса и ответа, что получил сам сервлет, то и добавив наш список имен к объекту запроса мы потом из этого объекта запроса во вьюхе сможем наш список имен пользователей и получить. С классом ListServlet мы закончили, поэтому привожу код всего класса package app.servlets; import app.model.Model; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; public class ListServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Model model = Model.getInstance(); List names = model.list(); req.setAttribute("userNames", names); RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/list.jsp"); requestDispatcher.forward(req, resp); } }
Выполнение java-кода в jsp файлах.
Теперь перейдем к файлу list.jsp. Этот файл выполнится только когда ListServlet передаст сюда процесс выполнения. Кроме того, мы в том сервлете уже подготовили список имен пользователей из модели и передали сюда в объекте запроса. Имея список имен мы можем пробежаться по нему циклом for и вывести каждое имя. Как я уже говорил, jsp файлы могут выполнять java-кода (в принципе, этим и отличаются от статичных html страничек). Для того, чтобы выполнить какой-то код - достаточно поставить в нужном нам месте конструкцию <% // java код %> Внутри такой конструкции мы получаем доступ к нескольким переменным: request - наш объект запроса, который мы передали из сервлета, где он назывался просто req responce - объект ответа, в сервлете назывался resp out - объект типа JspWriter (наследуется от обычного Writer), при помощи которого можем "писать" что-либо прямо в саму html страничку. Запись out.println("Hello world!") очень похожа на запись System.out.println("Hello world!"), но не стоит их путать! out.println() "пишет" в html страничку, а System.out.println - в системный вывод. Если вызвать внутри раздела с джава кодом jsp метод System.out.println() - то результаты увидите в консоли томката, а не на страничке, как возможно хотелось бы:) Про другие доступные объекты внутри jsp можно поискать . Используя объект request мы можем получить список имен, который передавали из сервлета (мы прикрепили соответствующий атрибут к этому объекту), а используя объект out - можем вывести эти имена. Сделаем это пока просто в виде html списка: <% List names = (List) request.getAttribute("userNames"); if (names != null && !names.isEmpty()) { for (String s: names) { out.println("" + s + ""); } } %> Если же хотим выводить список только в том случае, когда есть пользователи, а иначе выводить предупреждение, что пользователей пока нет - можем немного переписать этот участок: <% List names = (List) request.getAttribute("userNames"); if (names != null && !names.isEmpty()) { out.println(""); for (String s: names) { out.println("" + s + ""); } out.println(""); } else out.println("There are no users yet!"); %> Теперь, когда мы умеем передавать данные из сервлетов во вьюхи - можем немного улучшить наш AddServlet, чтобы выводилось уведомление об успешном добавлении пользователя. Для этого в методе doPost() после того, как добавили нового пользователя в модель - можем добавить имя этого пользователя в атрибуты объекта req и передать управление обратно во вьюху add.jsp. А в ней уже сделать участок с джава кодом, где проверять есть ли такой атрибут в запросе, и если да - то выводить сообщение, что пользователь успешно добавлен. После этих изменений полный код сервлета AddServlet будет выглядеть примерно так: package app.servlets; import app.entities.User; import app.model.Model; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class AddServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/add.jsp"); requestDispatcher.forward(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String name = req.getParameter("name"); String password = req.getParameter("pass"); User user = new User(name, password); Model model = Model.getInstance(); model.add(user); req.setAttribute("userName", name); doGet(req, resp); } } Тут в конце метода doPost() мы устанавливаем атрибут с именем добавленного в модель пользователя, после чего вызываем метод doGet(), в который передаем текущие запрос и ответ. А метод doGet() уже передает управление во вьюху, куда и отправляет объект запроса с прикрепленным именем добавленного пользователя в качестве атрибута. Осталось подправить саму add.jsp чтобы она выводила такое уведомление, если присутствует такой атрибут. Конечный вариант add.jsp <%@ page contentType="text/html;charset=UTF-8" language="java" %> Add new user Super app! <% if (request.getAttribute("userName") != null) { out.println("User "" + request.getAttribute("userName") + "" added!"); } %> Add user Name: Password: Submit Back to main Тело страницы состоит из div-a с шапкой, после чего div-контейнер для контента, в нем проверка существует ли атрибут с именем пользователя, потом div с формой добавления пользователей, ну и в конце футер с кнопкой возврата на главную страницу. Может показаться, что слишком много div-ов, но мы их потом используем, когда добавим стилей:) Ну и конечный вариант list.jsp <%@ page import="java.util.List" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> Users Super app! Users <% List names = (List) request.getAttribute("userNames"); if (names != null && !names.isEmpty()) { out.println(""); for (String s: names) { out.println("" + s + ""); } out.println(""); } else out.println("There are no users yet!"); %> Back to main Таким образом, мы имеем полностью рабочее веб приложение, которое умеет хранить и добавлять пользователей, а так же выводить список их имен. Осталось лишь приукрасить... :)
Добавление стилей. Используем фреймворк W3.CSS.
В данный момент наше приложение рабочее, но абсолютно вырвиглазное:) Нужно добавить фон, цвета текста и кнопок, стилизировать списки, сделать выравнивание, добавить отступов, в общем много чего. Если писать стили вручную - это может занять много времени и нервов. Поэтому я предлагаю воспользоваться CSS фреймворком W3.CSS . В нем уже есть готовые классы со стилями, осталось только расставить в нужных местах те css классы, которые мы хотим в этих местах применить. Для того, чтобы добавить их к себе на страницы во-первых нам надо подключить файл со стилями. Это можно сделать двумя способами: 1. пройтись по нашим страницам и в разделе head вставить прямую ссылку на файл со стилями Такой вариант подходит, если у вас постоянное подключение к интернету. Тогда при открытии ваших страниц на локальном сервере - стили подтянутся из интернета. 2. Если же вы хотите иметь все стили у себя локально и не быть зависимым от интернет-соединения - можете просто скачать файл со стилями и поместить его где-нибудь внутри папочки web (например web/styles/w3.css), после чего пройтись по всем нашим страничкам (index.html, add.jsp, list.jsp) и вписать внутри раздела head ссылку на этот файл со стилями После этого просто пройтись по тегам и подописывать им те стили, которые вам понравятся. Я не буду останавливаться на этом подробно, а сразу дам свои готовые варианты трех моих файлов с раставленными классами стилей. index.html Super app! Super app! List users Add user add.jsp <%@ page contentType="text/html;charset=UTF-8" language="java" %> Add new user Super app! <% if (request.getAttribute("userName") != null) { out.println("\n" + " ×\n" + " User "" + request.getAttribute("userName") + "" added!\n" + ""); } %> Add user Name: Password: Submit Back to main list.jsp <%@ page import="java.util.List" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> Users list Super app! Users <% List names = (List) request.getAttribute("userNames"); if (names != null && !names.isEmpty()) { out.println(""); for (String s: names) { out.println("" + s + ""); } out.println(""); } else out.println("\n" + " ×\n" + " There are no users yet!\n" + ""); %> Back to main Вот и все:) Если у вас остались какие-то вопросы или есть какие-то замечания, или же наоборот что-то не получается - оставьте комментарий. Ну и парочку скриншотов приложу что из этого всего получилось.

И напоследок. Если будет желание попрактиковаться с этим проектом - можете попробовать:
  • сделать сервлет и jsp для удаления пользователя и еще пару для изменения/редактирования существующего пользователя. Получится настоящее CrUD веб приложение:) на сервлетах))
  • заменить список (List) на работу с базой данных, чтоб добавленные пользователи не пропадали после перезапуска сервера:)
Удачи!
1) NetBeans 7.3;
2) Maven;
3) Hibernate;
4) Spring MVC;
5) JSP+JSTL;
6) Знание про Сервлеты, Сессии, JavaBean, XML и т.д.;
7) HTML+CSS (немного красоты по Вашему вкусу, но лучше заплатить левым людям, - у Вас с серверной стороной итак хлопот хватит);
8) Java SE (знание коллекций, умение обрабатывать исключения… В общем, стандартный набор);
9) Знание паттернов проектирования (DAO, Factory);
10) JPA;
11) SVN;
12) SQL (для написания скриптов, заполняющих наши БД).

Начнем с того, где мы будем хранить наш код и как обмениваться им с друзьями. Думаю, не все начинающие знают про репозитории, и эта часть именно для них.

SVN

Есть такое понятие, как репозиторий - удаленный сервер хранения кода.
Если Вам дадут тестовое задание, и Вы пошлете его архивом, то Вас скорее всего тоже пошлют. Может, не пошлют, но точно разочаруются в Вас.
Существуют различные репозитории CVS, SVN, Git. Для начинающих я считаю оптимальным SVN. Ну а Вам главное не знать что это, а уметь применять. Пока достаточно будет и этого, остальное придет с опытом.

После всего этого у Вас будет ссылка на Ваше пространство. Чтобы понять, что это такое - нужно взять один из ваших проектов (или создайте какой нибудь пустой проект в NetBeans). Нажимаете на нем правой кнопочкой и у Вас в меню будет доступно «Управление версиями» -> «импортировать в репозиторий Subversion». После этого будет диалоговое окно, в котом будет путь к репозиторию - это ссылка которую Вы получили на сайте во вкладке «Исходный код».

Далее, полностью удалите проект, который вы закоммитили. Дальше зайдите в папку, где у вас проекты хранятся, и проверьте что реально все удалено. Потом возвращаетесь в NetBeans и ищете в панели меню вкладку Группа(на панели где Файл, Вид, Правка, Переход, Источник...) в нем есть наш Subversion. И в подменю на нем есть «Получить». Дальше в диалоговых окнах надо будет указать ссылку на репозиторий (это ссылка которую вы получили на сайте во вкладке «Исходный код».) И когда он предложит выкачивать папки, то по дереву репозитория нужно будет найти ваш проект и выбрать его, и по окончанию вы выкачаете свой проект. Вот так происходит обмен кодом.
Ваш проект будет постоянно синхронизироваться с репозиторием и помечать файлы, которые были изменены, или новые(то что отличается от версии на репозитории). Чтобы обновить, нужно вызвать контекстное меню, и в закладке «Управление Версиями» будет большой список того, что можно делать с проектом. «Обновлять» - это обновить свои файлы; «Фиксировать» - ложить код который Вы написали или изменили в репозиторий; «Сбрасывать» - возвращаться к версии на репозитории, и «Сравнивать» - отображение изменений строк которые отличаются от удаленных. Это способ командного обмена кодом, который используется всегда и нужно к нему привыкать.

Вы уже скачали NetBeans, поигрались с SVN - теперь перейдем к делу. Создаете проект. Нажимаете «Создать проект», там выбираете Maven-> Веб-приложение. Называете как хотите, это все Ваша фантазия. Итак, у нас есть веб-приложение, сборка нашего проекта идет мавеном, у нас есть цель и теперь наступило время подумать над тем, как ее осуществить. То есть Вы, как разработчик, должны подумать над тем, как будет выглядеть Ваше приложение, какую иметь архитектуру, дерево пакетов и так далее. Общее количество строк кода здесь около 4000 и лучше позаботиться о красивой архитектуре заранее, иначе потом Вы просто не будете понимать что где и как у Вас работает, каким чудом Вы, к примеру, выводите последнюю купленную вещь, как считаете общую сумму покупок. И если Вас потом попросят что-то доделать или добавить - Вы осознаете что проще написать все с нуля.

Ну и конечно нам нужно прикинуть наш план действий.

Итак: План действий
1) описываем entity(entities) - сущности. Это POJO - класс, связанный с БД с помощью аннотации (@Entity) или через XML. Использовать будем JPA, поэтому импортировать надо javax.persistence.* Почему не Hibernate Persistence API, т.к если использовать его и потом мы захотим сменить ORM библиотеку, то придется переписывать и наши классы, а JPA - это стандарт от Sun. По поводу того, что такое JPA - ну для Вас могу своими словами сказать так: это библиотека предоставляющая API для работы с *долго живущими* объектами, то есть позволяет нам удобно сохранять наши объекты в БД. Могу дать совет: создайте для этого отдельный пакет назовите его entity или domain - как хотите, главное чтобы Вам было понятно. В конечном итоге это может выглядеть так: edu.shop.model.domain.Customer.java edu.shop.model.domain.Notebook.java.
Подробнее буду описывать непосредственно при рассмотрении данного пункта. Сейчас задача стоит прикинуть план действий.

2) Создаем HibernateUtil (вообще суффикс или приставка Util подразумевает, что код в этом классе есть универсальный и используется множеством классов).
Итак, в HibernateUtil мы размещаем SessionFactory. Он тяжеловесный. Этот код, по идее, должен быть независим от всего приложения, так как он устанавливает соединение с базой данных при старте и должен нам давать только Сессии с базой данных. Еще мы в этом классе регистрируем наши классы-сущности. Подробнее про этот класс расскажу позже. Засунем его тоже в отдельный пакет, к примеру, edu.shop.model.hbutil.HibernateUtil.java

3) Пишем DAO.
Что в нем писать? Пишем то, что мы хотим получить от базы данных, но нам не нужно думать как получились эти данные, важен результат. К примеру, мы определяем интерфейс ProductDAO и пишем в нем методы
List> getAllProducts(); потом пишем его реализацию ProductDAOImpl.

В чем идея? Если бы это приложение писал я и Вы, Вы бы сказали: «Миха, мне нужны от БД следующие данные: все товары что у меня есть в БД». Я отвечаю: «не вопрос». И далее следующее развитие событий: вы в своем коде, везде где нужно делать запросы к базе пишете следующее%

*здесь обращение к методу*.getAllProducts(); - и видите, что компилятор не ругается, а реализацию этого интерфейса я мог еще не успеть написать. И какой итог? У Вас все скомпилилось, а рабочего кода даже нет. Здесь мы применим Enums и паттерн Factory, и еще кое-что, но всему свое время. Именно в DAO нужно уделить особое внимание обработке исключений, хотя бы генерировать страницы с ошибками. Чтобы Вы быстро находили кусок неработающего кода. Иначе, Вы просто замучаетесь с отладкой.

3)Здесь начнется наша работа с Spring MVC. Это долгая история и этому будет посвящена отдельная статья. Сразу скажу - это самое сложное в этом приложении. Но я Вам покажу и более простой вариант, как выводить все, не особо заботясь про паттерн MVC.
Затронем использование скриплетов.

4) Здесь у нас будут вспомогательные классы, добавляющие всякие вкусности в наш проект: подсчет общей суммы покупок; последняя купленная вещь; вспомогательные переменные, которые пригодятся нам для работы метода, который, к примеру, будет выводить нам с БД вещи не дороже 5000 грн, или не дешевле 500; вывод всех ноутбуков марки Асус. Этот пункт тесно взаимосвязан с предыдущим.

Пока остановимся на этом. С остальным разберемся чуть позже. Итак, у нас есть намеченный план, приступим к его реализации.

Entity

Мы создали наш проект и создали наш пакет с сущностями. Пусть это будет edu.shop.entity. Там мы создаем такие классы:

Примечание. Корзина, в которой будут храниться наши купленные товары, будет как таблица в БД, это я сделал т.к на ней покажу некоторые основы работы с БД. Для реального случая целесообразнее будет использовать коллекции для хранения наших товаров.

1) Product
2) Notebook
3) Camera
4) Book
5) Cable
6) Customer
7) Cart

Поговорим немного о том, что такое класс-сущность.
Entity (Сущность) - POJO-класс, связанный с БД с помощью аннотации (@Entity) или через XML. К такому классу предъявляются следующие требования:

Должен иметь пустой конструктор (public или protected);
- Не может быть вложенным, интерфейсом или enum;
- Не может быть final и не может содержать final-полей/свойств;
- Должен содержать хотя бы одно @Id-поле.

При этом entity может:

Entities могут быть связаны друг с другом: один-к-одному, один-ко-многим, многие-к-одному и многие-ко-многим.

Использовать мы будем аннотации. И тут сразу у нас появляется возможность описать двумя способами. Либо мы будем писать аннотации непосредственно над полями, либо над геттерами. Скажу одно: правильно писать над геттерами, а причину Вы спросите в гугле. Не могу я все темы абсолютно здесь описать.

Есть еще одно что хочу сказать. Для этого придется показать 2 примера описания класса сущности. Итак, первый пример:
Коментарии к нему я написал в самом коде:

Import java.io.Serializable; import javax.persistence.*; import javax.validation.constraints.Size; /** * * @author Mikhail Shumenko */ @Entity //Этой аннотацией мы указываем, что данный класс является сущностью. @Table(name = "CART")// Этой аннотацией мы указываем, что за эту сущность в БД отвечает таблица с именем CART //Хочу отметить, что регистр не важен, эту анотацию можно не указывать, тогда хибернейт создаст нам БД с //именем как у класса public class CartEntity implements Serializable { //Здесь мы пишем аннотации над полями. Правильно писать над геттерами //Описываем Id таблицы @Id //Указываем, что это поле класса отвечает за столбец в таблице с именем Id //Если мы его указывать не будем, хибернейт создаст столбец с именем как у поля. @Column(name = "ID") //Здесь написать можно много)) Почему я написал здесь так? В общем можно в //@GeneratedValue(strategy=GenerationType.вместо TABLE написать AUTO) тогда //при первой загрузке таблицы, Id сгенерируются автоматически от 1 до своего максимального значения. //Если у вас 20 вещей в таблице, то сгенерируется от 1 до 20. //Но при последующих добавлениях, id у добавленной вещи будет примерно таким - 345768. //Я написал все так, чтобы последний мой id хранился в таблице и генерировался потом адекватно при последующих добавлениях. //Также есть SEQUENCE, но он не поддерживается в Derby, а работать мы будем именно с ней. //В общем, это нюансы. Можете узнать про них самостоятельно @TableGenerator(name = "cartid", table = "cartpktb", pkColumnName = "idCart", pkColumnValue = "idCartValue",allocationSize = 1) @GeneratedValue (strategy = GenerationType.TABLE, generator = "cartid") private Integer id; //Указываем максимальный размер. Это строка из 25 символов. @Size(max = 25) @Column(name = "NAMEITEM") //Если тип нашего поля String, то и создаваться будет столбец с типом VARCHAR(в Derby) //Если Integer, то будет столбец, в который поместить можно только Integer //boolean в Derby - это столбец с типом SMALLINT private String nameItem; @Column(name = "PRICE") private Integer price; public CartEntity() { } public CartEntity(String nameItem, int price) { this.nameItem = nameItem; this.price = price; } public CartEntity(Integer id,String nameItem, int price) { this.id=id; this.nameItem = nameItem; this.price = price; } public CartEntity(Integer id) { this.id = id; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getNameItem() { return nameItem; } public void setNameItem(String nameItem) { this.nameItem = nameItem; } public Integer getPrice() { return price; } public void setPrice(Integer price) { this.price = price; } }

Второй способ: пишем над геттерами. Пояснения смотрим в коде.

import java.io.Serializable; import javax.persistence.*; /** * * @author miha */ @Entity //Видите, я не указывал аннотацию @Table //Hibernate все поймет за меня. public class Product implements Serializable { private Integer id; private String nameProduct; private Integer availableProduct; @Id @GeneratedValue(strategy = GenerationType.AUTO) //Я описал Id над геттером, значит, и с остальными полями работа будет идти через геттеры. public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getNameProduct() { return nameProduct; } public void setNameProduct(String nameProduct) { this.nameProduct = nameProduct; } public Integer getAvailableProduct() { return availableProduct; } public void setAvailableProduct(Integer availableProduct) { this.availableProduct = availableProduct; } }

Итак, у Вас есть два примера классов сущностей. Создайте остальные, используя эти примеры. Такие поля как: модель, год публикации, имя, стоимость - все на Вашу фантазию. Включите обязательно поле Available(в переводе наличие). Оно Вам потом пригодится. Можете сделать его булевым и добавить столбец с именем количество. Это все нам пригодится.

Теперь приведем пример нашего HibernateUtil

/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package edu.shumenko.hibernate; import edu.shumenko.entity.BookEntity; import edu.shumenko.entity.CableEntity; import edu.shumenko.entity.CameraEntity; import edu.shumenko.entity.CartEntity; import edu.shumenko.entity.CustomerEntity; import edu.shumenko.entity.NotebookEntity; import edu.shumenko.entity.ProductEntity; import org.hibernate.cfg.AnnotationConfiguration; import org.hibernate.SessionFactory; /** * Hibernate Utility class with a convenient method to get Session Factory * object. * * @author Mikhail Shumenko */ public class HibernateUtil { //Создаем нашу SessionFactory. private static final SessionFactory sessionFactory; static { try { //Создаем новый екземпляр AnnotationConfiguration AnnotationConfiguration ac = new AnnotationConfiguration(); //Это нам нужно для того, чтобы мы добавили все наши классы сущности. //каждый ваш Entity здесь нужно прописать, не пропишете - не будет работать. ac.addAnnotatedClass(ProductEntity.class).addAnnotatedClass(BookEntity.class).addAnnotatedClass(CableEntity.class) .addAnnotatedClass(CameraEntity.class).addAnnotatedClass(NotebookEntity.class). addAnnotatedClass(CartEntity.class).addAnnotatedClass(CustomerEntity.class); //Вот мы собственно и создали нашу Фабрику сессий. //Она нужна т.к с БД мы работаем через сессии //Подробности будут чуть позже, пока знайте, как ее сделать и как с ней работать. sessionFactory = ac.configure().buildSessionFactory(); } catch (Throwable ex) { // Log the exception. System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } }

DAO

Приступим к следующей части. Что такое DAO. Это шаблон проектирования.

Его смысл:
- Весь доступ к базе данных в системе производится через DAO для инкапсуляции.
- Каждый экземпляр DAO отвечает за один первичный доменный объект или сущность. Если доменный объект имеет независимый цикл жизни, он должен иметь свой собственный DAO.
- DAO отвечает за операции создания, чтения (по первичному ключу), обновления и удаления (то есть, CRUD (create, read, update, delete)) доменного объекта.
- DAO может разрешать запросы, основанные на критерии, отличном от первичного ключа. Я ссылаюсь на такие методы как finder или finders. Метод finder обычно возвращает коллекцию доменных объектов, за которые отвечает DAO.
- DAO не занимается обработкой транзакций, сессий или соединений. Это делается вне DAO для обеспечения гибкости.
Подробнее всегда расскажет гугл.

Мы пока напишем DAO для наших продуктов.
Итак, подумаем что нам вообще нужно. Таблица Product будет иметь 4 поля Id,nameProduct,available+amount+actionForServlet. Она нам будет нужна, чтобы создать на нашем сайте категории. Над последним полем пока не заморачиваемся. Единственное что нам нужно - это получение списка продуктов.

Пишем интерфейс
public interface ProductDAO { ProductDAO INSTANCE_PRODUCT= new ProductDAOImpl(); ListGetProducts(); //и метод с которым мы будем работать }

Реализация нашего интерфейса. Пояснения смотрим в коде
/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package edu.shop.model.dao; import java.util.List; import org.hibernate.Criteria; import org.hibernate.Session; /** * * @author Mikhail Shumenko */ public class ProductDAOImpl implements ProductDAO { @Override public ListGetProducts() { ListResult = null; //Создаем сессию, она нужна для использования транзакций //Грубо говоря, транзакция - это как точка восстановления, если не прошла до конца, то все изменения откатываются. Session session = HibernateUtil.getSessionFactory().openSession(); try { session.beginTransaction().begin(); //Criteria используется для запроса с целью получения данных из БД //Такой формулировки, думаю, Вам пока хватит //Параметром мы передаем тот класс-сущность, который используем. Если бы данные получали из таблицы Cart то передавать //надо было бы Cart.class Criteria criteria = session.createCriteria(Product.class); result = (List) criteria.list(); session.getTransaction().commit } catch (Exception e) { //Обработку исключений обязательно пишите. Но это я оставлю Вам на самостоятельную работу. e.printStackTrace(); }finally { if (session != null) session.close(); } return result; } }

Итак, теперь у нас есть возможность получать данные из БД. Вы можете, используя скриплеты, создать незамысловатый цикл for-each и вывести свою продукцию на вашу страницу index.jsp

Категории

//INSTANCE_PRODUCT что это такое? //В ProductDAO описана такая переменная, отвечает за создание ProductDAOImpl //Ну у нас все будет по-другому, можете особо не запоминать это. //ProductDAO INSTANCE_PRODUCT= new ProductDAOImpl(); <% for (Product product:ProductDAO.INSTANCE_PRODUCT.getProducts()) {%> <%}%> <% for (Product product: ProductDAO.INSTANCE_PRODUCT.getProducts()) {%> <%}%>
Категория"><%=product.getName()%>
Наличие<%=product.getAvailable()%>

Но это на первое время, а вообще так делать плохо. Это нарушает наш паттерн MVC. Как сделать правильно я объясню в следующем уроке, если мне дадут инвайт. Во втором уроке мы займемся Spring, в третьем коснемся паттерна Factory, и углубимся в хибернейт. Для особо нетерпеливых, покажу как нужно удалять из БД, сохранять в БД и удалять полностью все из БД. Ну, а как сделать, чтобы все это взаимодействовало в целом с нашим приложением и подробное рассмотрение оставим на потом.

Сохранить в БД

public void addItemToCart(CartEntity cart) { Session session = HibernateUtil.getSessionFactory().openSession(); try { session.beginTransaction().begin(); session.save(cart); session.getTransaction().commit(); } catch (Exception ex) { ex.printStackTrace(); } finally { if (session != null) { session.close(); } } }

Удалить из базы по id

public void deleteItemFromCart(Integer id) { Session session = HibernateUtil.getSessionFactory().openSession(); try { session.beginTransaction().begin(); CartEntity itemDelete = (CartEntity) session.get(CartEntity.class, id); session.delete(itemDelete); session.getTransaction().commit(); } catch (Exception ex) { ex.printStackTrace(); } finally { if (session != null) { session.close(); } } }

Удаление из базы группы id .

public void deleteAllItemToCart(List idAllItemsInCart) { Session session = HibernateUtil.getSessionFactory().openSession(); try { session.beginTransaction().begin(); for(Integer id:idAllItemsInCart){ CartEntity itemDelete = (CartEntity) session.get(CartEntity.class, id); session.delete(itemDelete); } session.getTransaction().commit(); } catch (Exception ex) { ex.printStackTrace(); } finally { if (session != null) { session.close(); } } }

Также Вам нужен будет файл настройки Hibernate. Создайте в Derby БД shop. Имя и пароль пользователя root и pass соответственно. Если не получится - не расстраивайтесь - я уделю еще этому время.

org.hibernate.dialect.DerbyDialect org.apache.derby.jdbc.ClientDriver jdbc:derby://localhost:1527/shop root pass UTF-8 update

О том, как заполнять наши БД поговорим позже. Можете заполнить их вручную. Либо дождаться следующего урока.

JSP (JavaServer Pages ) - технология, позволяющая веб-разработчикам легко создавать содержимое, которое имеет как статические, так и динамические компоненты. По сути, страница JSP является текстовым документом, который содержит текст двух типов: статические исходные данные, которые могут быть оформлены в одном из текстовых форматов HTML , SVG , WML , или XML , и JSP элементы, которые конструируют динамическое содержимое. Кроме этого могут использоваться библиотеки JSP тегов, а также (Expression Language), для внедрения Java-кода в статичное содержимое JSP-страниц.

JSP - одна из высокопроизводительных технологий, так как весь код страницы транслируется в java-код сервлета с помощью компилятора JSP страниц Jasper , и затем компилируется в байт-код виртуальной машины java (JVM). Контейнеры сервлетов , способные исполнять JSP страницы, написаны на языке Java, который может работать на различных платформах. JSP страницы загружаются на сервере и управляются из структуры специального Java server packet, который называется Java EE Web Application, в большинстве своём упакованные в файловые архивы .war и .ear .

Выгода, которую дает технология JSP в сравнении с другими веб-технологиями заключается в том, что JSP является платформонезависимой, переносимой и легко расширяемой технологией для разработки веб-приложений.

Версии

Начиная с версии 1.2, JavaServer Pages были разработаны в рамках Java Community Process . JSR 53 определяет оба стандарта JSP 1.2 и Servlet 2.3, а JSR 152 определяет спецификацию JSP 2.0. В мае 2006 года JSP спецификация 2.1 была выпущена под JSR 245 в рамках Java EE 5 . 10 декабря 2009 года была выпущена спецификация JSP 2.2 как содержание выпуска JSR 245.

JSP 1.0 и JSP 1.1

Необходимо отметить, что эти версии кардинально отличаются от версий предыдущих, которые в свою очередь воспринимались больше, как ответ Java на ASP . Некоторые основные возможности и трюки прошлых версий были убраны или заменены другими. Например, возможность разрабатывать библиотеки тегов. Главной идеей было разделение кода и содержимого. Так как в больших объемах исходного кода трудно сориентироваться и отделить контент от самого кода, то пришла идея их разделить (перенести) с помощью JSP тегов таких как например . Для реализации этой задумки JSP теги разделили на три логические группы: директивы, скриптовые элементы и действия.

JSP 1.2

JSP 1.2 расширяет спецификацию JavaServer Pages 1.1 (JSP 1.1) следующим образом:

  • Требуют платформы Java 2 версии 1.2 или более поздней;
  • Использует Servlet 2.3 как основу своей семантики;
  • Определяет синтаксис XML для страниц JSP;
  • Предоставляет проверку страниц JSP на этапе трансляции;
  • Специфицирует очистку библиотеки тегов на этапе прогона;
  • Улучшает контракт обработчика тегов;
  • Предоставляет улучшенную поддержку авторизации страниц;
  • Улучшает поддержку кодировки символов и локализации;
  • Устраняет печально известное ограничение «flush before you include» из JSP 1.1.

JSP 2.0

Новая версия спецификации JSP дополнена функциональностью увеличивающей скорость работы программиста. А именно:

  • Expression Language (EL) - язык выражений, позволяет среди прочего создавать разработчикам шаблоны в стиле Velocity ;
  • Более простой и быстрый способ создавать новые теги с помощью файлов.tag , теперь для создания новых тегов не обязательно знать Java;
  • Удобный способ управления вложеными бинами (JavaBeans);
  • Более быстрый и лёгкий способ отображения параметров переменных:

Hello, ${ param.visitor } <% -- аналогично коду: Hello, <% =request.getParameter ("visitor" ) %> --%>

JSP 2.1

  • Включает в себя JSTL и JavaServer Faces ;
  • Новая версия поддерживает отложенное исполнение выражений и литеральные выражения, а также J5EE enumeration.

Платформа Java EE 5 главным образом фокусируется на простую разработку используя языковые аннотации Java, которые были введены J2SE 5.0 . JSP 2.1 поддерживает эту цель определением аннотаций для зависимых инъекций в JSP операторах и в контекстных слушателях (Listeners).

Обзор

JavaServer Pages (JSP) позволяют отделить динамическую часть страниц от статического HTML . Процедура довольно проста, создаёте обычный код HTML (статический), а динамическую часть заключаете в специальные теги "<% %>" .

Имя вашего хоста: <% = request.getRemoteHost () %>

JSP страницы имеют расширение.jsp и размещаются там же, где и обычные Web страницы. Структура таких страниц может состоять из пяти конструкций: HTML , комментарии, скриптовые элементы, директивы и действия. JSP страница при компиляции преобразуется в обычный сервлет со статическим содержимым, которое направляется в поток вывода, связанный с методом service. Поэтому при первом запросе этот процесс может вызвать некую задержку, но в большинстве своём незаметную первому пользователю. Комментарии в документе или программе служат к объяснению содержимого. Они не являются причиной замедления программы, так как транслятор и исполнитель их игнорируют. Скриптовые элементы позволяют вам указать код на языке Java , который впоследствии станет частью конечного сервлета, директивы дадут вам возможность управлять всей структурой сервлета, а действия служат для задания существующих используемых компонентов, а также для контроля над поведением движка JSP. Для упрощения работы со скриптами имеются заранее определённые переменные, такие как request, response, pageContext, session, out, application, config, page, exception . Пример JSP страницы с использованием всех составляющих JSP конструкции:

Комментарии

Комментарии используются для пояснения исходного текста программы. В JSP-страницах комментарии можно разделить на две группы:

  • комментарии исходного кода JSP
  • комментарии HTML -разметки.

Комментарии исходного кода JSP отмечаются специальной последовательностью символов: <%-- в начале и --%> в конце комментария. Данный вид комментариев удаляется на этапе компиляции JSP-страницы и потому не доступны пользователям. Пример JSP-комментария:

<% -- Отобразит каталог изделий и актуальную корзину покупателя. --%>

Комментарии HTML -разметки оформляются в соответствии с правилами языка HTML. Данный вид комментариев рассматривается JSP-компилятором как статический текст и помещается в выходной HTML-документ. JSP-выражения внутри HTML-комментариев исполняются. Пример HTML-комментария:

-->

Скриптовые элементы

Спецификация JSP различает три типа скриптовых элементов:

  • Объявления <%! одна или несколько деклараций %>
  • Выражения <%= одно выражение %>
  • Скриплеты <% скриплет %>

Объявления обычно используются для определения переменных, методов, внутренних классов и остальных действующих Java конструкций на уровне класса. В выражения вкладываются любые действующие выражения Java. С помощью скриплетов в JSP страницы вкладываются работающие части кода Java. Все эти элементы начинаются знаками <% и заканчиваются %> . Обратите внимание и на то, что все скриптовые элементы отличаются немного записью конструкции. Объявления используют восклицательный знак (! ) в конструкции (<%! %>), а выражения знак равенства (=) (<%= %>), в то время как скриплеты используют стандартный формат записи (<% %>).

Объявления JSP

Объявления JSP позволят вам задавать переменные, методы, внутренние классы и так далее. Другими словами объявления Вы используете для определения конструкций Java, которые Вы в программе используете. Так как объявления не осуществляют вывода, то обычно они используются совместно с JSP выражениями или скриплетами. В приведённом в качестве примера фрагменте JSP отображается количество запросов к данной странице с момента загрузки сервера (или с момента последнего изменения и перезагрузки сервлета). Обратите внимание, что в примере мы используем как объявление, так и выражение и что внутри конструкции после объявления стоит точка с запятой (; ):

<%! private int accessCount = 0 ; %> Количество обращений к странице с момента загрузки сервера: <% = ++accessCount %>

Выражения JSP

Выражения JSP применяются для того, чтобы вставить значения Java непосредственно в вывод. Выражения Java вычисляются, конвертируются в строку и вставляются в страницу. Эти вычисления проходят во время выполнения (то есть при запросе страницы), а потому существует полный доступ к информации о самом запросе. В выражениях можно использовать постоянные, переменные, вызовы различных методов. Все выражения, вне зависимости от сложности их содержимого, вычисляются в один результат или число. JSP страницы полагаются на JSP Writer, который берёт любой результат выражения, переводит его в тип String (текстовый) и заносит в буферную память. Например, следующий код служит для отображения даты и времени запроса данной страницы:

Текущее время: <% = new java.util .Date () %> Имя вашего хоста: <% = request.getRemoteHost () %>

Необходимо обратить внимание на три правила:

  • JSP выражения должны в себе содержать выражения Java;
  • каждое JSP выражение должно содержать только одно выражение Java;
  • выражения JSP не должны заканчиваться точкой с запятой (;), в отличие от Jаva объявлений.

Скриплеты JSP

Если вы хотите сделать что-то большее чем просто вставку выражений, то скриплеты JSP дадут вам возможность вставить любой код в метод сервлета, который будет создан при обработке данной страницы. В данном случае Вы можете использовать большинство конструкций Java. Скриплеты также имеют доступ к тем же заранее определённым переменным, что и выражения. Поэтому, например, если вы хотите вывести что-нибудь на страницу, вы должны использовать заранее определённую переменную out .

<% String queryData = request.getQueryString () ; out.println ("Дополнительные данные запроса: " + queryData) ; %>

Обратите внимание на то, что код внутри скриплета вставляется в том виде, как он был записан, и весь статический HTML (текст шаблона) до или после скриплета конвертируется при помощи оператора print . Например, следующий фрагмент JSP содержит смешанный текст шаблона и скриплета:

<% if (Math .random () < 0.5 ) { %> < B> Удачного< /B> вам дня! <% } else { %> < B> Неудачного< /B> вам дня! <% } %>

После преобразования скриплета код будет выглядеть следующим образом:

If (Math .random () < 0.5 ) { out.println ("Удачного вам дня!" ) ; } else { out.println ("Неудачного вам дня!" ) ; }

Это означает, что скриплеты не обязательно должны содержать завершённые фрагменты Java, и что оставленные открытыми блоки могут оказать влияние на статический HTML вне скриплета.

Директивы JSP

JSP страница может послать сообщение соответствующему контейнеру с указаниями какие действия необходимо провести. Эти сообщения называются директивами. Все директивы начинаются с <%@ , затем следует название директивы и один или несколько атрибутов со значениями, и заканчиваются %> . Директивы в JSP странице приводят к тому, что контейнер пошлёт заявку на исполнение определённой службы, которая в генерированном документе не объявляется. Форму записи директив можно изобразить следующим образом:

<% @ директива атрибут="значение" %>

Вы также можете объединить установку нескольких атрибутов для одной директивы:

<% @ директива атрибут1 ="значение1" атрибут2 ="значение2" ... атрибутN="значениеN" %>

Существует три основных типа директив: page , которая позволяет вам совершать такие операции, как импорт классов, изменение суперкласса сервлета, и т. п.; include , которая даёт вам возможность вставить файл в класс сервлета при трансляции JSP файла в сервлет; и taglib , позволяющий расширить множество тегов своими собственными, которые JSP контейнер способен истолковать.

Директива JSP page

Как можно догадаться из названия, данная директива предоставляет атрибуты для JSP страницы. Атрибуты, определённые в этой директиве, внедряются в данную JSP страницу и на все её вложенные статические элементы, независимо от того были ли они вставлены с помощью директивы include или с помощью действия jsp:include . Форма записи директивы page следующая:

<% @ page атрибут=“значение“ %>

В качестве примера приведём следующую запись:

<% @ page import =”java.util .* , com.myclasses .* ”, buffer=”15kb” %>

Эта директива заявляет, что JSP страница импортирует классы из двух пакетов Java, java.util и com.myclasses , а потом уточняет размер буферной памяти, которая должна быть использована для обработки данной JSP страницы.

  • import="пакет.class1, пакет.class2, ..., пакет.classN". Позволяет вам задать пакеты, которые должны быть импортированы. Это единственный атрибут, который может использоваться несколько раз в одной директиве. В список необходимо включить все классы Java, которые Вы хотите использовать и которые не являются частью исходного набора импортируемых классов. Исходный набор содержит: java.lang.*, javax.servlet.*, javax.servlet.jsp.* и javax.servlet.http.*. Пример использования атрибута import:

<% @ page import ="java.util.Date, javax.text.SimpleDateFormat, com.myclasses.*" %>

  • language="java". Данный атрибут предназначен для задания используемого языка программирования. По умолчанию принимается значение "java" . Этот атрибут необязательно использовать, но тем не менее проблема потом может наступить в случае, если поставщик JSP контейнера будет использовать другие языки (например, JavaScript). Пример записи данного атрибута следующий:

<% @ page language=”java” %>

  • extends="пакет.class". Задаёт суперкласс (родительский класс) для генерируемого сервлета. Обычно сервлет возникает расширением исходного класса. Опытные программисты могут с помощью этого атрибута создавать собственные суперклассы. Пример использования этого атрибута может выглядеть следующим образом:

<% @ page extends =”mojPaket.PrimerHttp ” %>

  • session="true|false". Данный атрибут может принимать значение true или false , которые определяют принимает ли участие JSP страница в трансляции HTTP . Значение true («истина», принимается по умолчанию) сигнализирует о том, что заранее определённая переменная session (тип HttpSession) должна быть привязана к существующей сессии, если таковая имеется, в противном случае создаётся новая сессия, к которой и осуществляется привязка. Значение false («ложь») определяет, что сессии не будут использоваться, и попытки обращения к переменной session приведут к возникновению ошибки при трансляции JSP страницы в сервлет. Пример использования данного атрибута может выглядеть следующим образом:

<% @ page session=”false ” %>

  • buffer="размерkb|none". Данный атрибут задаёт объём буферной памяти, необходимой для объекта JspWriter, на который ссылается заранее определённая переменная out . Значение принимаемое по умолчанию зависит от настроек сервера, но должно превышать 8kb . Значение задаётся либо в форме «размерkb» либо «none». Если Вы укажете значение буферной памяти как none , то сервлет не будет ничего сохранять в буферную память и передаст результат, записанный до переменной out , прямо объекту PrintWriter , который предоставляется вместе с объектом ServletResponse. Если Вы зададите значение буферной памяти на конкретную величину, то JspWriter будет в эту память сохранять данные, в результате чего увеличится производительность. В отличие от объекта PrintWriter объект JspWriter может вызывать исключительные ситуации IOExceptions . Исходная величина буферной памяти равна 8kB . Пример записи данного атрибута может выглядеть следующим образом:

<% @ page buffer=”12kb” %>

  • autoflush="true|false". true или false . Значение true («истина», принимаемое по умолчанию) устанавливает, что при переполнении буферной памяти он автоматически очистится. Значение false («ложь»), которое крайне редко используется, устанавливает что переполнение буфера должно приводить к возникновению исключительной ситуации (IOExceptions). Обычно атрибуты buffer и autoflush устанавливаются вместе в одной директиве. При установке значение атрибута buffer="none" установка значения false для атрибута autoflush недопустима. Пример может выглядеть следующим образом:

<% @ page buffer=”16kb” autoflush=”true ” %>

  • isThreadSafe="true|false". Данный атрибут может принимать значения true или false . Значение true («истина», принимается по умолчанию) задаёт нормальный режим выполнения сервлета, когда множественные запросы обрабатываются одновременно с использованием одного экземпляра сервлета, исходя из соображения что автор синхронизировал доступ к переменным этого экземпляра. Значение false («ложь») сигнализирует о том, что сервлет должен наследовать SingleThreadModel (однопоточную модель), при которой последовательные или одновременные запросы обрабатываются отдельными экземплярами сервлета. Другими словами значение true приведёт к тому, что контейнер может посылать сервлету сразу несколько запросов, в то время как при значении false контейнер посылает запросы по одному. Пример использования выглядит так:

<% @ page isThreadSafe=”false ” %>

  • info="информация". Задаёт строку, которая может быть получена при использовании метода Servlet.getServletInfo(). Обычно этот метод возвращает информацию о сервлете (например, авторе, версии и авторских правах). Пример записи данного атрибута может выглядеть следующим образом:

<% @ page info=” версия:1.0 ” %>

  • errorPage="url". Задаёт JSP страницу, которая вызывается в случае возникновения каких-либо событий Throwables , которые не обрабатываются на данной странице. Случится ли на JSP странице исключение и JSP страница не имеет собственного кода для решения этого исключения, то контейнер автоматически передаст управление на URL , которую Вы задали в качестве значения атрибута errorPage . Пример записи выглядит так:

<% @ page errorPage=“/myweb/errors/myerror.jsp “ %>

  • isErrorPage="true|false". Данный атрибут может принимать значения true или false . Сигнализирует о том, может ли эта страница использоваться для обработки ошибок для других JSP страниц или нет. По умолчанию принимается значение false («ложь»). Пример использования данного атрибута может выглядеть следующим образом:

<% @ page isErrorPage=”true ” %>

  • contentType="MIME-Тип". Данный атрибут задаёт тип MIME для вывода и по желанию можно задать кодировку знаков в ответе (HTML ответе). По умолчанию в качестве значения MIME используется text/html . Для наглядности можем использовать следующий пример:

<% @ page contentType="text/plain" %>

Того же результата можно добиться и использованием скриплета:

<% response.setContentType ("text/plain" ) ; %>

Директива JSP include

Эта директива позволяет Вам включать файлы в сервлет в процессе трансляции JSP страницы. Использование директивы выглядит следующим образом:

<% @ include file="относительный url" %>

Заданный URL обычно интерпретируется относительно JSP страницы, на которой расположена ссылка, но, как и при использовании любых других относительных URL вы можете задать системе положение интересующего вас ресурса относительно домашнего каталога Web сервера, добавив в начало URL символ «/ ». Содержимое подключаемого файла обрабатывается как обычный текст JSP и поэтому может включать такие элементы как статический HTML , элементы скриптов, директивы и действия. Например, многие сайты используют небольшую панель навигации на каждой странице. В связи с проблемами использования фреймов HTML часто эта задача решается размещением небольшой таблицы сверху или в левой половине страницы, HTML код которой многократно повторяется для каждой страницы сайта. Директива include наиболее естественный способ решения этой задачи, избавляющий разработчика от кошмара рутины копирования HTML в каждый отдельный файл. Это происходит следующим образом:

< html> < head> < title> Тестовая страница< /title> < /head> < body> <% @ include file="/navbar.html" %> < /body> < /html>

Учтите что поскольку директива include подключает файлы в ходе трансляции страницы, то после внесения изменений в панель навигации вам потребуется повторная трансляция всех использующих её JSP страниц. Что в данном случае является хорошим компромиссом, поскольку как правило панель навигации меняется достаточно редко и процесс подключения не теряет своей эффективности. Если же подключённые файлы меняются довольно часто, вы можете использовать вместо этого действие jsp:include . Это действие подключает файл в процессе обращения к JSP.

Директива JSP taglib

Как уже известно, в JSP страницах элементы записываются с помощью знаков (условных знаков, меток, марок). Множество знаков, которые JSP контейнер способен истолковать, можно расширить с помощью так называемых библиотек знаков. Также к расширенному множеству знаков можно присоединять действия, вследствие чего происходит расширение самого языка JSP. Действия можно разделить на стандартные и собственные. Обобщённый способ записи может выглядеть так:

<% @ taglib uri=”URI к библиотеке знаков” prefix=“префикс знака“ %>

Библиотеку знаков необходимо идентифицировать с помощью URI адреса (уникального идентификатора ресурса). URI может быть как абсолютным так и отностительным. Уникальный идентификатор ресурса определяет расположение библиотеки знаков (TLD), который определяет собственные знаки этой библиотеки. Пример записи директивы:

<% @ taglib uri=”http://www.moywebserver.ru/naydiznaki.tld” prefix=”iskat” %>

JSP страница может содержать бесконечное кол-во директив taglib , но для каждой директивы необходимо установить различные префиксы, которые определяют содержимое библиотеки на странице. В качестве префикса можете использовать какой угодно текст, слово. В то время, как директиву taglib можно использовать где угодно на JSP странице, все собственные знаки, которые эти директивы используют, должны использоваться за ними.

Действия

Действия JSP используют конструкции с синтаксисом XML для управления работой движка сервлета. Вы можете динамически подключать файл, многократно использовать компоненты JavaBeans , направить пользователя на другую страницу или сгенерировать HTML для Java plugin. Все эти действия детально рассмотрены далее. Помните что как и во всем XML , имена элементов и атрибутов регистрозависимы. Действия можно разделить на две группы: стандартные и созданные (собственные, что создает сам программист). Допустимо применение следующих стандартных действий:

  • jsp:declaration - Объявление, аналогичен тегу <%! … %>;
  • jsp:scriptlet - Скриптлет, аналогичен тегу <% … %>;
  • jsp:expression - Выражение, аналогичен тегу <%= … %>;
  • jsp:text - Вывод текста;
  • jsp:useBean - Поиск или создание нового экземпляра JavaBean;
  • jsp:setProperty - Установка свойств JavaBean;
  • jsp:getProperty - Вставить свойство JavaBean в поток вывода;
  • jsp:include - Подключает файл в момент запроса страницы;
  • jsp:forward - Перенаправляет запрос на другую страницу;
  • jsp:param - Добавляет параметры в объект запроса, например в элементах forward, include, plugin.;
  • jsp:plugin - Генерирует код (в зависимости от типа используемого броузера), который создает тег OBJECT или EMBED для Java plugin;
  • jsp:params - Группирует параметры внутри тега jsp:plugin;
  • jsp:fallback - Указывает содержимое, которое будет использоваться браузером клиента, если подключаемый модуль не сможет запуститься. Используется внутри элемента plugin.

Действие jsp:useBean

Это действие позволяет загружать JavaBean для последующего использования на JSP странице. Эта возможность позволяет многократно использовать классы Java, не отказываясь при этом от преимуществ, предоставляемых сервлетами JSP. Помимо этого, это один из способов, как большую часть обработки Java исключить из JSP страницы. Если перенести обработку Java из JSP страницы до JavaBean, то потом эти функции можно использовать и в остальных JSP страницах. Простейший синтаксис для указания используемого bean:

< jsp:useBean id="имя" class ="пакет.class" />

Как правило это означает «создание нового экземпляра объекта класса, заданного через class , и его связь с переменной с именем, заданным при помощи id ». Однако можно задать атрибут scope (принимает значения page|request|session|application , page для страницы, request для запросов, session для сессий или диалогов, application для аппликаций), который ассоциирует bean не только с текущей страницей. В таком случае, полезно получить ссылки на существующие beans , и действие jsp:useBean создает экземпляр нового объекта лишь в том случае если не существует ни одного объекта с теми же значениями id и scope . Теперь, когда у вас есть bean , вы можете изменять его свойства при помощи действия jsp:setProperty , или используя для этого скриплет и явно вызывая метод объекта с именем переменной заданном ранее через атрибут id . Recall that with beans , когда вы говорите «у этого bean есть свойство типа X с названием foo », вы на самом деле имеете ввиду «у этого класса есть метод getFoo , который возвращает данные типа X, и другой метод setFoo , которому в качестве параметра передается X.» Действие jsp:setProperty более подробно рассмотрено в следующем разделе, но сейчас вы должны запомнить что вы можете либо явно задавать value , задавая атрибут param , чтобы получить значение из соответствующего параметра запроса, или просто перечислить свойства, чтобы получить значения из параметров запроса с теми же именами что и свойства. Вы можете получить значения существующих свойств при помощи выражений JSP или скриплетов, вызвав соответствующий метод getXxx , или (чаще всего), воспользовавшись действием jsp:getProperty .

Класс, заданный для bean, должен находиться в обычном каталоге классов сервера, а не в части, зарезервированной для классов, автоматически перезагружаемых после редактирования. Например, для Java Web Server, все используемые классы должны размещаться в каталоге classes или в .jar файле каталога lib , а не в каталоге servlets . Ниже приведен простой пример, загружающий bean и устанавливающий/получающий простой строковый параметр.

BeanTest.jsp

"-//W3C//DTD HTML 4.0 Transitional//EN" > < html> < head> < title>< /title> < /head> < body> < h1> Многократное использование JavaBeans в JSP< /h1> < jsp:useBean id="test" class ="hall.SimpleBean" /> < jsp:setProperty name="test" property="message" value="Привет, WWW" /> < p> Сообщение: < jsp:getProperty name="test" property="message" /> < /p> < /body> < /html>

SimpleBean.java

Package hall ; public class SimpleBean { private String message = "Текст сообщения не задан" ; public String getMessage() { return (message) ; } public void setMessage(String message) { this .message = message; } }

Еще несколько деталей о использовании jsp:useBean . Простейший способ использовать bean - это использование конструкции:

< jsp:useBean id="имя" class ="пакет.class" />

для загрузки bean , а затем использовать jsp:setProperty и jsp:getProperty для модификации и получения его свойств (параметров). Однако существуют еще два других способа. Во-первых, вы можете использовать формат контейнера, а именно:

< jsp:useBean ...> Тело < /jsp:useBean>

для того чтобы обеспечить выполнение Тела только в том случае, если экземпляр bean создается впервые, а не тогда, когда находится и используется уже существующий bean . Как обсуждается далее, beans могут совместно использоваться, поэтому не каждое выражение jsp:useBean приводит к созданию экземпляра нового bean . Во-вторых, кроме id и class , существуют еще три других атрибута, которые вы можете использовать: scope , type , и beanName . Эти атрибуты описаны далее:

  • id - дает имя переменной, которая ссылается на bean . Если удается найти bean с теми же самыми значениями id и scope , то вместо создания нового экземпляра используется ранее созданный объект;
  • class - задает полное имя пакета bean ;
  • scope - задает область, в которой bean должен быть доступен. Может принимать четыре допустимых значения: page , request , session и application . По умолчанию принимает значение page , означающее что bean доступен только на текущей странице (размещается в PageContext текущей страницы). Значение request означает что bean доступен только для текущего запроса клиента (размещается в объекте ServletRequest). Значение session означает что объект доступен всем страницам на протяжении жизни текущей HttpSession . И, наконец, значение application означает что он доступен всем страницам, использующим тот же самый ServletContext . Причина необходимости этого атрибута заключается в том что jsp:useBean приводит к созданию нового экземпляра объекта в том случае, если нет уже существующего объекта с тем же id и scope . Иначе используется уже существующий объект, и все элементы jsp:setParameter или любые другие между тегами jsp:useBean игнорируются.
  • type - указывает тип переменной, которая ссылается на объект. Должен совпадать с именем класса, суперкласса или реализуемого интерфейса. Запомните что имя переменной задается через атрибут id .
  • beanName - дает имя bean , которое будет использовано методом instantiate . Можно задать type и beanName , и опустить атрибут class .

Действие jsp:setProperty

Вы можете использовать jsp:setProperty для присвоения значений свойствам ранее описанных beans . Вы можете делать это двумя способами. Во-первых, вы можете использовать jsp:setProperty после, но вне элемента jsp:useBean , так как это показано в примере:

< jsp:useBean id="myName" ... /> ... < jsp:setProperty name="myName" property="someProperty" ... />

В этом случае jsp:setProperty выполняется независимо от того, был ли найден существующий bean или был создан новый экземпляр. Другим вариантом заключается в размещении jsp:setProperty в теле элемента jsp:useBean , как это показано в другом примере:

< jsp:useBean id="myName" ... > ... < jsp:setProperty name="myName" property="someProperty" ... /> < /jsp:useBean>

При этом jsp:setProperty выполняется лишь в том случае, если был создан новый экземпляр объекта, а не тогда, когда находится уже существующий. Действие jsp:setProperty допускает применение следующих четырех атрибутов:

  • name - этот обязательный атрибут служит для задания bean , свойства которого будут устанавливаться. Элемент jsp:useBean должен предшествовать использованию элемента jsp:setProperty .
  • property - этот обязательный атрибут устанавливает свойство, которое вы хотите установить. Однако существует частный случай: значение «* » означает что все параметры запроса, чьи имена совпадают с именами свойств bean будут переданы соответствующему методу установки свойств.
  • value - этот необязательный атрибут устанавливает значение свойства. Строковые значения автоматически преобразуются в числовые, boolean , Boolean , byte , Byte , char и Character с использованием стандартного метода valueOf соответствующего класса. Например, значение "true" для свойства boolean или Boolean будет конвертированно при помощи метода Boolean.valueOf , а значение «42» для свойства int или Integer будет конвертированно при помощи метода Integer.valueOf . Вы не можете одновременно использовать атрибуты value и param , но можете вообще их не использовать. Ознакомьтесь с описанием атрибута param , которое представлено ниже.
  • param - этот необязательный атрибут устанавливает параметр запроса, используемый для получения свойства. Если в текущем запросе этот параметр отсутствует, никаких действий не происходит: система не передает значение null методу устанавливающему свойства. Таким образом, допустимо использование в bean свойств по умолчанию, переопределяя их лишь в том случае если этого требуют параметры запроса. Например, следующий фрагмент означает следующее: «установить свойство numberOfItems в соответствии со значением параметра запроса numItems , а если такой параметр в запросе отсутствует - никакие действия не выполняются.»

< jsp:setProperty name="orderBean" property="numberOfItems" param="numItems" />

Если вы не используете ни value , ни param , это приравнивается к тому, как если бы вы задали имя param совпадающее с именем property . Вы можете применить этот принцип автоматического использования свойств запроса, чьи имена совпадают с именами свойств и пойти далее, задав в качестве имени свойства «* » и опустив параметры value и param . В этом случае сервер обработает допустимые свойства и параметры запроса, на предмет совпадения их с идентичными именами. Далее приведен пример в котором используется bean для создания таблицы простых чисел. Если существует параметр numDigits в данных запроса, он передается в свойство bean numDigits . Аналогично для numPrimes . JspPrimes.jsp

"-//W3C//DTD HTML 4.0 Transitional//EN" > < html> < head> < title> Многократное использование JavaBeans в JSP< /title> < /head> < body> < h1> Многократное использование JavaBeans в JSP< /h1> < jsp:useBean id="primeTable" class ="hall.NumberedPrimes" /> < jsp:setProperty name="primeTable" property="numDigits" /> < jsp:setProperty name="primeTable" property="numPrimes" /> < p> Несколько < jsp:getProperty name="primeTable" property="numDigits" /> символьных простых чисел: < jsp:getProperty name="primeTable" property="numberedList" /> < /p> < /body> < /html>

Действие jsp:getProperty

Этот элемент определяет значение свойства bean , конвертирует его в строку и направляет в поток вывода. Для выполнения действия требуется задание двух атрибутов: имени bean , которое предварительно задается в действии jsp:useBean , и имя свойства, значение которого должно быть определено. Далее приведен пример использования этого действия:

< jsp:useBean id="itemBean" ... /> ... < UL> < LI> Количество предметов: < jsp:getProperty name="itemBean" property="numItems" /> < LI> Цена за штуку: < jsp:getProperty name="itemBean" property="unitCost" /> < /UL>

Действие jsp:include

Это действие позволяет вставлять содержимое файлов в генерируемую страницу. Синтаксис действия:

< jsp:include page="относительный URL" flush="true" />

В отличие от директивы include , которая вставляет файл на этапе трансляции JSP страницы, это действие вставляет файл при запросе страницы. Это приводит к некоторой потере эффективности и исключает возможность наличия во вставляемом файле кода JSP, но зато дает существенное преимущество в гибкости.

Пример вставки содержимого четырех файлов в JSP-страницу:

"http://www.w3.org/TR/html4/strict.dtd" > < html> < head> < title> Новости< /title> < /head> < body> < h1> Новости< /h1> < p> Вот фрагменты наших четырех самых популярных статей:< /p> < ol> < li>< jsp:include page="news/Item1.html" flush="true" />< /li> < li>< jsp:include page="news/Item2.html" flush="true" />< /li> < li>< jsp:include page="news/Item3.html" flush="true" />< /li> < li>< jsp:include page="news/Item4.html" flush="true" />< /li> < /ol> < /body> < /html>

Действие jsp:forward

Это действие позволяет вам передать запрос другой статической HTML странице, сервлету или JSP странице. В отличие от действия jsp:include обработка актуальной страницы заканчивается. Оно использует один атрибут page , который должен содержать относительный URL и на основании которого упорядочен объект request . К исходным параметрам запроса, которой передается другой странице, можете с помощью действия jsp:param добавить и другие параметры. Значением атрибута page может быть как статическое значение, так и вычисляемое в процессе запроса, что и показано на следующих двух примерах:

< jsp:forward page="/utils/errorReporter.jsp" /> < jsp:forward page="<%= какое-нибудьВыражениеНаJava %>" />

Также с помощью действия jsp:forward можно передать управление на другую страницу, но с условием, что перед вызовом этого действия ничего не было записано в выходящую буферную память (иначе будет вызвано исключение IllegalStateException).

Действие jsp:param и действие jsp:params

Это действие предоставляет информацию типа название/значение. Данное действие используется в основном вместе со знакомыми уже действиями jsp:include и jsp:forward . Кроме этого его можно использовать и вместе с действием jsp:plugin . В остальных случаях использование этого действия не имеет значения. Использование jsp:param с действиями jsp:include и jsp:forward передаться новым страницам исходный объект request , который будет расширен на новые параметры. Если Вы зададите новые значения для уже существующих параметров, то именно новые значения будут иметь преимущество. С помощью действия jsp:params можно задать сразу несколько параметров

Действие jsp:plugin

Это действие позволяет вам вставить элемент OBJECT или EMBED (в зависимости от типа используемого браузера), необходимый для запуска аплетов, использующих plugin Java. Другими словами данное действие служит к генерированию HTML для вложения Java API в JSP страницу. Таким же образом можете вставлять URL для скачивания модулей для Java API от JavaSoft, который предоставляет возможность запускать аплеты внутри браузера. Форма записи данного действия выглядит следующим образом.