Учебный курс по электронной коммерции в NetBeans - управление сеансами

This tutorial needs a review. You can open a JIRA issue, or edit it in GitHub following these contribution guidelines.
netbeans stamp 68 69
Figure 1. Содержимое на этой странице применимо к IDE NetBeans, версии 6.8 и 6.9

Каждое приложение электронной коммерции, предлагающее какие-либо возможности корзины покупок, должно обладать функцией запоминания пользовательских данных в процессе перехода по веб-страницам/страницам веб-сайта. К сожалению, протокол HTTP, посредством которого осуществляется взаимодействие в Интернете, является протоколом без поддержки состояния. Каждый запрос, получаемый сервером, является независимым элементом данных, не связанным с ранее поступившими запросами. Поэтому при нажатии кнопки для добавления товара в корзину покупок приложение должно не только обеспечивать обновление корзины пользователя, но и предупреждать влияние данной корзины на корзины других пользователей, просматривающих сайт в это же время.

Чтобы правильно обработать описанный выше сценарий, необходимо реализовать функцию для создания и ведения сеанса на протяжении пребывания пользователя на сайте. Технология сервлета, являющаяся основой для всех веб-приложений на базе Java, предоставляет для этих целей интерфейс `HttpSession`. Также необходимо определить некоторые классы, а именно ShoppingCart и ShoppingCartItem, что позволит приложению хранить данные пользователя, пока время сеанса не истекло.

Подход данного раздела учебного курса отличается от остальных подходов, рассматриваемых в учебном курсе по электронной коммерции NetBeans. Вместо создания файлов проекта и предоставления пошаговых инструкций с фрагментами кода для копирования и вставки в собственный проект предлагается открыть пример готового проекта для данного раздела и изучить код при помощи отладчика среды IDE и других средств. В процессе работы будут изучены способы применения объекта HttpSession к коду, чтобы в результате каждого посещения веб-сайта создавался отдельный сеанс. Также будут рассмотрены контекстные переменные и их использование как в классах Java, так и на страницах JSP. Кроме того, в этом разделе описывается стандартный механизм HttpSession для ведения сеансов (например файлов cookie) и пошаговые инструкции, которые необходимо выполнить в случае деактивации файлов cookie в браузере пользователя. В заключение затрагивается время ожидания сеанса и демонстрируется принцип его обработки с созданием элементарного фильтра, перехватывающего запросы для проверки существования сеанса.

Можно просмотреть интерактивную демонстрацию приложения, которое создается в этом учебном курсе: Демонстрация приложения электронной коммерции NetBeans

Программное обеспечение или материал Требуемая версия

IDE NetBeans

Набор Java, версия 6.8 или 6.9

Комплект для разработчика на языке Java (JDK)

версия 6

Сервер GlassFish

v3 или Open Source Edition 3.0.1

Сервер базы данных MySQL

Версия 5.1

Проект AffableBean

снимок 5

Примечания:

  • The IDE NetBeans requires the Java Development Kit (JDK) to run properly. Если указанные материалы не установлены, JDK следует загрузить и установить в первую очередь.

  • The IDE NetBeans Java Bundle includes Java Web and EE technologies, which are required for the application you build in this tutorial.

  • The IDE NetBeans Java Bundle also includes the GlassFish server, which you require for this tutorial. Можно загрузить сервер GlassFish отдельно, но версия, предоставляемая с NetBeans, имеет преимущество, так как автоматически зарегистрирована в среде IDE.

  • Этот учебный курс можно выполнять без выполнения предыдущих. Для этого обратитесь к инструкциям по настройке, в которых описана подготовка базы данных и настройка подключений между IDE, GlassFish, и MySQL.

Обработка данных сеанса

Приложения могут управлять пользовательскими сеансами при помощи объекта HttpSession. Можно привязать пользовательские данные к объекту HttpSession и получить возможность доступа к этим данным на дальнейших этапах. Операции привязки и доступа могут быть выполнены при помощи классов Java, а также переменных в контексте сеанса в выражениях на языке выражений.

Работа с объектом HttpSession

В приложении AffableBean используется объект HttpSession для идентификации пользователей при неоднократных запросах. Объект HttpSession можно получить при помощи метода getSession() для заданного запроса:

HttpSession session = request.getSession();

Если объект сеанса для запроса еще не существует, метод создает и возвращает новый объект сеанса.

Объект сеанса можно использовать в качестве средства для передачи данных между запросами. Метод setAttribute используется для привязки объектов к сеансу. Таким же образом метод getAttribute используется для извлечения объектов из сеанса. Например, в приложении AffableBean корзина покупок пользователя создается и привязывается к пользовательскому сеансу следующим образом:

ShoppingCart cart = new ShoppingCart();
session.setAttribute("cart", cart);

Для извлечения корзины из сеанса применяется метод getAttribute:

cart = (ShoppingCart) session.getAttribute("cart");

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

${cart}

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

  • удвоенный итог

  • int numberOfItems

  • List<String, ShoppingCartItem> items

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

<p>Your shopping cart contains ${cart.numberOfItems} items.</p>

Для извлечения данных из свойств с несколькими значениями, например списка items, приведенного выше, на странице cart.jsp используется цикл <c:forEach>:

<c:forEach var="cartItem" items="${cart.items}" varStatus="iter">

  <c:set var="product" value="${cartItem.product}"/>

    <tr class="${((iter.index % 2) == 0) ? 'lightBlue' : 'white'}">
        <td>
            <img src="${initParam.productImagePath}${product.name}.png"
                 alt="${product.name}">
        </td>

        <td>${product.name}</td>

        <td>
            &amp;euro; ${cartItem.total}
            <br>
            <span class="smallText">( &amp;euro; ${product.price} / unit )</span>
        </td>
        ...
    </tr>

</c:forEach>

Принадлежащая ShoppingCartItem собственность product определяет тип продукта для элемента корзины. Цикл, рассматриваемый выше, использует результаты определения при первой установке переменной product в выражении ${cartItem.product}. Затем переменная используется для получения сведений об этом продукте (например имя, цена).

Работа с контекстными переменными в веб-приложениях

При работе с технологией JSP/сервлетов доступны четыре контекстных объекта в области приложения. Технология JSP реализует скрытые объекты, позволяющие получить доступ к классам, определяемым интерфейсом API сервлетов.

Контекст Определение Класс сервлетов Скрытые объекты JSP

Приложение

Глобальная память веб-приложения

+javax.servlet.ServletContext+

applicationScope

Сеанс

Данные пользовательского сеанса

+javax.servlet.http.HttpSession+

sessionScope

Запрос

Данные отдельного запроса сервера

+javax.servlet.HttpServletRequest+

requestScope

Страница

Данные, действительные только в контексте отдельной страницы (только JSP)

неприменимо

pageScope

При открытии файла category.jsp проекта в редакторе обратите внимание, что выражения на языке выражений включают в себя различные контекстные переменные, в частности, ${categories}, ${selectedCategory} и ${categoryProducts}. Переменная ${categories} находится в контексте приложения, устанавливаемого в методе init файла ControllerServlet:

// store category list in servlet context
getServletContext().setAttribute("categories", categoryFacade.findAll());

Остальные переменные, ${selectedCategory} и ${categoryProducts}, размещаются в контексте сеанса приложения в файле ControllerServlet. Например:

// place selected category in session scope
session.setAttribute("selectedCategory", selectedCategory);

Примечание. Если изучить предыдущие разделы руководства, можно заметить, что ${selectedCategory} и ${categoryProducts} были изначально помещены в область запроса. В предыдущих разделах такое размещение было целесообразным, но рассмотрим, что случится, если пользователь нажмет кнопку "добавить в корзину" на странице категорий. В ответ на запрос addToCart сервлет возвратит текущую страницу категорий. Таким образом нужно будет получить информацию о selectedCategory и categoryProducts, относящихся к выбранной категории. Вместо того чтобы узнавать данную информацию о каждом запросе, достаточно поместить ее в область сеанса запроса category, так чтобы она поддерживалась многими запросами и могла быть получена, когда в ней возникнет необходимость. Рассмотрим также функциональность страницы корзины. (Функции описываются ниже). Кнопка "Продолжить покупки" возвращает пользователя в предыдущую просмотренную категорию. Опять же запрашиваются переменные selectedCategory и categoryProducts.

При ссылке на контекстные переменные в выражении на языке выражений нет необходимости в указании контекста переменной (при условии отсутствия двух переменных с одинаковым именем в различных контекстах). Механизм JSP выполняет проверку всех четырех контекстов и возвращает первое найденное соответствие переменных. Например, в файле category.jsp выражение

${categoryProducts}

является сокращением для

${sessionScope.categoryProducts}

Для получения дополнительных сведений ознакомьтесь со следующими материалами:

Изучение данных сеанса при помощи отладчика Java

Начало изучения принципов поведения приложения во время выполнения. Используйте отладчик среды IDE для перехода по коду и изучения способов создания объекта HttpSession и размещения прочих объектов в контексте сеанса для их дальнейшего извлечения.

  1. Откройте пример проекта для данного раздела учебного курса в среде IDE. В диалоговом окне "Открытие проекта" ( open project btn ) перейдите к папке на компьютере, в которой хранится разархивированный файл учебного проекта. Если изучить предыдущий раздел руководства, можно заметить, что снимок проекта включает новый пакет cart, содержащий классы ShoppingCart и ShoppingCartItem. Также изменены следующие файлы:

    • WEB-INF/web.xml

    • css/affablebean.css

    • WEB-INF/jspf/header.jspf

    • WEB-INF/jspf/footer.jspf

    • WEB-INF/view/cart.jsp

    • WEB-INF/view/category.jsp

    • WEB-INF/view/checkout.jsp

    • controller/ControllerServlet

  1. Запустите проект ( run project btn ), чтобы убедиться, что этот проект правильно настроен с помощью используемой базы данных и сервера приложений.

Если при выполнении проекта выводится сообщение об ошибке, еще раз обратитесь к указаниям по настройке, в которых описаны принципы подготовки базы данных и установки соединения между средой IDE, сервером GlassFish и MySQL.

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

страница категории

  • Первое нажатие кнопки "add to cart" активирует корзину покупок и виджеты "proceed to checkout", отображаемые в заголовке.

  • Нажатие кнопки "add to cart" приводит к обновлению числа товаров в виджете корзины покупок в заголовке.

  • В результате щелчка ссылки "view cart" отображается страница корзины.

  • При щелчке ссылки "proceed to checkout" открывается страница кассы.

category page
Figure 2. IDE NetBeans включает функции отладки.

страница корзины покупок

  • Щелчок ссылки "clear cart" обеспечивает удаление всех товаров из корзины покупок.

  • В результате щелчка ссылки "continue shopping" выполняется возврат к ранее просматриваемой категории.

  • При щелчке ссылки "proceed to checkout" открывается страница кассы.

  • Ввод числа (от 1 до 99) в поле количества товара и нажатие кнопки "update" запускает повторный расчет общей стоимости товара, а также промежуточной суммы.

  • При вводе нуля в поле количества товара и нажатии кнопки "update" товар удаляется из отображаемой таблицы.

cart page
Figure 3. IDE NetBeans включает функции отладки.

страница проверки

  • В результате щелчка ссылки "view cart" отображается страница корзины.

  • В результате нажатия "подтвердить покупку" на странице подтверждения отображаются результаты покупки (без указания информации о пользователе).

checkout page
Figure 4. Страница кассы включает функцию покупательской корзины
  1. Используйте диалоговое окно "Перейти к файлу", чтобы открыть файл ControllerServlet в редакторе. Нажмите ALT+SHIFT+O (CTRL+SHIFT+O в Mac OS), затем введите “Controller” в поле диалога и нажмите кнопку "ОК".

go to file dialog
Figure 5. С помощью диалогового окна
  1. Установите точку останова в методе doPost на строке, которая создает объект HttpSession (строка 150). Для установки точки останова щелкните в левом поле редактора.

breakpoint
Figure 6. Щелкните левую границу редактора для задания точек останова

Для переключения номеров строк в редакторе щелкните правой кнопкой мыши в левом поле и выберите команду "Показать номера строк".

  1. Запустите отладчик. Нажмите кнопку 'Отладка проекта' (debug project btn) на главной панели инструментов IDE. Сервер GlassFish запускается (или перезапускается, если уже работал ) и открывает подключение через сокет по его отладочному номеру порта. В браузере откроется страница приветствия приложения.

Можно просматривать и изменять номер порта отладки в диалоговом окне "Серверы" ("Сервис" > "Серверы"). Выберите вкладку "Java" для используемого сервера. Укажите номер порта в поле "Используемый адрес" под заголовком "Параметры отладки".

  1. При выводе страницы приветствия в браузере выберите категорию и добавьте несколько элементов в корзину покупок. Следует помнить, что нажатие кнопки "add to cart" отправляет запрос addToCart на сервер:

<form action="addToCart" method="post">

Как уже было описано в разделе Подготовка представлений страницы и сервлета контроллера, принадлежащий ControllerServlet метод doPost поддерживает запросы URL-адреса шаблона /addToCart. Следовательно, при нажатии кнопки "add to cart" ожидается вызов метода doPost.

  1. Нажмите кнопку "add to cart" для любого элемента на странице категорий. Перейдите к среде IDE и обратите внимание, что отладчик приостановил работу в точке останова.

breakpoint suspended
Figure 7. Отладчик приостанавливает работу по достижении точек останова, заданных в редакторе
  1. Поместите курсор в месте вызова метода getSession() и нажмите сочетание клавиш CTRL+ПРОБЕЛ для вывода документации Javadoc.

javadoc getsession
Figure 8. Нажмите Ctrl-Space для вызова документации Javadoc

В соответствии с документацией метод getSession() возвращает объект HttpSession, связанный в настоящее время с запросом, и (при отсутствии сеанса) создает новый объект сеанса.

Использование поддержки документации Javadoc в среде IDE

Среда IDE предоставляет встроенную поддержку документации Javadoc для разработки на базе Java EE. Среда IDE связывается со спецификацией интерфейса API Java EE 6, доступной во внешнем браузере по пути "Справка" > "Справочные сведения Javadoc" > "Java EE 6".

Также среда IDE включает в себя различные функции, позволяющие получить быстрый доступ к документации интерфейса API:

  • Диалоговое окно документации Javadoc: выберите "Окно" > "Прочее" > "Javadoc". В нижней области среды IDE откроется диалоговое окно "Javadoc", в котором отобразится документация интерфейса API, релевантная для позиции курсора в редакторе.

  • Поиск документации по индексу: выберите в меню "Справка" пункт "Поиск документации по индексу" (SHIFT+F1; fn+SHIFT+F1 в системе Mac). Введите имя искомого класса и выберите класс из списка результатов поиска. Полное описание класса в спецификации интерфейса API отображается на нижней панели диалогового окна.

  • Всплывающее окно документации в редакторе: документация Javadoc отображается во всплывающем окне при нажатии сочетания клавиш CTRL+ПРОБЕЛ для определенного элемента в редакторе. Можно нажать кнопку 'Внешний браузер' ( external browser btn ) для открытия документации в используемом браузере. Для использования сочетания клавиш CTRL+ПРОБЕЛ только для автозавершения кода можно деактивировать всплывающее окно документации, открыв диалоговое окно "Параметры" ("Сервис" > "Параметры"; "NetBeans" > "Параметры" для системы Mac), и затем выбрав в меню "Редактор" пункт "Автозавершение кода". Отмените выбор параметра "Автоматический вызов окна документации".

При документировании собственной работы рекомендуется добавить комментарии документации Javadoc к классам и методам. Откройте класс ShoppingCart и изучите комментарии документации Javadoc, добавленные к методам класса. Комментарии документации Javadoc отмечены парными символами /** …​ */. Например, для метода addItem добавлен следующий комментарий:

/**
 * Adds a <code>ShoppingCartItem</code> to the <code>ShoppingCart</code>'s
 * <code>items</code> list. If item of the specified <code>product</code>
 * already exists in shopping cart list, the quantity of that item is
 * incremented.
 *
 * @param product the <code>Product</code> that defines the type of shopping cart item
 * @see ShoppingCartItem
 */
public synchronized void addItem(Product product) {

Это позволяет разработчикам просматривать документацию Javadoc по методу. Для демонстрации откройте 'Навигатор' (Ctrl-7; ⌘-7 в Mac) и подведите курсор мыши к методу addItem.

javadoc additem
Figure 9. Подведите курсор мыши к 'Навигатору' для просмотра документации Javadoc

Также можно использовать среду IDE для создания набора страниц HTML документации Javadoc. В окне "Проекты" щелкните правой кнопкой мыши узел проекта и выберите пункт "Создание документации Javadoc". Среда IDE создает документацию Javadoc в папке dist/javadoc каталога проекта и открывает страницу-указатель в браузере.

Для получения дополнительных сведений о документации Javadoc обратитесь к следующим ресурсам:

  1. Наведите курсор на переменную session. Обратите внимание, что отладчик приостанавливает работу на строке, которая должна быть запущена в нем. Значение, возвращаемое getSession() еще не сохранено в переменной session и отображается всплываюшщее окно, в котором указывается, что "`session` не является известной переменной в текущем контексте".

session variable
Figure 10. Наведите курсор на переменные и выражения для определения их текущих значений
  1. Нажмите кнопку 'Обход процедур' (step over btn) в отладчике на панели инструментов, расположенной выше в редакторе. Строка обрабатывается, и отладчик переходит к следующей строке файла.

  1. Снова наведите курсор на переменную session. Можно увидеть, что текущее значение сохранено в переменной session.

session variable set

В NetBeans 6.9 можно щелкнуть серый указатель ( grey pointer ) во всплывающем окне, чтобы расширить список значений переменных, содержащихся в выделенном элементе.

  1. Нажмите кнопку 'Обход процедур' ( step over btn ) (F8; fn-F8 в Mac) для перехода к оператору if (строка 154). Поскольку в браузере только что была нажата кнопка "add to cart", выражение userPath.equals("/addToCart") должно иметь значение true.

  1. Выделите выражение userPath.equals("/addToCart") (нажав клавишу CTRL и щелкнув клавишей мыши). При этом будет выведено всплывающее окно со значением выделенного выражения.

expression
Figure 11. Выделите выражения для определения их текущих значений
  1. Нажмите клавишу F8 (fn-F8 в Mac OS) для перехода к следующей строке (строка 158). Приложение спроектировано таким образом, что объект ShoppingCart создается для пользовательского сеанса только при первом добавлении элемента в корзину пользователя. Поскольку запрос addToCart в этом сеансе отладки получен впервые, предполагается, что объект cart имеет значение null.

cart null
Figure 12. Объект покупательской корзины появляется только после добавления пользователем элемента к покупательской корзине
  1. Нажмите клавишу F8 (fn-F8 в Mac OS) для перехода к следующей линии (линия 160). Затем в строке 160, где создан объект ShoppingCart, нажмите кнопку 'Вход в' ( step into btn ). Отладчик переходит к вызываемому методу. В этом случае выполняется переход непосредственно к конструктору файла ShoppingCart.

cart constructor
Figure 13. Перейдите к методам для отслеживания этапа выполнения для других классов
  1. Нажмите сочетание клавиш CTRL+TAB для перехода к файлу ControllerServlet. Обратите внимание, что IDE предоставляет значок 'Стек вызовов' ( call stack badge ) в строке 160, указывая, что отладчик в настоящее время приостановлен где-то на методе выше в стеке вызовов.

Нажмите ALT+SHIFT+3 (CTRL+SHIFT+3 в Mac OS), чтобы открыть окно стека вызовов.

  1. Нажмите клавишу F8 (fn+F8 в системе Mac) для продолжения перехода по коду. При завершении обработки отладчиком конструктора ShoppingCart выполняется возврат к файлу ControllerServlet.

Строка 161 ControllerServlet привязывает вновь созданный объект cart к сеансу.

session.setAttribute("cart", cart);

Чтобы в этом удостовериться, откройте окно переменных отладчика. Выберите "Окно" > "Отладка" > "Переменные" или нажмите ALT+SHIFT+1 (CTRL+SHIFT+1 в Mac OS).

variables win session

При последовательной развертке узлов "session" > "session" > "attributes" можно просмотреть объекты, привязанные к сеансу. На изображении выше отображены два элемента, привязанные в настоящее время к сеансу (выделены на снимке). Это selectedCategory и categoryProducts, показанные в ControllerServlet на строках 83 и 89, соответственно. Оба элемента были привязаны ранее при щелчке изображения категории и обработке запроса страниц категории в файле ControllerServlet.

  1. Нажмите клавишу F8 (fn-F8 в Mac OS) для выполнения кода со строки 161. Объект cart привязывается к сеансу, и диалоговое окно "Переменные" обновляется для отображения изменений. Обратите внимание, что в окне "Переменные" сеанс содержит в настоящий момент три атрибута, третьим атрибутом является только что инициализированный объект ShoppingCart (выделен на снимке ниже).

variables win session cart

Пока что не было "доказано", что сеанс, как указано в диалоговом окне "Переменные", представляет объект HttpSession. Как упоминалось выше, HttpSession фактически является интерфейсом, так что при рассмотрении объекта HttpSession или объекта сеанса фактически имеется в виду любой объект, реализующий интерфейс HttpSession. При наведении курсора мыши в диалоговом окне "Переменные" на элемент session будет выведено всплывающее окно, указывающее на то, что переменная представляет объект HttpSession. Тип StandardSessionFacade, отображенный на снимке, является внутренним классом, используемым сервером GlassFish для реализации интерфейса HttpSession. При наличии опыта работы с Tomcat обратите внимание, что пути org.apache.catalina в столбце "Значение" обусловлены тем, что веб-контейнер/контейнер сервлета GlassFish фактически является производным от контейнера Apache Tomcat.

В сеанс добавляется новый объект ShoppingCart, и запрос продолжает обрабатываться. Для завершения реализации функции "add to cart" предпринимаются следующие действия: * Идентификатор выбранного продукта получается из запроса (строка 165). * Объект Product создается с помощью идентификатора (строка 169). * Новый экземпляр ShoppingCartItem создается с помощью product (строка 170). * Экземпляр ShoppingCartItem добавляется в состоящий из ShoppingCartItem список экземпляров (строка 170).

  1. Нажмите клавишу F8 (fn+F8 в системе Mac OS), чтобы продолжить выполнение перехода по коду с учетом перечисленных выше четырех действий. Сделайте паузу, когда отладчик временно остановится на строке 170.

  1. Создайте наблюдение за сеансом. Эта функция позволит просматривать значения, содержащиеся в сеансе, при переходе к методу addItem в следующем шаге. Щелкните правой кнопкой мыши сеанс в диалоговом окне "Переменные" и выберите команду "Установить постоянное наблюдение".

create watch
Figure 14. Создайте наблюдения за переменными при переходе по коду в сеансе отладки

Кроме того, вы можете поместить курсор на переменной session в редакторе, а затем щелкнуть правой кнопкой мыши и выбрать 'Новое наблюдение'. Диалоговое окно создания наблюдения позволяет определить переменные или выражения для постоянного наблюдения за отладкой приложения. (При использовании выражений, сначала выделите выражение, а затем щелкните правой кнопкой мыши и выберите 'Новое наблюдение').

new watch dialog
Figure 15. Щелкните правой кнопкой мыши переменные и выражения в редакторе и выберите 'Создать наблюдение'

Для переменной session и всех содержащихся в ней переменных создается наблюдение. Наблюдение отображается в окне 'Наблюдения' (Window > 'Отладка' > 'Наблюдения') или при переключении кнопки наблюдений ( watch btn ) на левой границе окна 'Переменные' оно отображается в верхней строке окна 'Переменные'.

Отладчик позволяет наблюдать за переменными по мере перехода по коду. Это важно, например, при отслеживании изменения для отдельных значений переменных (без просмотра полного списка в окне "Переменные" для каждого шага) или при временном переходе к классу, не содержащему рассматриваемые переменные.

  1. Нажмите кнопок 'Вход в' ( step into btn ) для перехода к ShoppingCart к методу addItem.

  1. Последовательно шагайте по методу addItem, пока не достигните строки 53. Согласно документации Javadoc addItem "добавляет элемент`ShoppingCartItem` в список items в файле ShoppingCart. Если указанный товар из списка product уже существует в списке корзины покупок, количество этого товара увеличивается."

  1. Изучите переменную session, для которой был создан параметр наблюдения (шаг 21 выше). Выражение items.add(scItem) на странице 51 добавляет новый экземпляр ShoppingCartItem в список items в ShoppingCart. Этот процесс можно проследить при переходе к третьему атрибуту, содержащемуся в сеансе (например, переменной cart).

variables window add item

На данном этапе можно изучить принцип создания HttpSession для запроса, создания объекта ShoppingCart и его прикрепления к сеансу, а также создания элемента ShoppingCartItem на основе пользовательского выбора продукта с последующим добавлением в список items файла ShoppingCart. Последним действием является переадресация запроса в представление category.jsp.

  1. Откройте в редакторе фрагмент JSP заголовка (header.jspf) и разместите точку останова в строке 86. Эта строка содержит оператор на языке выражений в пределах виджета корзины покупок, отображающего число элементов корзины.

breakpoint jsp
Figure 16. Отладчик можно приостановить на страницах JSP
  1. Нажмите кнопку 'Продолжить' ( continue btn ) на панели инструментов отладчика. Отладчик продолжает работу до завершения обработки или до следующей точки останова. В последнем случае отладчик приостанавливается на строке 86 фрагмента JSP заголовка.

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

  1. Откройте окно переменных (ALT+SHIFT+1; CTRL+SHIFT+1 в системе Mac OS), если оно еще не открыто. В отличие от классов Java отладчик не предоставляет подсказки при наведении курсора мыши на переменные или выражения на странице JSP. Однако диалоговое окно "Переменные" не позволяет определять значения переменных при переходе по коду. Где можно найти значение для переменной ${cart.numberOfItems}?

  1. Последовательно разверните в диалоговом окне "Переменные" узлы "Скрытые объекты" > "pageContext" > "session" > "session" > "attributes". В результате будет предоставлен доступ к объекту сеанса, как и при работе с файлом ControllerServlet. Обратите внимание, что сеанс, для которого на шаге 21 было создано наблюдение, указывает на сам объект. Здесь можно убедиться, что значение переменной ${cart.numberOfItems} составляет “1”.

variables window number of items

Разверните окно 'Переменные' или любое окно в IDE, щелкнув правой кнопкой мыши заголовок окна, а затем выбрав 'Развернуть окно' (Shift-Esc).

Отладчик предоставляет доступ к скрытому объекту pageContext. pageContext предоставляет контекст страницы JSP и открывает прямой доступ к различным объектам, включая объекты HttpServletRequest, HttpSession и ServletContext. Для получения дополнительных сведений обратитесь к Учебному курсу по Java EE 5: скрытые объекты.

  1. Нажмите кнопку 'Завершить сеанс' ( finish session btn ). Работа среды выполнения и сеанса отладки завершается. Браузер отображает страницу категорий с полной визуализацией, и виджет корзины покупок в заголовке страницы содержит один элемент.

Надеемся, что теперь использование отладчика среды IDE не только для анализа проекта при неожиданном поведении, но и в качестве средства изучения кода, не вызывает у вас затруднений. Ниже перечислены другие функциональные кнопки на панели инструментов:

  • ( step out ) Выход. Выполняется выход из вызова текущего метода. Выполняется обработка и удаление самого верхнего вызова метода в стеке вызовов.

  • ( run to cursor ) Переход к курсору Выполнение до строки, на которой размещен курсор.

  • ( apply code changes ) Применить изменения кода. После редактирования файла можно нажать эту кнопку, чтобы файл был повторно скомпилирован и изменения учитывались в сеансе отладки.

  • ( step over expression ) Выражение обхода процедур. Позволяет просматривать входные параметры и получаемые выходные значения всех вызовов методов в выражении. Можно изучить выходные значения для предыдущего метода и входные параметры для следующего метода в диалоговом окне "Локальные переменные". При отсутствии дальнейших вызовов методов, режим работы выражения обхода процедур аналогичено команде Step Over ( step over btn ).

Изучение параметров отслеживания сеанса

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

Проект AffableBean включает в себя пример метода скрытого поля на странице категорий и корзины. Кнопки "add to cart" и "update", отображаемые для элементов продукта, содержат скрытое поле, передающее идентификатор продукта на сервер при нажатии кнопки. При открытии страницы cart.jsp в редакторе можно заметить, что теги <form> содержат скрытое поле.

<form action="updateCart" method="post">
    *<input type="hidden"
           name="productId"
           value="${product.id}">*
    ...
</form>

Таким образом, идентификатор продукта отправляется в виде параметра запроса, используемого сервером для идентификации элемента в пользовательской корзине, количество которой необходимо изменить.

Интерфейс API сервлета предоставляет высокоуровневый механизм для управления сеансами. Фактически он создает и передает файлы cookie между клиентом и сервером в каждом цикле "запрос-ответ". Если браузер клиента не принимает файлы cookie, механизм сервлета автоматически возвращается к перезаписи URL-адреса. Следующие два упражнения демонстрируют работу этой функции.

Изучение обмена данными между сервером и клиентом с использованием монитора HTTP

По умолчанию механизм сервлета использует файлы cookie для ведения и идентификации сеансов между запросами. Для каждого объекта сеанса создается случайный буквенно-цифровой номер, служащий уникальным идентификатором. Этот идентификатор передается в клиент как файл cookie JSESSIONID. При создании запроса клиентом механизм сервлета считывает значение файла cookie JSESSIONID для определения сеанса, к которому относится запрос.

Для наглядности отладчик используется вместе с монитором HTTP среды IDE.

  1. Начните работу с активации монитора HTTP для используемого сервера. Выберите элементы "Сервис" > "Серверы". В левом столбце окна "Серверы" выберите используемый сервер (GlassFish). Затем выберите на главной панели режим "Включить монитор HTTP".

servers win http monitor
Figure 17. Выберите режим 'Включить монитор HTTP', чтобы активировать монитор HTTP
  1. Если сервер уже запущен, необходимо перезапустить его. Однако поскольку планируется использование отладчика, а при запуске отладчика выполняется перезапуск сервера для взаимодействия с другим портом, просто нажмите кнопку 'Отладка проекта' ( debug project btn ) на главной панели инструментов IDE. Будет выполнена перезагрузка сервера, запустится сеанс отладки, и в браузере откроется страница приветствия приложения. В нижней области среды IDE будет отображен монитор HTTP.

http monitor
Figure 18. Монитор HTTP отображается по умолчанию в нижней области среды IDE
  1. Щелкните запись AffableBean в левом столбце (как показано на снимке выше). При выборе записей в левом столбце правый (т.е. главный) столбец обновляется для отображения соответствующих данных. На изображении выше вкладка "Запрос" отображает идентификатор URI запроса (/AffableBean/), метод HTTP (GET) и указывает на отсутствие отправки строки запроса вместе с запросом.

  1. Выберите вкладку "Сеанс". Обратите внимание на утверждение: "Сеанс создан в результате этого запроса." Это вызвано отправкой сервером заголовка Set-Cookie для файла cookie JSESSIONID в качестве ответа. Также обратите внимание, что новый идентификатор сеанса указан в области "Свойства сеанса". Как будет продемонстрировано ниже, идентификатор сеанса представляет собой значение файла cookie JSESSIONID.

session tab
Figure 19. Сведения о сеансе отображаются на вкладке 'Сеанс' в мониторе HTTP

Может возникнуть вопрос о способе создания объекта сеанса из запроса для страницы приветствия сайта. Ведь в файле ControllerServlet не выполняется обработка начального запроса для /AffableBean/, и этот запрос нигде не сталкивается с методом getSession(). Или сталкивается? Напомним, что страницы JSP скомпилированы в сервлеты при развертывании. При первом развертывании проекта на сервере можно фактически использовать среду IDE для просмотра скомпилированного сервлета JSP на собственном сервере.

  1. В окне 'Проекты' щелкните правой кнопкой мыши файл index.jsp и выберите 'Просмотреть сервлет'. В редакторе откроется файл index_jsp.java. Файл является сервлетом, автоматически скомпилированным на основе страницы index.jsp.

  1. Выполните в файле поиск метода getSession. Нажмите Ctrl-F (⌘-F в Mac), введите ‘getSession’ на панели поиска, затем нажмите кклавишу Enter.

Ctrl-F (⌘-F в Mac) - это сочетание клавиш для 'Правка' > 'Найти'.

get session
Figure 20. Метод getSession существует в скомпилированном сервлете страницы JSP

Фактически выполняется вызов метода getSession. Это вызвано тем, что страницы JSP по умолчанию включают в себя скрытый объект pageContext.session. Для деактивации этого поведения можно добавить следующую директиву в верхнюю область файла JSP:

<%@page session="false" %>

, и метод`getSession` в скомпилированном сервлете будет деактивирован.

Для выяснения местоположения скомпилированного сервлета на сервере можно навести курсор мыши на вкладку с именем сервлета над редактором. Будет выведено всплывающее окно с путем к файлу на компьютере.

  1. Выберите категорию в браузере и добавьте товар в корзину. Перейдите в среду IDE. Заметим, что отладчик приостанавливает работу на точке останова в ControllerServlet, поставленную ранее (на строке 150). Все точки останова между сеансами запоминаются. Для удаления точки останова можно щелкнуть метку точки останова ( breakpoint badge ) на левой границе редактора. Тем не менее, поскольку в проект уже добавлено несколько точек останова, откройте окно отладчика "Точки останова" ("Окно" > "Отладка" > "Точки останова").

breakpoints window
Figure 21. Просмотрите все точки останова в проекте в окне 'Точка останова'

В окне "Точки останова" можно просматривать и вызывать действия для всех точек останова, установленных в проектах, которые открыты в среде IDE.

  1. Щелкните правой кнопкой мыши точку останова, установленную в файле header.jspf, и выберите команду "Удалить". Then щелкните правой кнопкой мыши the breakpoint set in the ControllerServlet and choose Disable. (Позднее в этом упражнении будет выполнено ее повторное включение).

  1. Нажмите кнопку 'Продолжить' ( continue btn ). Обработка запроса завершается, и на странице категорий браузера выводится добавленный в корзину товар.

  1. В мониторе HTTP выполните поиск запроса addToCart в левом столбце, затем выберите его для отображения подробных данных в главном столбце.

Нажмите кнопку 'Сортировка по возрастанию' ( ascending sort btn ), чтобы последние записи были указаны в верхней части.

Обратите внимание на идентификатор URI запроса (/AffableBean/addToCart), метод HTTP (POST) и параметры запроса (productId и submit) на вкладке "Запрос".

http monitor add to cart
  1. Выберите вкладку "Файлы cookie". Здесь отображаются данные о существовании файла cookie с именем JSESSIONID и его отправке от клиента на сервер. Обратите внимание, что значение файла cookie совпадает с идентификатором сеанса, отображаемом на вкладке "Сеанс".

cookies tab
Figure 22. Файлы cookies отображаются на вкладке 'Файлы Cookies' в мониторе HTTP

Схожие данные представлены на вкладке "Заголовок", на которой отображается файл cookie, поскольку Cookie является заголовком запроса, отправленного клиентом.

headers tab
Figure 23. Файлы cookies отображаются на вкладке 'Файлы Cookies' в мониторе HTTP

Для получения дополнительных сведений о заголовках запроса и ответа обратитесь к странице веб-энциклопедии Wikipedia Список заголовков HTTP.

  1. Выберите вкладку "Сеанс". На вкладке отображается сообщение "Сеанс предшествует запросу". Также обратите внимание, что атрибут cart отображается в списке "Атрибуты сеанса после запроса". И это объяснимо, ведь объект cart привязывается к сеансу при первой обработке запроса addToCart.

session tab add to cart
Figure 24. Атрибуты сеанса отображаются на вкладке 'Сеанс' в мониторе HTTP

В следующих нескольких шагах рассматривается поиск идентификатора сеанса и файла cookie JSESSIONID в диалоговом окне "Переменные".

  1. Снова активируйте точку останова, ранее установленную в файле ControllerServlet. Нажмите ALT+SHIFT+5 (CTRL+SHIFT+5 в Mac OS), чтобы открыть окно точек останова, затем установите флажок напротив точки останова, чтобы включить ее заново.

  1. Нажмите в браузере кнопку "add to cart" для одного из перечисленных продуктов.

  1. Перейдите в среду IDE и обратите внимание, что отладчик приостановился на точке останова, установленной в файле ControllerServlet. Нажмите кнопку 'Обход процедур' ( step over btn ) для назначения переменной session объекту сеанса.

  1. Откройте окно "Переменные" (ALT+SHIFT+1; CTRL+SHIFT+1 в Mac OS), чтобы развернуть session > session. Идентификатор сессии будет указан в качестве значения переменной id.

  1. При поиске файла cookie JSESSIONID следует помнить, что обычно файл cookie доступен из сервлета при вызове метода `getCookies` в объекте HttpServletRequest. Поэтому перейдите к объекту запроса по пути: "request" > "Inherited" > "request" > "request" > "Inherited" > "cookies". Здесь можно просмотреть список файлов cookie ArrayList. При развертке списка можно найти файл cookie JSESSIONID, значением которого является идентификатор сеанса.

  1. Нажмите кнопку 'Завершить сеанс' ( finish session btn ), чтобы завершить сеанс отладки.

Ведение сеансов с перезаписью URL-адреса

Как упоминалось выше, механизм сервлета обнаруживает возможность поддержки файлов cookie в браузере клиента, в случае невозможности поддержки механизм переходит к перезаписи URL-адреса как способа ведения сеансов. Эти процессы являются прозрачными для клиента. Для разработчиков процесс не является полностью прозрачным.

Необходимо убедиться, что приложение может перезаписывать URL-адреса при каждом отключении файлов cookie. Для этого вызовите метод отклика encodeURL для всех URL-адресов, возвращаемых сервлетами в приложении. В результате идентификатор сеанса будет добавлен к URL-адресу в случае, если использование файлов cookie невозможно; в противном случае URL-адрес будет возвращен без изменений.

Например, браузер отправляет запрос для третьей категории приложения AffableBean (bakery): category?3. Сервер отправляет в ответ идентификатор сеанса, включенный в URL-адрес:

/AffableBean/category*;jsessionid=364b636d75d90a6e4d0085119990*?3

Как описано выше, все URL-адреса, возвращенные сервлетами приложения, необходимо зашифровать. Помните, что страницы JSP компилируются в сервлеты. Как зашифровать URL-адреса на страницах JSP? Для этих целей необходимо использовать тег `<c:url>` JSTL. Следующие упражнения демонстрируют проблему и ее решение.

  1. Временно отключите файлы cookie в браузере. При использовании Firefox можно выбрать пункт "Настройки" в меню "Инструменты" ("Firefox" > "Параметры" в системе Mac). Выберите в открывшемся диалоговом окне вкладку "Приватность", затем выберите в области "История" пункт "будет использовать ваши настройки хранения истории" в предоставленном раскрывающемся списке. Снимите флажок параметра "Принимать cookie с сайтов".

firefox
Figure 25. Временно отключите файлы cookie в браузере
  1. Запустите проект AffableBean. При отображении страницы приветствия щелкните категорию и попытайтесь добавить элемент в корзину. Обратите внимание, что функциональные возможности приложения строго ограничены.

compromised
Figure 26. Для функций приложения возникает угроза в случае, если клиента не принимает файлы cookies

Как и ранее, сервер создает сеанс и привязывает к нему объекты. Это метод для отображения выбранной категории и продуктов на странице категорий. Тем не менее, при попытке установить файл cookie JSESSIONID на сервере происходит сбой. Следовательно, при повторном запросе клиента (когда пользователь нажмите кнопку "add to cart") сервер не может определить сеанс, к которому относится запрос. Поэтому невозможно найти атрибуты, ранее установленные в сеансе, например selectedCategory и categoryProducts. По этой причине в отображаемом ответе отсутствуют данные, определяемые этими атрибутами.

  1. Откройте в редакторе страницу category.jsp проекта. Найдите строку, в которой реализуется кнопка "add to cart" (строка 58). Атрибут action элемента <form> определяет запрос, отправленный на сервер.

<form action="addToCart" method="post">
  1. Измените запрос для его передачи посредством тега <c:url>.

<form action="*<c:url value='addToCart'/>*" method="post">
  1. Для сохранения изменений в файле нажмите сочетание клавиш CTRL+S (⌘-S в Mac). Помните, что среда IDE предоставляет функцию "Развертывание при сохранении", которая активна по умолчанию. Это означает, что все сохраненные изменения автоматически разворачиваются на сервере.

  1. Выберите в браузере другую категорию для отображения в приложении измененной страницы категорий.

  1. Изучите исходный код страницы. В Firefox можно нажать Ctrl-U (⌘-U в Mac). Отобразится кнопка "add to cart" для каждого продукта с идентификатором сеанса, добавленным к URL-адресу.

<form action="addToCart*;jsessionid=4188657e21d72f364e0782136dde*" method="post">
  1. Нажмите кнопку "add to cart" для любого товара. Теперь сервер способен определить сеанс, которому принадлежит запрос, и создает соответствующий ответ.

  1. Перед продолжением убедитесь, что файлы cookie в браузере снова включены.

Снова возникает необходимость в шифровании каждой активной ссылки приложения, ответ которой требует определенной формы данных сеанса. Иногда реализация выполняется не так очевидно, как описывается в примере выше. Например, в настоящий момент виджет "clear cart", используемый на странице cart.jsp, устанавливает для параметра clear значение true при щелчке ссылки.

<%-- clear cart widget --%>
<c:if test="${!empty cart &amp;&amp; cart.numberOfItems != 0}">
    <a href="viewCart*?clear=true*" class="bubble hMargin">clear cart</a>
</c:if>

Тег <c:url> можно применить к URL-адресу следующим образом:

<%-- clear cart widget --%>
<c:if test="${!empty cart &amp;&amp; cart.numberOfItems != 0}">

    *<c:url var="url" value="viewCart">
        <c:param name="clear" value="true"/>
    </c:url>*

    <a href="*${url}*" class="bubble hMargin">clear cart</a>
</c:if>

Параметр clear=true устанавливается путем добавления тега <c:param между тегами <c:url>. Переменная url устанавливается при помощи атрибута var тега <c:url>, затем доступ к атрибуту var осуществляется в теге привязки HTML с использованием выражения ${url}.

Можно загрузить и изучить снимок 6 для просмотра способа шифрования всех ссылок проекта.

Перезапись URL-адреса следует использовать только в случае, если файлы cookie не доступны как метод отслеживания. Перезапись URL, по общему мнению, не является оптимальным решением, поскольку он предоставляет идентификатор сеанса в журналах, закладках, ссылочных заголовках и коде HTML в кэше, а также адресной строке браузера. Также для этого требуются ресурсы на стороне сервера, поскольку серверу необходимо выполнить дополнительные шаги для каждого входящего запроса, чтобы извлечь идентификатор сеанса из URL-адреса и согласовать с существующим сеансом.

Обработка истечения времени ожидания сеанса

Установка временных интервалов сеанса

Необходимо учитывать максимальный интервал времени, в который выполняется ведение сеансов. Если веб-сайт обрабатывает большой поток данных, большое число сеансов может занять весь объем памяти. Следовательно, необходимо сократить интервал для удаления неиспользуемых сеансов. С другой стороны, следует избегать излишнего сокращения сеансов, поскольку это может привести к проблемам использования веб-сайта, сказывающимся на эффективности работы. В примере проекта AffableBean пользователь переходит к кассе после заполнения корзины покупок товарами. Затем пользователь выходит из сети, например, чтобы найти кредитную карту для ввода данных карты. После входа в сеть пользователь заполняет форму на кассе и нажимает кнопку подтверждения. Однако время ожидания сеанса на сервере уже истекло. Корзина покупок становится пустой, и пользователь перенаправляется на домашнюю страницу. Найдется ли у пользователя время на повторение процесса?

Следующие шаги демонстрируют способы установки в проекте AffableBean в качестве интервала для истечения времени ожидания сеанса значения в 10 минут. Конечно, фактическая длительность в конечном счете зависит от ресурсов сервера, бизнес-целей приложения и популярности веб-сайта.

  1. Откройте в редакторе дескриптор развертывания приложения. Нажмите ALT+SHIFT+O (CTRL+SHIFT+O в Mac OS) для использования диалога "Перейти к файлу". Введите “web”, затем нажмите кнопку "ОК".

go to file
Figure 27. Диалоговое окно 'Переход к файлу' позволяет быстро перейти к файлам проекта

В редакторе будет выведен файл web.xml в представлении XML. Шаблон, предоставляемый NetBeans для файла web.xml, включает в себя по умолчанию параметр с интервалом в 30 минут.

<session-config>
    <session-timeout>
        30
    </session-timeout>
</session-config>
  1. Выберите вкладку "Общее" и введите в поле "Время ожидания сеанса" значение “10”.

session timeout
Figure 28. Укажите время ожидания сеанса для приложения на вкладке 'Общие' файла web.xml
  1. Сохраните файл (сочетание клавиш Ctrl-S; ⌘-S в Mac).

При обратном переходе в представление XML можно заметить, что элемент <session-timeout> был обновлен.

<session-config>
    <session-timeout>10</session-timeout>
</session-config>

Примечание. В качестве альтернативы вы можете полностью удалить элемент <session-timeout> и изменить элемент session-properties в дескрипторе развертывания, связанном с GlassFish (sun-web.xml). В результате будет установлено глобальное время ожидания для всех приложений в веб-модуле сервера. Получить более подробную информацию можно в руководстве Oracle GlassFish Server 3.0.1 Application Development Guide: Creating and Managing Sessions (Oracle GlassFish Server 3.0.1 Руководство по разработке приложений. Создание сеансов и управление ими).

Автоматическая обработка истечения времени ожидания сеанса

Если приложение основано на сеансах, необходимо принять меры для обеспечения простоты и удобства обработки ситуаций, когда поступает запрос для сеанса, время ожидания которого истекло или который невозможно определить. Это можно выполнить в проекте AffableBean, создав простой фильтр, перехватывающий заголовки запросов в файле ControllerServlet. Фильтр проверяет факт существования сеанса; если сеанс не существует, он перенаправляет запрос на страницу приветствия сайта.

  1. Начните работу с изучения проблемы, возникающей при истечении времени ожидания сеанса до его завершения из-за посещения сайта пользователем. Временно установите для времени ожидания сеанса значение в 1 минуту. Откройте дескриптор развертывания веб-приложения (web.xml) и введите значение “1” между тегами <session-timeout>.

<session-config>
    <session-timeout>*1*</session-timeout>
</session-config>
  1. Запустите проект AffableBean. Щелкните на странице категорий в браузере, добавьте несколько элементов в корзину и щелкните ссылку "view cart".

cart page session intact
Figure 29. Страница корзины зависит от объекта сеанса при отображении элементов в покупательской корзине
  1. Подождите минимум 1 минуту.

  1. Обновите количество для одного из товаров на странице корзины. (Допустимо любое число от 1 до 99.) Нажмите кнопку "update". Сервер отправит сообщение со статусом HTTP "500".

glassfish error report
Figure 30. NullPointerException возникает при получении запроса для сеанса, срок действия которого истек
  1. Изучите журнал сервера GlassFish в среде IDE. Откройте окно вывода (Ctrl-4; ⌘-4 в Mac) и перейдите на вкладку 'Сервер GlassFish'. Прокрутите до конца журнала для изучения трассировки стека ошибок.

gf server output

Журнал сервера показывает, что исключение NullPointerException возникло в строке 184 ControllerServlet. В диалоговом окне "Вывод" появляется ссылка на строку, в которой возникло исключение.

  1. Щелкните ссылку. Вы попадете прямо на строку 184 в ControllerServlet. При наведении курсора мыши на значок ошибки в левом поле редактора выводится всплывающая подсказка с описанием исключения.

nullpointer exception
Figure 31. Метка ошибки и подсказка указывают местоположение и причину проблемы

Поскольку время ожидания сеанса истекло до получения запроса, механизму сервлета не удалось связать запрос с соответствующим сеансом. Таким образом, оказалось невозможным обнаружить объект cart (строка 151). В конце концов, исключение произойдет на строке 184, когда попытка вызова метода по переменной, имеющей значение null.

Проблема определена, для ее исправления необходимо реализовать фильтр.

  1. Нажмите кнопку 'Создать файл' (new file btn) на панели инструментов IDE. (В качестве альтернативы нажмите Ctrl-N; ⌘-N в Mac.)

  1. Выберите категорию "Веб", затем выберите "Фильтр" и нажмите кнопку "Далее".

  1. Присвойте фильтру имя SessionTimeoutFilter. Введите текст filter в поле "Пакеты" для размещения класса фильтра в новом пакете при его создании.

  1. Нажмите кнопку "Далее". Примите настройки по умолчанию и нажмите кнопку "Готово". Для фильтра SessionTimeoutFilter создается и открывается в редакторе шаблон.

Примечание. В настоящее время в NetBeans 6.9 не поддерживается использование мастера для задания сопоставления с сервлетом, которые не зарегистрирован в дескрипторе веб-развертывания. (ControllerServlet был зарегистрирован с помощью аннотации @WebServlet). Следовательно, необходимо изменить созданный код в следующем шаге.

  1. Измените подпись аннотации @WebFilter следующим образом:

@WebFilter(*servletNames = {"Controller"}*)
public class SessionTimeoutFilter implements Filter {

Фильтр с такими настройками будет перехватывать любой запрос, который управляется ControllerServlet. (Также можно сохранить атрибут urlPatterns и перечислить все шаблоны, обрабатываемые в файле ControllerServlet.)

Обратите внимание, что Controller является именем файла ControllerServlet, как указано в подписи аннотации @WebServlet сервлета. Заметим также, что атрибут filterName был удален, поскольку имя класса фильтра используется по умолчанию.

Шаблон фильтра среды IDE предоставляет множество примеров кода, которые рекомендуется изучить. Однако большая часть кода не потребуется для целей этого упражнения. Любой класс фильтра должен реализовывать интерфейс Filter, определяющий три метода. * init: выполняет действия после инициализации фильтра, но до его размещения в службе. * destroy: удаляет фильтр из службы. Этот метод может быть также использован для выполнения операций очистки. * doFilter: используется для выполнения операций для каждого запроса, перехваченного фильтром.

Используйте функцию поиска документации по индексу, чтобы вытянуть документацию по интерфейсу Filter. Нажмите сочетание клавиш SHIFT+F1 (fn+SHIFT+F1 в системе Mac), введите текст Filter в поле поиска и нажмите ENTER. Выберите запись "Interface in javax.servlet". Документация Javadoc выводится на нижней панели средства поиска по индексу.

  1. Замените тело фильтра SessionTimeoutFilter на следующее содержимое.

@WebFilter(servletNames = {"Controller"})
public class SessionTimeoutFilter implements Filter {

    *public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest) request;

        HttpSession session = req.getSession(false);

        // if session doesn't exist, forward user to welcome page
        if (session == null) {
            try {
                req.getRequestDispatcher("/index.jsp").forward(request, response);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return;
        }

        chain.doFilter(request, response);
    }

    public void init(FilterConfig filterConfig) throws ServletException {}

    public void destroy() {}*

}
  1. Нажмите Ctrl-Shift-I (⌘-Shift-I в Mac) для исправления операторов импорта. (Необходимо добавить импорт для HttpServletRequest и HttpSession.) Используйте подсказки редактора чтобы добавить аннотацию @Override к методам init, destroy и doFilter.

В следующих шагах выполняется запуск отладчика для проекта и переход по методу doFilter для просмотра способа определения привязки запроса существующему сеансу.

  1. Откройте окно точек останова (ALT+SHIFT+5; CTRL+SHIFT+5 в Mac OS) и удостоверьтесь, что не установлена ни одна точка останова. Для удаления точки останова щелкните правой кнопкой мыши точку останова и выбериет 'Удалить'. (Если было выполнено упражнение выше, Examining Client-Server Communication with the HTTP Monitor (Проверка соединения клиент-сервер с помощью HTTP-монитора), в ControllerServlet может быть установлена лишняя точка останова).

  1. Запустите отладчик. Нажмите кнопку 'Отладка проекта' (debug project btn) на главной панели инструментов IDE.

  1. При выводе страницы приветствия в браузере выберите категорию и добавьте несколько элементов в корзину покупок.

  1. Установите точку останова на строку принадлежащего фильтру SessionTimeoutFilter метода doFilter, который пытается получить доступ к сеансу (строка 32).

filter breakpoint
Figure 32. Установите точку останова в методе getSession
  1. Щелкните в браузере ссылку "view cart". Перейдите к среде IDE и обратите внимание, что отладчик приостановил работу в точке останова.

Учтите, что метод getSession() создает новый объект сеанса, если текущий объект не существует. В данном случае используется метод getSession(false), который не создает новый объект, если объект не найден. Другими словами, метод возвращает значение null, если сеанс не существует.

  1. Нажмите кнопку 'Обход процедур' ( step over btn ), затем подведите курсор мыши к переменной session. При условии, что с момента отправки предыдущего запроса не прошла минута, переменная присваивается типу StandardSessionFacade. Он представляет объект сеанса для запроса.

session exists
Figure 33. Наведите курсор на переменные для определения их текущих значений
  1. Продолжайте двигаться по строкам метода, пока запрос не будет обработан. Поскольку переменная session не равна null, можно пропустить выражение if, и фильтр chain.doFilter направит запрос прямо к ControllerServlet (строка 44).

  1. Перейдите в браузер, убедитесь, что прошла минута, и обновите количество для одного из элементов продукта в корзине. Это та же самая процедура, которая выполнялась ранее в упражнении с возвратом сообщения 500. Выясним, что происходит при истечении времени ожидания сеанса теперь, когда фильтр перехватывает заголовки запросов для файла ControllerServlet.

  1. После щелчка элемента "Обновить" перейдите в среду IDE и обратите внимание, что отладчик снова приостановился на точке останова, установленной в фильтре.

  1. Выделите выражение req.getSession(false) и наведите на него курсор мыши. Обратите внимание, что выражение имеет значение null, поскольку время ожидания сеанса истекло.

session null
Figure 34. Выделите выражения и наведите курсор мыши на них для определения их текущих значений
  1. Продолжите переход по коду. Теперь переменная session равна null, выражение if на странице 35 обрабатывается, и запрос направляется прямо к /index.jsp. Когда отладчик завершает работу, в браузере выводится страница приветствия сайта.

  1. Нажмите кнопку 'Завершить сеанс' ( finish session btn ), чтобы завершить сеанс отладки.

  1. Откройте файл web.xml проекта и снова измените время ожидания сеанса на 10 минут.

<session-config>
    <session-timeout>*10*</session-timeout>
</session-config>
  1. Сохраните файл (Ctrl-S; ⌘-S в Mac).

Снимок 6 демонстрирует полную версию проекта для данного раздела руководства. Рассмотрим еще один вопрос, касающийся управления сеансом. Можно завершить сеанс явным образом, вызвав метод invalidate для объекта сеанса. Если сеанс больше не требуется, необходимо удалить его для сохранения доступной памяти на сервере. После завершения следующего раздела, Интеграция транзакционной бизнес-логики, можно увидеть, как ControllerServlet после успешной обработки заказ клиента, уничтожает пользовательский объект cart и прерывает сессию, используя метод invalidate.

// if order processed successfully send user to confirmation page
if (orderId != 0) {

    // dissociate shopping cart from session
    cart = null;

    // end session
    session.invalidate();

    ...
}

Это демонстрируется в проектный снимок 8 (и следующих снимках).

link:/about/contact_form.html?to=3&subject=Feedback: NetBeans E-commerce Tutorial - Managing Sessions[Мы ждем ваших отзывов]

Дополнительные сведения