| « Тестируй веб-сайты вместе с Badboy. Часть 3 | Тестируй веб-сайты вместе с Jmeter » |
JSTL: Шаблоны для разработки веб-приложений в java. Часть 1
Эта статья является логическим развитием материалов посвященных средствам отображения информации (слой View в ставшей уже классической связке Model-View-Controller). Чтобы вы понимали место, которое занимают JSTL и Velocity нужно рассказать о Страшной Ошибке постигшей разработчиков jsp. Как вы наверняка слышали, много-много лет назад java-программисты хотевшие создать веб-приложение не имели в своем распоряжении ничего кроме сервлетов. Сервлет это был класс со специальным методом (doGet или doPost), который вызывался из браузера и должен был сгенерировать html-страницу. Очевидно, что сначала нужно было на основании пришедших от клиента данных (параметры ссылки или содержимое полей формы) выполнить расчет какой-то информации, подготовить набор переменных, массивов, списков и, второй шаг, каким-то образом надо это визуализировать, т.е. перемещать html-теги и те самые подготовленные данные. И было это ужасно:OutputStream out = response.getOutputStream();
out.println("<html>");
out.println("<body>");
out.println("<h1> Привет, " + vasyanoFIO + “</h1>”);
out.println("</body>");
out.println("</html>");
<%@ page contentType="text/html;charset=UTF-8" language="java"%><body><%String vasuanoFIO = "Бла-бла-бла";if ( 1 < 2)vasuanoFIO = "Бум-бам-тарарам";%><h1><%= vasuanoFIO %></h1></body>
public class HelloMachineBean {
public String fio;
public String age;
public String sex;
public String getFio() {
return fio;
}public void setFio(String fio) {
this.fio = fio;
}public String getAge() {
return age;
}public void setAge(String age) {
this.age = age;
}public String getSex() {
return sex;
}public void setSex(String sex) {
this.sex = sex;
}public String getResult (){
if ("male".equalsIgnoreCase(sex))
return "Это дядя " + fio + " его возраст "+age;
return "Это тетя "+fio+ " ее возраст "+age;
}}
// создаем объект Логики, указываем его имя и java-класс<jsp:useBean id="helloMachine" class="testi.HelloMachineBean" />
// теперь начинаем заполнять значениями поля этого класса-бина, синтаксис// property=”*” означает, что все пришедшие параметры запроса должны быть помещены внутрь bean-а.<jsp:setProperty name="helloMachine" property="*" />
// а вот еще вариант, когда указывается конкретное имя свойства, которое нужно заполнить информацией и имя поля из http-запроса<jsp:setProperty name="helloMachine" property="fio" param="fio" />
// в конце-концов, можно присвоить атрибуту значение в виде константы<jsp:setProperty name="helloMachine" property="sex" value="female" />
// а теперь использование, как будто бы в составе класса helloMachine есть свойство result.// на самом деле для обращения к свойствам используются методы getter-ы,// так что фактическое существование поля класса с именем result не существенно.<h2>
Hello <jsp:getProperty name="helloMachine" property="result" />
</h2>
<%If ( bla-bla)
…
Else…
%>
<%String vasuanoFIO = "Нет. Ты не сможешь победить силы Зла";
if ( 1 < 2)
vasuanoFIO = "Твоя борьба против каши в JSP обречена на провал, Ха-ха-ха";
%>
<showcalendar /><mailsend to=vasyano@mail.ru />
<my:if test=”bla == bla”>Bla-bla-bla
</my:if>
1. Загрузить с сайта архив с библиотекой jstl (я использую версию 1.2). 2. Добавить эту библиотеку в папку WEB-INF/lib вашего веб-приложения. 3. Подключить в начале jsp-файла с помощью специальных директив taglib те библиотеки тегов, которые хотите использовать:Основные теги позволяющие делать циклы, условия, выводить информацию на экран:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/xml" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/sql" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><html><head><title>Simple jsp page</title></head>
<body><c:out value="hello, Vasuano" /></body></html>
<c:out value="12+56*2" />
<c:out value="${12+56*2}" />
<c:out value="${param.fio}" />
http://center:8080/velo/a2.jsp?fio=%C2%E0%F1%FF (Эти кракозюбры – слово ВАСЯ)То увижу на страницу … какую-то белиберду.
ÂàñÿСобственно, другого не ожидалось: для того чтобы заставить tomcat нормально раскодировать входящие переменные нужно еще постараться. Как, что, и почему я писал в другой своей статье посвященной Русским буквами и java.
Внимание, перед тем как написать имя переменной (fio) я должен указать контекст (место, где нужно искать эту переменную). Есть список предопределенных контекстов:
| Контекст | Комментарий |
|---|---|
| pageScope | Контекст страницы (т.е. переменные объявленные на этой странице и доступные только для этой страницы). |
| requestScope | Доступ к таким переменным имеют все страницы, сервлеты обслуживающие один, текущий, вот этот самый, запрос пользователя. |
| sessionScope | Доступ к переменным сохраняется на протяжении всего сеанса пользователя (пока не закроет браузер или не истечет предельное время бездействия). |
| applicationScope | Доступ к переменным сохраняется изо всех страниц размещенных внутри веб-приложения (самый глобальный контекст). |
| param | В этом контексте находятся все переменные, полученные страницей от пользователя либо как параметры адресной строки, либо как поля html-формы. |
| paramValues | Список значений тех переменных, которые были переданы в страницу пользователем, правда, формат отличен от предыдущего случая. Если там param фактически имел тип HashMap |
| header | В этом объекте хранится информация об http-заголовках которые были переданы от браузера клиента вашему веб-серверу. |
| headerValues | Список значений http-заголовков. |
| initParam | Конфигурационные параметры, указанные для вашей страницы, сервлета в файле web.xml |
| cookie | Список переменных помещенных внутрь cookie. |
| pageContext | Ссылка на объект pageContext (см. описание служебных объектов автоматически создаваемых внутри jsp-страницы). |
<c:out value="${param.fio}" /><c:out value="${param['fio']}" />
<c:out value="${param.fio}" default="NO DATA" escapeXml="true" />
Научившись выводить переменные самое время задуматься над тем как эти переменные создавать. Помимо очевидных вариантов: из параметров запроса, из объекта java bean с логикой, из сессии есть еще способ самим внутри страницы положить какую-нибудь переменную внутрь одного и указанных выше контекстов. Для этого мы используем тег c:set. В качестве его атрибутов указывается название контекста, куда мы хотим положить переменную, имя переменной и значение:
<c:set var="vasyano" scope="session" value="Вася Тапкин" /><c:set var="petyano" scope="page">Петька Козлов на странице
</c:set><c:set var="petyano" scope="request">Петька Козлов в запросе
</c:set><c:set var="petyano" scope="session">Петька Козлов в сессии
</c:set><c:set var="petyano" scope="application">Петька Козлов в приложении
</c:set>vasyano: <c:out value="${sessionScope.vasyano}" /><br />petyano: <c:out value="${petyano}" />
Есть еще один вариант синтакиса оператора c:set, когда нужно установить значение свойства некоторого java-bean внедренного на страницу.
<c:set target="${helloMachine}" property="fio" value="Ленка Слонова" /><c:out value="${helloMachine.fio}" />
<c:set var="fio" scope="session" value="Vasyano Petrovno" />fio1 = <c:out value="${fio}" /><c:remove var="fio" />fio2 = <c:out value="${fio}" />
<c:if test="${param.age gt 12}">Возраст более 12 лет
</c:if><c:if test="${param.age lt 25}">Возраст менее 25 лет
</c:if>
<strong>eq</strong> – проверка на равенство <strong>ne</strong> – проверка на неравенство <strong>lt</strong> – строго менее чем <strong>gt</strong> – строго более чем <strong>le</strong> – меньше либо равно чему-то <strong>ge</strong> – больше или равно чему-тоУ тега if есть несколько необязательных атрибутов, которые возможно пригодятся вам, чтобы не записывать повторяющиеся выражения. Так если указан атрибут var, то в эту переменную будет записан результат вычисления условия (атрибута test). Куда именно будет положена эта переменная (в какой контекст) задается атрибутом scope.
<c:if test="${param.age gt 12}" var="if_less_12">Возраст более 12 лет
</c:if><c:if test="${if_less_12}">Еще раз повторяю: Возраст более 12 лет
</c:if>
<c:choose><c:when test="${param.age lt 10}">Возраст менее 10 лет
</c:when><c:when test="${param.age lt 20}">Возраст в отрезке от 10 до 20 лет
</c:when><c:otherwise>Срочно пройдите на процедуру усыпления
</c:otherwise></c:choose>
Прежде всего, я ввел в состав описанного выше класса HelloMachineBean несколько новых методов (как-бы-настоящий свойств) возвращающих массив элементов и список элементов.
public List< String> getFriendsAsList (){
return Arrays.asList(getFriendsAsArray ());
}public String[] getFriendsAsArray(){
return new String[]{"Васька", "Петька", "Ленка"};
}
<c:set var="friends" value="${helloMachine.friendsAsArray}" /><c:set var="friends2" value="${helloMachine.friendsAsList}" /><c:forEach items="${friends}" var="friend"><h2><c:out value="${friend}"/></h2></c:forEach><c:forEach items="${friends2}" var="friend"><h3><c:out value="${friend}"/></h3></c:forEach>
Второй вариант цикла ForEach предназначен для прохода по целым числам в отрезке от X до Y, например, так:
<c:forEach var="friend_i" begin="0" end="2"><h5><c:out value="${friend_i}"/> = <c:out value="${friends[friend_i]}"/>
</h5><h4><c:out value="${friend_i}"/> = <c:out value="${friends2[friend_i]}"/>
</h4></c:forEach>
Еще один атрибут для тега forEach – это step. Его назначение управлять величиной шага, с которым выполняется проход по элементам массива. Обратите внимание, что в следующем примере атрибут step умеет корректно работать не только, когда цикл перебирает цифры в отрезке от X до Y, но и когда перебирается содержимое некоторой коллекции элементов.
<c:forEach items="${friends}" var="friend" step="2"><h2><c:out value="${friend}"/></h2></c:forEach><c:forEach var="friend_i" begin="0" end="2" step="2"><h5><c:out value="${friend_i}"/> = <c:out value="${friends[friend_i]}"/>
</h5><h4><c:out value="${friend_i}"/> = <c:out value="${friends2[friend_i]}"/>
</h4></c:forEach>
<c:forEach var="friend_i" begin="0" end="2" step="2" varStatus=”friendStatus”><h5>friend_i = <c:out value="${friendStatus}"/>*<c:out value="${friend_i}"/> = <c:out value="${friends[friend_i]}"/>
</h5></c:forEach>
<c:forEach items="${friends}" var="friend" step="1" varStatus="friendStatus">Status:
index=<c:out value="${friendStatus.index}"/><br />count=<c:out value="${friendStatus.count}"/><br />first=<c:out value="${friendStatus.first}"/><br />last=<c:out value="${friendStatus.last}"/><br />step=<c:out value="${friendStatus.step}"/><br /><h2><c:out value="${friend}"/></h2></c:forEach>
<c:set var="str" value="Гравитон Фотон Бозон Мюон" /><c:forTokens items="${str}" delims=" " var="token" begin="1" varStatus="tokenStatus" step="1">index=<c:out value="${tokenStatus.index}"/><br />count=<c:out value="${tokenStatus.count}"/><br />first=<c:out value="${tokenStatus.first}"/><br />last=<c:out value="${tokenStatus.last}"/><br />step=<c:out value="${tokenStatus.step}"/><br /><h2> <c:out value="${token}"/> </h2>
</c:forTokens>
<c:set var="str" value="Гравитон,Фотон.Бозон Мюон" /><c:forTokens items="${str}" delims=" ,." var="token" begin="0" varStatus="tokenStatus" step="1"><h2><c:out value="${token}"/></h2></c:forTokens>
<c:import url="heading.html" />
Включаемая страница (footer.jsp):
<%@ page import="java.util.Date" %><%@ page contentType="text/html;charset=UTF-8" language="java"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><%out.write("Сложные расчеты по внедрению информации внутрь ... " + new Date());%><h1><c:out value="${externalVar}" /></h1>
А теперь пример кода главной страницы (обратите внимание на то, что я указал область действия переменной externalVar – значит, что она будет доступна всем страницам обслуживающим данный запрос):
<c:set var="externalVar" value="Hello from Outer page" scope="request"/><c:import url="footer.jsp" />
Естественно, что на включаемой странице будут доступны и те переменные, которые были переданы главному скрипту из html-формы.
Количество атрибутов управляющих поведением тега import гораздо больше, чем один адрес включаемого документа. Начнем с попытки включить как вложенную, страницу содержащую русские буквы. И конечно же мы увидели кракозюбры. Дело в том, что кодировка включаемого документа по-умолчанию рассматривается как ISO8859-1. Для того чтобы явно указать кодировку делайте так:
<c:import url="heading.html" charEncoding="utf-8" />
<c:import url="heading.html" charEncoding="utf-8" var="inner_c" scope="request" /><c:out value="${requestScope.inner_c}" escapeXml="true" />
Вторым наиболее часто используемым приемом сборки странички из кусочков, является перенаправление на другой адрес, для этого используем тег redirect, в качестве атрибута которого укажем url (есть еще атрибут var и scope, но глубокого смысла в их существовании я не нашел).
<c:redirect url="heading.html"><c:param name="fio" value="${helloMachine.fio}" /></c:redirect>
<c:import url="heading.jsp" charEncoding="utf-8"><c:param name="fio" value="${helloMachine.fio}" /></c:import>
<c:url value="/a3.jsp" />
/Имя-Моего-Контекста/a3.jsp
| « Тестируй веб-сайты вместе с Badboy. Часть 3 | Тестируй веб-сайты вместе с Jmeter » |