JAVA EE:Разработка web-приложения. GET/POST. Filter. JSTL part 2.
Поиск по сайту:
О разработчеке сайта
Header image

Новые статьи и уроки JAVA

JAVA EE:Разработка web-приложения. GET/POST. Filter. JSTL part 2.

Седьмая статья серии, посвященной технологии JavaEE. В этой статье мы продолжим расширять функционал нашего web-приложения. Более подробно в статье разобрана библиотека стандартных тегов JSTL. В прошлом уроке мы уже немного использовали эту библиотеку, но внимание на ней не заостряли, однако вещь эта очень полезная и знать ее нужно обязательно, так же научимся обрабатывать данные, полученные от пользователя путем GET или POST запросов. На десерт познакомимся с фильтром и с его помощью разрешим проблему кодировок пользовательских запросов к серверу.

1Для реализации примеров понадобится снимок проекта с прошлой статьи. Забрать можно здесь.

Также напомню, что используется сервер приложений GlassFish.

Начнем с изучения JSTL.

Библиотека стандартных тэгов JSTL

В прошлом уроке на главной странице сайта использовался следующий код.

<c:forEach var="article" items="${articles}">
                        <article>
                            <h1>${article.title}</h1>
                            <div class="text-article">
                                 ${fn:substring(article.text,0,300)} ...
                             </div>
                             <div class="fotter-article">
                                 <span class="read"><a href="article?id=${article.id}">Читать...</a></span>
                                 <span class="date-article">Дата статьи: ${article.date}</span>
                             </div>
                        </article>
</c:forEach>

 Тэг <c:forEach var="article" items="${articles}"> мы уже разобрали, он открывает цикл-перебор значений переменной articles которую мы передали в качестве атрибута из нашего сервлета-контроллера. На каждой итерации новое полученное значение присваивается переменной artile. Тэг </c:forEach> ознаменует окончание области действия цикла.

Описанный выше тэг относится к так называемой основной (core) библиотеке. Подключение к jsp файлу той или иной библиотеке происходит путем добавления специального объявление в начале файла:

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

Как видите мы указываем префикс (prefix) по которому будем обращаться к методам библиотеки.

Помимо этого существуют еще следующие библиотеки:

Библиотека для работы с xml-документами.

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/xml" %>

Библиотека для работы с базами данных (бессмысленно и беспощадно...не используйте ее, раз уж изучаете EJB).

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/sql" %>

Тэги форматирования данных выводимых пользователю.

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/fmt" %>

Тэги дополнительных функций.

<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>

Начнем с основной библиотеки (core).

Самое простое что мы можем сделать это вывести значение какой либо переменной:

<c:out value="${variable}" />

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

<c:out value="${variable}" default="variable is null" escapeXml="true" />

 теперь если переменная variable отсутствует или пуста, то выведется текст "variable is null", escapeXml указывает на необходимость экранирования специальных символов XML.

Прежде чем выводить содержимое переменных, было бы не плохо их создать:

<c:set var="variable" scope="page" value="Значение переменной" />

этим тэгом мы создали переменную variable и присвоили ей значение, указанное в атрибуте value. Атрибут scope указывает контекст в который будет сохраняться переменная. О контекстах было рассказано в прошлой статье.

Теперь ознакомимся с условным оператором:

<c:if test="${param.count gt 5}">
Количество больше 5  
</c:if>    
<c:if test="${param.count eq 3}">      
Количество срого равно 3  
</c:if>

В условном операторе нельзя объявить блок else, только блок выполнения при истинности условия; так же нельзя использовать привычные нам операторы сравнения "<",">" и т.д., вместо них используются специальные пары букв:

Виды условных операторов
eq равенство ==
ne неравенство !=
gt больше >
lt меньше <
ge больше или равно >=
le меньше или равно <=

 

 

 

 

 

 

Для проверки нескольких условий удобней использовать оператор:

<c:choose>      
<c:when test="${param.count lt 5}">        
   Значение меньше 5   
</c:when>      
<c:when test="${param.count lt 10}">        
   Значение меньше больше или равно 5 и меньше 10     
</c:when>      
<c:otherwise>        
   Больше или равно 10     
</c:otherwise>  
</c:choose>

<c:otherwise> - инструкция выполняющаяся по умолчанию, если выше ничего не подошло.

Рассмотрим циклы. Один из вариантов цикла мы уже видели в начале статьи. Тот же цикл можно объявить по другому:

<c:forEach var="iter" begin="0" end="2">
Итерация номер ${iter} <br/>
</c:forEach>

Объявленный таким образом цикл будет выполняться итерационно от 0 до 2 и номер текущей итерации присваивается переменой iter.

Еще два атрибута циклов это: step и varStatus.

<c:forEach var="article" step="2" items="${articles}">
${article.title}
</c:forEach

Как видно выше, атрибут step можно использовать не только в цикле от begin и до end, но и при переборе массивов.

Атрибут varStatus хранит в себе информацию о цикле. Если мы используем цикл с begin/end, то в ней хранится номер итерации, если же цикл-перебор массива, то в переменной хранится информация о том, является ли элемент первым/последний в цикле и прочее.

Закончим с циклами и рассмотрим еще несколько тэгов.

Тэг для вставки содержимого одного jsp файла в другой:

<c:import url="head.jsp" />

Перенаправление (редирект) пользователя на другую страницу:

<c:redirect url="head.jsp">      
<c:param name="name" value="${paran.name}" />  
</c:redirect>

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

<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>

 В нашем самом первом примере используется функция из этой библиотеки:

${fn:substring(article.text,0,300)}

Эта функция возвращает подстроку из значения article.text с 0 символа в количестве 300 символов.

Функция проверки вхождения одной подстроки в другую (возращает знаечение true/false):

${fn:contains('Vladimir Kiril guest', 'guest')}

Та же самая проверка, но без учета регистра (возвращает значение true/false):

${fn:containsIgnoreCase('Vladimir Kiril guest', 'GUEST')}

Проверка, начинается ли одна строка с заданной подстроки:

${fn:startsWith('Vladimir Kiril guest', 'Vlad')}

Проверка, заканчивается ли одна строка заданной подстрокой:

${fn:endsWith('Vladimir Kiril guest', 'est')}

Поиск позиции в строке, с которой начинается искомая подстрока:

${fn:indexOf('Vladimir Kiril guest', 'Kiril' )}

Вычисление длины строки:

${fn:length('Stroka')}

Для вырезания подстроки из строки до заданного маркера используется функция:

${fn:substringAfter('Vladimir Kiril guest', 'gu')}

Соответственно функция, вырезающая подстроку после заданного маркера:

${fn:substringBefore('Vladimir Kiril guest', 'gu')}

Функция, приводящая все символы строки к нижнему регистру:

${fn:toLowerCase(boy)}

и к верхнему:

${fn:toUpperCase(boy)}

Для замены некой подстроки на другую используется функция:

${fn:replace('Vladimir Kiril guest', 'Kiril', 'Anna')}

Функция деление строки на массив подстрок (вторым параметром указывается разделитель):

${fn:split('Vladimir,Kiril,huest', ',')}

Склеиванием массива строк в одну занимается функция:

${fn:join(arr_string, ',')}

Теперь, когда вы знакомы с основными JSTL тэгами, можете использовать их в своих проектах, избегая всевозможные скриплеты.

 Идем дальше, пора научиться обрабатывать параметры, полученные от пользователя и анализировать их.

Работа с GET и POST запросами пользователя

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

Необходимые нам данные от пользователя, а именно номер статьи, который передается в строке запроса, хранятся в перемененной HttpServletRequest request.

Основные функции, которые мы используем в этот раз - это:

функция, возвращающая перечисления имен параметров, полученных от пользователя,

request.getParameterNames();

функция, возвращающая значение параметра по его имени,

request.getParameter("paramName");
  1. Откройте наш web_controller и условный оператор, определяющий, что пользователь перешел на страницу статьи, добавьте следующий код:
    if ("/article".equals(userPath)){
                String id=null;
                Enumeration<String> params = request.getParameterNames()
    }
  2. Мы объявили переменную id, в которой будет храниться значение, переданное пользователем, и создали перечисление, в которое поместили список имен параметров.
  3. Далее нам необходимо пройтись по полученному списку имен и, если там есть интересующий нас параметр, то запомнить его:
    while (params.hasMoreElements()) {
                    String param = params.nextElement();
                    id="id".equals(param)?request.getParameter(param):id;
    }
  4. В объявленном массиве поочередно перебираются имена всех полученных от пользователя параметров, как только будет найден параметр с именем id, его значение присваиваем одноименной переменой.
  5. Далее добавляем блок try catch и в нем ищем статью по полученному id. Полученное значение передаем атрибутом.
    try{
                    Articles article = articlesFacade.find(Integer.parseInt(id));
                    request.setAttribute("article", article);
         }catch(Exception e){
                    e.printStackTrace();
         }
  6. Для поиска статьи использовалась функция find, которая в качестве параметра принимает идентификатор таблицы. Теперь воспользуемся созданным нами атрибутом и распределим его поля по нужным местам в файле article.jsp.
    <section>
                    <article>
                        <h1>${article.title}</h1>
                        <div class="text-article">
                            ${article.text}
                        </div>
                        <div class="fotter-article>
                            <span class="date-article">Дата статьи: ${article.date}</span>
                        </div>
                    </article>
    </section>
  7. Теперь, переходя по ссылкам на наши статьи (например http://localhost:8080/myblog/article?id=3), мы сможем созерцать полные тексты наших статей.
    Вид окна статей

Функционал просмотра статей можно считать готовым.

Фильтр

Прежде чем приступить к реализации фильтра, создадим предпосылку необходимости его использования. В файле article.jsp и перед открывающимся тэгов <section> добавьте строку кода ${param.name} :

</aside>
     ${param.name}
<section>

Теперь откройте любую из статей и в адресной строке браузера добавьте следующий текст: &name=Виктор, URL адрес будет выгледить примерно вот так:

http://localhost:8080/myblog/article?id=3&name=Виктор

или вот так:

http://localhost:8080/myblog/article?id=3&name=%D0%92%D0%B8%D0%BA%D1%82%D0%BE%D1%80

что по сути одно и тоже.

Обновите страницу... Вы увидите, что сервер некорректно обработал кириллицу и на выходе мы видим абсолютно нечитабельный текст:

Пример не правильной обработки кириллицы веб-серверов

 

Сервер обработал данные от пользователя, полученные GET-запросом в кодировке отличной от utf-8, то же самое произошло бы и с данными, полученными POST-запросом.

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

  1. Нажмите на кнопку создания нового файла Кнопка создания нового файла и в окне выбора типа файла укажите "Фильтр":
    Создание фильтра шаг 1
  2. На следующем шаге задайте имя фильтра web_filter и пакет filter:
    Создание фильтра шаг 2
  3. Параметры на следующих шагах оставьте по умолчанию. Пройдите все шаги до готовности фильтра.

IDE создало каркас фильтра. Его объявление происходит так же как и сервлет, путем аннотации:

@WebFilter(filterName = "web_filter", urlPatterns = {"/*"})

Думаю, после изучения аннотаций сервлета, эта аннотация вам вполне понятна. Можно установить urlPatterns чтобы указать все пути, какие должен обрабатывать данный фильтр, а можно сделать еще проще - замените аннотацию объявления фильтра на следующую:

@WebFilter(servletNames = {"web_controller"})

Мы просто указали сервлет, к которому относится фильтр и, тем самым закрепили за фильтром все пути, которые будет обрабатывать и сам сервлет.

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

  1. Удалите все содержимое функции doFilter и вставьте в ее тело следующий код:
    request.setCharacterEncoding("UTF-8");
    chain.doFilter(request, response);
  2. Обновите страницу /article и теперь кириллица отобразилась корректно.
    Пример корректной отображения кириллической кодировки

Вот так, очень просто и со смыслом мы решели проблему кодировок сервера и познакомились с фильтром.

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

Если вы изучаете JavaEE с самых первых статей, то наверняка уже затянулись этой технологией и ее возможностями. Однако мы едва ли прошли пол-пути из запланированных мной уроков. Могу гарантировать, что каждый последующий урок будет интереснее предыдущих, и в следующей статье мы научимся составлять собственные выборки, а главное мы научимся добавлять данные в базу, и тем самым попутно познакомимся с технологией транзакций, которую предоставляет нам JTA.

1Снимок готового урока можно забрать с GitHub'а

10.09.2012

Комментарии