| |
В этой главе рассматриваются контракты между JSP-контейнером и JSP-страницей.
Протокол прекомпиляции (см. Раздел JSP.8.4) также представлен здесь.
Информация, представленная здесь, не зависит от Языка Скриптинга, используемого на JSP-странице.
Глава JSP.6 описывает информацию для случая, когда атрибут
language директивы page установлен в "java".
Классы реализации
JSP-страницы должны использовать классы JspFactory и PageContext для получения
преимуществ платформозависимых реализаций.
JSP-страница представлена на этапе выполнения объектом реализации JSP-страницы и выполняется JSP-контейнером. Объект реализации JSP-страницы - это servlet/сервлет. JSP-контейнер направляет запросы от клиента объекту реализации JSP-страницы и ответы объекта реализации JSP-страницы - клиенту.
JSP-страница описывает создание объекта response из объекта request
для данного протокола, возможно, создавая и/или используя в ходе этого процесса
некоторые другие объекты. JSP-страница может также указывать, как должны обрабатываться некоторые события.
В JSP 1.2 только события init и destroy являются допустимыми событиями.
JSP-контейнер локализует соответствующий экземпляр класса реализации
JSP-страницы и направляет ему запросы, используя протокол Servlet.
JSP-контейнеру может потребоваться создать такой класс динамически из исходной JSP-страницы до
направления ей объектов request и response.
Класс Servlet
определяет контракт между JSP-контейнером и классом реализации JSP-страницы.
Если используется протокол HTTP, контракт описывается классом
HttpServlet. Большинство JSP-страниц используют протокол HTTP, но другие
протоколы также разрешены данной спецификацией.
JSP-контейнер автоматически делает несколько серверных/server-side объектов
доступными объекту реализации JSP-страницы. См. Раздел JSP.2.8.3.
JSP-спецификация определяет контракт между JSP-контейнером и автором JSP-страницы.
Этот контракт определяет обязательства, которые автор может установить для
акций, описанных на JSP-странице.
Главной частью этого контракта является метод _jspService(), который
генерируется автоматически JSP-контейнером из JSP-страницы.
Детальная информация об этом контракте дана в Главе JSP.6.
Контракт описывает также, как автор JSP может обозначить, какие акции будут предприниматься, когда будут вызываться
методы реализации страницы init() и destroy(). В спецификации
JSP 1.2 это делается через определение методов с именами jspInit() и jspDestroy()
в объявлении элемента скриптинга в JSP-странице.
Метод jspInit(), если он имеется, будет вызываться для подготовки
страницы перед направлением первого запроса. Аналогично, JSP-контейнер может
затребовать ресурсы, используемые JSP-страницей, если запрос не обслуживается JSP-страницей,
через вызов её метода jspDestroy(), если он имеется.
Автор JSP-страниц не может (пере)определять методы Servlet через объявление элемента скриптинга.
JSP-спецификация резервирует имена методов и переменных, начинающиеся с jsp, _jsp, jspx и _jspx, в любом сочетании регистров.
HttpJspPage
Выполнению контракта между JSP-контейнером и автором JSP-страницы помогает
требование о том, что класс Servlet, соответствующий JSP-странице, обязан
реализовывать интерфейс HttpJspPage (или интерфейс JspPage, если протокол - не HTTP).
| JSP-Контейнер |
JSP-Страница |
|---|---|
|
|
|
На Рисунке J2EE.8.1 показаны включённые контракты. Теперь мы рассмотрим этот процесс более детально.
JSP-контейнер создаёт класс реализации JSP-страницы для каждой JSP-страницы. Имя класса реализации JSP-страницы зависит от особенностей реализации. Объект реализации JSP-страницы принадлежит к зависящему от реализации именованному архиву. Этот архив может отличаться от одной JSP-страницы к другой. Неименованный архив не должен использоваться без явного "импортирования" класса.
JSP-контейнер может создавать для JSP-страницы класс реализации, либо суперкласс
может быть предоставлен автором JSP-страницы с помощью атрибута extends директивы page.
Механизм extends предназначен для опытных пользователей. Он должен
использоваться предельно осторожно, так как он ограничивает возможность принятия
решений JSP-контейнером. Он может, к примеру, свести на нет усилия по повышению производительности.
Класс реализации JSP-страницы будет реализовывать Servlet, а протокол
Servlet будет использоваться для направления запросов классу.
Класс реализации JSP-страницы может зависеть от поддержки других классов. Если
класс реализации JSP-страницы упакован в WAR, все связанные классы должны будут
быть включены, так что пакет будет переносим на все JSP-контейнеры.
Автор JSP-страницы пишет JSP-страницу, ожидая, что клиент и сервер будут
взаимодействовать по определённому протоколу. JSP-контейнер обязан
гарантировать, штаа запросы и ответы для страницы используют нужный протокол.
Большинство JSP-страниц используют протокол HTTP, и их классы реализаций обязаны
реализовать интерфейс HttpJspPage, который расширяет JspPage.
Если это не HTTP-протокол, тогда класс реализует интерфейс, расширяющий JspPage.
Контракт между JSP-контейнером и Java-классом, реализующим JSP-страницу, соответствует интерфейсу
Servlet. См. детали в спецификации Servlet 2.3.
Ответственность за выполнение этого контракта лежит на реализации JSP-контейнера,
если JSP-страница не использует атрибут extends директивы jsp.
Если атрибут extends директивы jsp
используется, автор JSP-страниц обязан гарантировать, что суперкласс, заданный в
атрибуте extends, поддерживает этот контракт.
| Комментарии | Методы, вызываемые JSP-Контейнером |
|---|---|
| Метод может по выбору/optionally быть определён в JSP-странице. Метод вызывается при инициализации JSP-страницы. Если метод вызывается, доступны все методы сервлета, включая getServletConfig(). |
void jspInit()
|
| Метод по выбору определяется в JSP-странице. Метод вызывается при уничтожении страницы. |
void jspDestroy()
|
| Метод не может быть определён в JSP-странице. JSP-контейнер автоматически генерирует этот метод, базируясь на содержимом JSP-страницы. Метод вызывается при каждом клиентском запросе. |
void_jspService(<ServletRequestSubtype>, <ServletResponseSubtype>) throws
IOException, |
Как видно из Таблицы JSP.8-1, методы контракта между JSP-контейнером и JSP-страницей требуют наличия параметров запроса и ответа.
Формальным типом параметра запроса (который в этой спецификации называется <ServletRequestSubtype>)
является интерфейс, расширяющий javax.servlet.ServletRequest.
Этот интерфейс обязан определять зависящий от используемого протокола запроса
контракт между JSP-контейнером и классом, реализующим JSP-страницу.
Аналогично и формальный тип параметра ответа (называемый в этой спецификации
<ServletResponseSubtype>)
является интерфейсом, расширяющим
javax.servlet.Servlet-Response. Этот интерфейс обязан определять зависящий от
используемого протокола ответа контракт между JSP-контейнером и классом,
реализующим JSP-страницу. Интерфейсы запроса и ответа вместе описывают зависящий
от протокола контракт между JSP-контейнером и классом, реализующим эту JSP-страницу.
HTTP-контракт определяется интерфейсами
javax.servlet.http.HttpServletRequest и javax.servlet.http.HttpServletResponse.
Интерфейс JspPage ссылается на эти методы,
но не может синтаксически описать методы, вызывающие подтипы
Servlet(Request,Response). Однако интерфейсы для специфических протоколов,
которые расширяют JspPage, могут делать это, так же, как
HttpJspPage описывает их для протокола HTTP.
JSP-контейнеры, соответствующие этой спецификации (классами реализации JSP-страницы
и работой JSP-контейнера), обязаны реализовывать интерфейсы запроса и ответа (request
и response) для HTTP-протокола, как описано в этом разделе.
extends
Если атрибут extends директивы page (см.
Раздел 2.10.1) в JSP-странице не используется, JSP-контейнер может
генерировать любой класс, удовлетворяющий контракту, описанному в Таблице JSP.8-1,
если он трансформирует JSP-страницу.
В следующих примерах Пример Кода 8.1 иллюстрирует общий/родовой HTTP-суперкласс,
названный ExampleHttpSuper.
В Примере Кода 8.2 показан подкласс, названный _jsp1344, который расширяет
ExampleHttpSuper и является классом, сгенерированным из JSP-страницы.
Используя отдельные классы _jsp1344 и
ExampleHttpSuper, транслятор JSP-страницы не нуждается в поиске информации,
содержит ли JSP-страница объявления с jspInit() или jspDestroy().
Это значительно упрощает реализацию.
imports javax.servlet.*;
imports javax.servlet.http.*;
imports javax.servlet.jsp.*;
/**
* Пример суперкласса для HTTP JSP-класса
*/
abstract class ExampleHttpSuper implements HttpJspPage {
private ServletConfig config;
final public void init(ServletConfig config) throws ServletException {
this.config = config;
jspInit();
public void jspInit() {
}
public void jspDestroy() {
}
}
final public ServletConfig getServletConfig() {
return config;
}
// Этот метод не является final, поэтому он может быть переопределён более точным методом
public String getServletInfo() {
return "Суперкласс для HTTP JSP"; // можно и получше?
}
final public void destroy() {
jspDestroy();
}
/**
* Точка входа в сервис.
*/
final public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
// количество отловленных исключений увеличится при наличии внутренней ошибки.
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
_jspService(request, resonse);
/**
* Абстрактный метод, предоставляемый JSP-процессором в подклассе,
* обязан быть определён в подклассе.
*/
abstract public void _jspService(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException;
}
imports javax.servlet.*;
imports javax.servlet.http.*;
imports javax.servlet.jsp.*;
/**
* Пример класса, генерируемого для JSP.
*
* Имя класса непредсказуемо.
* Мы принимаем, что это пакет HTTP JSP (как чаще всего и бывает)
*/
class _jsp1344 extends ExampleHttpSuper {
// Следующий код вставлен непосредственно через объявления.
// Любые следующие части могут или могут не иметься;
// если они не определены здесь, будут использоваться
// методы суперкласса.
public void jspInit() {....}
public void jspDestroy() {....}
// Следующий метод генерируется автоматически
// JSP-процессором.
// Тело/body JSP-страницы
public void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// инициализация неявных переменных
HttpSession session = request.getSession();
ServletContext context =
getServletConfig().getServletContext();
// для этого примера мы принимаем, что директива буферизована
JSPBufferedWriter out = new
JSPBufferedWriter(response.getWriter());
// далее идёт код из скриптлетов, выражений и статического текста.
}
}
extends
Если автор JSP-страниц использует extends,
генерируемый класс идентичен классу из Примера Кода 8.2, за исключением того,
что имя этого класса это имя, специфицированное в атрибуте extends.
Контракт класса реализации JSP-страницы не изменяется. JSP-контейнер должен
проверить (обычно через отражение/reflection), что предоставленный суперкласс:
HttpJspPage, если протокол - HTTP, либо
JspPage - в ином случае.Servlet объявлены final.service() из Servlet API вызывает метод _jspService();
init(ServletConfig) хранит конфигурацию,
даёт к ней доступ как к getServletConfig, затем вызывает jspInit;destroy вызывает jspDestroy.JSP-контейнер может выдавать фатальную ошибку трансляции, если обнаружит, что предоставленный суперкласс не удовлетворяет этим требованиям, но большинство JSP-контейнеров эту проверку не будут выполнять.
JSP-контейнер буферизует данные (если директива jsp специфицирует это, используя
атрибут buffer), когда они высылаются от сервера клиенту.
Headers/"Шапки"
клиенту не высылаются, пока не вызван первый метод
flush. Следовательно, ни одна из операций, имеющих отношение к шапкам, таких как
методы setContentType, redirect или error, не является верной до тех пор, пока метод flush не
начнёт выполняться и шапки не начнут высылаться.
Класс javax.servlet.jsp.JspWriter буферизует вывод и высылает его. Класс
JspWriter используется в методе _jspService, как в следующем примере:
import javax.servlet.jsp.JspWriter;
static JspFactory _jspFactory = JspFactory.getDefaultFactory();
_jspService(<SRequest> request, <SResponse> response) {
// инициализация неявных переменных ...
PageContext pageContext = _jspFactory.createPageContext(
this,
request,
response,
false,
PageContext.DEFAULT_BUFFER,
false
);
JSPWriter out = pageContext.getOut();
// ....
// .... тело идёт здесь через "out"
// ....
out.flush();
}
Вы можете найти полный листинг
javax.servlet.jsp.JspWriter в Главе JSP.9.
При включённой буферизации, Вы можете всё ещё использовать метод redirect
скриптлета в файле .jsp, вызывая
response.redirect(какой-то URL) напрямую.
JSP-страница, использующая протокол HTTP, будет получать HTTP-запросы.
Контейнеры, соответствующие JSP 1.2, обязаны поддерживать простой протокол
прекомпиляции, а также некоторые базовые зарезервированные имена
параметров. Заметьте, что протокол прекомпиляции это понятие близкое, но не
то же самое, что компиляция JSP-страницы в Servlet-класс (Приложение JSP.A).
Все имена параметров запроса, начинающиеся с префикса "jsp",
зарезервированы спецификацией
JSP и не должны использоваться иначе, чем установлено данной спецификацией.
Все JSP-страницы должны игнорировать (и не зависеть от) параметры, начинающиеся
с "jsp_"
Запрос к JSP-странице, содержащий параметр запроса с именем "jsp_precompile", является
запросом прекомпиляции. Параметр "jsp_precompile" может не
содержать значения или может содержать значения "true" или "false".
В любом случае, такой запрос не должен отправляться JSP-странице.
Назначение запроса прекомпиляции в том, чтобы указать JSP-контейнеру, что нужно
прекомпилировать (предварительно откомпилировать) JSP-страницу в класс
реализации JSP-страницы. Это указание переправляется путём задания параметру
значения "true", или не задавая никакого значения, но учтите, что
запрос может быть проигнорирован.
Например:
1. ?jsp_precompile
2. ?jsp_precompile="true"
3. ?jsp_precompile="false"
4. ?foobar="foobaz"&jsp_precompile="true"
5. ?foobar="foobaz"&jsp_precompile="false"
1, 2 и 4 - действуют; запросы не будут направлены странице.
3 и 5 - верны; запрос не будет направлен странице.
6. ?jsp_precompile="foo"
- это неверно, и будет генерироваться ошибка HTTP error; 500 (Server error).
|
Закладки на сайте Проследить за страницей |
Created 1996-2025 by Maxim Chirkov Добавить, Поддержать, Вебмастеру |