Технологии программирования. Компонентный подход В. В. Кулямин Лекция 7. Разработка пользовательского интерфейса в J2EE. Компоненты приложения J2EE, реализующие пользовательский интерфейс, отвечают за две функции в используемом образце данные-представление-обработчик — за представление данных для пользователя и за обработку его действий. Основной техникой, используемой для представления данных, являются серверные страницы Java (Java Server Pages, JSP). Для обработки запросов и действий пользователя используются сервлеты (servlets). Поскольку серверные страницы также в итоге преобразуются в сервлеты, сначала рассмотрим эти последние. Сервлеты представляют собой классы, реализующие обработку запросов, оформленных в виде стандартного протокола Интернет HTTP, и поэтому для лучшего понимания их работы стоит представлять себе в общих чертах устройство сообщений этого протокола. Формат сообщений HTTP HTTP (Hypertext Transfer Protocol, протокол передачи гипертекста) представляет собой протокол прикладного уровня, использующий для пересылки данных протокол транспортного уровня. Достаточно подробное описание его можно найти в [1,2]. Здесь же мы остановимся лишь на некоторых деталях устройства сообщений HTTP. Запрос HTTP состоит из идентификации метода запроса, универсального идентификатора запрашиваемого ресурса (Universal Resource Identifier), идентификации версии протокола и, возможно, набора заголовков с дополнительной информацией и поля данных общего вида. <Request> ::= GET <URI> CrLf | <Method> <URI> <HTTP-Version> CrLf <Rqt-Header>* ( CrLf <Data> )? <Header> ::= <Field> : <Value> CrLf Основные методы протокола HTTP следующие. GET Служит для получения любой информации по URI запроса. Может быть условным, если в запросе имеется заголовок If-Modified-Since, который предписывает не посылать тело запрашиваемого ресурса, если он не изменялся с указанной даты. HEAD Аналогичен методу GET, но в ответе на него сервер не возвращает тело ответа, оставляя только те же заголовки, которые будут и в ответе на аналогичный GET-запрос. POST Служит для создания нового ресурса, связанного с указанным по URI. Чаще всего используется для аннотации ресурсов, добавления сообщений в группы новостей, дистанционной работы с базами данных. Реальная обработка такого запроса зависит от содержащегося в нем URI. PUT Служит модификации ресурса, указанного в URI. DELETE Удаляет ресурс, указанный в URI. LINK Устанавливаетс связи между указанным в URI ресурсом и другими ресурсами, не изменяя их. UNLINK Удаляет одну или несколько связей ресурса, указанного в URI. Заголовки запроса служат для передачи дополнительной информации о запросе или клиенте. Заголовок состоит из идентификации поля и его значения, разделенных двоеточием, и бывает одного из следующих типов. From Содержит e-mail адрес пользователя, под чиьим именем работате клиент. Пример From: [email protected] Accept В таком заголовке через запятую перечисляются возможные форматы ответов на данный запрос. Пример Accept: text/plain, text/html, text/x-dvi; q=.8; mxb=100000; mxt=5.0 Accept-Encoding, Accept-Charset и Accept-Language Аналогично Accept, определяют возможные кодировки, используемые таблицы символов и языки ответа. User-Agent Содержит название используемой клиентской программы. Referer Используется для указания адреса ресурса, с которого был получен данный запрос. If-Modified-Since Используется для отмены ответной пересылки документов, модифицированных не позднее указанной даты, с целью снижения нагрузки на сеть. Authorization Содержит авторизационную информацию, специфичную для используемых сервером протоколов авторизации. ChargeTo Содержит информацию о том, куда выставить счет за обработку запроса. Pragma Содержит дополнительные директивы для промежуточных серверов, например, проксисерверов. Пример запроса. GET /locate?keywords=HTTP+description HTTP/1.1 Date: Mon, 15 Dec 2004 12:18:15 GMT Accept: image/gif, image/jpg, */* Accept-Charset: iso-8859-1, *, utf-8 Accept-Language: en Connection: keep-Alive User-Agent Mozilla/4.7 [en] (Win98; u) Ответ сервера на HTTP-запрос состоит либо только из запрашиваемого клиентом документа, либо в дополнение к нему содержит код статуса ответа и, возможно, несколько заголовков ответа. <Response> ::= ( <Content> )? | <HTTP-Version> <Code> <Explanation> CrLf <Resp-Header>* (CrLf <Content>)? <Resp-Header> ::= <Field> : <Value> Некоторые коды статуса ответа поясняются в таблице. 1xx 2xx 200 201 3xx 301 302 4xx 400 401 403 404 5xx 500 Информационное сообщение Успешная обработка Вcе нормально Документ создан Перенаправление запроса Ресурс перемещен Ресурс перемещен временно Ошибка клиента Некорректно составленный запрос Нужна аутентификация клиента Доступ к ресурсу запрещен Запрашиваемый ресурс отсутствует Ошибка сервера Внутрення ошибка сервера Возможны следующие загловки ответа. Allowed Перечисляются через пробел доступные для пользователя методы запросов по данному URI. Public Перечисляет доступные всем методы запросов. Content-Length Размер содержимого в байтах. Подразумевает, что содержимое имеет бинарный формат и не должно разбиваться на строки при чтении. Content-Type Определяет формат или MIME-тип содержимого ответа. Content-Encoding Кодировка содержимого ответа. Content-Language Язык содержимого. Date Дата создания содержащегося объекта. Last-Modified Дата последнего изменения содержащегося объекта. Expires Дата, послед которой содержащийся объект считается устаревшим. URI URI содержащегося объекта. Title Заголовок содержащего документа. Server Описывает серверную программу. Retry-After Определяет промежуток времени на обработку запроса, до прохождения которого не надо направлять запрос повторно, если ответа на него еще нет. Пример HTTP-ответа. HTTP/1.0 200 OK Content-Length: 2109 Content-Type: text/html Expires: 0 Last-Modified: Thu, 08 Feb 2001 09:23:17 GMT Server: Apache/1.3.12 <HTML> <HEAD> <TITLE> … </TITLE> </HEAD> <BODY> … </BODY> </HTML> Интерфейс сервлетов Сервлет представляет собой управляемый контейнером Web-компонент, генерирующий динамические документы. Интерфейс Java-сервлетов определяется набором классов и интерфейсов, входящих в состав пакетов javax.servlet и javax.servlet.http, в свою очередь являющихся частью J2EE SDK. Первый пакет содержит классы, описывающие независимые от протокола сервлеты, второй — сервлеты, работающие с помощью протокола HTTP. Основные классы и интерфейсы пакета javax.servlet следующие. Servlet Интерфейс всех сервлетов, определяющий методы их жизненного цикла — void destroy() для уничтожения компонента, void init(ServletConfig) для инициализации с заданной конфигурацией, а также void service(ServletRequest, ServletResponse), основной метод, вызываемый контейнером для обработки запросов. ServletRequest, ServletResponse — интерфейсы объектов, инкапсулирующих запросы и ответы. Предоставляют методы для чтения и установки (только второй интерфейс) атрибутов сообщения, а также выделенных атрибутов — протокола, кодировки, сервера, клиента и пр. Для формирования ответа в виде HTML-файла можно использовать выходной поток, получаемый с помощью методов ServletResponse getWriter() и getOutputStream(). RequestDispatcher Предоставляет интерфейс для перенаправления запросов между несколькими сервлетами. Основной метод void forward(ServletRequest, ServletResponse) позволяет провести предварительную обработку запроса в одном сервлете и преслать запрос на следующий этап обработки в другой. Получить такой объект можно с помощью метода getRequestDispatcher(String) у объекта типа ServletRequest. Filter Интерфейс объектов-фильтров, определяющих многократно переиспользуемые методы обработки запросов (например, аутентификацию пользователей, конвертацию изображений, кодирование-декодирование). Основной метод — void doFilter(ServletRequest, ServletResponse, FilterChain). Основные классы и интерфейсы пакета javax.servlet.http следующие. HttpServlet Предназначен для реализации сервлетов, работающих с HTTP-сообщениями. Содержит protected методы, обрабатывающие отдельные методы HTTP-запросов, из которых наиболее важны void doGet(HttpServletRequest, HttpServletResponse) и void doPost(HttpServletRequest, HttpServletResponse). Метод service() реализован как определяющий метод запроса и вызывающий соответствующий специализированный обработчик. HttpServletRequest и HttpServletResponse — интерфейсы, содержащие методы для получения и установки (второй) заголовков и других атрибутов HTTP-запросов и ответов. Cookie Класс, представляющий закладки сервера, хранимые на клиентской машине для запоминания информации о данном пользователе. HTTPSession Интерфейс, предоставляющий методы для управления сеансом обмена HTTPсообщениями. Информация о сеансе используется в том случае, если она должна быть доступна нескольким сервлетам. При развертывании J2EE приложения помимо самих классов сервлетов надо создать их дескриптор развертывания, который обычно оформляется в виде XML-файла web.xml и упаковывается вместе с классами приложения и используемыми библиотеками в архив .war. Заголовок дескриптора развертывания сервлета выглядит так. <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc...ВЕВ Web Application 2ю2..УТЭ http://java.sun.com/j2ee/dtds/web-app_2_2.dtd> Содержимое дексриптора развертывания помещается внутри тега <web-app> </webapp>. В нем указывается список сервлетов, входящих в приложение и отображение сервлетов в URL, запросы к которым они обрабатывают. Один сервлет описывается в следующем виде. <servlet> <servlet-name>ServletName</servlet-name> <servlet-class>com.company.deprtment.app.ServletClassName</servlet-class> <description>…</description> <init-param> <param-name>ParameterName</param-name> <param-value>ParameterValue</param-value> <description>…</description> </init-param> </servlet> Значения параметров инициализации сервлета можно получить с помощью методов String getInitParameter(String) и Enumeration getInitParametersNames() связанного с сервлетом объекта класса ServletContext. Отображение сервлета на URL описывается так. <servlet-mapping> <servlet-name>ServletName</servlet-name> <url-pattern>URL</url-pattern> </servlet-mapping> Кроме этого, в дескрипторе развертывания Web-приложения можно указать параметры приложения, которые могут быть некоторыми строками, доступными всем компонентам приложения. <context-param> <param-name>ParameterName</param-name> <param-value>ParameterValue</param-value> <description>…</description> </context-param> Интерфейс JSP JSP представляют собой компоненты, разрабатываемые на смеси из HTML и Java и предназначеннные для представления пользователю результатов его запросов к приложению. Таким образом, JSP обычно служат в касетве представления в образце данные-представление-обработчик, принятом за основу архитектуры приложений J2EE. Результатом работы JSP является HTML-страничка, а вставки Java кода служат для ее построения на основе данных приложения. При развертывании JSP компилируются в Java-сервлеты специального вида. Основные элементы JSP-страниц и их базовые классы находятся во входящих в J2EE SDK пакетах javax.servlet.jsp, javax.servlet.jsp.el, javax.servlet.jsp.tagext. Элементы JSP-страницы делятся на следующие группы. Теги и текст HTML JSP-директивы Служат для передачи информации механизму управления JSP-страницами. o Директива page дает информацию о данном файле и статически включаемых в него файлах. <%@ page …%> Атрибуты import contentType isThreadSafe = "true|false" Значение true позволяет использовать = "<имена включаемых классов и пакетов через запятую>" = "<MIME-тип>[;charset= <таблица символов>]" Задает тип MIME для вывода. По умолчанию используется text/html. Эквивалентен скриплету <% response.setContentType(<MIME-тип>); %> один экземпляр сервлета, полученного из странички, для обработки множественных запросов. При этом необходимо синхронизовать доступ к данным этого сервлета. session = "true|false" Значение true предписывает привязать сервлет к имеющейся HTTPсессии, значение false говорит, что сессии использоваться не будут и обращение к переменной session приведет к ошибке. autoFlush = "true|false" Определяет необходимсоть сбрасывать буфер вывода при заполнении. buffer extends = "<размер в KB>|none" Задает размер буфера для выходного потока сервлета. = "<наследуемый класс>" Задает наследуемый данным сервлетом класс. info errorPage isErrorPage = "true|false" = "<сообщение>" Определяет результат вызова getServletInfo(). = "<url странички с информацией об ошибках>" Определяет страницу, используемую для обработки исключений, не обрабатываемых в арамках данной. Допускает иил запрещает использование данной страницы lzk обработки ошибок. language = "java" o Директива include используется для включения в страничку внешнего документа. <%@ include file = "URL" %> Файлы включаются в ходе трансляции страницы в сервлет. Поэтому при их изменении необходимо заново оттранслировать JSP-страницу. o Директива taglib указывает используемую библиотеку пользовательских тегов. <%@ taglib uri = "<Library URI>" prefix = "<Prefix>"%> Атрибут uri определяет унифицированный идентификатор (Uniform Resource Identifier) библиотеки, атрибут prefix — используемый префикс тегов, уникальный для библиотеки, пустые префиксы не допускаются. JSP-теги Определяют основные действия, выполняемые при обработке данных. o jsp: include <jsp: include page = "<URL>" flush = "true" /> или <jsp: include page = "<URL>" flush = "true" > <jsp: param name="…" value = "…" /> </jsp: include> Задает динамическое включение файла в страницу при ее запросе. С помощью части jsp:param можно передать одну или более пар параметр-значение в качестве параметров включаемой страницы. o jsp: useBean <jsp: useBean … /> Задает используемый объект-экземляр компонента JavaBeans. Атрибуты id class scope = "page|request|session|application" = "<имя объекта>" Задает имя объекта, которое будет использоваться в коде JSP = "<класс объекта>" Задает класс объекта Задает область видимости объекта type beanName = "<тип используемой ссылки на объект>" Указанный тип должен быть надтипом класса объекта = "<класс объекта>" Указывается имя класса для инициализации переменной. Можно указать type и beanName и опустить class. o jsp: setProperty Устанавливает значение свойства компонента. Атрибуты name property value param = "<имя объекта>" = "<имя свойства>|*" * означает, что все праметры запроса с именами, совпадающими с миенами свойств данного объекта будут использованы для их установки = "<новое значение>" = "<имя параметра>" Определяет параметр запроса, используемый для установки свойства. Не может использоваться вместе с value. При отсутствии обоих атрибутов ищется параметр запроса с именем, совпадающим с именем свойства. o jsp: getProperty Получает значение свойства компонента и сбрасывает его в виде строки в выходной поток сервлета out. <jsp: getProperty name = "<имя объекта>" property = "<имя свойства>" /> o jsp: forward Передает управление другой странице. <jsp: forward page = "<URL>|<%= выражение %>" /> С помощью части jsp:param можно передать одно или несколько значений параметров странице, на которую переключается управление. o jsp: plugin Выполняет апплет или компонент, загружая подключаемый модуль Java для их выполнения. Атрибуты type = "bean|applet" Тип компонента. Значения по умолчанию нет. code codebase name archive align = "bottom|top|middle|left|right" = "<имя файла класса компонента>" = "<имя каталога, в котором находится файл класса компонента>" = "<имя экземпляра компонента>" = "<URI загружаемых перед выполнением архивов через запятую>" Задает положение экземпляра компонента относительно базовой строки текста height width hspace = "<ширина пустой рамки в точках>" vspace = "высота пустой рамки в точках" jreversion nspluginurl = "<высота изображения объекта в точках>" = "<ширина изображения объекта в точках>" = "<версия JRE, необходимая для работы компонента>|1.1" = "<URL для модуля Netscape Navigator>" iepluginurl = "<URL для модуля Internet Explorer>" JSP-объявления Используются для определения вспомогательных переменных и методов. <%! Код на Java %> JSP-скриплеты Используются для вставки кода на Java, производящего обработку данных перед их выдачей пользователю. <% Код на Java %> JSP-выражения Используются для вставки вычисляемых значений непосредственно в текст HTML. <% = выражение на Java %> ${выражение на Java} (в JSP 2.0) Данное выражение вычисляется и его значение в виде строки вставляется в данное место страницы. Помимо объявленных переменных в выражениях и скриплетах могут использоваться неявно доступные объекты. request — запрос клиента (тип ServletRequest) response — ответ сервера (тип ServletResponse) out — выходной поток сервлета (тип PrintWriter) session — сеанс (тип HttpSession) application —приложение (ServletContext) config — конфигурация сервлета (ServletConfig) pageContext — контекст страницы (javax.servlet.jsp.PageContext) exception — произошедшее исключение Пример JSP страницы приведен ниже. <%@ page import="java.util.Date, java.util.Iterator, com.company.Client" %> <jsp:useBean id="clients" class="com.company.ClientList" scope="page" /> <jsp:useBean id="convertor" class="com.company.ExchangeRate" scope="page" /> <html> <head> <title>Table of clients</title> </head> <body> <h3 align="center">Table of clients</h3> Created on <%= new Date() %> <br><br> <table width="98%" border="1" cellspacing="1" cellpadding="1"> <tr> <%! private double dollarsToRubles(double m) { return m*convertor.getDollarToRubleRate(new Date()); } %> <th width="50%" scope="col">Client</th> <th width="25%" scope="col">Balance, dollars</th> <th width="25%" scope="col">Balance, rubles</th> </tr> <% Iterator it = clients.getNumberOfClients().iterator(); while(it.hasNext()) { Client ßlient = (Client)it.next(); %> <tr> <td> ${client.getFullName()} </td> <td> ${client.getBalance()} </td> <td> ${dollarsToRubles(client.getBalance())} </td> </tr> <% } %> </table> <br><br> <jsp: include page="footer.txt" flush= "true" /> </body> </html> Развитие архитектуры приложений J2EE Framework Struts Framework Spring Object-relational mappers — Hibernate Будущий стандарт EJB 3.0 Литература [1] http://www.w3.org/Protocols/HTTP/HTTP2.html [2] http://www.opennet.ru/docs/RUS/http/index.html [3] http://java.sun.com/j2ee/1.4/docs/index.html Документация по платформе J2EE [4] П. Аллен, Дж. Бамбара, М. Ашнаульт, Зияд Дин, Т. Гарбен, Ш. Смит. J2EE. Разработка бизнес-приложений. ДиаСофт, 2002.