JSP – библиотека пользовательских тегов JSTL - Параметризованные теги
ОГЛАВЛЕНИЕ
Параметризованные теги
Надо отметить два момента по обработке атрибутов при разработке параметризованных тегов:
1. Добавить заданный метод в обработчик тега
2. Добавить новый тег в customTag.tld
Можно сослаться на выделенную часть предыдущего примера.
Теги с телом
Обработчик тега для тега с телом реализуется по-разному в зависимости от того, один или несколько раз надо вычислять тело.
• Однократное вычисление: Если тело надо вычислять однократно, обработчик тега должен реализовывать интерфейс Tag или расширять абстрактный класс TagSupport; метод doStartTag должен возвращать EVAL_BODY_INCLUDE, и если тело вообще не надо вычислять, то он должен возвращать BODY_SKIP.
• Многократное вычисление: Если тело надо вычислять многократно, должен реализовываться интерфейс BodyTag. Интерфейс BodyTag расширяет интерфейс Tag и определяет дополнительные методы (setBodyContent, doInitBody и doAfterBody), позволяющие обработчику тега проверять и по возможности менять его тело. Кроме того, аналогично классу TagSupport, можно расширить класс BodyTagSupport, предоставляющий стандартные реализации для методов в интерфейсе BodyTag. Обычно надо реализовать методы doInitBody и doAfterBody. doInitBody вызывается после установления содержимого тела, но до его вычисления, и doAfterBody вызывается после вычисления содержимого тела.
Однократное вычисление
Ниже показан пример однократного вычисления с расширением класса BodyTagSupport. Этот пример читает содержимое тела и переводит его в верхний или нижний регистр в зависимости от заданного атрибута.
Вначале надо создать класс обработчика тега:
package jstl;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTagSupport;
public class ChangeCaseTag extends BodyTagSupport {
private String mCase;
public void setCase(String pCase) {
mCase = pCase;
}
public int doAfterBody() throws JspException {
try {
BodyContent bc = getBodyContent();
String body = bc.getString();
JspWriter out = bc.getEnclosingWriter();
if (body != null) {
if ("upper".equalsIgnoreCase(mCase)) {
out.print(body.toUpperCase());
} else {
out.print(body.toLowerCase());
}
}
} catch (IOException ioe) {
throw new JspException("Error: " + ioe.getMessage());
}
return SKIP_BODY;
}
}
Следующий шаг – добавить тег в файл описателя библиотеки тегов customTag.tld:
<taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>ct</short-name>
<uri>/WEB-INF/customTag</uri>
<tag>
<name>changeCase</name>
<tag-class>jstl.ChangeCaseTag</tag-class>
<body-content>JSP</body-content>
<info>Этот тег отображает текущую дату сервера в заданном пользователем формате</info>
<attribute>
<name>case</name>
<required>true</required>
<description>Задайте верхний или нижний регистр</description>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
</taglib>
Имейте в виду, что при написании тега с телом значение тега <body-content> должно быть JSP или jspcontent.
Тест-драйвер для этого примера показан ниже:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="/WEB-INF/customTag.tld" prefix="ct" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Верхний или нижний регистр</title>
</head>
<body>
<h2>
Верхний регистр:
<ct:changeCase case="upper">
Hello World
</ct:changeCase>
</h2>
<h2>
Нижний регистр:
<ct:changeCase case="lower">
Hello World
</ct:changeCase>
</h2>
</body>
</html>
Результаты должны быть подобны рисунку, показанному ниже:
Многократное вычисление
Теперь рассмотрим пример тега тела, вычисляемого несколько раз. Тег принимает целое число в качестве атрибута и распечатывает свое HTML тело столько раз, сколько указано в коде JSP.
Снова вначале создаем класс обработчика тега:
package jstl;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTagSupport;
public class LoopTextTag extends BodyTagSupport {
private int mTimes = 0;
private BodyContent mBodyContent;
public void setTimes(int pTimes) {
mTimes = pTimes;
}
public void setBodyContent(BodyContent pBodyContent) {
mBodyContent = pBodyContent;
}
public int doStartTag() throws JspException {
if (mTimes > 1) {
return EVAL_BODY_TAG;
} else {
return SKIP_BODY;
}
}
public int doAfterBody() throws JspException {
if (mTimes > 1) {
mTimes--;
return EVAL_BODY_TAG;
} else {
return SKIP_BODY;
}
}
public int doEndTag() throws JspException {
try {
if (mBodyContent != null) {
mBodyContent.writeOut(mBodyContent.getEnclosingWriter());
}
} catch (IOException pIOEx) {
throw new JspException("Error: " + pIOEx.getMessage());
}
return EVAL_PAGE;
}
}
Методы этого тега выполняют следующие задачи:
• Метод doStartTag вызывается в начале тега. Он проверяет, надо ли выполнять цикл.
• setBodyContent вызывается контейнером JSP, чтобы проверить на наличие нескольких циклов.
• Метод doAfterBody вызывается после каждого вычисления; число требуемых выполнений цикла уменьшается на единицу, затем он возвращает SKIP_BODY, когда число выполнений не превышает один.
• Метод doEndTag вызывается в конце тега, и содержимое (если имеется) записывается в закрывающий писатель.
Аналогично предыдущим примерам, следующий шаг – добавить описатель нового тега в customTag.tld:
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>ct</short-name>
<uri>/WEB-INF/customTag</uri>
<tag>
<name>loopText</name>
<tag-class>jstl.LoopTextTag</tag-class>
<body-content>JSP</body-content>
<info>Этот тег отображает заданный текст несколько раз</info>
<attribute>
<name>times</name>
<required>true</required>
<description>Укажите число повторений текста</description>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
Заметьте, что тег <rtexprvalue> равен true, что указывает, что вычисления производятся во время выполнения.
Наконец, пишем пример страницы JSP для тестирования тега <loopText>.
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="/WEB-INF/customTag.tld" prefix="ct" %>
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=UTF-8">
<title>Текст цикла пользовательского тега JSTL</title>
</head>
<body>
<center>
<ct:loopText times="5">
<h3>Текст цикла!</h3>
</ct:loopText>
</center>
</body>
</html>
Вывод должен выглядеть подобно рисунку, показанному ниже:
Вывод
Пользовательские теги улучшают разделение логики программы и представления. Разные примеры в данной статье показывают способы разработки и развертывания простых и сложных пользовательских тегов. Также посмотрите, что проект Jakarta Taglibs предлагает для разных библиотек пользовательских тегов.