Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ТАБЛИЦА ТЭГОВ HTML.doc
Скачиваний:
24
Добавлен:
12.05.2015
Размер:
401.41 Кб
Скачать

Итеративные тэги

Одна из наиболее мощных особенностей произвольных тэгов в JSP - это то, что они могут итерировать, как цикл for или while в Java и, таким образом, производить динамический вывод.

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

Предположим, что вы хотите сгенерировать список простых чисел (чисел, делящихся только на себя и на 1) и отобразить его в HTML в виде ненумерованного списка. Что вам действительно желательно - это тэг, который может генерировать все простые числа в пределах указанного диапазона, предоставит вам доступ к каждому значению и поместит его в желаемый вам формат. Так как вы не знаете, сколько чисел будет в заданном диапазоне, а их может быть несколько, вы не захотите набирать HTML тэги для списка <li> и </li> для каждого из них. Допустим, что ваш тэг называется primtag, и вы хотите, чтобы ваш JSP файл выглядел примерно так:

<ul>

<tijtags:primetag start = "1" end= "25">

<li><%=value%></li>

</tijtags:primetag>

</ul>

Обратите внимание, что есть начальный и конечный HTML тэги <ul>, окружающий весь блок. **(HTML лекция выходит далеко за пределы темы этой главы, но коротко скажу, что они определяют ненумерованный список и внутри тела того тэга все данные между парой <li> и </li> будут отображаться, как помеченный элемент списка.)

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

В этом тэге, в отличие от двух предыдущих тэгов, есть не только завершающий тэг, указанный отдельно, </tijtags…, но также некое содержимое тела между начальным и конечным тегами. Вот что делает этот тэг особенно интересным. Тэги <li> являются простым HTML, как сказано выше, но между этим, заключенная в скриплетные скобки JSP, есть ссылка на переменную value.

Есть два очень мощных свойства этого произвольного тэга. Во-первых, он делает доступной переменную value для использования в скриплете или в простом JSP выражении, таком как <%=value%>. Во-вторых, все, что находится в теле нашего произвольного тэга, неоднократно обрабатывается и добавляется в выходной поток, чтобы быть представленным браузеру. Это значит, что не только приведенный выше тэг будет зациклен до тех пор, пока не найдет все примитивные числа внутри указанного диапазона, но также будут отображаться тэги <li> и </li> наряду со значением переменной value для каждого числа! Другими словами, приведенный выше JSP код - это все, что вам необходимо для отображения значений простых чисел в чистом списке. И вам даже не нужно знать, сколько чисел должно получиться.

Случайно это стало очень полезно. Это тот тэг, который помогает снизить количество встроенного кода скриплета в нашем хорошо сделанном тэге, но дает нам полную программную функциональность, такую, как цикл.

Чтобы реализовать этот тэг вам необходимо выполнить следующие задачи:

Создать (или найти) класс с подходящей логикой для генерации простых чисел.

Написать класс тэга, который реализует подходящий интерфейс тэга.

Написать методы установки для параметров start и end.

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

Создать для тэга TLD или файл дескриптора библиотеки тэга.

Вы можете найти класс PrimeUtilities на CD (??) или в приложении (??). Этот пример использует метод sievePrimes( ), который находит простые числа. Есть много ресурсов в Интернете для нахождения такого алгоритма, если вы интересуетесь подобного рода вещами.

Давайте взглянем на реальный класс тэга.

package cx2.tags;

import java.util.ArrayList;

import java.util.Iterator;

import javax.servlet.jsp.tagext.BodyTagSupport;

import javax.servlet.jsp.JspException;

import javax.servlet.jsp.PageContext;

import com.bruceeckel.PrimeUtilities;

 

public class PrimeNumTag extends BodyTagSupport {

  private int start = 0;

  private int end = 0;

  ArrayList primeList;

  Iterator primeIterator;

  public void setStart(int start) {

      this.start = start;

  }

  public void setEnd(int end) {

      this.end = end;

  }        

  public int doStartTag() throws JspException {

   

      try {

          primeList = PrimeUtilities.sievePrimes(start, end);

          primeIterator = primeList.iterator();

      } catch (Exception e) {

          e.printStackTrace();

          return SKIP_BODY;

      }

      return EVAL_BODY_BUFFERED;

  }

  public void doInitBody() throws JspException {

      try {

          if (primeIterator.hasNext()) {

              pageContext.setAttribute("value",

             primeIterator.next());

          }

      } catch (Exception e) {

          e.printStackTrace();

      }        

  }

  public int doAfterBody() {

      try {

          if (primeIterator.hasNext()) {

              pageContext.setAttribute("value",

                                       primeIterator.next());

              return EVAL_BODY_BUFFERED;

          } else {

             bodyContent.writeOut(bodyContent.getEnclosingWriter());

              return SKIP_BODY;

          }

      } catch (Exception e) {

          e.printStackTrace();

          return SKIP_BODY;

      }

  }

   public void release() {

      primeList = null;

      start = 0;

  }

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

Этот класс, опять таки, использует объект PageContext, предоставляемый контейнером посредством метода setPageContext( ). Так как этот класс тэга наследуется от BodyTagSupport, больше нет необходимости хранить объект pageContext самостоятельно. Об этом заботится родительский класс. Это хороший пример повторного использования кода посредством наследования.

Метод doStartTag( ) становиться первым методом, о котором вам необходимо позаботиться. В приведенной выше реализации используется класс PrimeUtilities, использующийся для получения и хранения объекта типа Iterator, который содержит простые числа. Обратите внимание, что если не возникнет исключения, этот метод возвращает значение EVAL_BODY_BUFFERED, в отличие от двух предыдущих примеров, в которых возвращалось значение SKIP_BODY во всех случаях. Как вы можете предположить, это ключевое значение для реализации тэга, который обрабатывает содержимое своего тела.

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

Мы употребляли аналогичную форму setAttribute( ) ранее, но в этот раз вы заметите, что метод имеет только два параметра, поскольку этот класс использует область видимости по умолчанию PAGE_SCOPE. Действия, делающие этот объект доступным для использования в JSP странице, заключены в части ответственности специального класса, называемого TagExtraInfo - класс, который будет рассмотрен немного позднее. Конструкция цикла теперь инициализирована и, если не произошло никаких исключений, в этом месте тэг будет читать текст тела.

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

Если вы посмотрите внимательнее, вы увидите, что все это не достаточно очевидно. Объект, на который ссылается bodyContent, фактически является экземпляром класса BodyContent, который находится в пакете javax.servlet.jsp.tagext. Он инкапсулирует содержимое тела этого конкретного тэга, а это немного похоже на выходной поток, но с некоторой дополнительной функциональностью. Если бы объект PrimeNumTag не наследовался бы от класса BodyTagSupport, то необходимо было бы реализовать метод setBodyContent( ) и сохранять объект bodyContent "вручную", аналогично тому, как это мы делали с объектом pageContext в предыдущих примерах.

Поскольку объект содержимого тела включает только тело вашего конкретного тэга, вам будет необходимо вызывать метод getEnclosingWriter(), чтобы получить верный выходной поток.

Что является реальной причиной возникновения цикла - это возвращаемое значение. Если метод doAfterBody( ) возвращает константу EVAL_BODY_BUFFERED, то контейнер будет обрабатывать тело тэга и вызовет метод снова. Если метод возвращает SKIP_BODY, то цикл прекращается и вам предоставляется возможность послать содержимое тела в прилагающийся поток writer'а, ваши значения будут отображены на экране браузера.

Теперь осталось только создать запись о тэге в TLD файле.

  <tag>

   <name>primetag</name>

   <tagclass>cx2.tags.PrimeNumTag</tagclass>

        <bodycontent>JSP</bodycontent>

   <info> Generates Prime Number sequences </info>

   <attribute>

       <name>start</name>

      <required>false</required>

   </attribute>

   <attribute>

       <name>end</name>

      <required>true</required>

   </attribute>

   <variable>

      <name-given>value</name-given>

       <variable-class>Integer</variable-class>

      <declare>true</declare>

      <scope>AT_BEGIN</scope>

   </variable>

  </tag>

Если вы посмотрите на атрибуты тэга, вы увидите, что атрибут start не является обязательным, а атрибут end - является. Это происходит просто из-за выбранного дизайна класса. Здесь имеется в виду, что если start не указывается, используется значение по умолчанию 0, но так как (по всей видимости) существует бесконечное количество простых чисел, то хорошо бы ограничить конечное число. Вы должны помнить, что если автор JSP страницы не согласен с этим ограничением при написании JSP страницы и не обратит внимания на значение end, контейнер выбросит исключение в окно web браузера.

После тэга атрибута есть новый тэг, с которым вы еще не знакомы, это тэг <variable> со своими вложенными тэгами <name-given>, <variable-class> и <declare>. Они, как вы можете ожидать, сообщают JSP контейнеру о переменной, которая добавляется в контекст страницы вашим тэгом. Так как эта переменная является объектом, а не JavaBean'ом, нет автоматического механизма, чтобы сообщить контейнеру тип переменной, так что вам необходимо сделать это с помощью такого тэга. Значения этих тэгов перечисляется в конце этой главы, но давайте взглянем на некоторые из них сейчас.

Тэг <name-given> сообщает контейнеру, какое имя дается используемой переменной. Вы можете использовать другой тэг, <name-from-attribute> в этом месте, который позволит вам указать имя атрибута, значение времени трансляции которого будет содержать имя вашей переменной. Таким образом, вы можете сделать имя в зависимости от некоторых других значений времени трансляции.

Тэг <variable-class> сообщает контейнеру переменную какого типа необходимо создать, класс, с указанным именем, должен содержаться в classpath во время трансляции, а именно в то время, когда JSP страница компилируется в первый раз на сервере. Чаще всего вы будете использовать стандартные типы, находящиеся в java.lang.

Тэг <declare> сообщает контейнеру нужно или нет декларировать эту переменную. Это предназначено для дальнейших реализаций JSP. Пока же вы всегда будете желать, чтобы переменная декларировалась, что является значением по умолчанию.

Значение <scope> сообщает контейнеру в каком месте вашего скрипта переменная должны быть доступна автору JSP страницы. Возможные значения: NESTED - что делает переменную доступной только между начальным и конечным тегами на JSP странице; AT_BEGIN - что делает переменную доступной между начальным тэгом и концом страницы; или AT_END - что делает переменную доступной после конечного тэга до конца страницы.

Во время написания наблюдались некоторые проблемы в текущей реализации Tomcat (4.0.4) при чтении тэга <attribute>. По этой причине вы можете использовать более продвинутую и мощную технику класса TagExtraInfo. Это влечет за собой замену тэга <variable> на тэг, называемый <teiclass> или тэг класса дополнительной информации. Более детально это описано ниже в этой главе.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]