JSTL: Шаблоны для разработки веб-приложений в java. Часть 1

Добавлено : 3 Nov 2008, 16:09

Эта статья является логическим развитием материалов посвященных средствам отображения информации (слой 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>");

Потом придумали jsp. Сделали его, похоже, для того, чтобы пишущие на asp (тогда еще не было asp.net) или php, не могли тыкать в java-программистов пальцами и тихо хихикать в кулачок. Действительно типовая страница характеризуется значительным превышением количества html-кода над динамической информацией (взятой из файлов, баз данных, вычисленных веб-приложением). Поэтому логично было не встраивать html-код внутрь java-кода, а наоборот встроить java-код внутрь html-шаблона.

<%@ page contentType="text/html;charset=UTF-8" language="java"%>
<body>
<%
    String vasuanoFIO = "Бла-бла-бла";
    if ( 1 < 2)
        vasuanoFIO = "Бум-бам-тарарам";
%>
<h1><%= vasuanoFIO %></h1>
</body>

Выглядит ужасно. Конечно, если нужно сделать одну страничку и быстро, то это наилучший выход. Вот только “пихать” логику (в примере сравнение, расчет чему же будет равна переменная vasyanoFIO) это не кошерно. По мере роста количества расчетов и усложнения верстки код превращается в винегрет. Большой код не читаем. Код, где и html и логика, не читаем вдвойне. Очень скоро будет продублирована часть логики, и размазана по тысяче файлов, так что понять, откуда что взялось не возможно. Где-то тут еще “повесился” дизайнер, когда понял то, сколько ему нужно потратить здоровья, для того чтобы заменить размер шрифта заголовка h1 на h2. Вообще-то в стандарте jsp рекомендуемой практикой является вынос логики обработки запроса в объект bean. Например, задачу с приветствиями можно оформить в виде отдельного класса, добавить к нему поля (управляющие расчетом итогового значения).

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;
   
}
}

Обратите внимание на метод getResult – именно он содержит логику расчета сообщения, которое будет показано пользователю. Теперь нужно создать jsp-файл, в котором создается объект bean, наполняются его свойства значениями и в нужном месте извлекается расчет значения (getResult).

// создаем объект Логики, указываем его имя и java-класс 
<jsp:useBean id="helloMachine" class="t
sti.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>

Такой подход имеет слишком много подводных камней (я не про то, что инициализация всех нужных полей должна быть выполнена до использования bean-а, или то, что поступающие на вход данные нужно проверить, экранировать и прочая и прочая – все это решается без проблем. Например, если создать jsp-страницу как наследник от некоторого класса сервлета, который выполняет столь нужные но рутинные действия. Основных проблем две: программисты могут (а значат, будут) смешивать java-код и html, если бы были запрещены такие теги как:

<% 
 If ( bla-bla)
   …
 Else%>

То у нас не было бы никакого выбора, и мы должны были бы уже писать так код, чтобы четко разделить логику (bean-ы) и внешний вид (jsp). Но тут подкралась другая проблема: реальный сайт оперирует данными не только скалярными (переменная со строковым значением fio), но и списками, массивами. Так что для их обработки нам нужны циклы, условные конструкции (если сумма денег на счету меньше чем 100 баков, то вывести ее красной, иначе зеленой). Можно было бы перенести циклы и условия внутрь bean-ов, но фактически это означает, что мы должны будем внутрь этих bean-ов перетащить также и генерацию html-кода (а к чему приводит такое решение, мы уже видели на примере сервлетов). В общем, как ни крутись, но хоть какая-то примитивная обработка условий и циклов на странице должна быть, иначе мы получим гораздо большее количество проблем.

<%
    String vasuanoFIO = "Нет. Ты не сможешь победить силы Зла";
    if ( 1 < 2)
        vasuanoFIO = "Твоя борьба против каши в JSP обречена на провал, Ха-ха-ха";
%>

На далеком диком западе, в стране непуганых дизайнеров, существует страшное поверье, что если дизайнер увидит код java в странице jsp, то он сойдет с ума и ему не поможет даже волшебное зелье “Гамбургер с кока-колой”. Поэтому придумали пользовательские теги. Т.е. вы создаете java-класс, который умеет делать что-то, и внедряете его в страницу, примерно, так (детали как создавать теги, описывать их с помощью tld-файлов я пропускаю, они есть в любом уважающем себя учебнике):

<showcalendar />
<mailsend to="vasyano@mail.ru" />

Это очень удобно, ведь теперь дизайнер не пугается тегов, он знает, что что-то заключенное в угловые скобочки никак не может ему навредить (собственно, он может не отличать тег H1 от придуманного вами тега <mailsend>). И началось время, когда все стали создавать собственные библиотеки “очень нужных” тегов. Признаюсь, я сам на начальных этапах занимался изобретением тегов вида:

<my:if test=”bla == bla”>
   Bla-bla-bla
</my:if>

В любом случае такой подход не способствовал накоплению знаний, библиотек тегов было слишком много, их делали все кому ни лень, страдало качество. Так что появление каких-то стандартов, принятых наборов тегов и их качественная реализация с последующим клеймением позором тех, кто продолжал использовать собственные “уникально-неповторимые” поделки была предопределена. И так появились JSTL – тема сегодняшнего материала.

1. Загрузить с сайта  архив с библиотекой jstl (я использую версию 1.2).
2. Добавить эту библиотеку в папку WEB-INF/lib вашего веб-приложения.
3. Подключить в начале jsp-файла с помощью специальных директив taglib те библиотеки тегов, которые хотите использовать:

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

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

Теги для работы с xml-документами:

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

Теги для работы с базами данных (Ну зачем вы это сюда вставили …):

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

Теги для форматирования информации перед выводом и работы с i10n и i18n:

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

Сначала разберем теги из библиотеки http://java.sun.com/jsp/jstl/core. Начнем мы с самого простого: нужно вывести на экран браузера некоторый текст.

<%@ 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>

Вот, правда, смысла в такой конструкции мало, ведь простой, статический текст мы можем выводить и без использования тегов jstl. А вот если нужно вывести на экран какие-то динамически рассчитываемые величины, то c:out уже нужен:

<c:out value="12+56*2" />

Запустили, проверили, что получилось? Да ничего не получилось: на экран вывелся сам текст формулы, а не результат вычисления 12+56*2. Дело в том, что если мы хотим вывести некоторую информацию вычисляемую “на-лету”, то эту часть значения атрибута value тега c:out нужно поместить внутрь фигурных скобок.

<c:out value="${12+56*2}" />

Уже лучше: на экране мы увидели цифру 124. Однако вывод на экран просто статических формул не слишком частое занятие, а вот вывести значение полученной от пользователя или html-формы переменной уже лучше: <c:out value="${param.fio}" /> Теперь если я введу в адресную строку браузера нечто вроде: http://center:8080/velo/a2.jsp?fio=%C2%E0%F1%FF (Эти кракозюбры – слово ВАСЯ) И увижу на страницу … какую-то белиберду.

Aany

Собственно, другого не ожидалось: для того чтобы заставить tomcat нормально раскодировать входящие переменные нужно еще постараться. Как, что, и почему я писал в другой своей статье посвященной Русским буквами и java. Внимание, перед тем как написать имя переменной (fio) я должен указать контекст (место, где нужно искать эту переменную). Есть список предопределенных контекстов:

Контекст Комментарий
pageScope Контекст страницы (т.е. переменные объявленные на этой странице и доступные только для этой страницы).
requestScope Доступ к таким переменным имеют все страницы, сервлеты обслуживающие один, текущий, вот этот самый, запрос пользователя.
sessionScope Доступ к переменным сохраняется на протяжении всего сеанса пользователя (пока не закроет браузер или не истечет предельное время бездействия).
applicationScope Доступ к переменным сохраняется изо всех страниц размещенных внутри веб-приложения (самый глобальный контекст).
param В этом контексте находятся все переменные, полученные страницей от пользователя либо как параметры адресной строки, либо как поля html-формы.
paramValues Список значений тех переменных, которые были переданы в страницу пользователем, правда, формат отличен от предыдущего случая. Если там param фактически имел тип HashMap<String, String>, то здесь HashMap<String, String [] >.
header В этом объекте хранится информация об http-заголовках которые были переданы от браузера клиента вашему веб-серверу.
headerValues Список значений http-заголовков.
initParam Конфигурационные параметры, указанные для вашей страницы, сервлета в файле web.xml
cookie Список переменных помещенных внутрь cookie.
pageContext Ссылка на объект pageContext (см. описание служебных объектов автоматически создаваемых внутри jsp-страницы).

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

<c:out value="${param.fio}" />
<c:out value="${param['fio']}" />

У тега c:out есть еще несколько атрибутов:

<c:out value="${param.fio}" default="NO DATA" escapeXml="true" />

В этом примере, в случае если на вход странице не была подана переменная fio, то будет выведена фраза “NO DATA”. Атрибут же escapeXML служит для того чтобы экранировать (заменить специальные символы xml: знаки больше, меньше, кавычки …) на их entities (т.е. < > …)

Научившись выводить переменные самое время задуматься над тем как эти переменные создавать. Помимо очевидных вариантов: из параметров запроса, из объекта 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}" />

Здесь я показываю несколько хитрых моментов в работе jstl. Во-первых, обратите внимание, как отличаются имена контекстов при операции положить переменную (set) и операции извлечь переменную (out). В первом случае я должен писать слово session, а во втором случае – sessionScope. Также посмотрите, что я создал переменную petyan сразу во всех четырех контекстах. Когда же я вывожу эту переменную на экран, то название контекста, к которому принадлежит переменная, я не указал. В этом случае работает правило поиска нужного контекста: ищем переменную внутри pageScope, если не найдено внутри requestScope, если опять не найдено внутри sessionScope и, наконец, внутри applicationScope.

Есть еще один вариант синтакиса оператора c:set, когда нужно установить значение свойства некоторого java-bean внедренного на страницу.

<c:set target="${helloMachine}" property="fio" value="Ленка Слонова" />
<c:out value="${helloMachine.fio}" />

Для удаления переменных (на самом деле простого присвоения имя значения null) используется оператор remove, например, так:

<c:set var="fio" scope="session" value="Vasyano Petrovno" />
 fio1 = <c:out value="${fio}" />
 <c:remove var="fio" />
 fio2 = <c:out value="${fio}" />

Вывод переменных без предварительного их анализа, без условных операторов малополезен. Так что нам нужны операторы if и switch. Оператор if не слишком похож на своих больших братьев в java и других языках: нельзя задать ни ветку else, ни ветку elseif (elif), можно только проверить некоторое условие и если оно истинно, то сделать что-то:

<c:if test="${param.age gt 12}">
  Возраст более 12 лет
</c:if>
 
<c:if test="${param.age lt 25}">
  Возраст менее 25 лет
</c:if>

Обратите внимание на то, что я в условии использую не знаки “<” или “>”, а слова “gt” и “lt”, это необходимо т.к. в противном случае мы нарушим правила записи xml-документов. Еще есть такие слова-операторы:

eq – проверка на равенство
ne – проверка на неравенство
lt – строго менее чем
gt – строго более чем
le – меньше либо равно чему-то
ge – больше или равно чему-то

У тега 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>

В случае если нам нужно проверить несколько условий, то оператор if – не самое лучшее решение, здесь нужно использовать тег choose -> when -> otherwise:

<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>

Теперь разберемся как работать в JSTL с циклами. Есть две разновидности циклов: для прохода по элементам некоторого списка (для прохода всех чисел в отрезке ОТ и ДО). И вторая разновидность служит для прохода по списку token-ов (частей, на которые была разбита строка на основании некоторого символа разделителя). Первый тег “c:ForEach” имеет целых 6 атрибутов управляющих его работой, но среди них нет ни одного обязательного. Все дело в том, что c:ForEach предназначен и для прохода по элементам некоторого списка, например, так:

Прежде всего, я ввел в состав описанного выше класса 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 – это items играющий роль источника данных и var – переменная, в которую будет последовательно помещаться элементы массива/списка.

Второй вариант цикла 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>

И, наконец, последний атрибут для цикла For – varStatus. В эту переменную будет помещена информация о выполняемом цикле и текущем его шаге. Значение переменной разнится в зависимости от того, какая разновидность цикла нами используется, например, когда у нас обычный цикл от X до Y, то значением этой переменной будет текущий индекс:

<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>

Если же цикл выполняется по элементам коллекции, то поведение varStatus меняется. Теперь это не число, а сложный объект с информацией о начальном и конечном шаге цикла, об том первый элемент коллекции перебирается или нет, например:

<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>

Разобравшись с одной разновидностью цикла (наиболее часто встречающейся и наиболее полезной), перейдем ко второй – forTokens. Этот цикл похож на ранее приведенный 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>

Итак: строка “Гравитон Фотон Бозон Мюон” была разбита на отдельные подстроки с помощью разделителя delims (пробела). Цикл был начат не с первого элемента “Гравитона”, а со второго “Фотона”. На каждой итерации цикла также выводились сведения о номере этой итерации, признаке первая ли это итерация, а может последняя. Неприятность только в том, что значение переменной count использовать нельзя, эта величина не равна “4”, как ожидалось, а растет по мере изменения цикла (похоже, цикл идет по мере разбора строки, а не после его завершения). Значением атрибута tokens может быть не отдельный символ, а некоторое их количество, например, следующий пример идентичен ранее приведенному (значение delims теперь пробел, точка и запятая):

<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>

Очевидно, что написать хороший код страницы в одном файле, без разбиения его на части тяжело. Поэтому в состав JSTL входит тег, позволяющий в один jsp-файл включить другой jsp-файл, и называется этот тег import. Тег этот очень гибкий, в самом простом случае в страницу можно включить статический кусочек текста в виде html/txt-блока:

<c:import url="heading.html" />

Однако настоящей гибкости мы можем добиться лишь, когда включаемое содержимое является динамическим. Проверим, умеет ли import “включать” в jsp-страницу результат работы другой jsp-страницы:

Включаемая страница (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. Откуда же она взялась?

А теперь пример кода главной страницы (обратите внимание на то, что я указал область действия переменной 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" />

Последний атрибут для импорта – это varReader. В случае если мы укажем его, то результат вставки страницы не будет ни выведен на экран, ни помещен в строковую переменную var, а будет доступен только при чтении потока varReader.

Вторым наиболее часто используемым приемом сборки странички из кусочков, является перенаправление на другой адрес, для этого используем тег redirect, в качестве атрибута которого укажем url (есть еще атрибут var и scope, но глубокого смысла в их существовании я не нашел).

<c:redirect url="heading.html">
    <c:param name="fio" value="${helloMachine.fio}" />
</c:redirect>

Тег param можно использовать и при внедрении в страницу “подстраницы”:

<c:import url="heading.jsp" charEncoding="utf-8">
    <c:param name="fio" value="${helloMachine.fio}" />
</c:import>

Еще один малополезный тег = c:url, он служит для декорирования некоторого адреса, так если я запишу:

<c:url value="/a3.jsp" />

То на страницу будет вставлен адрес включая контекст приложения (собственно говоря, идея контекстов специфична для java, а браузер не может отличить контекст от просто имени папки), например, так:

/Имя-Моего-Контекста/a3.jsp

Источник — http://black-zorro.com/mediawiki/JSTL:_Шаблоны_для_разработки_веб-приложений_в_java._Часть_1

Теги: j2ee jstl patterns taglib