Текст
                    Java, сервлеты и JSP.
сборник рецептов
КУДИЦ-ОБРАЗ
O’REILLY®
Брюс У. Перри

Java™ Servlet and JSP™ Cookbook™ Bruce W. Perry t O’REILLY’ Beijir g • CartTdge • Fcmham • Koh • Paris • Sebastopol • Taipei * Tokyo
1 Брюс У. Пер^и Java™ сервлеты и JSP™ сборник рецептов КУДИЦ-ОБРАЗ Москва • 2006
ББК 32.973.26-018.2 Перри Б. Java сервлеты и JSP: сборник рецептов. Изд. 2-е / Пер. с англ. - М.: КУДИЦ-ПРЕСС, 2006. — 7б8 с. Данная книга написана экспертом в области Java, имеющи и многолетний опыт практи- ческих разработок с использованием технологий Java Servlet и JSP. В книге приведены решения проблем, с которыми приходится сталкиваться web- разработчикам на Java. Рецепты даны по мере нарастания сложности и рассмотрены в свя- зи с такими популярными серверами приложений, как Tomcat и Weblogic. Книга предназначена для широкого круга читателей - от опытных Java-разработчиков, желающих усовершенствовать свое мастерство в использовании технологий Java Servlet и JSP, до студентов,-изучающих Java. Брюс У. Перри Java сервлеты и JSP: сборник рецептов Учебно-справочное издание Перевод с англ. В. В. Акимов Научный редактор Л. Б. Сиховец «ИД КУДИЦ-ОБРАЗ» Тел.: 333-82-11; E-mail: ok@kudits.ru; http://books.kudits.ru 119049, Москва, Ленинский пр-т. д. 4, стр. 1А Подписано в печать 20.08.06 \ Формат 70x90/16. Бумага газетная. Печать офсетная Усл. печ. л. 56,16. Тираж 1000. Заказ 1545 у Отпечатано в ОАО «Щербинская типография» . 117623, Москва, ул. Типографская, д. 10 Т. 659-23-27. ISBN 5-9579-0073-7 (рус.) © Перевод, макет, обложка «ИД КУДИЦ-ОБРАЗ», 2005-2006 ISBN 0-596-00572-5 © 2004 O'Reilly Media, Inc. © Kudits-Obraz 2005-2006. Authorized translation of the English edition1 © 2004 O'Reilly Media, Inv This translation is published and sold by permission of O'Reilly Media, Inc., the owner of all-rights to publish and sell the same. Все права защищены. Русское издание опубликовано издательством КУДИЦ-ОБРАЗ, © 2005-2006. Никакая часть данной книги не может быть воспроизведена в какой бы то ни было форме без письменного разрешения владельцев авторских прав. Информация, содержащаяся в данной книге, получена из источников, рассматриваемых издатель- ством как надежные. Тем не менее, имея в виду возможные человеческие или технические ошиб- ки, издательство не может гарантировать абсолютную точность и полноту приводимых сведений и не несет ответственности за возможные ошибки, связанные с использованием книги.
Предисловие На исторической оси времени сага о Java как о наилучшем инструменте для соз- дания программ, работающих на стороне сервера, началась в 1997, когда фирма Sun , Microsystems создала бета-версию «Java™ Web Server», а также Jaya Servlet Develop- l ers Kit (набор инструментов для разработчика сервлетов). Сервлет - это тип Java- класса, который выполняется на сервере. Сервлеты динамически обрабатывают сете- вые запросы и ответы, используя, главным образом, HTTP (Hypertext Transfer Proto- col - протокол передачи гипертекста). В июне 1999 Sun представила JSP (JavaServer Pages - серверные страницы Java), в которых Java-код перемешивается с JavaScript и шаблонным HTML-текстом. JSP, в их настоящем виде (начиная с версии 2.0), предназначены для инкапсуля- ции доменной логики в стандартных и пользовательских тегах и отделения этого доменного слоя от презентационной логики, реализуемой самим компонентом JSP. Презентационная логика - это действия по формированию «тех вещей, которые видят люди», когда они взаимодействуют с web-приложением, например тю формированию связанных с HTML экранных визуальных элементов. В идеале, JSP, используя теги для взаимодействия с базами данных и инкапсуляции доменных правил, статически или динамически генерирует шаблонный текст, например XML или XHTML, созда- вая визуальную страницу для пользователя. В конце 90-х я был «свободным художником», разработчиком серверной части web-приложений на разных языках программирования. Когда на сцене появилась Java для серверных приложений, я воспринял эту новое я ь с большой радостью. Java, созданная от начала и до конца как объектно-ориентированный и модульный язык, представлял собой обнадеживающую альтернативу плохо спроектированному, хотя и с самыми лучшими намерениями, web-коду, с которым я часто и г.’лкивался, когда ' '' та или иная организация бросала меня в самую середину проекта. С помощью Java вы не только можете легко создавать свои собственные повторно используемые компоненты, например, для отправки почтовых сообщений, спроектировав их и скачав для своего web-приложения один или несколько Java-клас- t сов, но в вашем распоряжении целый набор Java API для работы с базовыми, низ- коуровневыми элементами, например для обработки строк, файлового ввода-вывода .. и математических вычислений. Неплохо! 5 '
Другой сильной стороной Java является ее независимость от платформы. Web- разработчики могут создавать свди приложения, упаковывать их в специальный JAR- файл для web-компонентов, называемый Web Application Archive - архив web-приложе- ния, и затем инсталлировать эти WAR-файлы на серверах, работающих под управле- нием самых разных операционных систем (ОС). Web-компоненты Java не привязаны к какой-либо определенной ОС или к серверному ПО одного определенного производи- теля, как другие программные технологии, ориентированные на web. Перенесемся в настоящее время. К 2003 году Java приобрел статус наиболее популярной технологии для разработки программ, работающих на стороне сервера. Сервлеты и JSP были включены в Java 2 Enterprise Edition (J2EE), широко распространенную технологию основанных на сети и распределенных вычислений. Сотни тысяч разработчиков по всему миру работают на «web-уровне» технологий, основанных на J2EE, и используют сервлеты, JSP и, зачастую, специальные фреймворки, например Struts. Сейчас многие web-разработчики проводят большое количество времени за изучением различных «серверов приложений», таких, как BEA WebLogic, JBoss или WebSphere от фирмы IBM, объединяющих воедино web-уровень, бизнес-объекгы (доменные объекты) (например, компоненты, которые обрабатывают данные о погоде или финансовые счета клиентов), и информационные системы предприятия (Enterprise Information Systems - EIS). Серверы приложений представляют собой программное обеспечение, на базе которого выполняются сервлеты и JSP (хост для сервлетов и JSP). Многие web-разработчики, в том числе и я, проводят массу времени, работая над web-компонентами, хостом для которых служит Tomcat, популярная исполнительная подсистема поддержки сервлетов (servlet engine) с открытыми исходными текстами (http://www.opensource.org), являющаяся «справочной реализацией»* новых API сервлетов и JSP. Быстрое развитие и укоренившаяся природа Java естественным образом определили форму этой книги - «сборник рецептов». Сборник рецептов фокусируется на том, как решить конкретные задачи, связанные с web, средствами Java, а не на том, чтобы объяснить читателю основы работы с языком Java, или детально описать использование API сервлетов и JSP. Недостаток в руководствах по Java все еще ощущается, однако в обновленной форме или в форме переизданий, что свидетельствует о популярности Java как платформы для web-разработок. * Справочная реализация - это ПО, базирующееся на общепринятой спецификации и свободно распространяемое среди разработчиков ПО и других лиц для демонстрации того, как должна функционировать подобная программная система. / 6 | Предисловие
Что вы найдете в этой книге Создавая рецепты для этой книги, я пытался объять столько рядовых и более сложных задач, сколько способно поместиться в одной книге. Это около 230 разных рецептов. В каждом из рецептов показано, как решать определенную задачу, используя сервлеты, JSP и, во многих рецептах, один или несколько поддерживающих Java-классов. В этих рецептах показано как: • аутентифицировать web-клиентов; • работать с базой данных; • отправлять почтовые сообщения; • обрабатывать данные, полученные от web-формы; *• • читать и устанавливать cookie; • выгружать файлы от клиента; • интегрировать JavaScript с сервлетами и JSP; • встраивать в JSP и сервлеты файлы мультимедиа; например цифровое видео и музыку; • работать с web-клиентами, говорящими на разных языках (интернационализация); • протоколировать сообщения от сервлетов и JSP; • динамически включать фрагменты содержимого, как это делается в традиционном; коде включений на стороне сервера (SSI); • взаимодействовать в сервлете или JSP с компонентами Enteiprise JavaBeans (EJB); • использовать в сервлете и JSP программные интерфейсы web-сервисов сайтов Ama- zon.com и Google.com. Я также включил большое число рецептов, связанных с определенной технологией, например: • использование «сеансов» в ваших web-приложениях (концепция, представляющая отслеживание хода взаимодействия пользователя с web-сайтом); • работа с «фильтрами»; • использование инструмента ANT (open source - ПО с открытыми исходными кодами) для сборки web-приложения; • связывание Java объектов с сеансом или web-приложением, с тем, чтобы использовать их как контейнер с данными; • создание собственных пользовательских тегов для JSP; • использование библиотеки JSTL (JavaServer Pages Standard Tag Library - библиотеки стандартных тегов JSP), которая является крупным набором готовых тегов, которые вы можете использовать на своих страницах JSP. Короче говоря, книга создана, чтобы помочь Java-разработчикам в решении их повсе- дневных задач и дать быстрые ответы на типичные проблемы web-программирования. Что вы найдетеъ этой книге | 7
Рецепты, связанные с BEA WebLogic Поскольку web-разработчики, работающие на Java, обычно используют не только Tom- cat, но и какой-либо коммерческий сервер приложений, я включил ряд рецептов, демонстрирующих, как решать ряд распространенных задач, используя сервер ВЕА WebLogic. По понятным причинам я не мог охватить все существующие серверы приложе- ний, такие, как WebSphere фирмы IBM, JBoss, Jetty, сервер приложений Oracle 9i, или коммерческие исполнительные подсистемы для поддержки сервлетов, например New Atlanta ServletExec и Caucho Resin. Но мне все-таки хотелось включить рецепты, демонстрирующие, «как живут другие», и показать как для управления повседневными web-задачами можно использовать инструменты разных поставщиков. Такие решения, как развертывание или изменение web-компонентов и дескрипторов развертывания при использовании графического интерфейса, например консоли администрирования WebLogic или WebLogic Builder, могут несколько отличаться от аналогичных решений в Tomcat. В результате эта книга включает набор базовых рецептов, связанных с WebLogic, например, развертывание web-приложения на сервере WebLogic или использование сервлета для доступа к источнику данных на WebLogic. В главе 25, Использование JNDI и Enterprise JavaBeans, показано, как сервлет может взаимодействовать с компонентом EJB, инсталлированным на сервере WebLogic. Аудитория Данные рецепты создавались в расчете на опытных разработчиков, которым прихо- дится заниматься созданием, сборкой, развертыванием и изменением web-приложений на базе Java. К ним относятся разработчики JSP, сервлетов и компонентов JavaBean. Книга также подойдет опытным web-разработчикам, мигрировавшим с других платформ web-программирования (Active Server Pages, PHP или Perl) и только изучающим Java. Эти люди, как правило, хорошо разбираются в базовых механизмах, таких, как сеансы, cookie, выгрузка файлов, входная аутентификация и обработка POST-запросов HTTP, но пока еще не знают, как эти задачи можно реализовать средствами Java. Данная книга позволит им быстро вникнуть в решение проблемы, с которой они, возможно, уже сталкивались, используя другой язык. Java-разработчики, которые хотят знать, как реализовать новые возможности, зало- женные в API сервлетов версии 2.4 и в JSP 2.0 (например,, новые элементы filter- mapping файла web.xml для диспетчеров запросов и встраивание языка выражений (Expression Language - EL) в шаблонный текст JSP), также найдут в этой книге много полезного для себя. 8 | Предисловие
Что необходимо знать Читателям необходимо знать основы языка Java или учиться программированию на Java. Глава 1 Создание сервлетов и JSP включает краткую информацию по сервлетам, JSP и дескриптору развертывания для читателей, не знакомых с этими концепциями. Однако на протяжении всей книги, объяснение концентрируется на специфических задачах и не содержит длинных пояснений API сервлетов и JSP. Каждый рецепт включает введе- ние, содержащее необходимую информацию, чтобы приступить к работе с разными техно- логиями и примерами кода. Специально для читателей, которые хотят углубить свои знания по обсуждаемой теме, рецепты включают большое количество ссылок на информационные ресурсы Интернета, например страницы документации (Javadoc) и руководства. " Читатели, уже знакомые с разными областями J2EE, например с Java Database Connec- tivity (JDpC), Java Naming and Directory Interface (JNDI) и Enterprise JavaBeans (я включил один рецепт, посвященный соединению web-компонента с EJB, с использованием JNDI), будут иметь преимущество. И, наконец, полезными окажутся практические знания XML, поскольку web-разработка на Java включает дескрипторы развертывания и файлы конфигурации, базирующиеся наХМЬ. Организация Книгу открывают три главы, посвященные основам создания сервлетов и JSP, развертыванию сервлетов и JSP, именованию и регистрации сервлетов, а также исполь- зованию инструмента Ant. Затем я поднимаю несколько базовых тем web-разработки, таких, как динамическое включение содержания в web-страницу, выгрузка файлов, обработка данных, посланных из HTML-формы, чтение и установка cookie, отслеживание сеанса и интеграция JavaScript с сервлетами и JSP. Далее книга включает ряд более сложных рецептов, например протоколирование сооб- щений, аутентификация клиентов, привязка атрибутов, работа с запросом клиента и созда- ние фильтров сервлета. Глава 20 Работа с электронной почтой в сервлетах и JSP и глава 21 Доступ к базам данных посвящены двум сложным задачам web-разработки 20 различных рецептов. Глава 22 Использование пользовательской библиотеки тегов и глава 23 Использование JSTL описывают пользовательские теги и JSTL. Глава 24 Интернационализация обсуждает критическую тему интернационализации ваших web-приложений, содержащих сервлеты hJSP. Для web-разработчиков, чьи web-компоненты должны взаимодействовать с компо- нентами EJB, используя Java JNDI, глава 25 Использование JNDI и компонентов Enter- prise JavaBean показывает, как настроить JNDI на серверах Tomcat и WebLogic, а также как получить доступ к JNDI-объекту, используя эти серверы. Организация | 9
Книга завершается двумя рецептами, в которых описываются разные стратегии извлечения данных с web-сайтов web-компонентами Java. В главе 26 Пожинание информации из Web содержатся рецепты по harvesting (пожинанию) или scraping (выскабливанию) данных из web-страниц. В главе 27 Использование Web API сайтов Google и Amazon описано, как использовать интерфейсы прикладных программ web- сервисов Google и Amazon.com. Соглашения, используемые в этой книге В данной книге используются следующие соглашения по использованию шрифтов. Курсив Используется для выделения новых терминов, URL, адресов электронной почты, расширений файлов, имен, входящих в пути к файлам, каталогов, и служебных программ Unix. Моноширинный шрифт Используется для выделения команд, опций, переключателей, переменных, атрибу- тов, ключей, функций, типов, классов, пространств им^н, методов, модулей, свойств, параметров, значений, объектов, событий, обработчиков событий, XML-тегов, HTML- тегов, макросов, содержимого файлов, результата работы команд. Моноширинный полужирный шрифт Используется для выделения команд или другого текста, который должен быть напечатан пользователем дословно (буква в букву), а также для выделение кода в примерах. Моноширинный шрифт с курсивом Используется для выделения текста, который должен быть заменен, собственным значением пользователя. В некоторых случаях, там, где текст уже набран курсивом, тескт, который нужно заменить на собственные значения пользователя заключается в угловые скобки (о). Эта пиктограмма обозначает совет, указание, или общее замечание. М?' 4 - ту Эта пиктограмма обозначает предупреждение или опасность. 10 | Предисловие
Использование примеров кода Эта книга призвана помочь вам в работе. Вы можете свободно использовать код, приведенный здесь в своих программах и документации. При этом вам не требуется свя- зываться с нами, чтобы получить специальное разрешение, за исключением случая, когда вы воспроизводите значительные порции кода. К примеру, создание программу, в которой используется несколько фрагментов кода из книги, не требует получения разрешения. Для продажи или распространения CD-ROM с примерами из книг O’Reilly разрешение потребуется. Ответы на вопросы путем цитирования этой книги и приведе- ния примеров кода не требуют разрешения. Для переноса в документацию по вашему продукту значительного количества кода из книги разрешение потребуется. O'Reilly & Партнеры, а также автор будут вам признательны* если вы будете указы- вать авторство книги (но не требуют этого). Авторство обычно включает название, автора, издателя и ISBN. К примеру, «Java Servlet and JSP Cookbook, by Bruce Perry. Copyright 2004 O'Reilly & Associates, Inc., 0-596-00572-5». Если у вас возникнут сомнения по поводу правомерности вашего использования примеров кода, свяжитесь с нами по адресу permissions @ oreilly.com. Вопросы и замечания Просьба замечания и вопросы, касающиеся данной книги, присылать издателю: O'Reilly & Associates, Inc. 1005 Gravenstein Highway North Sebastopol, CA 95472 (800) 998-9938 (США или Канада) (707) 829-0515 (международный или местный) (707) 829-0104 (факс) O'Reilly поддерживает web-страницу данной книги, где вы найдете список опечаток, примеры и другую дополнительную информацию. Адрес страницы: http://www.oreilly.cofn/catalog/jsvltjspckbk Комментарии и технические вопросы присылайте по адресу: bookquestions @ oreilly. сот Дополнительную информацию о книгах издательства O'Reilly, конференциях, центрах ресурсов и сети O'Reilly ищите на web-сайте: http://www.oreilly.com Вопросы и замечания | 11
Благодарности Kaij-то ночью, более года назад, я отправил в издательство O'Reilly письмо с идеей этой книги. В то время шансы на то, что это легкомысленное письмо действительно приведет к написанию книги, казались чрезвычайно низкими. После оживленной переписки между мной и парой Java-редакторов издательства O'Reilly и нескольких месяцев мягких подталкиваний, основательного редактирования, а порой и изменения концепции, и само собой - работы, работы и еще раз работы идея написания книги переросла в реальный итог. Родилась книга! Формирование книги - это всегда результат сотрудничества нескольких людей. Воз- можно, эта книга никогда не увидела бы свет без, иногда коротких, иногда длинных, напоминаний моего редактора Брета Маклафлина (Brett McLaughlin) о том, что отличает сборник рецептов от книг другого типа. Брет также является прекрасным выпускающим редактором; Я, как автор, оценил его усилия и повысил свои познания в области редакторского дела. Брет имеет глубокие знания Java и его замечания в ряде случаев помогли мне избежать неуклюжих решений при создании кода. Я очень рад, что техническими редакторами у меня были Джейсон Хантер (Jason Hunter) и Сэнг Шин (Sang Shin). Они являются известными экспертами по Java, и книга очень выиграла благодаря тому, что они прочли текст и написали свои комментарии к значительным фрагментам книги. Их рецензия как короткий поводок и сама по себе является большой книгой. Я был поражен широтой масштаба, проявленной в сравни- тельно узких рамках. Как автор технической книги, я признателен тем, кто удержал меня от досадных ошибок! Некоторые из нас в списке людей, которых они благодарят за помощь, ставят членов своей семьи на последнее место. Возможно, это связано с тем, что последний абзац - это основа, на которой зиждется все остальное, а семья - это основа для любрго писателя, она поддерживает его и защищает от внешних раздражителей, когда он погружен в изло- жение и технологию. Эта книга не была бы создана без помощи моей жены Стейси (Stacy), дочери Рейчел (Rachel) и даже Скотта (Scott), который вдохновлял меня, хотя ему не было еще и года. Я также повторю то, что написал в другой своей книге, по AppleScript: я благодарен моим родителям Роберту и Анне Перри (Robert и Anne Perry) за то, что они привили мне Любовь к писательскому делу и книгам. 12 | Предисловие
ГЛАВА 1 Создание сервлетов и JSP 1.0 Введение Целью этой главы является краткое изложение основ создания, компиляции и упа- ковки сервлетов и JSP. Если вам до сих пор не приходилось разрабатывать сервлеты или JSP илИ вам необходимо просто освежить знания по этой технологии для начала практической работы, тогда следующие ниже рецепты предоставят вам примеры программ и краткие описания компонент, которые вам понадобится включить в поль- зовательский путь к классам (user classpath), чтобы иметь возможность ком- пилировать сервлеты. Рецепты 1.1 и 1.2 содержат краткое введение в сервлеты и JSP соответственно. Полное описание роли сервлетов и JSP для корпоративной редакции платформы Java 2 (J2EE) выходит за рамки данной книги. Однако информация, имеющая прямое отношение к технологии J2EE, такая, как базы данных и JDBC, использование JNDI (Java Naming an<^ Directory Interface - Java интерфейс именования и каталогов) и использование сервлетов с Java Mail (или электронной почтой), содержится в этой книге (и в предметном указателе!). Разделы «См. также», которыми завершается каждый рецепт, содержат ссылки на близкие по содержанию главы, оп1те-руковод<?тво от Sun Microsystems и другие книги издательства O’Reilly, углубляющие поднятые темы. I 1.1 Создание сервлетов Задача Необходимо написать сервлет, являющийся частью web-приложения. Решение Создайте класс, расширяющий класс javax. servlet .http.HttpServlet. He забудьте импортировать классы из servlet.jar (или servlet-api.jar) - они необхо- димы для компиляции вашего сервлета. 13
Обсуждение Сервлет - это класс Java, предназначенный для динамического формирования содержимого ответа на запрос клиента по сети.' Если вам зцакомы CGI-программы (Com- mon Gateway Interface - общий шлюзовой интерфейс), то сервлеты - это технология Java, которая может заменить CGI-программы. Сервлеты (как и JSP) часто называют web-компонентами, они выполняются в специальной среде исполнения, создаваемой контейнером сервлетов илй web-контейнером, таким, как Jakarta Tomcat или BEA WebLogic. Web-контейнер может быть компонентом-надстройкой (add-on) HTTP-сервера или отдельным сервером, как, например, Tomcat, который способен обслуживать НТТР- * запросы как к статичному содержимому (НТ ГР-файлы), так и к сервлетам и JSP. Сервлеты инсталлируются в web-контейнерах как часть web-приложения. Такие прило- жения по сути являются набором web-рссурсов: HTML-страниц, изображений, мультиме- диа, сервлетов, JSP, XML-файлов конфигурации, классов и библиотек поддержки Java. После развертывания web-приложения в web-контейнере контейнер создает и загружает экземпляр класса сервлета в виртуальную машину Java (JVM) для обслуживания запросов, поступающих на сервер. Сервлет обслуживает каждый запрос в отдельном потоке. Таким образом, создатели сервлетов должны решать, надо ли обеспечивать синхронизацию доступа к переменным экземпляра и переменным класса или нужно использовать разделяемые ресурсы, например соединение с базой данных, в зависимости от того, как эти ресурсы используются. Все сервлеты реализуют интерфейс javax.servlet .Servlet. Разработчики web- приложений обычно пишут сервлеты, расширяющие javax. servlet .http.Http- Servlet - абстрактный класс, который реализует интерфейс Servlet и создан специ- ально для обслуживания HTTP-запросов. При создании web-контейнером экземпляра сервлета, осуществляются следующие действия. 1. 2. Контейнер вызывает Метод init () сервлета, который предназначен для инициализа- ции ресурсов, необходимых сервлету, например сервлету-регистратору (см. главу 14). Метод ini t () вызывается только один раз за время жизни сервлета. Метод init () инициализирует объект, реализующий интерфейс javax. servlet. ServletConfig. Этот объект открывает сервлету доступ к .параметрам инициализа- ции, объявленным в дескрипторе развертывания (см. Рецепт 1.5). ServletConfig также открывает сервлету доступ к объекту javax.servlet.ServletContext, с помощью которого сервлет может протоколировать события, перенаправлять запросы к другим web-компонентам и получать доступ к прочйм web-ресурсам этого же прило- жения (см. рецепт 13.5). 14 | Глава 1. Создание сервлетов и JSP
Разработчикам не нужно реализовывать метод init () в своих подклассах класса HttpServlet. При запросе к сервлету контейнер вызывает метод service () сервлета. В терминах HttpServlet, метод service () для обработки запроса авотматически вызывает подходящий HTTP-метод сервлета: do Post () или doGet (). Например, при посылке от пользователя HTTP-запроса POST сервлет отзывается выполнением метода doPost(). При вызове двух главных методов сервлета HttpServlet (doPostO или doGet О) контейнер сервлета создает объекты javax.servlet.http.Http- Servlet Request и HttpServletResponse и передает их в качестве параметров этим методам обработки запроса. Объект HttpServletRequest представляет исходный запрос, а объект HttpServletResponse инкапсулирует ответ сервлета на этот запрос. Пример 1.1 демонстрирует типичное использование объектов запроса и ответа. Хотя большинство имен методов говорят об их назначении, стоит также ознакомиться с документацией по API сервлета (http://java.sun.com/j2ee/L4/docs/ api/javax/servlet/http/package-summary.html). 5. Не разработчик, а сам сервлет или web-контейнер управляют жизненным циклом Сервлета, то есть тем, как долго экземпляр сервлета существует в виртуальной машине Java (JVM) и обрабатывает запросы. Когда контейнер сервлета намеревается исключить сервлет из обслуживания, он вызывает метод destroy () Сервлета, в котором сервлет может освободить любые ресурсы, например соединение с базой данных. Пример 1.1 показывает типичную схему обработки сервлетом HTML-формы. Метод doGet () отображает саму форму. Метод doPost () обрабатывет введенные в форму данные, если соответствующий тег сформированной в doGet () HTML-формы задает в качестве места назначения вводимых данных этот сервлет. Данный сервлет (с именем FirstServlet) указывает, что объявляемый класс явля- ется частью пакета com.jspservletcookbook. Очень важно создавать пакеты для ваших собственных классов сервлетов и вспомогательных классов и затем сохранять эти классы в структуре каталогов, соответствующей именам пакетов, в каталоге WEB-INF. Класс FirstServlet импортирует классы, необходимые для компиляции базового сервлета - в примере 1.1 эти операторы import выделены полужирным шрифтом. Дан- ный Java-класс расширяет Класс HttpServlet. В нем объявлены всего два метода: doGet (), отображающий HTML-форму в ответ на HTTP-запрос Get; doPostO, обрабатывающий введенные в форму данные. Создание сервлетов | 15
Пример 1.1. Типичный HttpServlet для обработки HTML-формы - package com.jspservletcookbook; import j ava.io.lOException; import java.io.Printwriter; inport java.util.Enumeration; import javax.servlet.ServletExceptIon; import j avax. servlet. http. HttpServlet import javax.servlet.http.HttpServletRequest; import javax. servlet. http, HttpServletResponse; public class FirstServlet extends HttpServlet { public void doGet(HttpServletRequest request, ’ HttpServletResponse response) throws ServletException, java.io.lOException { //устанавливаем тип Mime ответа в "text/html" response.setContentType <"text/html"); //используем Printwriter для отправки данных клиенту, 1 //обратившемуся с сервлету java.io.Printwriter out = response.getWriter(); //Начало формирования HTML-содержимого out. print In (" <htmlxhead>"); out. printin (•<title>Help Page* / ti tlex /headxbody> ") ; out.printin("<h2>Please submit your information«/h2>"); //MeTOfl="post" поскольку метод сервлета service //вызывает doPost для обработки данных введенных в форму out.printlnf "«form method=\"post\" action =\"" + request.getContextPath() + "/firstservletX" >"); out.printlnf"«table border=\"0\"xtr><td valign=\"top\">"); out.printIn("Your first name: </td> <td valign=\"top\n>"); out.printlnf"«input type=\"text\" name=A"firstname\" size=\"20\">"); out.printin("</tdx/trxtrxtd valign=\"topX">"); ’ out. printing Your last name: </td> <td valign=\"topX">"); out.printlnf"«input type=\"text\" name=\"lastname\" size^\"20\">"); out.printlnf "</tdx/trxtrxtd valign=\"top\">")? out.printIn("Your email: </td> <td valign=\"top\">"); out.printlnf"«input type=\"text\* name=\"email\" size=\"20\">"); out .printlnf "</tdx/trxtrxtd valign=X"topX">") ; out.printlnf "«input type=\"submit\" value=\"Submit InfoX "x/tdx/tr>"); 16 | Глава 1. Создание сервлетов и JSP
out .printin ("</tablex/form>*); out. print In ("</bodyx/html>"); }//doGet public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.lOException { //отображаем имена и значения параметров Enumeration paramNames = request.getParameterNamesO; String parName;//здесь хранится имя параметра boolean emptyEnum = false; f % if (! paramNames.hasMoreElements()) emptyEnum = true; 11 устанавливаем тип Mime ответа в "text/html" response.setContentTypef"text/html"); // используем PrintWriter для отправки данных клиенту java.io.PrihtWriter out = response.getWriter(); // Начало формирования HTML-содержимого out .printin ("<htmlxhead>"); out.println( "<title>Submitted Parameters</titlex/headxbody>"); if (emptyEnum) { » out.println( "<h2>Sorry, the request does not contain any parameters</h2>"); ) else { out.printIn( "<h2>Here are the submitted parameter values</h2>"); } 1 while(paramNames.hasMoreElements())( parName = (String)paramNames.nextElement(); out.printIn( "<strong>" + parName + "</strong> : " + request.getParameter(parName)); out.println("<br />"); }//while out. printin (" < /bodyx/html>"); }// doPost » Создание сервлетов | 17
Вы, возможно, заметили, что и doGet (), и doPost () могут вызвать исключения ServletException и lOException. Сервлет может вызвать lOException, поскольку вызов метода response.getWriter() (как и метода Printwriter, close ()) может вызвать это исключение. Методы doGet () и doPost () могут вызвать исключение ServletException, чтобы сигнализировать о возникновении ошибки в ходе обработки запроса. Например, если сервлет определяет факт нарушения безопасно- сти или другие проблемы с запросов, в тело методов doGet () и doPost () можно включитьследующий код: //обнаружена проблема, препятствующая корректной обработке запроса throw new ServletException("Сервлет не может обработать этот запрос."); Рис. 1.1 демонстрирует отображение в браузере выходной информации метода doGet(). Рис. 1.1. Выходная информация метода doGet() См. также Рецепт 1.3 по компиляции сервлета; рецепт 1.4 по упаковке сервлетов и JSP; рецепт 1.5 по созданию дескриптора развертывания; главу 2 по развертыванию сервлетов и JSP; главу 3 по именованию сервлетов; документацию по javax. servlet .http: http://ja.va. sun.'com/j2ee/1.4/docs/api/javax/servlet/http/package-siunmary.html', руководство от Sun Micro- systems no J2EE: http://java.sun.cotn/j2ee/tutoTial/1^3~fcs/doc/J2eeTutorialTOC.html', книгу Jason Hunter «Java Servlet Programming» (O'Reilly). 18 | Глава 1. Создание сервлетов и JSP
Рис. 1.2. Выходная информация метода doPost() сервлета 1.2 Создание JSP Задача Требуется создать страницу JSP и включить ее в web-приложение. Решение Создать JSP в виде простого текстового файла, используя при необходимости шаб- лонный текст HTML. Сохранить файл с JSP на верхнем уровне иерархии данного web- приложения. ') Обсуждение Компонент JSP (JavaServlet Pages - серверные страницы Java) - тип сервлета, создан- ный для исполнения роли пользовательского интерфейса в web-приложениях Java. Разработчики пишут JSP в виде текстовых файлов, сочетающих код HTML и XHTML, XML-элементы и встроенные действия и команды JSP. Изначально JSP разрабатывалисЕ| согласно модели встроенных сценарных инструментов на стороне сервера, как и технология Создание JSP | 19
ASP от Microsoft, однако JSP развивались в сторону ориентации на XML-элементы, включая элементы, создаваемые пользователем, иди пользовательские теги, как главный метод генерирования динамического web-содержимого. Обычно имена файлов JSP имеют расширение .jsp, например mypage.jsp. При первом запросе клиентом страницы JSP или при перекомпиляции JSP, разработчиком (см. главу 5) web-контейнер транслирует этот тексто- вый документ в сервлет. Спецификация JSP 2.0 называет преобразование JSP в сервлет фазой трансляции. При этом полученный экземпляр сервлета называется объект-реализация страницы. Ж Компилятор JSP (например, компонент Jasper сервера Tomcat) автоматически преобразует исходный текстовый документ в сервлет. Web-контейнер созд. экзем- пляр полученного сервлета и делает сервлет доступным для обработки запросов. Эти задачи выполняются незаметно Для разработчика, которому совсем не нужно зани- маться транслированным исходным кодом сервлета (хотя он может проверить этот код, чтобы увидеть, что происходит за сценой, что всегда поучительно). Разработчик сосредотачивает внимание на динамическом поведении JSP и на трм, какие элементы или пользовательские теги в ней используются для генерации ответа. Создание JSP в виде текстового документа, а не в виде исходного кода на языке Java позволяет профессиональному дизайнеру работать над графикой, HTML или DHTML, оставляя XML-теги и динамическое содержимое программистам. В примере 1.2 показана JSP-страница, отображающая текущую дату'и время. Этот пример показывает, как импортировать и использовать библиотеку пользовательских тегов, детали этого описаны в главе 23. В этом коде также используется стандартное действие j.sp: us eBean, встроенный XML-элемент, который можно применять для соз- дания нового объекта Java, используемого на странице.. Ниже перечислены основные пункты написания JSP. 1. Откройте текстовый редактор или редактор среды программирования, выделяющий синтаксис JSP цветом. 2. Если вы создаете JSP для обработки HTTP-запросов, введите код HTML так, как вы это делаете для HTML-файла. 3. Включите в текст, в начало файла, необходимые директивы JSP, например директиву taglib из примера, 1.2. Директивы должны начинаться с символов <%@ 4. При необходимости введите также стандартные действия или пользовательские теги. 5. Сохраните полученный файл с расширением .jsp в каталоге, который вы отвели под JSP. Обычно это каталог верхнего уровня web-приложения, который вы создаете в своей файловой системе. Некоторые JSP создаются как XML-файлы, их еще называют JSP-документами, они состоят исключительно из корректных XML-элементов и атрибутов. Спецификация JSP 2.0 рекомендует давать таким файлам расширение .jspx. См рецепт 5.5 ’ для уточнения деталей о JSP-документах. 20 | Глава 1. Создание сервлетов и JSP
Пример 1.2. JSP-файл для отображения даты <%— исполь'зуём директиву ’taglib’ чтобы получить доступ к тегам ядра JSTL 1.0; uri библиотеки JSTL 1.1 "http://java.sun.сот/jsp/jstl/core" —%> <%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <%— используем стандартное действие’jsp:useBean’ для создания объекта Date; этот объект становится атрибутом с областью видимости - страница —%> <jsp:useBean id="date" class="java.util.Date" /> <html> <head>«ttitle>First JSP</title></head> <body> <. <h2>Here i-s today's date</h2> <c:out value="${date}" /> </body> </html> Чтобы увидеть результат работы этого файла в браузере, запросите файл, напечатав в поле адреса браузера http://localhost:8080/home/firstJ.jsp. Имя данного файла - firstJ.jsp. Если это первое обращение к данной странице, вы почувствуете задержку, связанную с тем, что JSP-контейнер преобразует текстовый файл в исходный код Java и затем ком- пилирует его в сервлет. ;S * • Задержки можно избежать путем предварительной компиляции (прекомпиляции) JSP Если вы запросите JSP с параметром jsp_precompile=true, Tomcat транслирует J । .?• JSP, но не будет посылать ответ на этот запрос. Вот пример* http://ldcalhost:8080/ *’ home/firstJ.jsp?jsp_precompile=true. На рис. 1.3 показан вывод JSP в браузере. Если в меню браузера вы выберете «Показать в виде HTML», чтобы увидеть исходный код страницы, то не увидите никакого специального синтаксиса JSP: ни символов ком- ментария (<%— —%>), ни директиву taglib, ни действие j sp: useBean, ни тег с: out. Сервлет посылает клиенту только шаблонный текст и сгенерированную строку с датой. См. также Рецепты 5.1—5.3 по прекомпиляции JSP; главу 2 по развертыванию JSP; рецепты 1.1-1.3 по созданию и компиляции сервлетов; рецепт 1.4 по упаковке сервлетов и JSP; рецепт 1.5 по созданию дескриптора развертывания; руководство от Sun Microsystems по J2EE: http:// java.sun.com/j2ee/tutorial/l_3-fcs/doc/J2eeTutorialTOC.html’, книгу Hans Bergsten «JavaServer Pages» (O'Reilly). Создание JSP | 21
Рис. 1.3. Вывод страницы first J.jsp в браузере 1.3 Компиляция сервлетов Задача* Сервлет написан, необходимо компилировать его в class-файл. Решение Убедитесь, что servletjar (для Tomcat 4.1.24) или servlet-api.jar (для Tomcat 5) нахо- дятся там, куда указывает ваш пользовательский путь к классам (classpath). Используйте j avac, так же, как вы это делаете для компиляции любых других исходных файлов Java. Обсуждение Для компиляции вам необходимо иметь классы для сервлета там, куда указывает путь к классам. Эти классы находятся в следующих пакетах: • javax. servlet; • javax.servlet.http. Tomcat 5 поддерживает версию 2.4 API сервлетов; J AR-файл, путь к которому вам необ- ходимо поместить в путь к классам, находится в каталоге: инсталляционный каталог Тот- cat>/common/lib/servlet-api.jar. Tomcat 4.1.24 поддерживает версию 2.3 API сервлетов. Классы сервлетов находятся в инсталляционный каталог Tomcat>/common/lib/servlet.jar. 22 | Глава 1. Создание сервлетов и JSP
Для BEA WebLogic 7.0 классы сервлетов и другие подпакеты пакета javax.(TO есть javax.ejb, javax.mail, javax.sql) размещаются в каталоге инсталляционный каталог WebLogic >/ weblogic700/server/lib/weblogic.jar. tjr— * ’ Если для компиляции классов сервлетов вы используете Ant, следуйте рецепту 4.4, не передавайте Go и не собирайте $200. Этот рецепт посвящен теме использования * f Ant для компиляции сервлетов. Если вы используете интегрированную среду разработки (IDE), следуйте ее инструкциям, чтобы поместить путь к файлу JAR в путь к классам (classpath). Следующая ниже командная строка компилирует сервлет из каталога src и размещает откомпилированный класс в каталогах, относящихся к его пакету, внутри каталога build. javac -classpath К:\tomcat5\jakarta-tomcat-5\dist\coinmon\lib\servlet-api. jar -d ./build ./src/FirstServlet.java Чтобы команда успешно выполнилась, необходимо предварительно перейти в роди- тельский каталог каталога src. Рецепт 1.4 описывает типичную структуру каталогов для разработки web- приложений, включая и каталог src. Если сервлет использует и другие библиотеки, то путь к этим JAR-файлам следует также включить в путь к каталогам. В приведенной командной строке Подключается только JAR- файл servlet-api.jar. В этой команде также необходимо заменить путь к инсталляционному каталогу Tomcat на тот, где Tomcat инсталлирован на вашем компьютере. К: \tomcat5\jakarta-tomcat-5\dist\coiranon\lib\servlet-api. jar Приведенная командная строка используется для встроенного компилятора javac, поставляемого в составе JDK (Java Software Development Kit - набора средств для разработки для Java) от Sun Microsystems. Чтобы командная строка работала правильно, необходимо в переменной окружения PATH задать путь к JDK. К примеру, для основанной на Unix системе Mac OS X 10.2 в переменную PATH следует включить путь /usr/bin. На моей машине под Windows NT переменная PATH включает h:\2sdkl. 4.1J)]\bin. СМ. также Главу 2 по развертыванию JSP; главу 3 по именованию сервлетов; рецепт 1.4 по упа- ковке сервлетов и JSP; рецепт 1.5 по созданию дескриптора развертывания; руководство от Sun Microsystems по J2EE: http://java.sun.cotn/j2ee/tutorial/l_3-fcs/doc/J2eeTutorialTOC. htmT, книгу Jason Hunter «Java Servlet Programming» (O'Reilly). Компиляция сервлетов
1.4 Упаковка .сервлетов и JSP Задача Необходимо создать структуру каталогов для упаковки и создания WAR-файла (Web ARchive) для сервлетов и JSP. Решение Создать в файловой системе необходимую струпуру каталогов, затем, используя инструмент j аг или Ant, создать W AR-файл. Обсуждение За редким исключением, сервлеты и JSP обычно создаются как часть web-приложения. Создать структуру каталогов для размещения компонентов web-приложения (HTML-фай- лов, сервлетов, JSP, графики, библиотек JAR, возможно, видео- и аудиофайлов, XML-фай- лов конфигурации (например, дескриптор развертывания, см. рецепт 1.5)) относительно легко. Простейший вариант организации такой структуры - создать точный слепок схемы web-, приложения, после чего можно использовать инструмент jar для создания WAR-файла. Структура web-приложения, включающая подкаталог WEB-INF, является стандартной для всех web-приложений Java и задана в спецификации API сервлетов (в разделе web- приложения). Эта структура выглядит следующим образом, если каталог верхнего уровня имеет имя туарр. /туарр /images /WEB-INF /classes /lib. Спецификация сервлета определяет подкаталог WEB-INF и два его дочерних ката- лога classes и lib. Подкаталог WEB-INF содержит дескриптор развертывания приложе- ния web.xml. Файлы JSP и HTML находятся в каталоге верхнего уровня (в данном случае туарр). Классы сервлетов и JavaBean и прочие вспомогательные классы размещаются в каталоге WEB-INF/classes, в структуре каталогов, соответствующей именам их паке- тов. Если полностью квалифицированное имя класса сервлета com.myorg.MyServlet, то этот класс сервлета должен находиться в WEB-INF/classes/com/myorg/MyServlet.class. Каталог WEB-INFAib содержит все необходимые приложению библиотеки JAR, такие, как драйверы баз данных, log4j.jar, а также те, что требуются для использования библио- теки стандартных тегов JSP (JavaServer Pages Standard Tag Library) (см. главу 23). 24 I Глава lf Создание сервлетов и JSP
Когда все готово для перевода приложения в формат WAR, перейдите в каталог верхнего уровня. Наберите следующую ниже команду, вводя имя WAR-файла после ката- лога верхнего уровня вашего приложения. Эта командная строка работает и для Windows, и для Unix (я применял ее для Windows NT и Mac OS X 10.2): jar cvf myapp.war He забудьте точку в конце, она указывает инструменту jar включить в WAR-файл содержимое текущего каталога и его подкаталогов. Данная команда создает файл myapp. war в текущем каталоге. Заданное имя WAR-файла становится именем приложения и подразумеваемым путем к этому web-приложению. К примеру, когда приложение./иуарр.ишг развертывается £ в web-кон геинере, с ним обычно ассоциируется путь /туарр”. Чтобы из командной строки посмотреть содержимое полученного WAR-файла, вве- дите следующее. jar tvf alpine-final.war Ниже представлен пример результата выполнения этой, команды. Н:\classes\webservices\finalproj\dist>jar tvf alpine-final.war 0 Mon Nov 18 14:10:36 EST 2002 META-INF/ 48 Mon Nov 18 14:10:36 EST 2002 META-INF/MANIFEST.MF 555 Tue Nov 05 17:08:16 EST "2002 request, jsp 914 Mon Nov 18 08:53:00 EST 2002 respbrise.jsp 0 Mon Nov 18 14:10:36 EST 2002 WEB-INF/ 4 0 Mon .Nov 18 14:10:36 EST 2002 WEB-INF/classes/ • 0 Tue Nov 05 11:09:34 EST 2002 WEB-INF/classes/com/' > 0 Tue Nov 05 11:09:34 EST 2002 WEB-INF/classes/com/parkeryiver/ CONTINUED. . . Многие команды разработчиков для компиляции сервлетов и JSP и создания W AR- файлов используют Ant. Чтобы лучше пояснить обсуждаемую тему, приведу пример структуры каталогов для всеобъемлющего web-приложения, содержащего разные сервлеты, JSP, статичные HTML-файлы, а также графические и мультимедиа компо- ненты. При создании WAR-файла из структуры каталогов подобного типа с помощью Arit, необходимо отфильтровать те каталоги, которые вы не хотите включать в итого- вый WAR-файл, например находящиеся на верхнем уровне каталоги src, dist, и meta. myapp /build /dist /lib , /meta ' /src /web /images /multimedia Упаковка сервлетов и JSP | 25*
/WEB- IMF /classes /.lib /tlds /jspf *. ’ *' Необязательные каталоги WEB-lNF/tlds и WEB-INF/jspf могут содержать, соответ- ственно, файлы дескрипторов библиотек тегов и сегменты JSP (фрагменты JSP, &' । созданные для включения в другие JSP, такие, как включения на стороне сервера). См. также Главу 2 по развертыванию JSP; главу 3 по именованию сервлетов; книгу «.The deploy- ment sections of Tomcat: The-Definitive Guide» авторов Brittain и Darwin (O'Reilly);.руко- водство от Sun Microsystems nO J2EE: htlp://java.sun.coni/j2ee/tutorial/J_3rfc$/doc/ J2eeTutorialTOC.html. ’ - 1.5 Создание дескриптора развертывания Задача Создать дескриптор развертывания для web-приложения. Решение Создайте XML-файл с именем web.xml и разместите его в каталоге WEB-INF своего web-приложения. Если у вас нет образца файла web.xml, скопируйте его из специфика- ции сервлета версии 2.3 или 2.4 и используйте как стартовую точку. Обсуждение Дескриптор развертывания - очень важная часть web-приложения. В нем, в кратком виде, содержатся требования web-приложения. Его можно прочитать в большинстве 4 XML-редакторов. Web.xml файл - это то место, где вы: ' Г. • Регистрируете и создаете отображения URL на ваши сервлеты; • Регистрируете или задаете любые фильтры и слушатели приложения; , • Задаете начальные параметры контекста в виде пар имя/значение; • Конфигурируете страницы ошибок; Указываете начальные файлы приложения; • Задаете время простоя сеанса (тайм-аут); • Задаете настройки безопасности, управляющие тем, кто к каким web-компоненТам может обращаться, 26 | Глава 1. Создание сервлетов и JSP к . . . .. .............
И эхо только часть тех настроек, которые Ложно задать в файле web.xml. В данном рецепте показаны упрощенные версии дескрипторов развертывания в соответствии со спецификацией сервлетов 2.3 и 2.4, в дальнейших главах книги содержаться более детализированные примеры web.xtnl (см. раздел «См. также»). В примере 1.3 приведено простое web-приложение с сервлетом, фильтром, слушателем и элементом session-config, а также конфигурацией страницы ошибок. Файл web.xml из примера 1.3 использует DTD (Document Type Definition), в соответствии со спецификам цией сервлета 2.3. Главное отличие между дескрипторами развертывания версий 2.3 и 2.4 в том, что 2.3 использует DTD, а 2.4 базируется на XML-схеме. Вы увидите, что ранняя (2.3) версия web.xml в начале файла содержит объявление DOCTYPE, тогда как версия 2.4 ссыла- ется на XML-схему с помощью атрибутов пространства имен элемента web-app. Соответ- ственно, XML-элементы в примере 1.3 следуют в порядке, определимом в DTD. Пример 1.3. Дескриптор развертывания в соответствии с API сервлета 2.3 <?xml version=”1.О" encodings"ISO-8859-1”?> <IDOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-application_2_3 .dtd" <web-app> <display-name»Servlet 2.3 deployment descriptor</display-name> <filter> < f i1ter-name»RequestFi1ter</ fi1ter-name> <filter-class»com.jspservletcookbook.RequestFilter</filter-class> </filter> . <filter-mapping> <filter-name>RequestFilter</filter-name> <ur 1-pa t'tem> / * </url.-pat t em> </filter-mapping> .. <listener> <listener-class»com.jspservletcookbook.ReqListener</listener-class> </listener» <servlet> < servlet -name»MyServlet < / servlet -name» <servlet-class>ccxn.d spservletcookbook.MyServlet</servlet-class> </servlet» r <servlet mapping» <servlet-name> Myservlet </servlet-name» <ur1-pattern»/myservlet</url-pattern» <I servlet-mapping» <session-config> Создание дескриптора развертывания | 27
<session-timeout>15</sessiori-timeout> </sessi.on-config> <error-page> <error-code>404</error-code> <location>/err404.jsp</location> </error-page> </web-app> В примере 1.3 показан файл web.xml для приложения, имеющего только один сервлет, на который указывает путь <путь к KOHmeKcmy>/myservlet. Время простоя cearica задано в 15 минут. Если клиент запрашивает URL, который не удается найти, web-контейнер перенаправляет запрос на страницу /err404.jsp, в соответствии с кон- фигурацией error-page (страницы ошибок). Для всех запросов, как к статическому, так и к динамическому содержимому в данном контексте, используется фильтр с име- нем RequestFilter. При запуске web-контейнер создает экземпляр класса слушателя com.j spservletcookbook.ReqListener. Все, относящееся к примеру 1.3, относится и к примеру 1.4, за исключением того, что элемент web-app (в начале файла) ссылается на XML-схему и содержит атрибуты с характеристиками ее пространства имен. Кроме того, элементы в этом дескрипторе развертывания по версии 2.4 могут следовать в произвольном порядке. К примеру, вы можете по желанию сначала поместить перечень сервлетов и отображения, а потом уже слушателей и фильтры. Пример 1:4. Дескриптор развертывания по версии 2.4 „ <?xml versions"1.0" encodings"ISO-8859-1"?> <web-app xmlns«"http://java, sun.com/xml/ns/j2ee" xmlns :xsi="http://www.w3 .org/2001/XMLSchema-instance" xsi ischemaLocation* "http: //java. sun. ccm/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" versions"2.4"> <!-оставшаяся часть та же, что и в примере 1.3 после открывающего тега web-app —> </web-app> Дескриптор развертывания по версии 2.4 также содержит определения разных элементов, не входящих в версию 2.3: jsp-config, message-destination, f Л* message-destination-ref и service-ref. Синтаксис этих элементов ' появился в спецификациях JSP версии 2.0 и J2EE версии 1.4. См, также Главу 2 по развертыванию JSP; главу 3 по именованию сервлетов; главу 9 по кон- фигурированию дескрипторов развертывания для обработки ошибок; руководство от Sun Microsystems по J2EE: http://java.sun.com/j2ee/tutorial/l__3-fcs/doc/J2eeTutorialTOC.htinl. 28 | Глава 1. Создание сервлетов и JSP
ГЛАВА2 Развертывание сервлетов и JSP 2.0 Введение Данная глава описывает, что нужно сделать, чтобы написанные сервлеты и JSP начали работать (получать запросы) под управлением контейнеров сервлетов Tom- cat или BEA WebLogic Server 7.0. Обсуждение начинается с развертывания сервле- тов и JSP, то есть включения их в работу под Tomcat и WebLogic, индивидуально или в составе web-приложения. Разработка и компиляция сервлета или JSP с помощью интегрированной среды разработки (IDE) - это одно. И совсем другое - сделать так, чтобы эти web-компо- ненты начали отвечать на HTTP-запросы. Развертывание для web-программ заключается в помещении их на обслуживание в web-контейнер, например Tomcat, или другой сервер приложений, например BEA WebLogic Server 7.0. В следующие далее рецепты подробно вписывают развертывание сервлетов и JSP на базе этих web- контейнеров, первые рецепты - индивидуальное развертывание, а последующие - развертывание в составе web-приложения. Для указанных целей обычно используется прекрасный инструмент сборки и автоматизации Jakarta Ant (открытое ПО). Он упоминается, где уместно, в следующих ниже рецептах, а глава 4 полностью посвящена инсталляции и использованию Ant 2.1 Развертывание отдельного сервлета Задача Вы хотите взять откомпилированный сервлет и инсталлировать его Tomcat, чтобы убедиться в его работоспособности. Вы делаете предварительную проверку и не собираетесь тратить время на сборку законченного web-приложения для сервлета. 29
решение Копируйте файл своего класса и вставьте его в web-приложение по умолчанию сервера Tomcat (если вы ранее инсталлировали какое-либо web-приложение, то вставьте в него), затем обратитесь к нему с запросом, используя вызывающий (invoker) сервлёт. Или используйте для временного перемещения файла с классом в приложение по умолчанию файл build.xml инструмента Ant. Обсуждение Иногда, когда вы разрабатываете сервлет, вам необходимо просто посмотреть, работает ли он. Если сервлет не зависит ют других сервлетов или компонентов всего приложения, его работоспособность можно проверить на сервере Tomcat, вставив файл класса (включая каталоги, относящиеся к его пакету) в приложение по умолчанию сервера Tomcat. Обычно это приложение находится в <инсталляционный-каталог-Тотса1 >/web-apps/ROOT. Если класс сервлета имеет полностью квалифицированное имя j spservletcook- book. CookieServlet, то можно следующими действиями, вручную запустить этот сервлет под Tomcat. 1. Остановите сервер Tomcat, выполнив командный сценарий <инсталляЦионный- каталог-Tomcat >/bin/shutdown или аналогичный сценарий, предлагаемый адми- нистратором вашего сервера. Альтернатива - остановить приложение по умолчанию, задав в браузере такой URL: http:// localhost:8080/manager/stop?path=/. 2. Создайте в каталоге <инсталляционный-каталог-Тотсш >/ webapps/ROOT/WEB- INF/classes подкаталог jspservletcookbook (если каталога classes нет, создайте его). 3. Вставьте файл класса CookieServlet в каталог <инсталляционный^каталог-Тот- cat >/ webapps/ROOT/WEB-INF/classes/ jspservletcookbook. 4. Запустите сервер Tomcat, выполнив командный сценарий <инсталляционный-ката- лог-Tomcat >/bin/startup или аналогичный от администратора вашего сервера. Альтернатива - запустите приложение по умолчанию, запросив в браузере следующий URL - http:// localhost:8080/manager/start?path=/. 5. Запросите сервлет в браузере, набрав URL ltttp://localhost:8080/servlet/jspservletcook- book. CookieServlet. Вы возможно скажете: «Должна существовать более элегантная альтернатива этой мед- ленной ручной инсталляции отдельного сервлета». Все правильно, этот процесс можно автоматизировать с помощью Jakarta Ant. Если вы установите у себя Ant, как описано в главе 4, файл build.xml из примера 2.1 выполнит тот же процесс проверки сервлета. Поместите этот сборочный файл в подходя- щий каталог. Создайте в этом же каталоге файл global.properties, настроенный в соответст- вии с вашими потребностями (см. пример 2.2). Находясь в командном окне, перейдите в этот каталог и наберите ant. Все остальное, включая запуск и остановку web-приложе- ния по умолчанию сервера Tomcat, сделает Ant. i 30 | Глава 2. Развертывание сервлетов и JSP
Пример 2.1. Инсталляция сервлета в приложение по умолчанию <project name-"Cookbook" default="deploy-servlet" basedir="."» «taskdef names"start" classname="org.apache.catalina.ant.StartTask’ /> <taskdef names"stop" classname="org*apache.catalina.ant.StopTaSk" /> <>—загрузка ряда глобальных свойств —> «property file="global.properties" /> «target name="init" descriptions"initializes some properties."> «echo message="Initializing properties."/> «property name="build" values".\buiId" /> «property names"src" values".\src* /> <1—Для корневого приложения путь к контексту - только слеш "/*; см. цели start и stop, которые уже включают слеш в состав шаблона URL «property name="context-path" values"" /> «/target» «target names "prepare", depends= " init "> • ч «echo message»"Cleaning up the build directory."/» «delete dir="${build}"/> «mkdir dir="${build}"/> «/target» <!—Устанавливаем путь к классам на.jar файлы Tomcat —» «path id="classpath"» «fileset dir="${tomcat.dir}/common/lib"» «include name="*.jar" /» «/fileset» «fileset dir="${tomcat.dir}/common/endorsed"» «include names"*.jar" /» «/fileset» «/path» <!—стартуем web-приложение по умолчанию Tomcat —» 4 «target names"start" descriptions"Starts the default Web application"» «echo messages"Starting the default application...."/» «start; url="${url}" usernames"${username}" passwords"${password}" path=" / $ {context-path}" /> Развертывание отдельного сервлета | 31
</target» <!—останавливаем web-приложение по умолчанию Tomcat —> <target name="stop" descriptions"Stops the default Web application"» <echo messages"Stopping the application...."/> <stop url="${url}" usernames"${username}" passwords"${password}" patty="/${context-path}* /> </target» <•— останавливаем web-приложение по умолчанию, компилируем сервлет, добав- ляем его к web-приложению по умолчанию, затем стартуем web-приложение по умолчанию —> ctarget name="deploy-servlet* depends= "prepare" descriptions "Compile the specified servlet, then move it into Tomcat's default Web application.’> <echo messages"Stopping the default Tomcat application...."/> <antcall targets*stop"/» <echo message="Compiling the servlet...."/» <javac srcdir="${ferc}" destdifs"${build}"» cinclude name="${conpiled.servlet}.java* /» cclasspath refid="classpath"/> </javac» <echo messages "Copying the servlet to Tomcat ROOT web application..."/» <copy todir= * ${tomcat.webapps}/WEB-INF/classes"> <fileset dir="${build}" /> </copy» <echo messages"Starting the default application...."/> <antcall- ta»get="start"/» </target» </project» Файл global.properties, размещаемый в том же каталоге, что и build.xml, выглядит так, как показано в примере 2.2. ь. 32 | Глава 2. Развертывание сервлетов и JSP
Пример 2.2. Файл global.properties для Ant tomcat .webapps=k: /jakarta-tomcat-4.1.12/webapps/R00T tomcat.dir=k:/jakarta-tomcat-4.1.12 url=http://localhost:8080/manager compiled.servlet=CookieServlet username=tomcat pas sword=tomcat Файл globaLproperties состоит из пар имя- свойства=значение. Иными словами, каждая строка файла состоит из символов, представляющих имя свойства (которое может включать символ точка ), символа *=’, за которым следуют символы, представляющие значение. Online-руководство по Jakarta Ant находится в http://jakarta.apache.org/ant/manual/ index.hml. А вот что делает файл buildxml. 1. В элементах taskDef определяет две задачи с именами start и stop. Эти задачи используются в файле buildxml позднее, в элементах target. Они позволяют исполь- зовать инструмент развертывания приложений сервера Tomcat из ваших файлов Ant. 2. Использует задачу property для загрузки набора свойств, определяемых в файле global.properties. Это означает, что свойство с именем tomcat. dir с этого момента можно использовать в файле build.xml. Элемент path использует свойство tomcat, dir, включая его значение (в данном примере «k:/jakarta-tomcat-4.1.12») как часть определения пути к классу (classpath). Получить значение этих необходимых свойств можно, используя ссылку вида: ${tomcat.dir}. В любой момент времени, когда вы захотите изменить значения этих свойств перед запуском Ant, нужно йросто напечатать новые значения в файле свойств global.properties в текстовом редакторе. 3. Создает цель init, которая выводит сообщение на консоль и создает три свойства (build, src и context-path). Значения этих свойств доступны только после завершения выполнения цели init. Например, если цель prepare не содержит «init» в качестве значения атрибута depends (зависит от), цель deploy-servlet, зависящая от prepare (depends=prepare), не сможет использовать значения свойств, определяемых в init. 4. Определяет цель под названием prepare. 5. Создает повторно используемый путь к классам (с идентификатором «classpath»), включая в него все JAR-файлы, находящиеся в паре каталогов Tomcat. 6. Создает цели start и stop. Они выдают на консоль сообщение и затем вызывают соответствующие задачи (например, stop), которые были определены в элементах taskDef в начале файла buildxml. Цели start и stop в действительности вызываются целью deploy-servlet, которая включает в себя все остальные цели. 2-1545 Развертывание отдельного сервлета | 33
7. Создает цель deploy-servlet. Эта цель выполняет всю основную работу в файле buildxml. Заметьте, что атрибут depends (зависит от) имеет значение «prepare». Это значит, что до выполнения инструкций, содержащихся з цели deploy-servlet, Ant должен сначала выполните цели init и prepare. Поскольку цель prepare зависит от цели init, deploy-servlet вызывает prepare, которая в свою очередь вызывает цель init, от которой она зависит. Таким образом, запуская цель deploy-servlet, вы инициируете цепочку целей init -э prepare deploy-servlet. Используя элемент ant call, с помощью которого цель может явно вызвать другую цель, deploy- servlet вызывает цели start и stop. Таким образом, deploy-servlet: а) останавливает приложение по умолчанию сервера Tomcat; b) компилирует сервлет с помощью задачи javac. Задача javac подключает сервлет, заданный свойством compiled, servlet, значение которого задается в файле glo- bal.properties. * , 8. Копирует откомпилированный сервлет в каталог WEB-INF/classes приложения по умол- чанию сервера Tomcat Если каталог classes не существует, задача сору создаст его. 9. Стартует web-приложение по умолчанию, после чего к нему можно обращаться из браузера. ' “ z См. также Книгу «The deployment sections of Tomcat: The Definitive Guide» авторов Brittain и Darwin (O'Reilly); рецепты 2.2,2.4, и 2.6; online-руководство no Jakarta Ant по адресу http: //jakarta.apache.org/ant/manual/index.html. 2.2 Использование элемента Context в файле server.xml для Tomcat Г Задача Требуется развернуть сервлет на Tomcat 4.1.x и затем, не перезапуская web-кон- тейнер Tomcat, развернуть его снова. Решение Разверните сервлетжак часть элемента Context файла server.xml сервера Tomcat. Обсуждение Для того чтобы вставить перекомпилированный класс сервлета вместо существующего класса сервлета и запустить этот сервлет, не перезагружая Tomcat, сделайте следущее. Найдите элемент Context вашего web-приложения или создайте новый элемент Con- text в файле <инсталляционный-каталог-Тотса1>/соп//5еп>ег.хтп1. Элемент Context должен быть вложен в элемент Host, представляющий виртуальный хост, под которым работает ваше web-приложение. 34 | Глава 2. Развертывание сервлетов и JSP
' Установите значение атрибута reloadable этого элемента Context в true. Это заставит Tomcat отслеживать изменение содержимого каталоге! WEB-INF/classes и WEB- INF/lib. При обнаружении изменений Tomcat автоматически перезагрузит web-приложение. Элемент Context файла server.xml выглядит примерно следующим образом: <Context className="org.apache.catalina.core.Standardcontext" z crossContext="false" reloadable="true" mapperClass="org.apache.catalina.core.StandardContextMapper" useNaming="true" debug=“0* swallowOutput="false" privileged="false" displayName="Home Web App" wrapperClass="org.apache.catalina.core.Standardwrapper" docBase="h:\home" cookies="true" path="/home" cachingAllowed="true" charsetMapperClass="org.apache.catalina.util.CharsetMapper" Атрибут path представляет путь к контексту приложения. Атрибут docBase уазы- вает каталог верхнего уровня данного приложения. Большинство прочих атрибутов имеют значения, которые используются совместно с другими элементами Context. К примеру,-cookie=" true" свидетельствует, что контекст для идентификации сеанса будет использовать cookie, a crossContext="false" запрещает сервлетам этого web-приложения перенаправлять запросы к другим web-приложениям, работающим на этом виртуальном хосте. ! ... Установка атрибута reloadable в true ведет к потере производительности наэтапе выполнения, поэтому рекомендуется использовать такую конфигурацию 1^—только на период разработки приложения. При такой конфигурации, когда вы вставите в web-приложение новый класс сервлета вместо старого, Tomcat спустя некоторое время отобразит на консоль сообщение. Ниже представлен пример сообщения, выдаваемого при динамической перезагрузке сервлета. WebappClassLoader: Resource 1/WEB-INF/classes/com/jspservletcookbook/ OracleTest.class1 was modified; Date is now: Sun Feb 02 22:17:41 EST 2003 WaS: Sun Feb 02 21:38:52 EST 2003 См. также Книгу «The deployment sections of Tomcat: The Definitive Guide» авторов Brittain и Darwin (O'Reilly); рецепты 2.1, 2.4, и 2.6; документацию Jakarta Tomcat по элементу Context http:// jakarta.apache:org/tomcat/tomcat-4.1-doc/config/context.html. Использование элемента Context в файле server.xml для Tomcat | 35
2.3 Развертывание отдельного сервлета в WebLogic ; Задача Требуется взять откомпилированный сервлет и инсталлировать его в BEA WebLogic Server 7.0, чтобы убедиться в его работоспособности. Решение Копируйте файл класса и вставьте его в web-приложение по умолчанию сервера WebLogic (если вы ранее инсталлировали какое-либо приложение, вставьте в него). Используйте консоль администрирования WebLogic для изменения файла web.xml и дайте сервлету узнаваемое имя, по которому будете обращаться к нему из браузера, или используйте файл сборки Ant для временного перемещения этого файла в приложе- ние по умолчанию сервера WebLogic. Обсуждение ' Приложение по умолчанию сервера WebLogic размещается в каталоге <инсталляцион- ный-каталог-WebLogio/user_projects/<Moii-doMeH>/applications/DefaultWebApp. При типич- ной инсталляции сервера WebLogic 7.0, в приложении по умолчанию мало что есть, только дескриптор развертывания web.xml и несколько файлов изображений. Чтобы к приложению по умолчанию добавить сервлет, вставьте свой класс сервлета, включая связанные с его паке- том каталоги в каталог DefaultWebApp/WEB-INF/classes. Если вы делаете это в первый раз, может потребоваться создать каталог classes. Перед повторным развертыванием web-прило- жения (см. описание из рецепта 2.4) измените файл web.xml, чтобы дать сервлету имя (это проще сделать с помощью консоли администрирования). С помощью консоли администрирования отредактируйте файл web.xml, чтобы дать новому сервлету зарегистрированное имя и поставить ему в соответствие элемент serv- let-mapping. Для этого также можно использовать и другой инструмент, например WebLogic Builder (рецепт 2.9) или текстовый редактор. На рис. 2.1 показано отображение приложения по умолчанию в консоли администрирования. Щелкните по «Edit Web Appli- cation Deployment Descriptors...». ' Будет показан экран, изображенный на рис. 2,2. Этот экран позволяет легко в графи- ческом виде отредактировать файл web.xml любого web-приложения (в данном случае приложения по умолчанию). С помощью данного графического редактора создайте элементы servlet и servlet- mapping для только что добавленного сервлета. Не забудьте щелкнуть по кнопке «Web Descriptor» в левой колонке окна на рис. 2.2 и затем сохранить внесенные в web.xml измене- ния. Эго действие приведет к перезаписи файла web.xml уже с новыми элементами serv- let и servlet Tinapping. 36 | Глава 2. Развертывание сервлетов и JSP
Рис. 2.1. Консоль администрирования WebLogic После сделанного повторно разверните web-приложение, что сводится к простому щел- канью по нескольким гипертекстовым ссылкам в консоли. В левой колонке консоли, в узле <мойдомен> -> Deployments Web Applications дерева навигации по структуре, выберите имя своего web-прйложения. Отображаемое после этого окно показано на рис. 2.3. В полученной таблице HTML щелкните по вкладке «Deploy», а затем щелкните по кнопке «Undeploy». Чтобы повторно развернуть приложение, щелкните по вкладке «Deploy», а затем щелкните по кнопке «Deploy», см. рис. 2.4. Если сервлет, над которым вы работаете, уже присутствует в web-приложении, то вы можете копировать и вставить новый класс сервлета вместо старого в каталоге WEB- INF/classes web-приложения. Новая версия сервлета станет доступна сразу после этого, без необходимости использования консоли для повторного развертывания всего web- приложения. Для компиляции сервлета и копирования его в приложение по умолчанию сервера WebLogic также можно использовать файл (сборки) Ant. Файл сборки для примера 2.3 очень похож на тот, что использовался в рецепте 2.1, но с изменениями, учитывающими использование WebLogic, а не Tomcat. Развертывание отдельного сервлета в WebLogic | 37
Рис. 2.2. Редактирование web.xml в графическом виде Пример 2.3. Использование файла Ant для сервлета на сервере WebLogic «project name="Cookbook" default="deploy-servlet" basedir=". <property file="wl.properties" /> «target name="init" description;;"Initializes some properties."> <echo message="Initializing properties."/> «property name="build" value=".\build" /> «property name=”src" value=".\src" /> «/target> '•* «target name="prepare" depends="init"> «echo message="Cleaning up the build directory."/> «delete dir="${build}“/> «mkdir dir="${build}“/> </target> «path id="classpath"> «fileset dir="${wl.dir}\server\lib"> «include name="*.jar" /> __________________________ _ ______ «. _______:_________________ 38 | Глава 2. Развертывание сервлетов и JSP
Рис. 2.3. Использование консоли для повторного развертывания web-приложения </fileset> <:/path> ctarget names"deploy-servlet" depends="prepare" descriptions"Compile the specified servlet, then move it into WL's default Web application."> <echo messages"Compiling the servlet ${compiled.servlet}...."/> •£javac srcdir="${src}" destdir="${build}"> cinclude name="${compiled.servlet}.java" /> <classpath refid="classpath"/> </javac> <echo messages "Copying the servlet to WL default web application... "/> <copy todir=" $ {wl. webapp} /WEB-INF/classes" > <fileset dir="${build}" /> </copy> </target> • </project> i Развертывание отдельного сервлета в WebLogic | 39
i^Mtchlnn CJ|Network Channels E0it.w$t- Appiication D$p|gwnt.p«picK?rs... 'Monitoring, Notes] Configuration ],Targets.1. Deploy e Ootpioymtnts ^Applications SfiilEJB a&lweb Applications ® cartreats «DsftultWsbApp ®_a₽psdrij»ma_dlr . Owe» Sanies Components , £>iconn<dor> SlstartupS Shutdown j. В Osowlcss I CJjCOM > Я CJjobc »: в CJjms В Oinosssging Bridge OxML Ojta j В OsNMP £ 5MlEC OwebLoglc Tuxedo Connect j Ojolt ZlUvirtuei Hosts Д SB £?Msll Й СУгютэ Hi jB.OSocuri»___________. . ± Deployment Status by Target: twenyserrer Server false Счриул» t.| Deploy or redeploy this component to all targets Deployment Activity: Wed Sep 03 Unprepare application rnmrw«i wed Sep 03 appsdif-hcime Jirontwoenyeerrer V ° 10:52:12 EDT 2003 Wed Sep 03 10:52:12 EDT2003 Note: To configure additional deployment targets for this component, please move to the Targets* tab . Deploy Л *E**^fHT Puc. 2.4. Развертывание сервлета в графическом режиме Данный сборочный файл Ant сначала загружает набор свойств, содержащихся в файле wLproperties, который распологается в том же каталоге, что и сам сборочный файл. Обычно файл сборки имеет имя builcLxml, однако можно вызвать и другой файл сборки из этого же каталога, использовав опцию командной строки -buildfile, например: ant -build- file wl_build. xml. Файл wLproperties для данного примера приведен в примере 2.4. Пример 2.4. Файл wLproperties для сборочного файла Ant на сервере WebLogic wl.properties for WebLogic Ant build file wl .webapp=k:/bea/user_projects/bwpdomain/applications/DefaultWebApp wl.dir=k:/bea/weblogic700 compiled.servlet=test Цель deploy-servlet зависит от цели prepare, которая также определяется в файле сборки. Цель prepare в свою очередь в атрибуте depends содержит значение «init», что означает, Что цель init выполняется до цели prepare. Таким образом, цель deploy-servlet создает цепочку выполняющихся целей: init -»prepare -»de- ploy-servlet. И вот что делает файл сборки в целом. 40 | Глава 2. Развертывание сервлетов и JSP
1. Цель init создает два свойства (build и source), указывающие на каталоги сборки и исходных файлов. , 2. Цель prepare удаляет и затем создает заново каталог сборки. Таким образом, ката- лог сборки очищается. 3. Цель deploy-servlet компилирует сервлет в каталог сборки, азатем копирует его в каталог, задаваемый свойством wl. webapp (значение которого находится в файле wl.pwperties). Элемент path создает путь к классам (classpath) из путей к JAR-файлам, найденным в каталоге k:/bea/weblogic700/server/lib. Этот каталог Ant получает, расшифровывая фразу "${wl.dir) \server\lib", то есть присоединяя к значению свойства wl.dir строку "\servef\hb". с. См. также Рецепт 2.5; рецепты 2.7-2.10; разделы по развертыванию книги «WebLogic: The Definitive Guide» авторов Mountjoy и Chugh (O'Reilly); документацию для программи- стов WebLogic Server 7.0: http://e-docs.bea.com/wls/docs70/programming.html. 2. 4 Развертывание одиночной страницы JSP под Tomcat Задача Необходимо поместить JSP в web-приложение. Решение Скопируйте вновь созданный или исправленный файл JSP в каталог верхнего уровня приложения по умолчанию сервера Tomcat или другого развернутого на сервере прило- жения. Обсуждение Простейший способ проверить работу нового файла JSP - поместить его в каталог верхнего уровня приложения по умолчанию сервера Tomcat. Это приложение находится в каталоге <инсталляцио1Шый-каталог-ТотсаГ>/ыеЬарр$/КООТ/. Сервер Tomcat 4.1.x скомпилирует (или перекомпилирует, если вы вставили новый файл JSP вместо старого) страницу JSP и отобразит ее ответ на запрос в виде web-страницы. Вам не потребуется останавливать и запускать Tomcat с помощью управляющего приложения сервера, чтобы сделать новый файл JSP доступным для вашего web-приложения. Развертывание одиночной страницы JSP под Tomcat | 41
ч4 * Простое размещение файла JSP в развернутом web-приложении не сработает если JSP зависит от каких-либо ресурсов приложения, например от сервлетов, х****»**у' пользовательских тегов hih других классов Java, поскольку нет гарантий, что web- Прияожение, которое вы временно используете в качестве хоста для JSP, имеет доступ к этцм ресурсам. Если вы развертываете JSP отдельно от его web-приложения, вы можете поместить этот файл J§P в другое развернутое на Tomcat web-приложение, необязатедьно в прило- жение по умолчанию. Это сделает страницу JSP доступной пользователям приложения, без необходимости остановки и перезапуска сервера Tomcat. Помните» что файлы JSP должны находиться в каталоге верхнего уровня web-приложения, а вообще оно имеет следующую структуру каталогов, index. html default.jsp anotherJsp.j sp imagesI logo.jpeg : WEB-INF/classes/j spservletcookbook/myservlet.class WEB-INF/lib/helperclasses.jar s WEB-INF/1ib/uti1itids,jar WEB-INF/web. xml WEB-INF/mytags.tld Иными словами, каталог верхнего уровня содержит файлы HTML и JSP, а также каталог WEB-INF. Каталог WEB-INF содержит: • дескриптор развертывания web.xml, • каталог classes, содержащий каталоги, связанные с пакетом и классы сервлетов или классы поддержки, например, JavaBeans, • каталог lib, в котором находятся любые файлы Java-архивов (JAR), содержащие слу- жебные или вспомогательные классы, используемые вашим web-приложением, • при необходимости, файлы дескрипторов библиотек тегов (файлы с расширением .tld), • при необходимости, каталоги для изображений, файлов видео, XML-файлов или иных ресурсов web. См. также 1 Книгу «The deployment sections of WebLogic: The Definitive Guide» авторов Mountjoy и Chugh (O'Reilly); рецепты 2.1,2.2 и 2.6. 42 | Глава 2. Развертывание сервлетов и JSP
2.5 Развертывание одиночной страницы JSP на WebLogic Задача Необходимо быстро проверить работоспособность JSP без развертывания ее в составе нового web-приложения. Решение Скопируйте JSP и вставьте ее в каталог верхнего уровня приложения по умолчанию сервера BEA WebLogic 7.0, а затем запросите эту JSP из браузера. Обсуждение Файл JSP можно развернуть на WebLogic в «горячем режиме», в составе web-приложе- ния по умолчанию, без необходимости создания и развертывания целого web-приложения. Приложение по умолчанию находится в каталоге <uHcmajumifuoHHbiu-Kamano2-WebLogic>/ user-projects/<uMn-eaiue2o-doMeHa>/applications/DefaultWebApp/. Если поместить файл JSP в этот каталог (DefaultWebApp), JSP сможет получать запросы без повторного развертыва- ния web-приложения по умолчанию. Если файл со страницей JSP называется newfile.jsp, то URL для запросов к данной странице будет: http://localhost:7001/neyvfile.jsp. Отметьте отсутствие в этом URL пути к контексту или имени web-приложения. Если запрос адресо- ван к web-приложению по умолчанию, имена файлов JSP следуют в URL сразу за слешем (/), после части хост:порт (то есть после localhost:7001/). Повторим предыдущее предостережение: простое размещение файла JSP в развернутом web-приложении не сработает, если JSP зависит от каких-либо ресурсов приложения, например от сервлетов, пользовательских тегов или других классов Java, поскольку нет гарантий, что web-приложение, которое вы временно используете в качестве хоста для JSP, имеет доступ к этим ресурсам. В большинство случаев JSP уже является частью некоего web-приложения, а для повторного развертывания web-приложения существует несколько инструментов, в числе которых* Ant, компоновщик (Builder) BEA WebLogic и консоль администрирова- ния WebLogic. И наконец, можно копировать и вставить файл JSP в другое web-приложение на сервере WebLogic. Однако это приложение должно быть установлено в формате «развернутых каталогов», то есть приложение не должно находиться в форме архива (WAR или EAR). Просто поместите JSP-файл в каталог верхнего уровня этого приложения. Для приложе- ния с именем «пеыарр» этот каталог будет называться <инсталляционный-каталог- WebLogic >/ user-projects/<uMn вашего-doAteHa>/appli cation.s/newapp. Развертывание одиночной страницы JSP на WebLogic | 43
См. также ; v.„ Рецепт 2.3; рецепты 2.7-2.10; документацию для программистов сервера WebLogic http://e-docs.bea.com/wls/docs70/programming.html. 2.6 Развертывание web-приложения на сервере Tomcat Задача Развернуть на сервере Tomcat целое приложение. Решение Создайте файл сборки для Jakarta Ant. Ant может автоматически откомпилировать классы сервлетов, создать файл архива web-приложения (.war) и затем развернуть этот WAR на сервере Tomcat 4.1.x.- Обсуждение Для компиляции и развертывания web-приложения рекомендуется использовать инструмент автоматизации Jakarta Ant. Если впоследствии вы что-либо измените в приложении (например, сервлет или JSP), для упаковки и повторного развертывания достаточно будет* набрать одну командную строку с вызовом Ant. Не нужно будет вручную перекомпилировать измененный сервлет, создавать новый W AR-файл, запус- кать и останавливать Tomcat и повторно развертывать web-приложение. Другой метод развертывания web-приложения на Tomcat - поместить - каталог, содержащий web-приложение, в надлежащую структуру каталогов в каталоге webapps сервера Tomcat. Имя каталога web-приложения (например, туарр) после этого становится путем к контексту или именем нового web-приложения. Этот способ развертывания может не работать с другими серверами приложений и, следовательно, неэффективен при созда- нии переносимых приложений. Кроме того, поскольку этот способ ни в какой степени не автоматизирован, трудности будут сопутствовать и внесению изменений в любой класс сервлета или JavaBeans в каталогах такого web-приложения. В завершение обсуждения опишем, как настроить файл конфигурации server .xml сервера Tomcat, чтобы путь к контексту указывал на распакованный каталог web-прило- жения, где бы на сервере он ни находился. Как альтернатива созданию архивированного приложения (WAR), этот способ развертывания во время разработки и тестирования также может использоваться разработчиками под Tomcat. 44 | Глава 2. Развертывание сервлетов и JSP
Использование Ant для развертывания web-приложения Использование Ant для компиляции и развертывания приложения включает следующие шаги. 1. Выбор каталога для файла сборки Ant - buikLxml, любых файлов свойств buildprop- erties и всего содержимого web-приложения. 2. Создание каталогов для файлов с исходным кодом (Java) сервлета, файлов JSP и HTML, архивных файлов (JAR) компонентов, например драйверов баз данных, и архивного файла web-приложения (WAR-файла). Один из способов организации необходимой структуры каталогов показан на рис. 2.5. Рис. 2.5.Структура каталогов web-приложения 3. В этом примере каталог src содержит файлы с исходным кодом (Java) сервлетов и JavaBeans. Каталог web содержит файлы, находящиеся на верхнем уровне web-прило- жения, например JSP и HTML файлы Каталог meta содержит дескрипторы развертыва- ния (как минимум, web.xml). Каталог build - то место, где Ant компилирует исходные файлы. Результаты компиляции, в конце концов, будут находиться в каталоге WEB-INF/ classes web-приложения. Каталог lib предназначен для всех JAR-файлов, используе- мых приложением, например драйверов базы данных, и/или библиотек тегов. И, наконец, каталог dist содержит WAR-файл. 4. Создание исходного кода приложения и размещение всех связанных с ним файлов (например, файлы JSP и web.xml) в предназначенных для них каталогах. 5. Создание всех необходимых значений свойств в файле build.properties, эти свойства будут использоваться в файле build.xml в процессе компиляции и развертывания. Ниже свойства будут обсуждаться подробнее. 6. Запуск файла build.xml из командной строки. Для этого необходимо перейти в ката- лог, содержащий этот файл, и напечатать в командной строке ant. В примере 2.5 показан файл build.properties, упомянутый в шаге 5. Развертывание web-приложения на сервере Tomcat | 45
Необязательно называть Этот файл именно build.properties. Это имя используется просто по взаимной договоренности Можно назвать этот файл, например, global: props Пример 2.5. Файл build.properties для развертывания web-приложения tomcat .webapps=к:/Jakarta-tomcat-4.1.12/webapps/ tomcat.dir=k:/Jakarta-tomcat-4.1.12 url=http://localhost:8080/manager _ usernaxne=t omca t password=tomcat manager.path=$(tomcat.dir}/work/standalone/localhost/manager Эти свойства можно сделать доступными (импортировать) в файле buildxml с помощью следующей строки.- <property file="build.properties" /> Данная строка представляет задачу property или XML-элемент в файле buildxml. Например, значение свойства tomcat, di г" внутри XML-файла сборки Ant равно «к:/ jakarta-tomcat-4.1.12.» В примере 2.6 файл build.xml приведен полностью. Этот файл можно использовать для компиляции классов Java, создания WAR-файла и развертывания его в Tomcat - дос- таточно только запустить в командной строке ant. Главное преимущество использова- ния Ant - автоматизация процессов, которые без этого были бы достаточно сложными. Если, к примеру, потребуется изменить или добавить сервлет в web-приложение, то, чтобы заново откомпилировать и развернуть это приложение, достаточно просто запус- тить Ant. Сам файл buildxml достаточно сложен и демонстрирует использование ряда продвинутых возможностей Ant. Пример 2.6. Файл сборки Ant для развертывания web-приложения cproject name="Deplpy Project" default="deploy-application"> <taskdef name="deploy" classname="org.apache.catalina.ant.DeployTask" /> <taskdef name="undeploy" classname="org.apache.catalina.ant.UndeployTask" /> <property file="build.properties" /> <path id="classpath"> <fileset dir="${tomcat.dir}/common/lib"> cinclude name="*.jar" /> </fileset> <fileset dir=h ${tomcat.dir}/common/endorsed"> cinclude name="*.jar" /> </fileset> » </path> 46 | Глава 2. Развертывание сервлетов и JSP
«target name="init" descriptions"Initializes some properties."> <echo message^"Initializing properties."/* «property name="build" values" .AbuiId" /> <property name="src" values".\src" /> «property name="dist" values".\dist" /> «property name="lib" values".\lib" /> > «property name="web" values".\web" /> «property name="meta" values".\meta" /> «property name= "context-path" value’s"myapp" /> «/target* «target name="prepare" depends="init"> *• «echo messages"Cleaning up the build and dist directories."/* «delete dirsn $ {build}"/* «mkdir dir="${build}"/> «delete dir="${dist}"/> «mkdir dir="${dist}"/> «/target* \ «target name="deploy" descriptions"Deploys a Web application"* «deploy url=*${url}" usernames"${username}" passwords"${password}* path="/${context-path}" war="file:${dist}/${context-path}.war" /> «/target* «target name="undeploy" descriptions"Undeploys a Web application" if="already.deployed"^ «undeploy url=" $ {url}" usemame=" $ {username}" passwords«$ {password}" paths"/ ${context-path}* /> «/target* «target name="create-war" descriptions"creates a web application archive file"* ' «war destfile="${dist}/${context-path} *war" webxml="${meta}/web.xml"> «classes dir»"${build} 7* «lib dir»"${lib}"/> «fileset dir="${web}"/* «/war* «/target* «target name="deploy-application" depends="prepare" descriptions"Compile the web application...."> «echo message»"Undeploying the application only if it's deployed..."/* - «available file="${manager.path}/${context-path}:war" property="already, deployed"/> Развертывание web-приложения на сервере Tomcat | 47
<antcall target?"undeploy"/> <echo message^"Compiling the application files..,"/> «javac srcdir="${src}" destdir="${build}"> «include name="*.java" /> «classpath refid="classpath"/> </javac> «echo messages"creating the WAR file...."/> л «antcall targetsncreate-war"/> «antcall targets"deploy"/> «/target> </project> Цель create-war использует Ant-задачу war, для генерации файла WAR на основе определенных значений атрибутов и вложенных элементов. Например, файл web.xml, который будет включен в WAR, задаётся как значение атрибута webxml задачи war. Кроме, того, классы, которые будут включены в каталог WEB-lNF/classes WAR-файла, задаются следующим вложенным элементом задачи war. «classes dir="${build}"/> Приятная новость, касающаяся этого элемента classes и вложенных элементов lib и fileset, заключается в том, что все вложенные в build, lib и web каталоги авто- матически включаются в WAR. К примеру, каталог web включает каталог images, содержащий различные GIF-файлы приложения. Каталог images включается на верхний уровень WAR-файла, вместе со всеми HTML и JSP файлами, хранимыми в каталоге web всего лишь одним вложенным элементом (см. ниже). «fileset dir="${web}"/> Рассмотрим также цель deploy-application, составляющую костяк файла build, xml. Если вы правильно установили значение переменной окружения РАТИ, чтобы она указывала на компонент Ant, цель deploy-application будет автоматически вызвана сразу после того, как вы напечатаете в командной строке ant- Сначала эта цель ищет, не было ли данное web-приложёние уже развернуто на Tomcat ранее. Данная функция включена, поскольку предполагается запускать этот файл неод- нократно, а не только при первом развертывании web-приложения. Строка, отвечающая за это, использует задачу available, которая устанавливает значение соответствующего свойства в «true», только если файл, заданный атрибутом file, существует. «available file="${manager.path}/${context-path}.war" property="already.deployed"/> «antcall targets"undeploy"/> Если такой файл существует, это означаёт, что приложение Tomcat Manager уже развернуло этот WAR-файл и значение свойства already.deployed устанавливается в «true». Это позволяет файлу build.xml по условию удалить ранее развернутое приложе- ние перед его повторным развертыванием в измененном вйде. Иными словами, web-прило- 48 | Глава 2. Развертывание сервлетов й JSP
жение удаляется с сервера, только если оно когда-то уже было развернуто (в противном случае запуск цели undeploy сгенерирует ошибку, на чем выполнение файла сборки прервется). Цель undeploy запускается, только если свойство already.deployed установлено в «true». •«target name="undeploy" descriptions"Undeploys a Web application" if = "already. deployed". > Задача ant call вызывает выполнение другой цели файла, подобно тому как вызываются методы. И, наконец, цель deploy-application использует задачу j avac' для компиляции сервлетов приложения в каталог build, а затем посредством задачи ant call создает WAR-файл и развертывает новое или измененное web-прило- жение на сервере Tomcat. При работе цель выдает на консоль сообщения, помогающие разработчику понять, что происходит. «target name="deploy-application" depends="prepare" descriptions"Compile the web application...."» <echo messages"Compiling the application files..."/» < javac srcdir="${src}" destdir="${build}"> «include name="*. java" /•» «classpath refids "classpath"/» </javac» <echo messages"creating the WAR file. <antcall target="create-war”/> <antcal1 targets"deploy"/> «/target» z- В качестве альтернативы предшествующему методу развертывания можно скон- фигурировать Tomcat так, чтобы указать на внешний каталог, содержащий корректное web-приложение. При таком подходе web-приложение будет развернуто при следующем перезапуске сервера Tomcat. Подобная стратегия применима, когда приложение находится в процессе разработки, поскольку можно сконфигурировать Tomcat для автоматической перезагрузки приложения (рецепт 2.2) при изменении сервлета или при добавлении JAR- файла в WEB-INFAib. Однако когда придет время запускать приложения на реально работающем сервере, разработчики должны создать приложения в виде WAR-файлов. Создайте файл, содержащий элемент Context, в том виде, как этот элемент должен появиться в server.xml. Дайте этому файлу расширение .xml. Можно присвоить этому файлу имя, совпадающее с путем к контексту или именем приложения (например, myapp.xml), но не обязательно. Содержимое файла будет примерно следующим: «Context className="org.apache.catalina.core.Standardcontext" crossContext="false" reloadable="true" mapperClass="org.apache.catalina.core.StandardContextMapper" useNamingsHtrue" debugs"0" swallowOutput="false" Развертывание web-приложения на сервере Tomcat | 49
privileged='" false" wrapperClass=“org.apache.cataiina.core.Standardwrapper" docBase="h:\book\cookbook\secl\secl_l\dist" cookies="true" path="7newapp" cachingAllowed=“true" y charsetMapperClass="org.apache.catalina.util.CharsetMapper"> </Context> Значение «true» атрибута reloadable настраивает Tomcat на отслеживание любых изменений классов в каталоге WEB-INF/classes и Компонентов в WEB-INF/lib. При обнаруже- нии там каких-либо изменений Tomcat автоматически перезагрузит web-приложение. Значением атрибута docBase может быть абсолютный путь к каталогу, содержащему web-приложение, или корневой каталог контекста. Его значением также может быть путь к WAR-файлу. Также атрибут docBase может содержать путь относительно каталога арр- Base объетЛлющего (родительского) элемента Host в файле server.xml, например относи- тельно каталога <инсталяционный-каталог-Тотсаг>/^сЬарр5. Атрибут path объявляет путь к контексту для нового приложения как http:/flocalhost:8080/newapp/ (где /newapp - путь к контексту). Поместите этот файл в каталог <инсталяционный-каталог-ТотсаГ>/л>еЬарр$ (или в тот каталог, который указан как appBase в объемлющем элементе Host в conf/server.xml) и перестартуйте Tomcat. Теперь web-приложение будет работать на Tomcat. - J См. также Книгу «The deployment sections of Tomcat: The Definitive Guide» авторов Brittain и Darwin (O'Reilly); рецепты 2.1, 2.2 и 2.4. 2.7 Развертывание web-приложения на WebLogic при помощи Ant Задача Необходимо, используя Jakarta Ant, развернуть web-приложение на сервере WebLogic 7.0. Решение Создайте сборочный файл для Jakarta Ant. После этого Ant сможет автоматически компилировать классы сервлетов. Создать файл архива web-прилОжения (.war) и затем развернуть этот WAR на сервере WebLogic 7.0. 50 | Глава 2. Развертывание сервлетов и JSP
Обсуждение Можно вручную компилировать и вставить web-компоненты в каталог applications сервера WebLogic (как описано ниже), а можно использовать Ant для автоматизации процесса компиляции, генерирования WAR-файла и копирования его в указанный ката- лог. Путь к каталогу applications может, например, выглядеть так: k:\bea\user_projects\ bwpdomain\applications. Последний способ подразумевает редактирование файлов build, xml и build.properties, описанных в рецепте 2.6. Развертывание web-приложения вручную Когда сервер WebLogic работает в режиме разработки, то, если поместить WAR-файл, EAR-файл (Enterprise ARchive application - заархивйрованное прило- жение предприятия) или каталог, содержащий корректное web-приложение, в каталог applications, это приложение будет автоматически развернуто и станет доступным на сервере. Корректное web-приложение содержит дескриптор развертывания WEB-INF/ web.xml, который не вызывает никаких исключений при синтаксическом разборе. Если каталог, который вы поместили в каталог applications, не содержит дескриптора развертывания, WebLogic не станет автоматически развертывать это приложение, даже если сервер функционирует в режиме разработки. WebLogic возбудит исключение и выведет на консоль, с которой его запустили, сообщение следующего вида. <Unable to activate application, _appsdir_dist_dir, from source, K:\bea\user_projects\bwpdomain\applications\dist. Reason: No-J2EE deployment descriptor found at "K:\bea\user_projects\bwpdomain\ applications\dist".> Для развертывания под WebLogic 7.0 необходимо отредактировать в build.xml цель deploy-application. <target name»"deploy-application" depends="prepare" description»"Compile the web application...."> <echo message»"Compiling the application files..."/> <javac srcdir="${src}" destdir»"${build}“> cinclude name»"*.java" /> <classpath refid»"classpath"/> </javac> <echo message»"creating the. WAR file.*.."/> <antcall target»"create-war"/> 4 <copy todir="${wl.applications}"> <fileset dir="$£dist)" /> </copy> </target> Развертывание web-приложения на WebLogic при помощи Ant | 51
Кроме того, в файле buildproperties можно определить свойство wl.applica- tions со значением типа: "k:\bed\user__projects\bwpdomain\applicationsn. После того как WAR-файл будет скопирован в этот специальный каталог, сервер WebLogic, функ- ционирующий в режиме разработки, автоматически развернет его. В каталоге \user_projecNjwpdomaih (в зависимости от имени домена вашего сервера) сценарий запуска WebLogic называется startWebLogic.cmd (для Windows) и startWebLogic.sh (для Unix). Чтобы запустить сервер в режиме разработки, соответствующая строка сценария должна выглядеть так: 8ТАКТМООЕ=(значение - пустая строка) или STARTMODE=false. Если STARTMODE=true, сервер стартует в режиме реальной работы. См. также Рецепт 2.3; рецепты 2.8-2.10; документацию для программистов сервера WebLogic 7.0 http://e-docs.bea.com/wls/docs70/programming.html. 2.8 Использование консоли администрирования WebLogic Задача Необходимо развернуть web-приложение с помощью консоли администрирования WebLogic. Решение Войдите в консоль администрирования из своего браузера щ используя ее графический интерфейс, разверните или WAR-файл, или каталог web-приложения. Обсуждение Консоль администрирования WebLogic - инструмент, опирающийся на сорвлеты и браузер, для управления ресурсами сервера WebLogic и 12ЕЕ-приложениями (J2EE - Java 2 Enterprise Edition). Чтобы использовать консоль, сервер WebLogic должен быть в работе. Во- первых, необходимо из браузера запросить URL http:/hocalhost:7001/consdle (если у вас иной адрес сервера и номер порта, то http://<adpec-Weblx)gic>:<nopm>/console). Затем введите логин и пароль. В итоге экран будет выглядеть подобно изображенному на рис. 2.6, с иерархическим списком возможностей в левой колонке и текущим выбором в правой. 52 |4 Глава 2. Развертывание сервлетов и JSP
Рис. 2.6. Консоль администрирования WebLogic В левой колонке выберите имя своего'домена, щелкнув по соответствующему знаку плюс (+) и отобразив тем самым подузлы домена. Подузлы домена включают Servers (серверы), Clusters (кластеры), Machines (машины), Network Channels (каналы сети), Deployments (развернутые программы), Services (сервисы) и Security (безопасность). После этого выберите узел «Deployments», что позволит добраться до подузла «Web applications» (web-приложения). Раскройте узел «Web applications», щелкнув по соответствующему знаку плюс. Полученный экран будет выглядеть, как показано на рис. 2.7. В окне Web applications щелкните гиперссылку «Configure a New Web Application...» (настройка нового web-приложения). Следующий экран предоставляет вам возможность выгрузить WAR-файл или EAR-файл в файловую систему сервера, не выходя из браузера (см. рис. 2.8). Инициируйте выгрузку и затем щелкните по ссылке «select», расположенную после WAR-файла. Выполните три шага,, показанные на рис. 2.9: щелкните по кнопке со стрелкой, чтобы из списка доступных серверов (колонка Available Servers) выбрать сервер, на котором вы хотите развернуть приложение (колонка Target Servers), присвойте приложению имя (оставьте то же имя, что у WAR-файла минус суффикс .war), а затем нажмите кнопку «Configure and Deploy» (настроить и развернуть). И это все, что требуется, для развертывания WAR-файла на сервере. Теперь проверьте работу развернутого приложения, обратившись с запросом из браузера к одному из сервлетов; используйте в качестве пути к контексту То имя, которое вы дали приложению. Итоговый URL может выглядеть так: http://localhost:7001/cookbook/cookieserv- let. Этот URL запрашивает сервлет, который сопоставлен имени “/cookieservlef. Путь к кон- тексту web-приложения: /cookbook. Использование консоли администрирования WebLogic | 53
Рис. 2.7. Узел «Web applications» Повторное развертывание ранее развернутого web-приложения с помощью консоли администрирования WebLogic включает следующие шаги. 1. Выберите в левой колонке консоли под узлом Web applications ваше приложение. Полученный экран будет выглядеть, как показано на рис. 2.10. 2. Щелкните по кнопке «Deploy» (развернуть) в правой части экрана, это реактивирует приложение, и оно сможет получать запросы в web-контейнере WebLogic. Если необходимо с помощью консоли администрирования удалить приложение, в левой колонке экрана консоли щелкните по имени своего домена, затем щелкните по на узлам «Deployments» и «WebApplications». Щелчок на мусорной корзине напротив приложения удалит это приложение с сервера WebLogic (см. рис. 2.11). Удаление приложения таким способом означает, что данное приложение не сможет больше получать запросы в контейнере WebLogic. См. также' Рецепты 2.3 и 2.7; рецепты 2.9 и 2.10; документацию для программистов сервера WebLogic 7.0 http://e-docs.bea.com/wls/docs70/programming.html. 54 | Глава 2. Развертывание сервлетов и JSP
3 WebLojsc Sent -i Console Mictosoft Internet t spk*er Stop Prim EdtwttXM.. ВВВВЯВВМ^В^ВН ^^еолИиип^.1(К259445 gJInriMnnFS @w£om«>Sjw>mi (gJAPlbocunmUbon ^JBatoChaptm gJGoo^e ©0wimU«v«2PMamEE vl.4) * Consol* В ФропуаопмНп В dsowon ♦ewpnryoon и Осшвого ^Mochlno* ONMwrk Channel* в uJo«* ти- и , оЗдррг^ло . St? EJB В «?VlКЛЛйХсМом •coittcot* *о*гшмтд|* •_*pp*er_hom*_W ^Wtt Son** Component* cflConnoctor* aJ Startup < Shutdown S CSsonito* -> В CJskut»». I SJDomoln LopFHor* Итмк» Locate Application or Component to configure S50Sr"ES35ii This wizard will guide you through thp process of configuring and deploying a J2EE application or module. This can be any one of the fotaMng types of files: • A Jar containing EJBs (Enterprise Java Beans) • A .war (Web Application Archive) containing JSPs and Servlets A.rar (Resource Adapter Archive) containing a JCA Connector module. • An лаг (J2EE Enterprise Application Archive)contairingeny of the above Step T. The .ear. .war. jar. or .rar file you wish to configure and deploy must be available in the Admin servers file system. It may already be there; if it is not. you can either copy it there yourself or (iioloaditl tnfQUflhJgMlf.brmsalinto #» directory selected below. Step 2. Select the .ear. .war, jar. or rar file you would Ike to configure and deploy Note that you may also configure an 'exploded* application or component by simply selecting its root directory. Cick on the [select] Ink to the left of the desired directory or file to choose it and proceed to the next step. Listing it l*c*lli**t\K:ih** 70\u**t proitct*\wrrv*—*1» [Up to parent directory] fsetect] appl .aiiQns i*eleetl bwoerryxrwr' Isaz |s<4eil] yserConfiq Puc. 2.8. Развертывание web-приложения в виде WAR или EAR файла 2.9 Использование компоновщика WebLogic Builder для развертывания web-приложения Задача Развернуть web-приложение, используя WebLogic Builder. Решение WebLogic Builder инсталлируется вместе с сервером WebLogic 7.0, таким образом, его можно запустить и, используя его графические возможности, развернуть web-приложение. Использование компоновщика WebLogic Builder для развертывания web-приложения | 55
Рис. 2.9. Заключительные шаги развертывания WAR-файла Обсуждение Компоновщик WebLogic Builder - графический инструмент, который инсталлируется вместе с сервером WebLogic 7J0. Его можно использовать для редактирования файлов дескрипторов развертывания, таких, как web.xml, а также weblogic.xml, а также для развертывания web-приложения на сервере. Используя Builder, можно открывать, редактировать и развертывать web-приложение, находящееся или в виде WAR-файла, или в распакованном формате, то есть в развернутом на каталоги виде. Формат «распакованный по каталогам» представляет собой структуру каталогов web- приложения, в том виде, в каком эта структура должна появиться в файловой системе, но не в архивированной (WAR) форме. Чтобы приложение было развернуто на WebLogic, корневой каталог web-приложения должен включать дескриптор развертывания WEB-INF/xml и все другие правильно разобранные по каталогам компоненты приложения, например каталог WEB-INF/classes, содержащий сервлеты (включая все связанные с пакетами каталоги). 56 | Глава!. Развертывание сервлетов и JSP
5 WebLogx Server Cont ok - M—пиЫ1 Irrt '-net Explorer fl. £Л y~ 1 * Ьж. mu.i; . / ~~R^n ~~ — ~i 111 ? ana in' ~ ~r । । Addtw. fe] httn:/A>e*x>rt70m/corw^»c«ontAnbMrvM8wrft«i»«*Action?t«M>«Ft«>iaJ-wl eoraole ftMM 1062S94«53223bd3«~4dt»U»red j.<oonM<fi«nw..10&5344 Hu BJIt»» -orFS ,JWafcOTwloSputawk JAPI Docu-w-uSor ,^]B«*.OMpk-t pjGeop. e]0vr-rimll«v«2PlatlanEEy'l * Console P CBpertytJomain В tOsemra ^bwpsnysbtvsr AJciustsrS i^Mschlnes ^Network Chsrmels В ^Deployments ^Applications a cPejb В bhiweb Applications «certificate *DefieuHWeoApp ® rnywebapp •_appsdir_home_dlr CJweb Senice Components о ^Connectors ta*Startup& Shutdown В ^Services E-Jjcom В ffl Cljosc В 1-ljMS В ^Messaging Bridge » t-JxML Qjta s Osnmp ; ^WLEC DJwebLoglc Tuxedo Conned 1-bolt ZpVIrtual Hosts perrvdomain* Web Applications* rnywebapp <bea ? Edit Web Application Deployment Descriptors. Configuration! Targets | Monitoring , Notes'! Deployment Status by Target: Target Type Deployed * Server false Ewfiy?eiypr |MP DentoyMi^.^ Deploy or redeploy this component to aU targets Deployment Activity: Statu* I Вея1п'П^'1”Уа^" — ДлЧЧгЦЦе ъ.'чл Description onhwoenyserver • । . n зч;?ам FfiT Art* > . imam -r am Connecter! tn localhpst 7Й01 Deploy ...a..................... Completed ^f$3°3 09:3209 Note: To configure additional deployment targets for this component, please move to the Targets' tab. Deploy, -] End Time? Wed Sep 03 09:32:09 EDT 2003 Puc. 2.10. Выбор web-приложения в консоли В Windows WebLogic Builder можно запустить с помощью меню «Пуск» или из командной строки. Сценарий запуска Builder находится в файле <ВЕА_НОМЕ>/ weblogic700/server/bin/startWLBuilder.cmd (или в файле startWLBuilder.sh в Unix). Здесь <ВЕА_НОМЕ> - каталог, в который инсталлирован сервер WebLogic 7.0. Builder позволяет легко открывать и редактировать дескриптор развертывания web- приложения. Достаточно выбрать в меню «File -♦ Open» и добраться до WAR-файла или корневого каталога приложения. В результате появится окно, изображенное на рис. 2.12. Дерево навигации в верхнем левом окне позволяет конфигурировать web-ресурсы (например, сервлеты) и элементы дескриптора развертывания (например, ограничения безопасности), а затем сохранить изменения в web.xml. Вы, например, можете добавить или удалить элементы для сервлетов, отображения (mapping) сервлетов и фильтры. Если с помощью Builder вы внесете изменения в прило- жение и сохраните их, эти изменения будут сохранены в дескрипторе развертывания. При необходимости, после этого можно подключиться к серверу (с помощью меню «Tools») и развернуть приложение. х Использование компоновщика WebLogic Builder для развертывания web-приложения | 57
Рис. 2.11. Удаление web-приложения Рис. 2.12. Открытие WAR-файла в WebLogic Builder 58 | Глава 2. Развертывание сервлетов и JSP
Окно «Deploy Module» показывает, развернуто ли уже приложение или еще нет. Это окно показано на рис. 2.13. Если ваше приложение уже развернуто» вы все еще можете внести изменения в дескриптор развертывания с помощью Builder, а затем снова развернуть приложение посредством меню «Tools». Builder специально свернет прило- жение, а после развернет заново, с изменениями, которые вы внесли в web.xml. Рис. 2.13. Окно Deploy Module Builder не показывает JSP-файлы, являющиеся частью web-приложения. Он показы- вает все отображения сервлетов, связанные с JSP-файлами. См. также Рецепты 2.3, 2.7, 2.8, и 2.10; документацию для программистов сервера WebLogic 7 0 http://e-docs.bea.com/wls/docs70/programming.htmV, встроенную справку WebLogic Builder: <BEA_HOME>\weblogic700\seiye/^buildei\index.html. Использование компоновщика WebLogic Builder для развертывания web-приложения | 59
2.10 Использование инструмента командной строки weblogic.Dep!oyer Задача Необходимо развернуть web-приложение на сервере WebLogic 7.0 из командной строки. Решение Используйте утилиту командной строки weblogic. Deployer, которая инсталлируется вместе с WebLogic Server 7.0 и работает на базе Java. Обсуждение Для. разработчиков и администраторов, предпочитающих для развертывания и переразвертывания web-приложений использовать командную строку или командные Сценарии, сервер WebLogic 7.0 предоставляет утилиту Depl oyer (работающую на платформе Java). Эта j тилита позволяет выполнять те же задачи по развертыванию и повторному развертыванию web-приложений, что и консоль администрирования, снаб- женная графическим интерфейсом. В начале данного рецепта описывается, как из командной строки с помощью утилиты Depl oyer развернуть и переразвернуть web- приложение. Азатем приводится пример командного файла Windows, выполняющего утилиту Depl oyer. Утилита Depl oyer может выполнять и другие задачи, например переразвертывание отдельных web-компонент приложения, документацию по утилите можно найти по адресу http://e-docs.bea.com/wls/docs70/programming/deploying.html^!094693. Утилита Depl oyer - это Java-программа, и для ее запуска необходимо, чтобы в пути к классам (classpath) был прописан следующий JAR-файл: <BEA_HOME>\servei\ lib\weblogic.jar. Здесь <ВЕА_НОМЕ> - каталог, где инсталлирован WebLogic Server 7.0. На машине с Windows NT следующий командный сценарии повторно развернет web- приложение cookbook.war на сервере с именем bwpserver. java -Ср k:\bea\weblogic700\server\lib\weblogic.jar; %CLASSPATH% weblogic.Deployer -adminurl http://localhost:7001 * -user bwperry -name cookbook -source .\dist\cookbpok.war -targets bwpserver -activate 60 | Глава 2. Развертывание сервлетов и JSP
Этот сцёнарий развёртывает web-приложение, представленное файлом архива cookbook, war, после чего это приложение может получать запросы с путем к контексту /cookbook. При запуске из командной строки сценарий выдаёт приглашение на ввод пароля (если вы не включили пароль в сценарий с помощью опции -password). Опция -source задает местоположение WAR-файла или каталогов web-приложения. Опция -targets задает один или несколько серверов, на которых необходимо развернуть web-приложение. Заключительная команда для развертывания web-приложение -activate. Приводимые ниже строки деактивируют (делают недоступным) web-приложение, находящёеся на сервере bwpserver. Если вы не добавите опцию -password с паролем, в начале выполнения будет запрашиваться пароль. java -ср k: \bea\weblogic7.00\server\lib\weblogic,jar; %CLASSPATH% weblogic.Deployer -adminurl http://localhost:7001 -user bwperry -name cookbook -targets bwpserver -deactivate Опция -ср задает путь к классам, используемый для запуска утилиты Deployer, и этот путь должен включать путь к JAR-файлу weblogic.jar. Переключатель -admin- url задает административный сервер (по умолчанию http://localhost:7001, то есть это значение не обязательно было включать в сценарий). Опция -name задает имя деакти- вйзируемого приложения, и опция -targets указывает имя сервера, на котором это приложение работает. Приводимые ниже строки переразвертывают все то же приложе- ние «cookbook». ( java -ср k:\bea\weblogic700\server\lib\weblogic.jar; %CLASSPATH% weblogic.Deployer -user кмрёггу -name cookbook -activate На этот раз опции -adminurl и -targets опущены. По умолчанию эти переключатели имеют значения, соответственно, http://localhost:700J и все текущие серверы (если повторно развертывается уже существующее приложение). Если же приложение развертывается впервые, значением по умолчанию для -targets является административный сервер. , Проще задавать эти команды в составе командного файла, поскольку это требует меньше усилий по печатанию сложных командных строк и к тому же позволяет сохранять сценарии на будущее. Пример 2.7 - первый пример, оформленный в виде командного файла Windows NT. Пример 2.7. Развертывание приложения set WL_HOME=*K: \bea\weblogic700 set BEA_CLASSPATH=%WL_HOME%\server\lib\weblogic.jar;%CLASSPATH% java -cp %BEA_CLASSPATH% weblogic.Deployer -adminurl http://localhost:70.01 - user bwperry. -name cookbook -source .XdistXcookbook.war -targets bwpserver - activate Использование инструмента командной строки weblogic.Deployer | 61
В этом командном файле задаются две переменные окружения: WL_HOME и ВЕА_ CLASSPATH. Они используются, чтобы включить в путь к классам путь к файлу weblogic, jar, в котором содержится утилита Deployer Если этот сценарий сохраню ь под именем deploy.bat, то его можно будет запускать из следующей командной строки. Н:\book\cookbook>deploy После запуска на консоль будет выводиться примерно следующая информация. Enter a password for the user "bwperry":bwpserver_19G8 Operation .started, waiting for notifications... #TaskID Action Status Target 15 Activate Success bwpserver book\cookbook\.\dist\cook Type Application Source Server cookbook* ~ H:\ См. также Рецепты 2.3 и 2.5; рецепты 2.7-2.9; документацию для программистов сервера WebLogic 7.0 http://e-docs.bea.com/wls/docs70/programmingJitml. 62 | Глава 2. Развертывание сервлетов и JSP
z ГЛАВА3 Присвоение имен сервлетам 3.0 Введение Одной из важных задач конфигурации web-приложения является создание пути, с помощью которого пользователи сети будут обращаться к сервлету. Это то,, что пользователь вводит в поле адреса браузера, чтобы обратиться к сервлету. Иногда в этом качестве используют полное имя сервлета, что приводит к появлению невообразимых URI. Пусть, к примеру, на сайте имеется сервлет, динамически создающий страницу «Resources», вместо статичной страницы resources.html. При использовании полного имени сервлета URL запроса может выглядеть так: http: //www.myorganization.com/servlet/com.organizAtion.ser\iets.resources.ResourceServlet. Не каждому человеку под силу набрать такой адрес, поэтому имеет смысл .поста- вить сервлету в соответствие некоторый путь к сервлету (servlet path), который будет являться псевдонимом данного сервлета. Новый адрес динамической страницы (с использованием пути к сервлету) может быть таким: http://www.myorga- nization.com/resources. В данном случае /resources - путь к сервлету. Путь к сервлету также является идентификатором, используемым другими сервле- тами или JSP, для переадресации запросов на этот сервлет, он также является адресом, используемым в атрибуте action тегов HTML-форм для передачи сервлету имен и значений параметров. Спецификация сервлетов предлагает интуи- тивно понятный и гибкий способ: отображение HTTP-запросов на сервлеты с помощью дескриптора развертывания web.xml. В данной главе описано, как использовать дескриптор развертывания web.xml для создания одного или нескольких псевдонимов сервлета (путей к сервлету). Здесь также обсуждается, как вызвать сервлет с помощью URL других типов, в частности такого, который выглядит как обращение к странице JSP (например, info.jsp) или как обращение к HTML-странице (например, info.html). В рецепте 3.5 также описано, как обратиться к сервлету без применения отображения в web.xml, например, если разработчик хочет отладить сервлет, не изменяя файл web.xml. И, наконец, в рецептах 3.7,3.9 и 3.10 показано, как отобразить все запросы на один «управляющий» сервлет (3.7), ограничить доступ к определенным сервлетам только пользователями с соответствующими полномочиями (3.9) и блокировать все запросы к некоторым сервлетам, 'за исключением запросов, переадресуемых к ним от управляющего сервлета (контроллера) (3.10). 63
3.1 Отображение сервлета на определенное имя с помощью файла web.xml Задача Необходимо создать псевдоним сервлета (путь к сервлету). Решение Создайте в web.xml эдементы servlet; и servlet-mapping. Обсуждение Создание псевдонима сервлета осуществляется с помощью элемента servlet-map- ping находящегося в дескрипторе развертывания. Согласно API сервлетов версии 2.3, все элементы servlet в дескрипторе должны идти раньше любого из элементов servlet- mapping. Элемент servlet-mapping ссылается на имя сервлета, появляющееся в элементе servlet-name, например на следующее. <servlet><servlet-jname>inyservleC</servlet-name></servlet> Это зарегистрированное имя сервлета. Затем в servlet-mapping приводится имя или шаблон URL, .которое пользователи web-приложения могут вводить в браузере для доступа к данному сервлету. Пример 3.1 показывает файл web.xml с элементами servlet и servlet-mapping. В данном случае зарегистрированное имя сервлета: «CookieServlet». Пример 3.1. Элементы servlet и servlet-mapping <?xml versions"1.0" encodings"ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-application_2_3.dtd" <web-app> <servlet> •» t <serVlet-name>CookieServlet</servlet-name> <servlet-class>com.jspservletcookbook.CookieServlet</servlet-class> </servlet> 'lb < servlet-mapping> <servlet-name>CookieServlet</servlet-name> <ur1-pattern>/cookieservlet</иг1-pattern> <I servlet-mapping> </web-app> 64 | Глава 3. Присвоение имен сервлетам
В этом примере в элементе servlet регистрируется имя «CookieServlet» (путем зада- ния его в servlet-name). Имя класса указывается в элементе servlet-class. Этот класс сервлета может находиться в каталоге WEB-INF/classes/com/jspseryletcookbook/ или в JAR-файле, расположенном в WEB-INF/lib. Имя «CookieServlet» становится заре- гистрированным именем, под которым сервлет выступает в оставшейся части файла webjanl. А теперь создадим путь к сервлету, по которому пользователи web-приложения будут обращаться к сервлету из браузеров. Это назначение псевдонима выполняется с помощью элемента servlet-mapping. Итак, servlet-name определяет зарегистрированное имя, по которому можно ссылаться на сервлет в файле web.xml, а элемент ur 1-pattern создает URL для доступа к этому сервлету. Символ «/>> в шаблоне /cookieservlet означает «начиная с корневого каталога web-приложения». К примеру, если «cookbook» - путь к контексту для сайта http://www.mysite.org, то полный адрес доступа к сервлету Cook- ieServlet - http://www.mysite.org/cookbook/cookieservlet. Часть /cookbook этого URL является путем к контексту web-приложения. Затем, внутри этого контекста, сервлет иден- тифицируется шаблоном /cookservlet. Обобщая, любому сервлету соответствует следующий URL. http://<хост>:<порт>/<путь-к-контексту>/<путь-к-сервлету> ' *’ Большинство контейнеров сервлетов допускает использование контекста j по умолчанию, для которого путь, к сервлету /. В этом случае URL имеет * следующую форму. http://<хост>:<порт>/<путь-к-сервлету> Например, если вы используете на своем компьютере сервер Tomcat 4.1 и у вас соз- дано приложение «туарр», а шаблон URL сервлета - /myservlet, то полный адрес сервлета выглядит примерно так: http://localhost:8080/myapp/myservlet. Вы можете обращаться к сервлету и по URL следующего вида. http; //хост : порт /путь -к -контексту/servl е t /зарегистрированно -имя-сервлета. Если зарегистрированное имя сервлета «MyServIet», то запрос выглядит так: http:// localhost:8080/myapp/servlet/MySerylet. Некоторые исполнительные подсистемы (servlet engine) используют путь к сервлетам, отличный от/servler, другие позволяют администратору изменить этот путь. Чтобы узнать, какой путь для установки является корректным у вас, ознакомьтесь с документацией по используемому контейнеру сервлетов. Какой, к примеру, элемент servlet-mapping должен появиться в файле web.xml приложения по умолчанию, у которого путь к контек- сту - «Л>? В этом случае пользователи должны обращаться к сервлету CookieServlet, используя адрес http://www.mysite.org/cookieservlet. 3-1S4S Отображение сервлета на определенное имя с помощью файла webjanl | 65
.... В Tomcat и WebLogic url-pattern, который вы создаете для сервлета в элементе iCSlS servlet-mapping, является чувствительным к регистру символов. Согласно главе х*»*****у SRV.11.1 спецификации сервлетов версии 2.3 и предлагаемой окончательной редакции версии 2.4, «контейнер должен использовать чувствительный к регистру символов способ сравнения строк». Если вместо http://www.mysite.org/cookbook/ cookieservlet пользователь введет http://www.mysite.org/co0kbook/cook1eSERVLET, запрос не будет направлен к отображаемому сервлету (CookieServlet). В Tomcat 4.1.x и WebLogic 7.0, в ответ на такой запрос, сервером будет возвращен кдд ошибки HTTP 404 («Файл не найден»). Элемент url-pattern в элементе servlet-mapping может иметь разные формы; это обсуждается в последующих рецептах. См. также Главу 1 по web.xml; рецепту 3.2-3.8; главу 11 спецификации сервлетов Версии 2.3 и 2.4 в части отображения запросов на сервлеты. i ' т 3.2 Создание более одного отображения на сервлет Задача Необходимо создать несколько имен или шаблонов URL, используя которые, пользо- » . ватели смогут обращаться к одному и тому же сервлету. i Решение В дескрипторе развертывания создать элемент servlet с несколькими элементами servlet-mapping. ’ i Обсуждение Как показано в примере 3.2, для одного сервлета можно создать несколько элемен- тов servlet-mapping. Пользователь может обращаться к этому сервлету, используя»: Один из двух адресов: http://www.mysite.org/cookbook/cookieservlet и http://www.mysite. > org/cookbook/mycookie. Пример3.2. Два тега servlet-mapping <?xml version="l.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.suh.com/dtd/web-applicatipn_2_3.dtd" 66 I Глава 3. Присвоение имен сервлетам '
<web-app> <servlet> <servlet-name>C?pokieSerVlet< I servlet-name> <servlet-class>cpm.parkerriver.cookbook.CookieServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>CookieServlet</servlet-name> <ur1-pattern>/cpokieservlet</иг1-pattern> </sepvlet-mapping> <servlet-mapping> <servlet-name>CookieServlet</servlet-name> f. <url-pattem>/mycookie</url-pattern> ' </servlet-mapping> </web-app> И помните, что в дескрипторе развертывания элементы servlet-mapping должны появляться только после всех элементов servlet (согласно версии 2.3). Сработает только точное совпадение с шаблонов URI Ес [и -тодьтоватрль вместо . /cookieservlet запросит /cookieservlet/ (со слешем на конце), он получит, вместо ^**ш*у' ожидаемой сгенерированной страницы, ошибку HTTP. Для расширения шаблона отображения можно использовать симврл подстановки (*). Отображения в примере 3.3 приведут к выводу сервлета CookieServlet для всех URL. которые начинаются с /cookie/ и затем, возможно, содержат некоторое имя после слеша. Например, используя этот дескриптор, сервлет CookieServlet можно вызвать с URL http:/ /www.mysite.org/cookbook/cookie/. И все потому, что шаблону (url-pattern) соответ- ствует любой запрос с любой строкой после /cookie/. Пример 3.3. Использование звездочки в шаблоне URL <?xml version="1.О" encodingsмISO-8859-1"?> <!DOCTYPE web-app ... . PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "https//java.sun.com/dtcl/web-application_2_3 .dtd" > ;n' - <serylet> /л ..* ' <servlet-name>CookieServlet</servlet-name> . ' <servlet-class>com.jspservletcookbobk.CookieServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>CookieServlet</servlet-name> <url-pattern>/cookie/*</url-pattern> </servlet-mapping> Создание более одного отоЗражениг на сервлет | 67 3*
Не допускается использование символа (*) в качестве символа подстановки в элементе servlet-name. Звездочку в этом качестве можно использовать только в элементе 74; url-pattem, например <url-pattem»/cookie/*</url-pattem>, или даже в шаблонах, указывающих на все файлы с некоторым расширение^ (<url- pattern>*. jsp</url-pattern>> Последний вариант шаблона называют отображение на расширение (extension mapping) См. также Главу 1 по web.xml; рецепт 3.1; рецепты 3.3-3.8; главу И спецификации сервлетов версии 2.3 и 2.4 в части отображения запросов на сервлеты. г • > > 3.3 Создание для сервлетов URL как у JSP Задача Требуется создать для сервлета шаблон URL, выглядящий как запрос к JSP-файлу. Решение Создайте элемент servlet-mapping, содержащий шаблон в стиле JSP. Обсуждение Как уже говорилось, имеется масса вариантов создания псевдонимов, указывающих на сервлет. Например, можно легко отобразить на сервлет запрос, выглядящий как запрос JSP-файла. Дескриптор развертывания из примера 3.4 ставит сервлету Jspinfо в соответствие шаблон URL /info.jsp. Пример 3.4. Пример дескриптора развертывания с URL в стиле JSR <?xml version="1.0’ encoding="ISO-8859-1"?> <! DOCTYPE web-app > PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http:11 java.sun.com/dtd/web-application_2_3.dtd" > <web-app> <servlet> <servlet-name>Jspinfo</servlet-name> <servlet-class>com.parkerriver.cookbook.Jspinfo</servlet-qlass» > </servlet» <servlet-mapping» <servlet-name»Jsplnfo</servlet-name» 68 | Глава 3. Присвоение имен сервлетам s
<url-pattern:*/info. jsp</url-pattern* <7servlet-mapping* </web-app> " • ‘ )# Прямой слеш, с которого начинается шаблон URL /info.jsp, означает «начиная с корневого каталога web-приложения, использующего данный дескриптор развертыва- ния». В результате полный URL сервлета Jsplnf о приложения cookbook выглядит так: http://www.mysite.org/cookbook/info.jsp. Можно отобразить все ссылки на все страницы JSP на единственный сервлет (Пример 3.5). I- > . < i . ’!-• : Пример 3.5. Отображение URL всех страниц JSP на один сервлет <?xml version="1.0" encoding="ISO-8859-1"?> '• < -doctype web-ад?.., .u .. .-J . PtfBLlt "-//Sun Microsystems, Inc./,DTD Web Application 2.37/EN" "http: / /java. sun. com/dtd/web-application_2_3. dtd" <web-app* <ser*vlet> <servlet-name>Jsplnfo</servlet-name> ' <serviet-class>com.parkerriver.cookbook.Jsplnfo<I servletr-olass* </servlet* <servlet-mapping> <servlet-name*Jsplnfo</servlet-name> , <url-pattern**.jsp</url-pattern* 4- - s </servlet-mapping: </web-app> Убедитесь, что вы исключили слеш (/) из этого шаблона URL. поскольку отображе- ние на расширение файла всегда задается так: звездочка, точка и расширение файла (например, <url-pattern** . jsp</иг 1-pattern*). Такой тип отображения может быть полезен при переходе 6т старой версии приложения, использующей т.шогб страниц JSP, к новой версии, целиком построенной на сервлетах. Это т- забота о пользователях, сохранивших закладки с URL, указывающие на страницы JSP. << * *' Сервер Tomcat 4’ 1.x включает неявное отображение на собственный сервлет компиляции и выполнения JSP-страниц. Если вы включите отображение, приведенное £ в предыдущем фрагменте web-app, то ваше отображение перезапишет собой неявное отображение сервера Tomcat. См. также Главу 1 по web.xml; рецепты 3.1 и 3.2; рецепты 3.4-3.8; главу 11 спецификации сервле- тов версии 2.3 и 2.4 в части отображения запросов на сервлеты. Создание для сервлетов URL как у JSP | 69
3.4 Отображение на сервлет обращений к статичному содержимому Задача Требуется, чтобы запросы на статичный контент (например, URL в HTML-стиле) направлялись к сервлету. Решение Используйте элемент servlet-ntapping файла web.xml, отображающий имя сервлета на статичное содержимое. Обсуждение Вы можете сделать так, чтобы ответы на запросы с URL, выглядящими как запросы к статичному содержимому (например, к HTML-файлам), формировал сервлет, хотя это зачастую излишне. В примере 3.5 сервлет JitrflServlet отображается на все URL, заканчивающиеся суффиксом .html. Любой запрос внутри web-приложения, содержащего этот дескриптор развертывания и ? заканчивающийся на .hfml. будет' направлен к HtmlServlet. Пример 3.6. Отображение статичного контента на сервлет в web.xml <?xml versions"1.0" encodings"ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http: //java, suh.com/dtd/web-application__2_3 .dtd" > - <web-app> ,. <servlet> <servlet-name>HtmlServlet</servlet-name> <servlet-class*com.jspservletcookbook.HtmlServlet</servlet-class* </servlet> "* <servl e t -mapping* <servlet-name*HtmlServlet</servlet-name> <url-pattern*w.html</url-pattern* </servlet-mapping* </web-app* 70 | Глава 3. Присвоение имен Сервлетам
На этом, листинге ^eM^HT^^ryl^t^ppin^i содержиттлабпон UR^ отображающий сервлет на расширение .html, но начинаетсяяСо звездочки и заканчиваемся символами .html. Если необходимо отобразись, СВрвлет гол?, и ндбдиН HTML-файл, чело, тьСуйте XML следующего вида. <url-pattern>myfile.html</url-pattern». Г( л При таком шаблоне к сервлету HtmlServlet будут направляться только запросы к файлу inyfilc.lttMl, | Создавая шаблон URL с отображением на расширение файла, помнит». что он никогда не начинается со слеша (/). L См. также Главу 1 по web.xml; рецепты 3.5-3.8; главу 11 спецификации сервлетов версии 2,3 д 2.4 в части отображения запросов .на сервлеты ‘ ' !Ь. .. 5 ’ ИС1 ’’ ' • / И.’* 3.5 Вызов сервлетов, не имеющих >и. отображения в web.xml Задача з * Необходимо обратиться к сервлету, для которого не существует элемента servlet- mapping в дескрипторе развертывания web.xml. Решение Используйте для обращения к сервлету URL в стиле invoker: http://www.mysite.org/ mywebapp/servlet/com.jspservletcookbook.MyServlet. Обсуждение Некоторые сервлеты могут не иметь отображения на путь в дескрипторе развертыва- ния web-приложенйя. Каким образом пользователь может обратиться к этому сервлету? Какое имя и URL он должен использовать? Tomcat и другие контейнеры сервлетов предоставляют способ обращения к сервле- там, не отображенным в web.xml. Для этого используется URL следующей формы. http://www. ту site, org/mywefrapp/servlet/<полностыо квалифицированное имя класса сервлета>. Вызов сервлетов не имеющих отображении b web.xml | 71
. К сервлету с именем класса и пакета jspservletcookbookMyServlet можно обратиться с запросом с помощью URL http://www.mysite.org/mywebapp/servlet/jspservletcookbook. MyServlet. Убедитесь, что сегмент пути после имени web-приложения-Zserv/ei/, а не/serv- lets/. Если сервлет находится в web-приложении по умолчанию (обычно на верхнем уровне контейнера сервлетов), то URL для обращения к нему - http:// www.mysite.org/servlet/jsps- ervletcookbook.MyServlet. Файл web.xml, размещаемый в каталоге <инсталяционный-каталог-Тотсм>/соп/, включает следующее определение и отображение сервлета invoker (вызывающий). <servlet> <servlet-name»invoker</servlet-name» <servlet-class>org.apache.catalina.servlets.lnvokerServlet</servlet- class> < init-param» <param-name»debug</param-name» <param-value>0< /param-value» </init-param> <load-on-startup>2</load-on-startup» </servlet» <servlet-mapping> <servlet-name»invoker-q/servlet-name» <url-pattem»/servlet/*</url-pattern» ’ . </servlet-mapping> Сервлет invoker (вызывающий) можно использовать и для обращения к сервлетам, зарегистрированным в web.xml. Для этого используется URL вида http://www.mysite.org/ cookbook/servlet/oapezucmpupoeaHHoe имя сервлета>. Допустим у вас есть следующий элемент servlet- >. <servlet> к <serylet-name»myservlet</servlet-niim<!> । < <servlet-class»jspservletcookbook.MyServlet</servlet-class» </servlet> . Предположим также, что путь к контексту web-приложения -/cookbook. Если для этого приложения доступен сервлет invoker сервера Tomcat, то ваш сервлет можеп быть вызван по зарегистрированному имени, посредством URL http://www.mysite.orz/cookbOok/ servlet/myservlet. На сервере Tomcat 4.1.x, в фыле'<инсталяционный-каталог-ТотсШ>/соп//меЬ.хт1, отображение сервлета invoker можно закомментировать. В результате этот сервлет будет недоступен и обратиться к другим сервлетам можно будет только * с помощью путей, задаваемых в элементах servlet-mapping файла web.xml. 72 | Глава 3* Присвоение имен сервлетам^
Если к сервлету обращаются не по его зарегистрированному имени, а используя форму http://ww.mysite.ofg/mywebapp/servlet/<nonHOcmwo квалифицированное имя класса сервлета>, любые параметры инициализации, заданные в файле web.xml, недоступны. В примере 3.7 приводится зарегистрированный Сервлет с параметрами инициализации. Пример 3.7. Зарегистрированный сервлет с параметрами инициализации <servlet> <servlet-name>Weather</servlet-name> <servlet-class>home.Weather</servlet-class> <init-param> <param-name>reqion</param-name> <param-value>New England</param-value> , </init-param> </servlet> Поскольку параметр с названием региона (region) связан с конкретным зарегистрированным именем, то только обращение с использованием этого имени (или пути к сервлету, отображенного на это имя) задействует параметр region. При обращении по полностью квалифицированному имени параметр region не будет передан сервлету Weather. , См. также Главу 1 по web.xml\ рецепты 3.1-3.4; рецепты 3.6-3.8; главу 11 спецификации сервле- тов версии 2.3 и 2.4 по отображению запросов на сервлеты. 3.6 Отображение на сервлет всех запросов к web-приложению Задача Требуется, чтобы все запросы к web-,приложению направлялись к одному управляющему сервлету (контроллеру). Решение Необходимо использовать в дескрипторе развертывания элемент servlet-mapping, содержащий следующий элемент: ur 1 -pattern: <ur 1-pattern:*/*</игl-pattern>. Отображение на сервлет всех запросов к web-приложению | 73
Обсуждение В некоторых случаях требуется, чтобы все запросы к web-приложению направлялись к одному сервлету. Этот сервлет-контроллер может протоколировать запросы, реализо- вывать политику безопасности или анализировать и, возможно, изменять объект-запрос перед его переадресацией в другое место (обычно к сервлету или JSP). Ознакомьтесь с описанием от Sun Microsystems шаблона проектирования фрон- МЛ’ л контР°ллеРа как способа использования сервлета в качестве центральной точки 4 L “ цЛ* обработки. См. голубые Страницы по ядру J2EE http://java.sun.coin/blueprints/ corej2eepattems/Pattems/FrontController.htptL - - ; •'»' ; Повторяясь, webjanl - это место настройки сервлета на получение всех запросов web-лриложения В примере 3.8 показано, как использовать шаблон URL для. направле- ния всех запросов к сервлету-контроллеру. <4, Пример 3.8. Направление всех запросов К сервлету-контроллеру > <?xml version="1.0" encoding="ISO-8859-1"?> <! DOCTYPE web-a^ PUBLIC "-//Sun Microsystems^ Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-application_2_3.dtd" <web-app> <servlst> S servlet -name»Intarcaptor < I servlet -name» <ssrvlet-class»com.jspservletcookbook.Interceptor</servlet-class> </servlet> < 1— The mappings for the Interceptor servlet —> < servlet -mapping» <servlet-name»Interceptor</eervlet-name>:’ <url-pattern»/.*</url-pattSrfa» v ' •’3 v> < / servlet -mapping» 3 •'* r ’' ~ A v 3s’ < servlet -mapping» 1 ”' ' ' <servlet -name» Interceptor < / Servlet -name» <url -pattern» I servlet / * < /иг 1 -pattern» < / servlet -mapping» </web-app> Вы можете переопределить любой заданный по умолчанию вызывающий сервлет (invoker) собственным отображением; -Ь. <url-pattern>/servlet/*</urJj-pattem> 4 --х;1 Отобразите сервлет, который должен получать все вызовы приложения на этот шаб- лон URL. Если вы сохраните вызывающий сервлет в неизменном виде, пользователи смогут обойти сервлет-контроллер, используя URL вида http://www.mysite.org/myapp/ serX'let/com.jspservletcookbook.CookieServlet. Т4 | Глава Присвоение им£н сервлетам v
На сервере Tomcat вызывающий (invoker) сервлет также можно сделать недоступным, закомментировав элемент servlet-mapping в файле web.xml верхнего уровня (в каталоге <инсталяционный-каталог-Тотса1>/соп/). Это повлияет ‘ на все web-приложения, запущенные под этим экземпляром Nomcat, однако такое решение необходимо принимать совместно с администратором, развертывающим приложения на этом сервере. Вам также необходимо удалить, изменить или закомментировать Другие элементы servlet-mapping, которые позволяют обращаться к сервлетам в обход сервлета- контроллера. Если в web.xml включено какое-либо специфическое отображение (как в примере 3.9), запросы к сервлету CookieServlet будут идти в обход сервлета- контроллера Interceptor. € Пример 3.9. Специфическое отображение переопределяет отображение, использующее символы подстановки <?xml version="1.О" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Micrgsystems, Inc.//DTD Web Application 2.3//EN" "ht tp: 7/j ava. sun. com/dtd/web-applicat ion_2_3. dtd" <web-app> <servlet> <servlet-name>Interceptor*/servlet-name> <servlet-class>jspservletcookbook.Interceptor*/servlet-class» </servlet> <servlet» < servlet-name»CookieServlet</servlet-name> <servlet-class» com.j spservletcookbook.CookieServlet </servlet-class» </servlet» <servlet-mapping» <servlet-name»Interceptor</servlet-name> ' <url-pattern»/**/url-pattern» </servlet-mapping» <servlet-mapping» <servlet-name»CookieServlet</servlet-name» <url-pattern»/CookieServlet</url-pattern» </servlet-mapping» </web-app> \ Отображение на сервлет всех запросов к web-приложению | 75
В этом примере элемент servlet-mapping для CookieServlet позволяет исполь- зовать путь /CookieServlet к данному сервлету, в обход сервлета Interceptor,- поскольку путь /CookieServlet (как часть запроса вада http://xocm:nopm/context-path/CookieServlet) точнее соответствует шаблону VRL/CookieServlet, нежели шаблону У*. Запросы к статичному содержимому, типа начальных файлов (Например, index html), тоже перехватываются шаблоном /♦. Эти запросы также направляются । ч • сервлету-контроллеру. См. также Главу 1 по web.xml-, рецепты 3.1-3.4; рецепты 3.6-3.8; главу 11 Спецификации сервле- тов версии 2.3 и 2.4 по отображению запросов на сервлеты; голубые страницы по ядру J2EE http://java.sun.com/blueprinis/corej2eepattems/Patterns/FrontController.html. 3.7 Отображение запросов на контроллер с сохранением отображений сервлетов Задача Требуется направить все запросы единственному сервлету-контроллеру, сохранив при этом, в безопасном режиме, отображения для других сервлетов. Решение Для предотвращения возможности обращений пользователей с запросами к осталь- ным сервлетам (всем, кроме контроллера) используйте в файле web.xml элементы secu- rity-constraint. Обсуждение Что, если сервлет-кднтроллер, получающий все запросы,, захочет при определенных условиях направить поступивший запрос на специализированную обработку другому сервлету? Если все остальные отображения на сервлеты удалены из web.xml, а шаблон URL в стиле invoker (/servlet/*) также отображен на контроллер, то даже сам сервлет- контроллер не сможет передать запрос другому сервлету! Как обойти это ограничение? Решение заключается во введении в файле web.xml Персональных отображений на сервлеты. Для этого используются элементы security-constraint, предот- вращающие возможность обращения с запросами к сервлетамгнеконтроллерам со. стороны пользователей. Когда сервлет-контроллер хочет перенаправить запрос к другому сервлету, он 76 | Глава 3. Присвоение «мен сервлетам •.<» лпре • ; И?
* исцользует объект, реализующий интерфейс javax.servlet.RequestDispatcher (диспетчер запросов). Диспетчеры запросов (RequestDispatcher) не ограничены в воз- можности передавать запросы (с помощью метода RequestDispatcher. for- ward (request, response)) на шаблоны URL, заданные в элементах security- constraint. Пример 3.10 демонстрирует сервлет с именем Controller, использующий диспетчер запросов (RequestDispatcher) для передачи запроса другому сервлету. Рецепт 3.9 описывает, как с помощью элемента защитить security-constraint сервлеты от получения любых запросов от web-пользователей, поэтому я не привожу эту информацию здесь. Пример3.10. Использование RequestDispatcher для перенаправления запросов import javax. servlet. *; .*• import javax.servlet.http.*; public class Controller extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response!/ - s. " " * Г ’ ‘ > /J’ throws ServletException, java.io.IOException { RequestDispatcher dispatcher = thill? i String param = request.getParameter("go"); if (param == null) throw new ServletException("Missing parameter in Controller.");. else if (param.equals("weather")) dispatcher = request. getRequestDispatcher /weather") ; else if (param.equals("maps")) dispatcher = request.getRequestDispatcher("/maps"); else throw new ServletException( "Improper parameter passed to Controller."); //if we get this far, dispatch the request to the correct URL if (dispatcher != null) dispatcher.forward(request,response); else throw hew ServletException( "ConttOll^r received a null dispatcher from request object."); } . r-ir.. • } Этот сервлет проверяет значение параметра go. Запрос к нему может выглядеть так: http://localhost:8080/home?go-weather. Сервлет Controller из приведенного примера, с помощью отображения, настроен на получение всех запросов к \уе1>приложению «home», Другими Словами, его элемент set viet-mapping в web.xml содержит шаблон URL /*. Отображение запросов на контроллер с сохранением отображений сервлетов | 77
Для передачи запроса в зависимости от параметра до, сервлет Controller создает объект RequestDispatcher с тем или иным URL назначения. Сначала сервлет подучает объект RequestDispatcher, для чего вызывает метод getRequestDis- patcher (String path) объекта request. Значение параметра path может быть задано относительно корневого каталога контекста web-приложения, но оно не должно выходить за пределы текущего контекста сервлета. Предположим, шаблон URL /weather отображен на зарегистрированное имя сервлета «Weather». <servlet-mapping> <servlet-name>Weather< / servlet-name> <url -pat tem> /weather< /url -pat tem> </servlet-mapping> В этом случае путь, передаваемый методу getRequestDispatcher, выглядит так: getReques t Di spa t cher ("/weather"). Если параметр go задан неверно или опущен, Controller вызывает исключение ServletException с соответствующим сообщением. Сервлет Weather не доступен web-пользователям* поскольку доступ к нему ограничен элементом security-constraint* однако на метод RequestDis- patcher . forward (request, response) эти ограничения не распространяются. Для получения объекта RequestDispatcher можно также использовать метод javax.servlet.ServletContext.getNamedDispatcher(String name) При использований этого метода не нужно включать никаких элементов servlet-mapping для сервлетов назначения. Метод getNamedDispatcher () принимает в качестве параметра зарегистрированное в web.xml имя сервлета. В примере 3.11 показан сервлет из предыдущего примера, но с использованием метода getNamedDispatcher (Weather) и зарегис- трированного имени сервлета. Пример 3.11. Использование getNamedDispatcher () для передачи Запроса inrport javax. servlet. *; import j avax.servlet.http.*; public class Controller extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.lOException { RequestDispatcher dispatcher = null; String param = request.getParameter("go*); if (param == null) ,, . throw new ServletException("Missing parameter in Controller."); else if (param.equals("weather")) dispatcher = getServletContext(). getNamedDispatcher("Weather"); else if (param.equals("maps")) 78 | Глава 3. Присвоение имен сервлетам ; -.щ. • ns
dispatcher *, getServletContext() . j; • v!' : ggtNamedpispatcher ("Maps") ; else *• * ( thrpw new ServletException! ( "improper parameter passed to Controller."); /*Check for a null dispatcher, then dispatch the request to the correct URL*/ if (dispatcher != null) dispatcher.forward(request,response); else throw new ServletException( "Controller received a null dispatcher.*); i j. ‘ Здесь метод doGet О изменен и в нем используется получение объекта Request- Dispatcher с помощью метода ServletContext. getNamedDispatcher (String «зарегистрированное-имя-сервлета»). Вместо пути к сервлету объект Dis- patcher использует зарегистрированное в webjanl имя сервлета Weather. «servlet» • , < servlet-name»Weathpr</servlet-name» <servlet-class»com. jspservletcookbook.Weather «/servlet-class» .«/servlet? Если ServletContext вернет null из-за того, что кто-то пропустил в web.xml требуемый XML-элемент, то doGet () вызовет исключение ServletException с объясне- нием, что объект dispatcher пуст. Альтернативная стратегия - использовать слушатель (listener) для проверки i запроса до того как он найдет путь к сервлету. Глава 11 описывает, как д использовать слушатель для проверки НТТР-запроса. См. также Главу 1 по web.xml; рецепты З.Ь-3,5; рецепт 3.8; главу 19 по использованию слуша- теля для проверки запроса; главу 11 спецификации сервлетов версии 2.3 и 2.4 по отображению запросов на сервлеты; голубые страницы по ядру J2EE http://java.sun. com/blueprints/corej2eepattems/Pattems/FrontController.html. г ' 4 Отображение запросов на контроллер с сохранением отображений сервлетов | 79
3.8 Создание начальных (welcome) файлов web-приложения Задача Необходимо сконфигурировать один или несколько начальных файдов web-приложения. Решение Используйте элемент welcome-file-list дескриптора развертывания. Обсуждение Начальный, или стартовый, файл - традиция столь же старая, как и сам гипертекстовый Интернет. На многих сайтах имеются домашние страницы или начальные файлы, призван- ные быть заглавной страницей, или входной дверью этих web-сайтов. Такие страницы обычно носят имя index.html wclcome.html, или default.html. Можно сконфигурировать web- приложение, чтобы обеспечить передачу запросов к таким страницам, для этого нужно добавить в дескриптор развертывания web-приложения элемент welcome-f ile-list. - Создайте в web.xml список начальных файлов, как показано в примере 3.12. Элемент wel- come-file-list в дескрипторе развертывания должен находиться после любого из элементов error-page или taglib (по версии 2.3 спецификации сервлетов). Пример 3.12. Задание начальных файлов в web.xml <?xml versions"1.0" encodings-'ISO-8859-1 "?> >. <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD, Web Application 2.3//EN" ' " http: / / j ava. sun. com/dtd/web-applicat ion_2_3. dtd" <web-app> <i— Define servlets and servlet-mappings here —> <welcome-file-list> J <welcome-file>index.html</welcome-file> f <welcome-f ile>default. jsp</welcome-files* </welcome-file-list> н </web-app> - Когда контейнер сервлетов сталкивается с URL web-приложения,, задающим только п каталог, а не конкретное имя файла или сервлет, он ищет в дескрипторе развертывания >ч элемент welcome-file-list (со списком начальных файлов). В спецификации сервле- тов версии 2.3 такой тип URL называется valid partial request (корректный неполный запрос) Контейнер сервлетов прикрепляет к запросу любой найденный в web.xml началь- ный файл (в порядке их перечисления в web.xml) и возвращает,этот файл клиенту. 80 | Глава 3. Присвоение имен сервлетам
Предположим, Tomcat получил запрос к http://www.mysite.org/cookbook/. И пусть также файл weh.xml приложения cookbook содержит элемент welcome-file-list, показан- ный в примере 3.12. В этом случае Tomcat вернет файл http://www.mysite.org/cookbook/ index.html, если такой существует, если нет, Tomcat ищет в каталоге cookbook файл default, jsp и возвращает его. Контейнер сервлетов инициирует такой поиск в ответ на любой URL с запросом каталога, который он получает (например, http://www.mysite.org/cookbook/bookinfo/). Иными словами, если index.html или default.jsp (или другой выбранный вами файл) суще- ствует в корневом каталоге web-приложения и разработчик правильно настроил элемент welcome-file-list, то эти файлы автоматически возвращаются в ответ на запросы каталога. С. См. также Главу 1 по web.xml’, рецепты 3.1-3.6; рецепт 3.9; главу 11 спецификации сервлетов версии 2.3 и 2.4 по отображению запросов на сервлеты; 3.9 Ограничение запросов к определенным сервлетам Задача Предоставить доступ к определенным сервлетам только для аутентифицированных пользователей. Решение Используйте элемент security-constraint дескриптора развертывания web.xml. Обсуждение Некоторые web-приложения включают сервлеты, которые не должны вызываться непосредственно пользователями, поскольку они обрабатывают важные данные или имеют специальное назначение (например, администрирование сервера или web-прило- жения). К примеру, вы могли разработать сервлет, предназначенный только для систем- ных администраторов. Как защитить подобные сервлеты от непосредственного вызова неавторизованных пользователей? Ограничение запросов к определенным сервлетам | 81
В крайнем случае, можно использовать декларативную безопасность (declarative secu- rity) или безопасность управляемую контейнером. Эта стратегия включает конфигурирова- ние дескриптора развертывания web.xml на основе информации по безопасности приложения и, таким образом, вынос информации по безопасности из кода сервлета. Любые последующие изменения политики безопасности приложения могут осущедтв- ляться редактированием XML-файлов конфигурации (или с помощью консоли адми- нистрирования сервера WebLogic 7.0) без вмешательства в исходный код сервлетов. Далее контейнер сервлета загружает и реализует созданную конфигурацию безопасности. Также можно использовать программируемую безопасность, которая предполагает включение в сервлет кода, связанного с реализацией политики безопасности, например для контроля объекта HttpServletRequest на предмет принадлежности пользова- теля к числу допущенных к определенному web-pecypcy. Для Tomcat использование элемента security-constraint в web.xm/ требует заведения имени пользователя и пароля в XML-файле, находящемся по адресу <инстал- ляционный-каталог-Тотса1>/соп//1отса!-ихегх.хт1. Этот файл предназначен для хране- ния имен и паролей пользователей. Он выглядит так, как показано в примере 3.13. Пример 3.13. Файл tomcat-users.xml <?xml versions * 1.0' encoding=*utf-8’?> <tomcat-users> <role rolename="manager"/> н * <role rolename= * tomcat"7 > »’• <role rolename="developer"/> , «user Usernames" tomcat" passwords "tomcat* rdlfefe» "tomcat, manager "/> cuser usernames"bruce" passwords"brucel957* 1 ’* roles="tomcat,manager,developer"/> ’ iii <user usernames"stacy" passwords"stacyl986" roles="tomcat"/> t</tomcat-users> . Показанный фрагмент XML включает корневой элемент tomcat-users, содержащий один или несколько элементов role (роль), и user (пользователь), в зави- 3 симости от числа пользователей web-приложений на сервере Tomcat. Этот файл кон- фигурации tomcat-users.xml доступен всем web-приложениям сервера. ' ; f, Далее, в дескрипторе развертывания приложения (web.xml), необходимо создать элементы security-constraint, login-config и security-role. ‘ч* 1 —' » ......... Если вы не используете дескриптор развертывания по версий 2.4 спецификации ЛиО сервлетов, элементы, связанные с безопасностью, должны следовать именно в этом порядке, после большинства других элементов, которые могут присутствовать в web.xml, в противном случае дескриптор развертывания не. будет являться корректным XML-файлом. После элемента security-г ole могут следовать п,......только элементы env-entry, ejb-ref и е jb-local-r^fj. 82 | Глава 3. Присвоение имен сервлетам
Элемент security-constraint выглядит так, как показано в примере 3.14; защи- щаемый шаблон URL в данном случае - <url-pattern>/CookieServlet</url- -* pattern*. Пример3.14. Элемент security-constraint «security-constraint» <web-resource-collection» ' <web-resource-name»CookieInfo</web-resource-name> <url-pattern»/CookieServlet</url-pattern» <http-method»GET< /http-method» <http-method»POST</http-method» </web-resource-collection> f <auth-constraint} <description»This applies only to the "developer" security role</description> <role-name>developer</role-name» </autH-constraint> <user-data-sonstraint> ' <transport-guarantee»NONE</transport-guarantee» </user-data-constraint> </securi ty-cons traint» »Л-’% I Элемент security-constraint должен содержать один или более элементов web-resource-collection. Элемент4 web-resource-collection описывает, какие ресурсы web-приложения защищаются указанным ограничением безопасности. Другими словами, запрос web-pecypca через Интернет (например, сервлета) активизирует каждое из ограничений безопасности, относящихся к этому ресурсу. В рассматриваемом примере ограничения безопасности распространяются на любой запрос, удовлетворяющий шаблону URL <каталог-у^еЬ-приложения>/Соок1е8еп>1е1. Элементы http-method задают методы HTTP, на которые действуют данные ограничения безопасности. В этом примере GET и POST с запросом к /CookieServlet активизируют механизм безопасности. Если в, элементы security-constraint не включено никаких элементов http- method, ограничения будут применяться ко всем методам HTTP (таким, как PUT и DELETE, в дополнение к GET и POST). Объекты, реализующие интерфейс javax.servlet.RequestDispatcher, могут передавать HTTP-запросы от сервлета к защищаемому сервлету без активизации ограничений безопасности. М-' 1 Элемент auth-constraint предназначен для описания ролей безопасности, R которым разрешен доступ * к web-компоненту. Роль безопасности - это имя, л представляющее пользователю или группе пользователей полномочия доступа к опреде- ленному ресурсу, например сервлету. К примерам ролей безопасности относятся: admin Ограничение запросов к определенным сервлетам | 83
(администратор), manager (менеджер) или developer (разработчик). Эти роли назначаются пользовагелям в файле tomcat-users.xml. В приведенном в примере элементе secur ity- f constraint доступ к CookieServlet открыт только для пользователей, которым в файле tomcat-users.xml назначена роль developer. Как web-приложение аутентифицирует пользователя? Как, например, web-приложение Ц. находит имя и пароль обращающегося с запросом пользователя, таким образом определяя, имеет ли он доступ к сервлету? При безопасности, управляемой контейнером, для этого предназначен элемент login-config. В файле web.xml этот элемент следует сразу после |V элемента Security-constraint. В дескрипторе развертывания web-приложейия все | это выглядит примерно так, как показано в примере 3.15. Пример 3.15. Использование элемента login-config с элементом security-constraint «security-constraint» <web-resource-collection> <web-resource-name»Cookielnfо*/web-resource-name> <ur 1 -pattern» /CookieServlet* /иг 1 -pat tem> t <http-method»GET</http-method» , » , <http-method>POST</http-method> i </web-resource-collection> <auth-constraint> <description>This applies only to the "developer" security role*/description» <role-name:>developer< /role-name» <Iauth-conStraint> <user-data-constraint> <transport-guarantee>NONE*/transport-guarantee> </user-data-constraint> ^/security-constraint» -Ж <login-config> <auth-method>BASIC*Iauth-method> <I login-config> «security-role» <role-name»deyeloper*/role-name> Элемент login-config задает способ, используемый для аутентификации любог^ пользователя, запрашивающего защищаемый web-pecypc. Защищаемыми являются web- ресурсы, указанные в элементе web-resource-collection, внутри элемента secu- rity-constraint. В приведенном примере для ^любого запроса, соответствующего шаблону URL /CookieServlet используется способ аутентификации BASIC (базовый). BASIC - знакомая вам форма web-аутентификации, при которой браузер открывает перед пользователями диалоговое окно для ввода имени и, пароля пользователя. Tomcat сравнивает полученные имя и пароль с информацией о пользователях, заданной в файле зав 84 | Глава 3, Присвоение имен сервлетам
tomcat'-users.jmil, и затем, Используя настройку ограничений для web-приложения из соответствующего Элемента ty—cohstr efint, определяет, Имеет ли Данный пользовательправо доступа к зашишаемдМу ресурсу. ...... ' * • ДочернийДЛя lbgin-ebn¥'ig элемент, aut hornet hod также может принимать значенияFORM, CLIENT*CERT ИЛи DIGEST. ” LZJJ* л я-.’ -И' ' - Н .. ... •' i -i • Для 1авершенности пой конфигурации.безопасности требуется еще один ингредиент: элемент security-role (роль бе .опасности). В примере 3.15 создается роль безопасно- сти developer (разработчик). Значение developer также присутствует в дочернем элементе auth-constraint элемента security-constraint. Это означает, что пользова- тели, которым назначена роль безопасности developer, имеют доступ к web-ресурсам, защищенным данными ограничениями (то есть ресурсам, перечисленным в элементе web- resource-collection, дочернем по отношению к security-constraint). Иными словами, описываемый способ аутентификации состоит из двух шагов. 1. Проверка корректности получаемых имени и пароля пользователя. 2. Определение, присвоена ли этому пользователю требуемая роль безопасности. К примеру, пользователь может ввести корректны? имя и пароль, однако требуемая роль безопасности ему не присвоена. В этом случае он не допускается к использо- ванию запрошенного web-pecypca. На сервере Tomcat присвоение пользователям ролей безопасности производится с помощью файла tomcat-users.xml. Вот пример того, как может выглядеть элемент user (пользователь) файла tomcat-users.xml. <username="bwperry" password="bruce2002"' roles="developer,standard,manager" /> Пользователь назначены три разные роли: developer,standard и manager. Контейнер сервлетов Tomcat использует эти XML-элементЫ из файла tomcat-users.xml для определе- ния, назначена ли некоторой комбинации имя/пароЛь определенная роль. На рис. 3.1 изображен процесс прохода по этим перекрестным ссылкам. Считайте роли безопасности просто дополнительным способом деления пользователей приложений на группы, в дан- ном случае - в соответствии с их привилегиями. XML-текст с конфигурацией безопасности, приведенный в примере 3,15, может использоваться и. для WebLogic, но там существует свой специфичный файл кон- фигураций w^blogi^bbiil.!! г о .( т . щис л‘- ' I Файл weblagiCfXml,. как и дескриптор развертывания web-xml, находится £ каталог WEB-INF web-приложения. п В примере 3.16 приведен XML из дескриптора развертывания weblogic.xml. ’ э» -л ’-.ь;.....* 1 ' . ; j Ограничение iiinffoltiB й определенный егрвЛетям | 85
web. xml deployment descriptor <security-constraint> <web-resource-collection> <web-resource-name>MyServtet </web-resource-name> <url-pattem>/myservlet</ur1-pattem> <http-method>GET</http-method> <A№b-resource-collecfion> GET /myservlet Q (?) Check servlet configuration Web container Клиент ® BASIC аи1*,еп®с?®оп (3) Check security role I tomcat-users.xml <userrame~"b.vperry password="bruce2002' role$a’"developer,star ftnin’aiager7> Рис. 3.1. Использование элемента ограничения доступа Пример 3.16. Роль безопасности в weblogic.xml <!— weblogic.xml security role mapping —> <securi ty-role-assignment> <role-name>developer</role-name> ’ <principal-name>bwperry</principal-name> </security-role-assignment> В WebLogic 7.0 можно задать пользователей, группы и роли безопасности, глобально по отношению^ определенному серверу WebLogic, с помощью консоли администрирования. В этом рецепте было описано, как ограничить "запросы к определенным сервлетам. В следующем рецепте приведен способ запретить все запросы, за исключением тех, что передаются от сервлета-контроллера. См. также Главу 1 no web.xml-, рецепты 3.1-3.8; главу И спецификации сервлетов версии 2.3 и 2.4 по отображению запросов на сервлеты; голубые страницы по ядру J2EE http://java.sun.com/ blueprints/corej2eepattems/Pattems/FrontController.html. 86 | Глава 3. Присвоение имен сервлетам
3,10 Предоставление доступа к определённым сервлетам только для контроллера Задача Необходимо установит^ web-приложение так, чтобы к определенным сервлетам имел доступ только сервлет-контроллер. Решение » • Создайте роль безопасности, которая не назначена никакому иЗ пользователей, затем в элементе security-constraint укажите сервлеты, к которым может обращаться только контроллер. —........ Обсуждение Этот рецепт показывает, как создать элемент security-constraint, запрещающий все запросы к указанным шаблонам URL, Сервлеты, отображаемые на эти шаблоны URL, получают запросы только через один или несколько сервлетов-контроллеров, использующих объект, реализующий интерфейс javax.servlet.RequestDispatcher. Рецепт 3.7 включает пример сервлета-контроллера, направляющего запросы с помощью RequestDis- patcher к другому сервлету. Пример 3.17 показывает, как задать элемент security- constraint для примера сервлета с зарегистрированным именем «Weather*. Пример3.17. Элемент security-constraint, пропускающий только запросы, нанрасленные посредством RequestDispatcher <?xml versions"1.0" encodings" ISO-8859-1 "?,> <!DOCTYPE web-app- : - PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application. 2.3/7ENj; "http://java.sun.com/dtd/web-application_2_3.dtd"> <*!— Configure the Weather servlet; '.n it receives- .requests from a jJiiPtiocqy-\ 07- -Contrail®] s.srvlfet J .UT <servlet> ‘' <servlet-name>Weather</servlet-name> <servlet-class> M com.j spservletcookbook.Weather £ < . ; c/sclt.]et-class». _ </servlet>..< l;?r, -у. <servlet-mapping> Предоставление доступа к определенным сервлетам Только Д. 1я контроллера |: 87
<servlet-name>Weather</servlet-name» curl-pattern» /weatherurl -pa t tem> <I servlet-mapping» <!— this element prevents the Weather servlet from directly receiving requests from users, •because no users are mapped to the ‘nullrole’ role—> <securi ty-cons traint» cweb-resource-collection» , <web-resource-name»Weather </web-reSource-name» « * <url-pattern»/weather</url-pattern» <http-method»GET</http-method» <http-method»POST< /http-method» </web-resource-collection» 3 <auth-constraint» <role-name»nullrole</role-name> </auth-constraint> cuser-data-constraint» < transport -guar ant ee»NONE </transport-guarantee» Г ' ) </user-data-constraint» c/security-Constraint» clogin-config» cauth-method»BASIC< /auth-method> с/login-confxg> • csecurity-role» ' crole-name»nullrolec/role-name> с/security-role» c/web-app» Следующий шаг по защите сервлета Weather - убедиться, что в файле tomcat-users, xml роль «nullrole» не назначена никому из пользователей. Элемент security-role выглядит примерно следующим образом: csecurity-role» • crole-name»nullrolec/role-name> с/security-role» А вот так выглядит типичный файл <инсталляционный-каталог-Тотса1>/соп//Ют- cat-users.xml. c?xml version='1.0' encodings’utf-8'?> ctomcat-usets» crole rolename="manager"/» crole rolename="tomcat"/» crole rolename="developer"/» 88 | Глава 3. Присвоение имен сервлетам
<user usernames"tomcat" passwords"tomcat" roles="tomcat,manager"/> <user username="bruce" passwords"brucel957" roles=" tomcat, ihanager, developer" /> </tomcat-users> В web-приложениях, сконфигурированных как в примере 3.17, на любой прямой запрос к шаблону URL /weather будет возвращен ответ типа «HTTP статус 403 - в доступе к запрашиваемому ресурсу отказано». Однако сервлет-контроллер, используя метод RequestDispatcher. forward (request, response), по-прежнему может направлять запросы к URL /weather на обработку. В рецепте 3.7 и примере 3.10 показан сервлет, использующий этот способ передачи, поэтому я не стану повторять этот код здесь. --- е- < '' Позаботьтесь о создании доброжелательных страниц с сообщением об ошибке, отправляемых пользователям, обращающимся к защищенным сервлетам. Описание 4 * £ того, как с помощью дескриптора развертывания web-приложения, для определенных кодов возврата HTTP, назначить страницы с сообщениями об ошибках, содержится в главе 9. Вам может потребоваться из страницы с сообщением об ошибке, после небольшого интервала, делать автоматические обновления контроллера или каких- либо login-страниц. См. также Главу 1 по web.xml-, рецепты 3.1-3.9; главу 11 спецификации сервлетов версии 2.3 и 2.4 по отображению запросов на сервлеты; голубые страницы по ядру J2EE http://java.sun.com/ blueprints/corej2eepattems/Pattems/FrontController.html. Предоставление доступа к определенным сервлетам только для контроллера | 89
h'A ЛШЮШТ/ H <тил’ЛлОП яГЛАВД 4 Использование ApacheAnt / f г, 41! .J й. ; 4.0,; ..Введение" , Apache Ant (http://ant.apache.org/) - средство автоматизации, созданное нЙ баз^ Java и XML и распространяемое Apache Software Foundation как ПО с открытым исходным кодом (open source software). Ant эволюционировал в инструмецт^компо) новки, используемый для автоматизации работы над программными проектами JaVa, тоесть для Построений Этих проектов от начала ио конца. Сюда относится койгп (Линия классов Java; создание JAR или WAR файлов и выполнение задач, свя* зайнЫх 0 файловой системой,' например Создание каталогов и перемещение или копирование файлов. Выполнение этих1 задач для определенного проекта управляв ется в Ant файлом компоновки. Файл компоновки Апг* это XML-Лайл. запускаемый на обработку из команд- ной ст^оки'й’ выполняющий Javaknaccbi, йахЬдяЩиеся’за сценой. Ant является расширяемым инструментом; вы можете настроить его для выполнения собствен- f ( ны* зед?Чь А, кроме того, Дп( -независим от платформы и комцтктец поскольку осцоврн на XML и Java. Однажды позрркомивщи;сг с этим удобным и мощныэд инструментом,,web-разработчики быстро оценят то насколько он облегчает выпо^ нение задач по компиляции, упаковке, внесению изменений и переразвертыванвдф V. u.,/.;,. M/.sUv . Л.." йбэб В начале главы Списывается, как скачать Ant и установить его в системе, Затем для новичков объясняются понятия Ant ^цельь и «задача» В заключительной части описано, как создать путь к классам (classpath), включающий необходимы JAR-файлы Tomcat, как создать WAR и JAR файлы и как использовать Ant для выполнения приложения Менеджер. Т01 neat. уk • Sfe %- H. !9O?jZ'
4.1 Как получить и установить Ant Задача Требуется скачать и установить Apache Ant на компьютер. ✓ Решение Направьте браузер по адресу http://ant.apache.org/, скачайте дистрибутив Ant (двоичный код или исходный файл) и затем следуйте инструкциям этого рецепта и сайта поддержки Ant. Обсуждение я. Двоичный дистрибутив Ant можно скачать с http://ant.apache.org/bindownload.cgi. Можно скачать, дистрибутив в виде исходного кода, который содержит исходные Java- файлы, с http://ant.apache.org/srcdownload.cgi. Для инсталляции вам необходимо иметь установленный Java SDK (Software Development Kit - набор для разработчика ПО). ЧЛ- Ant версии 1.5.3 будет последней версией, поддерживающей JDK 1.1. Ant версии 1.5.1 может работать с ЛЖ 1.1, хотя отдельные задачи работают только с JDK 1.2. v- Для использования Ant необходимо иметь синтаксический анализатор XML, совмести- мый с Java API для обработки XML (Java API for XML Processing - JAXP), и путь к классам, указывающий на него. Двоичный дистрибутив Ant включает Apache Xerces2 - син- таксический анализатор XML. Если вы хотите использовать другой JAXP-совместимый син- таксический анализатор, удалите из каталога Ant верхнего уровня /lib (например, jakarta-ant- 1.5.1/lib) файлы xerceslmpl.jar и xmlParserAPIs.jar и поместите в Aib JAR-файлы другого син- таксического анализатора. Их можно добавить и по-другому, напрямую в ваш пользователь- ский путь к классам. Пользовательский путь к классам -г это путь к классам, представленный на вашей машине переменной окружения CLASSPATH. Этот путь к классам замещает значение принятое по умолчанию (., или текущий каталог). В инструменте командной строки * java переключатели -ср и -classpath замешают значение переменной окружения CLASSPATH. Пользовательский путь к классам также можно установить с помощью опции -jar средства java, если путь включает JAR-файлы. Этот способ, в свою очередь, замещает значение пути к классам, заданное другим способом. В общем, проще поместить выбранный вами синтаксический анализатор в каталог jakarta-ant-1.5.1Aib и не связываться с суетой вокруг пути к классам. Как получить и установить Ant | 91
Полное руководство по установке* Ад^ссы^ web-страницы находятся р http://ani.apache.org/mdnual/iridex.ntml. Для запуска Ant на вашей машине необходимо сделать следующее. 1. Распакуйте сжатый файл (в формате ZIP или TAR), содержащий инструмент Ant Для Ant * версии. L5.1 после распаковки дистрибутива будет создан хата тог jakarta-ant-1.5.1.< '' 2. Установите значением переменной окружения ANT_HOME каталог» в который инсталлируется Ant. В Unix это можно сделать, набрав в командной строке следующее: export ANT_HOME=/usr/local/jakarta-ant-1.5.1 В Windows наберите следующее: set ANT_HOME=h:\jakarta-ant-1.5.1 I 3. К переменной окружения PATH добавьте каталог <инсталляционный-каталог-Ап1>/ bin. Это позволит разработчику перейти в любой рабочий каталог* содержащий файл build.xml, и, напечатав ant, выполнить этот файл (выполнение файла build.xml опи- , сано в следующем рецепте). Каталог <‘нстйлляционныи-каталог-Ап1>/Ь1псодержит сценарии, которые запускают классы Java, формирующие основу Ant. Г 4. При необходимости, в переменной окружения tTAVA^_HOME задайте каталог где устач норлер JDK Если,это .сделать, при использовании вами задач javac или rmic# сценарии из каталога/Ъот, входящие в поставку Ant, смогут автоматически присоеди- нить необходимые классы из JDK. Задачи - это XML-элементы, делающие в файла^ Ant основную работу, например, задача war создает war-файлы, а задача javac ком- пилирует классы Java. 5. Проверьте правильность установки, напечатав ant-version. Если все Пройдет хорошо, эта команда дозвратит значение версии,-как доказано ниже; < ' 1 -.\Л .. г K:\>ant -version Apache Ant version 1.5.1 compiled on October 2 2002 См. также Рёцепт 4.2 по использованию целей Aht, рецепт 4.3 ito включений) JAR-файлбв Tomcat в путь к классам Ant; рецепт 4.4 по коМпйЛЯцйй сервлетой’с помощью Ant, рецепт 4.^ по созданию с помощ^о Ant WAR-файлов, рецеп г 4.6 созданию с помощью An( JAR-$arf- Лов; рецепты14.7 и 4.8 по запуску и остановке TOmcdf с помощью ’Arib, рецепты 2.1 й 2„d по развертыванию созданию с помощью Ant web-приложений; руководство по Apache АпЬ http'//ant.apache.org/manual/index.htm!; проек*. Apache Ant: http://ant.apache.org. < '-цэ -лэ 92 | Глава 4. Использование Apache Ant
4.2 Использование целей Aht Задача Для разрабатывающегося приложения создать в файле сборки необходимые элементы target (цель). Решение 1 Создайте один или несколько элементов target в качестве дочерних элементов элемента project. Проследите, чтобы элементы target имели необходимый атрибут name и значение. Обсуждение Файл сборки -г это XML-файл, то есть простой текстовый файл, состоящий из элемен- тов и атрибутов.- В примере 4.1 показан файл сборки Ant (далее - просто файл Ant), выдающий эхо-сообщение на консоль. Как уже говорилось, файлы Ant выполняют Java-код, находящийся за сценой. Тем, какие именно действия необходимо выполнить, вы управляете, помещая в корневой элемент pro j ес t один или несколько элементов target. Пример 4.1. Сборочный файл Ant, выдающий сообщения на консоль <project name="Cookbook" default»"echo-message" basedir,» । <target nanu.«"echo-messagu" description»"Echoing a message to the console•> <echo message»"Hello from the first Ant file"/> </target> </project> Файлы Ant имеют единственный корневой элемент project, который должен содержать атрибут default и значение. Атрибут default задает цель, кстгора.'. ы шолня ^гся, если в командной строке не обнаружено других целей. Атрибуты name и basedir можно не указывать. Атрибут name присваивает элементу project описательное имя. ^трибут basedir задает каталог, относительно которого вычисляются пути,, указанные ^файле. По умолчанию его Значением является каталог, в котором расположен данный сборочный файл. * Что такое цель? Это группа задач, представленная в Ant элементом target. Цели объ- единяют одну или несколько задач (которые в свою очередь представлены элементами task) в логические поименованные единицы управления, наподобие методов Java. Задачи выполняют: компиляцию файлов Java (задача javac), копирование файлов с места на место (задача сору), создание JAR и WAR файлов (задачи jar и war) и кое- что еще. К примеру, цель echo-message из примера 4.1 вызывает задачу echo. ’ Использование целей Ant | 93
Имя echo-message цели из примера 4.1 - это просто некоторое придуманное мною имя. Атрибут description не является обязательным, как и три чругих атрибута: depends, if и unless. Я уже вкратце объяснял назначение атрибута depends; атрибуты if и unless позволяют задавать условия выполнения целей. После того как Ant корректно установлен на компьютер, можно выполнить приве- денной выше файл сборки build.xml с помощью следующей командной строки. Н:\book\cookbook\secl\secl_3»ant Buildfile: build.xml. echo-message: [echo] Hello from the first Ant file.-4 BUILD SUCCESSFUL . , . .„j Total time: 3 seconds ,r Но вначале этот XML-текст с корневым (.цементом project сохраняется в фдмле с именем build.xml. Затем необходимо перейти в каталог, содержащий данный файл сборки, и напечатать ant, без каких-либо опций. После этого Ant ищет в текущем ката- логе файл build.xml и запускает цель по умолчанию (default) проекта (в примере 4.1 это3 цель echo-message). г*^г Можно дать сборочному файлу другое имя (не build.xml)i но тогда Ant необходимо запускать с переключателем -bui Idf i le. ant -buildfile dev.xml Большинство сборочных файлов включают несколько целей, которые в определенной' последовательности инициируют задачи разработки. Пример 4.2 демонстрирует использо- вание атрибута depends (зависит от). В нем показано, как выполнить несколько целей в определенной последовательности. ’ р Пример 4.2. Использование атрибута depends элементов target для выполнения целей в определенной последовательности «project name®"Cookbook" default="echo-message" basedir®"»"> «target name®‘'init"» <*•' * lV «property name®"name" value®"Bruce Perry"/» o- «/target» «target name®"show-props" depends®"init"» «echo message® \ "The 'name' property value is: $[name}"7» «echo message® "OS name and version is: $‘{os.name} $ {os. version} "/> «echo message® < < n- "Your Java home is: ${java.home} "/> , r «/target» 94 | Глава 4. Испст зов~ние Apache Ant
«target name='’ccho'message,, depends="show-props“> • '< j «echo message? ar, ‘и. . ., "Helld from: the first Ant file in directory: ${basedir}"/> </targe t> «/projects» j Здесь в элемент project вложен ие один, а несколько элементов target. Цель echo-message все еще является целью по умолчанию, но ее поведение меняется из-за значения атрибута depends. Этот необязательный атрибут задает имя одной или несколь- ких целей Ant, которые должны быть выполнены до данной цели. Другими словами, цель echo-message говорит: «я завишу от цели show-props, сначала выполните ее». Цель show-props, в свою очередь, тоже имеет атрибут depends, свидетельствующий, что она зависит от цели init. В результате сборочный файл устанавливает такую последова- тельность выполнения своих целей: init -»show-props -»echo-message. Результат выполнения файла сборки из командной строки показан ниже.. < Н: \bdoX\cookbook\secl\seclT_3>ant. Buildfile: build.xml init: show-props: / «[echo] Thu 'name* property value is: Bruce Perry [echo] OS name and version is: Windows NT 4.0 ’ [echo] Your Java home is: h:\jdkl.3.1_02\jre echo-message:- , j •<,„ , r. [echo} Hello from the first Ant file id directory: л \book\ccokbook\secl\secL_J3 ‘ i BUILD SUCCESSFUL ~ ( Tgtal time; 2 seconds Вот что делает этот файл. 1. Сначала цель init создает свойство name, содержащее значение «Bruce Perry». , Для этого цель использует задачу property. Повторюсь, реальную работу 'в Ant выполняют задачи; цели же просто 1гуппируют элементй, вызывающие.одну или несколько задач. , , 2. Затем цель show-props выводит на консоль значение свойства name (созданного целью init) и трех встроенных свойств: os .name, os. version и java.home. 3. Цель echo-message выводит на консоль сообщение и значение свойства basedir. Для вывода на консоль все цели используют задачу echo. Заметьте, что свойство name не будет установлено, если цель init не будет выпол- нена. И если цель show-props определить так, как показано ниже, появятся проблемы. «target name="show-props"> . . . </target> '• Использование целей Ant j iV *
Однако эта цель объявлена правильно. <target name="show-props” depends="init"> . . . </target» Без атрибута depends цель init никогда не будет выполнена, поскольку в этом случае цепочка выполнения сборочного файла будет такой: show-props -*echo-message. Свойство name никогда не получит значение. В реальности, сборочные файлы Ant намного сложнее, чем приведенные примеры, которые являются скорее демонстрацией широких возможностей Ant, чем примерами плохого проектирования. В главе 2 показано, как развертывать отдельные сервлеты и web-приложение с помощью более развитых файлов Ant См. также Рецепт 4.1 по скачиванию и установке Ant; рецепт 4.3 по включению JAR-файлов Tomcat в путь к классам для Ant; рецепт 4.4 по компиляции сервлета с помощью Ant; рецепт 4.5 по созданию с помощью Ant WAR-файла; рецепты 4.7 и 4.8 по запуску и остановке Tomcat с помощью Ant; рецепты 2.1 и 2.6 по развертыванию с помощью Ant web-приложения; руководство по Ant, раздел по задаче property: http://ant.apache.org/ manual/CoreTasks/property.htmh руководство по Ant, сегмент цо целям: http://ant.apache. org/manual/using.html#targets; индексную страницу руководства по Ant: http://ant.apache. org/manual/index.html; проект Apache Ant: http://ant.apache.org. 4.3 Включение JAR-файлов Tomcat в путь к классам сборочного файла Задача Требуется установить для Ant путь к классам, включающий различные JAR-файлы Tomcat. Решение Для определения пути к классам создайте структуру, отражающую путь, и затем, при необходимости, ссылайтесь на нее. Задайте каталоги, в которых размещаются необ- ходимые JAR-файлы с Помощью внешнего файла свойств. 96 | Глава 4. Использование Apache Ant
Обсуждение Перед началом компиляции сервлета с помощью Ant, необходимо убедиться, что в путь к классам, используемый при компиляции в сборочном файле, включены ссылки на классы API сервлетов. К примеру, каталог <инсталляционный-каталог-Тотса1>/соттопЛ1Ь содержит servletjar, включающий классы, необходимые для компиляции сервлета.. А для компиляции сервлета, использующего JavaMaii API, потребуется включить файл mailjar, находящийся в том же каталоге. В другом каталоге, <инсталляционный-каталог- Totncat>/common/endorsed, содержится файл xmlParserAPIs.jar, который необходимо ука- зать в пути к классам, если требуется использовать классы, связанные с синтаксическими анализаторами SAX или DOM для XML. В примере 4.3 путь к классам задается с помощью XML-элемента path. Ниже в этом XML-файле, в цели compile-servlet, этот путь к классам используется для компи- ляции сервлета. Пример 4.3. Определение пути к классам, содержащего JAR-файлы Tomcat «project name="Cookbook" default="compile-servlet-" basedir="."» <!—включаем свойства compiled-servlet и tomcat-dir —> <property file="global.properties" /> «path id*"servlet-classpath"> «fileset dir*"${tomcat.dir}/сопвпоп/11Ь"> «include name»"*.jar" /> «/fileset» «fileset dir="${tomcat.dirI/common/endorsed"» <include name"”*.jar" /> </fileset> «/path» <target name= "compile-servlet"». «echo message^"Compiling the servlet....“/> <javac srcdir="${src}" destdir="$-{build} "> •«include name="${compiled.servlet}.java" /> «classpath refid»"servlet-classpath "/> </javac> </target» «/project» С помощью элемента path можно определить путь к классам и затем использовать его повсюду в сборочном файле, наподобие экземпляра переменной Java-класса. К преимуще- ствам такого подхода относится то, что можно создать очень сложный путь к классам, при этом определив его всего один раз. В тех местах сборочного файла, где потребуется данный путь к классам, его можно подтянуть с помощью элемента classpath'c атрибу- том refid. В примере 4.3 элементу path присвоен уникальный идентификатор serv- let-classpath. Разработчик создает это имя для однозначной идентификации структуры, хранящей путь. Включение JAR-файлов Tomcat в путь к классам сборочного файла | 97
Другим базовым типом задачи Ant является задача fileset (набор файлов), fileset -г это элемент, представляющий группу файлов. Два вложенных элемента fileset в примере имеют атрибут dir и задают два подкаталога инсталляционного каталога Tomcat: ./common/lib и ./common/endorsed. В этих подкаталогах находятся мно- гие важные библиотеки Java, например servlet.jar и mailjar. Вложенные в fileset элементы include создают шаблон (в атрибуте name), задающий тип файлов, включаемых в данную группу файлов. В примере в группу файлов включаются все файлы указанных каталогов, имеющие расширение «.jar». Если в дальнейшем потребуется отсеять некоторые виды JAR-файлов из группы фай- лов, можно использовать вложенный в fileset элемент exclude. <fileset dir="${tomcat.dir}/c<xnmon/lib"> ' •«include name="*.jar" /> «exclude name="commons *.j ar"/> </fileset> Шаблон commons* .jar исключает из пути к классам все JAR-файлы, начинающиеся на «common», за которыми следует ноль и более символов и расширение «.jar». Цель compile, servlet из примера 4.3 выдает эхо-сообщение на консоль, после чего использует задачу javac для компиляции сервлета. Следующий код из примера 4.3 делает доступными в сборочном файле Ant два свой- ства, которые определены в другом файле. «property file="global.properties" /> Файл global .properties выглядит примерно следующим образом: tomcat.dir=k:/jakarta-tomcat-4.1.12 compiled.servlet=MyTask src=.\src build=.\build Свойство compiled, servlet содержит имя исходного Java-файла, подлежащего компиляции. А свойство tomcat. dir - путь к корневому каталогу Tomcat. В примере 4.3 элемент classpath вложен в задачу javac. «javac srcdir="${src}" destdir= "${build} "> «include names-${compiled.servlet}.java" /> «classpath refid="servlet-classpath"/> </javac> Атрибут refid элемента classpath подтягивает путь к классам, определенный ранее в этом же сборочном файле (путь включает все JAR-файлы Tomcat из каталогов ./ сопипон/ИЬ и ./common/endorsed}. Значением атрибута refid является идентификатор элемента path (“servlet-classpath”). Короче говоря, элемент path из прймера 4.3 представляет путь к классам; идентификатор или имя этого элемента - servlet-class- path. 98 | Глава 4. Использование Apache Ant • <
Если в путь к классам, определенный в файле Ant, потребуется добавить другие классы или JAR, просто добавьте в элемент path дополнительные вложенные элементы fileset. В примере 4.4, с помощью третьего вложенного fileset, к пути к классам из примера 4.3 (с относящимися к Tomcat JAR-файлами) добавляется все содержимое каталога build. Пример 4.4. Структура пути из трех вложенных групп файлов «path id="servlet-classpath"> <fileset dir=“${tomcat.dir}/common/lib"> «include name="*.jar4 /> </fileset> <fileset dir="${tomcat.dir}/common/endorsedn> r «include name="*.jar" /> / «/fileset> «fileset dir="./build"/> </path> Идиома **, часто появляющаяся в шаблонах пути, означает ноль или более каталогов. Например, следующий тег fileset включает все файлы, содержащиеся в любом и? вложенных каталогов images независимо от того, насколько глубоко они вложены (src - имя свойства, указывающего исходный каталог для данного fileset). «fileset dir="${src}"> «include name="**/images/*"/> </fileset> См. также Рецепт 4.1 по скачиванию и установке Ant; рецепт 4.2 по созданию целей Ant; рецепт 4.4 по компиляции сервлета с помощью Ant; рецепт 4.5 по созданию с помощью Ant WAR- файла; рецепт 4.6 по использованию Ant для создания JAR-файлов; рецепты 4.7 и 4.8 - по запуску и Остановке Tomcat с помощью Ant; рецепты 2.1 и 2.6 по развертыванию с помощью Ant web-приложения; руководство по Ant, раздел по задаче property: http://ant. apache.org/manual/CoreTasks/property.hti1il; руководство по Ant, сегмент по целям: http://ant. apache.org/manual/using.htmlkhargets; индексную страницу руководства по Ant: http://ant. apache.org/manual/index.html; проект Apache Ant: http://ant.apache.org. Включение JAR-файлов Tomcat в путь к классам сборочного файла | 99
4.4 Компиляция сервлета с помощью сборочного файла Ant Задача Создать простой сборочный файл для компиляции отдельных сервлетов, избавляющий от утомительного ручного ввода имен сервлетов. Решение Спроектировать сборочный файл Ant так, чтобы имя Java-класса, подлежащего ком- пиляции. можно было задавать во внешнем файле свойств или в командной строке. Обсуждение Если для разработки и компиляции сервлетов вы не используете IDE, то сборочный файл Ant может помочь автоматизировать процесс компиляции исходных файлов. Для того чтобы этот файл можно было использовать неоднократно, его необходимо спроектировать так, чтобы он получал имя исходного файла из внешнего файла свойств или из командной ' строки. Преимущества Ant особенно заметны при использовании его для автоматизации всех аспектов сборки, архивирования и развертывания web-приложения. Однако Ant также можно использовать и как командный процессор. В данном рецепте Ant используется для динамического выбора Java-файла на компиляцию. Файл build.xml из примера 4.5 импортирует ряд свойств из файла buildproperties, включая имя сервлета подлежащего компиляции. Единственный' способ выбрать Java- файл для компиляции, не изменяя сборочный файл, - изменить в файле свойств значение свойства compiled, servlet. tomcat.dir=/users/bruceper/java/jakarta-tomcat-4.1.12 compiled. servlet=MyServlet Чтобы выполнить пример 4.5, необходимо перейти в каталог с файлом build.xml и напечатать ant без всяких параметров. Если вы выполняете сборочный файл с другим именем - не buildxml, а, например, ant_.compiler.xml, то в командной строке необходимо набрать следующее. _____ЪЛ’ ant -buildfile ant_compiler.xml Сначала сборочный файл импортирует свойства tomcat .dir и compiled, serv- let из файла build.properties. Этот файл находится в том же каталоге, что и сборочный файл. Свойство tomcat .dir используется для создания пути к классам, указывающего на JAR-файлы из двух каталогов, являющихся частью дерева’Тошса! (см. рецепт 4.2). 100 | Глава 4. Использование Apache Ant
Пример 4.5. Компиляция сервлета с помощью сборочного файла Ant , » «project name="servlet compiler" default*"compile" basedir=*."> <property file="build.properties" /> «path id>->" servlet-classpath"» <fileset dir*"${tomcat.dir}/common/lib"> «include name""*.jar" /> «/fileset» < fileset dir"" $ {tomcat.dir}/coumon/endorsed"> «include name""*.jar" /> «/fileset» c. </path> / «target name*4init" descriptions"Initializes some properties."» «echo messages"Initializing properties."/» «property name="build" value="./build" /> «property name="src" values".Isrc" /> «/target» «target name="prepare" depends="init"> «echo messages"Cleaning up the build directory."/» «delete dir="${build}"/> «mkdir dir="${build}"/» «/target» «target name«"coiqpile" depends*"prepare" description*"Compile the servlet"» «echo message*"Compiling the Java file "/» «echo message""${compiled.servlet}.java..."/» «javac srcdir-"${src}" destdir«"${build}"» «include name*"${compiled,servlet}.java" /» «classpath refid*"servlet-classpath "/» «/javac» «/target» «/project» Цель init создает два свойства, представляющие исходный каталог (src) и каталог для записи результата компиляции (build). Java-файл, подлежащий компиляции, нахо- дится в каталоге src. Типичный сборочный файл также содержит цель init, но обычно она инициализирует несколько большее количество свойств. Поскольку цель compile имеет атрибут depends, указывающий на цель prepare, а цель prepare, в свою очередь, зависит от init, то последовательность сборки выглядит так: init ->pre- pare -> compile. , \ Компиляция сервлета с помощью сборочного файла Ant | 101
Цель prepare просто очищает каталог build, чтобы удостовериться, что в итоге он будет содержать только результат последней компиляции. Цель compile для компиляции Java-файла использует задачу javac. Элемент javac имеет атрибуты, задающие исходный каталог и каталог результата для Java-файлов, подле- жащих компиляции. В примере 4.5 значения для этих атрибутов берутся из свойств src и build. Два вложенных в задачу javac элемента компилируют заданный файл сервлета и формируют путь к классам, используемый задачей j avac (см. рецепт 4.2). » Вот что остается на консоли после выполнения данного сборочного файла (с некоторыми изменениями для удобочитаемости). init: [echo] Initializing properties. prepare: [echo] Cleaning up the build directory. [delete! Deleting directory /Users/bruceper/books/cookbook/seel/secl_3/buiId [mkdir] Created dir: /Users/bruceper/books/cookbopk/secl/secl_3/build ' compile: [echo] Compiling the Java file MyServlet.java... [javac] Compiling 1 source file to /Users/bruceper/books/cookbook/secl/secl_3/build BUILD SUCCESSFUL Total time: 6 seconds f Использование командной строки для задания сервлета, подлежащего компиляции Что делать, если необходимо откомпилировать уже другой сервлет, но вы не хотите набирать новое имя Java-файла в файле build.properties! Выполнение сборочного файла build.xml с помощью командной строки, приведенной ниже, перезапишет значение импортируемого свойства compiled. servlet. * ; ant -Dcompiled.servlet=AnotherServlet Здесь AnotherServlet.java - имя файла, ожидающего компиляцию в каталоге src. Вот фрагмент выдачи на консоль, подтверждающий, что значение свойства, переданное из командной строки, перезаписывает значение свойства с таким же име- нем, импортируемого из внешнего файла или создаваемого в самом сборочном файле. compile: [echo] Compiling the Java file AnotherServlet.java... [javac] Compiling 1 source file to /Users/bruceper/books/cookbook/seelIsecl_3/build 102 | Глава 4. Использование Apache Ant
, Задача javac компилирует только те Java-файлы из каталога src, для которых нет соот- ветствующего файла класса или когда файл, класса более старый, ием исходный Java-файл. И, как всегда, чтобы узнать все возможные варианты использования и атрибуты javac, обращайтесь к руководству по Ant: http://ant.apache.ofg/ntanuaI/CoreTasks/javac.html. Если необходимо скопировать откомпилированный класс сервлета в каталог web- приложения, можно добавить цель deploy-servlet, использующую задачу сору. Л*.< target names: * deploy- servlet" depends=" compile"» <echo message= "Copying the servlet to Tomcat web app"/> <copy todir="${tomcat.webapps}/WEB-INF/classes"» <fileset dir="${build} /> </copy> </target» Задача copy, используя в качестве копируемых файлов вложенный в нее fileset, представляющий содержимое каталога, имя которого берется из свойства build, копирует эти файлы классов в каталог WEB-INF/classes приложения по умолчанию Tomcat. См. также Рецепт 4.1 по скачиванию и установке Ant; рецепт 4.2 по созданию целей Ant; рецепт 4.3 по созданию пути к классам для файла Ant; рецепт 4.5 по созданию с помощью Ant WAR- файла; рецепт 4.6 по использованию Ant для создания JAR-файлов; рецепты 4.7 и 4.8 пр запуску и остановке Tomcat с помощью Ant; рецепты 2.1 и 2.6 по развертыванию с помощью Ant web-прилРжения; руководство по Ant раздел по задаче property: httpr// ant.apache.org/manual/CoreTasks/property.html-, руководство по Apt, сегмент пр целям: http:// ant.apache.org/manual/using.htnil#targets\ индексную страницу руководства по Ant: http://ant. apache.org/manual/index.html-, проект Apache Ant: http://ant.apache.org. 4.5 Создание WAR-файла с помощью Ant Задача . Используя Ant создать файл web-архива (WAR). I Решение Воспользуйтесь задачей war. 4 Создание WAR-файла с помощью Ant | 103
Обсуждение WAR-файл - это архив web-приложения, содержащий классы сёрвлетов, JSP-файлы, HTML-файлы, каталоги с изображениями, JAR-файлы, XML-файлы конфигурации и другие ресурсы, от которых зависит web-приложение. Для того чтобы сделать wtjb-приложение доступным пользователям, WAR развертывается в web-контейнере, например в Tomcat. Для облегчения генерирования WAR из структуры каталогов, содержащих необходимые файлы web-приложения, Ant включает задачу war. В примере 4.6 показан отдельный сборочный файл, предназначенный только для создания WAR-файла. Это проще, чем изучать одну цель в составе сложного сборочного файла, который компилирует Java-файлы, создает WAR и развертывает приложение (см. рецепт 2.6). В данном примере задается следующая последовательность сборки. init-» pre- pare -»create -»war. Цель init создает несколько свойств, указывающих на ката- логи, например, каталог build, содержащий файлы классов сервлета. Свойство context- path представляет путь к контексту для web-приложения и, в данно^ случае, имя WAR- файла (myapp.war). При выполнении этого сборочного файла из командной строки теку- щим каталогом должен быть корневой каталог web-приложения. Пример 4.6. Файл Ant, использующий задачу war «project names"war-task" defaults"create-war" basedir="."> «target name="init" descriptions"Initializes some properties."> «echo messages"Initializing properties."/* «property name="build" values".\buiId" /> «property name=src" values".\src" /> «property names"dist" values".\dist" /> «property names"lib" values".\lib" /> «property name=“web" values".\web" /> «property names"meta" values".\meta" /> «property name="context-path" values"myapp" /> «/target* «target name="prepare" depends="init"> «echo messages "Cleaning up the build and dist directories."/* «delete dir="${build}"/> «mkdir dir="${build}"/> «delete dir="$(dist}"/> «mkdir dir="${dist}"/> «/target* «target names"create-war" descriptions 104 | Глава 4. Использование Apache Ant
"creates a web application archive file" depends"prepare"> <war destfilea"${dist}/${context-path} .war" webxml" " $ {meta} /web.xml"> <classes dir«"${build}"/> <lib dir""${lib}"/> ( <fileset dir«"${web}"/> </war> </target> i </project> Если сборочный файл имеет имя war-task.xml, то для его г выполнения требуется следующая командная строка. ant -buildfile war-task.xml Цель create-war вызывает задачу war. Атрибут destfile задачи war необходим - он указывает местоположение итого- вого WAR-файла. В примере 4.6 WAR-файл создается в каталоге dist. Атрибут webxml указывает местоположение дескриптора развертывания web-приложения. В данном примере файл web.xml находится в каталоге meta. В примере задача war имеет гри вложенных элемента: classes, lib и fileset. Атрибут dir элемента classes указывает на каталог, содержащий Java-классы, которые будут размещаться в каталоге WEB-INF/classes. Задача war автоматически создает в WAR- файле каталог WEB-INF/classes. При его создании эта задача также автоматически воспроизводит все связанные с пакетом каталоги из каталога build. Иными словами, если каталог build включает структуру каталогов com/jspservletcookbook, то и WAR-файл будет иметь такую же структуру каталогов в WEB-INF/classes. Элемент lib выбирает и сохраняет все JAR-файлы, которые будут размещаться в ката- логе WEB-INF/lib WAR-файла. И, наконец, вдоженнь/й элемент fileset, в данном случае, выбирает из каталога /web все статичные файлы и любые вложенные каталоги image и поме- щает все это на верхний уровень дерева каталогов файла WAR. Вот так выглядит выдача на консоль данного сборочного файла (с некоторыми правками для удобства чтения) init: [echo] Initializing properties. prepare: [echo] Cleaning up the build and dist directories. [delete] Deleting directory /Users/bruceper/books/cookbook/buiId [mkdir] Created dir: /Users/bruceper/books/cookbook/build [delete] Deleting directory /Users/bruceper/books/cookbook/dist Создание WAR-файла с помощью Ant | 105
[mkdir] Created dir: » ‘ •' /Users/bruceper/books/cookbook/dist create-war: [war] Building war: , /Users/bruceper/books/cookbook/dist/туарр.war Задача war имеет много других, необязательных атрибутов, все они описаны в руко- водстве по Ant: http.//ant.apache.org/manual/CoreTasks/war.html. См. также Рецепт 4.1 по скачиванию и установке Ant; рецепт 4.2 по созданию целей Ant; рецепт 4.3 по созданию пути к классам для файла Ant; рецепт 4.4 по компиляции сервлета при помощи Ant; рецепт 4.6 по использованию Ant для создания JAR-файлов; рецепты 4.7 и 4.8 по запуску и остановке Tomcat с помощью Ant; рецепты 2.1 и 2.6 по развертыванию с помощью Ant web-приложения; руководство по Ant, раздел по задаче property: http:// ant.apache.org/manual/CoreTasks/property.html", руководство по Ant, сегмент по целям: http:// ant.apache.org/manual/usmg.htn-ilthargets', индексную страницу руководства по Ant: http://ant. apache.org/manual/index.html", проект Apache Ant: http://ant.apache.org. 4.6 Создание JAR-файла с помощью Ant Задача Создать JAR-файл при помощи Ant. Решение Используйте встроенную задачу jar. Обсуждение Задача jar автоматизирует создание JAR-файлов. Так же как задача war для W AR- файлов, задача j аг позволяет автоматизировать процесс набора командных строк, необ- ходимых для создания JAR-файла. Таким образом, сборочные файлы используют задачу jar наподобие сценария или командного файла. Спецификацию Sun Microsystems на JAR-файл можно найти в http://java.sun.coni/j2se/1.4/docs/guide/jar/jar.html. В web-приложениях JAR-файлы используются как хранилище отдельных библиотек с кодом, необходимых для работы приложения (например, JAR-файл с драйвером базы данных) Они содержаться е каталоге WEB-INFAib приложения. В примере 4.7 показана цель Ant, использующая задачу j аг для создания JAR-файла и последующего копирова- ния его в каталог lib web-приложения. Эти действия предшествуют архивированию web- приложения в WAR-файл, которое можно включить в этот же сборочный файл, для более полной автоматизации (см. рецепт 4.5 по созданию WAR-файла). 106 | Глава 4. Использование Apache Ant
Пример 4.7. Создание JAR-файла с помощью Ant f «project name="jar-task" defaults"create-jar" basedir="."> <target name="init" descriptions"Initializes some properties,"» <echo messages"Initializing properties."/» <property name="dist" values"dist" /» <property name="web" values"web" /> «property name="meta" values"meta" /> «property names'!jar-name" values"myutils" /> «/target» «target name="prepare" depends="init"> «echo messages" •Cleaning up the build and dist directories."/» «delete dir="${dist}"/» «mkdir dir="${dist}"/» «/target:» «target name*"create-jar" descriptIon*"creates a JAR archive file" depends*"prepare"» «jar destfile*"${diet}/${jar-name}.jar" basedir*"../.,/" includes*"**/".class **/${wub}/*.html"> «fileset dir*"../../images”/» </jar> «/target» «/project» Этот сборочный файл включает три цели, выполняемые в следующем порядке: ini t->prepare->create- j аг. Эти цели создают ряд свойств и очищают каталог dist, предназначенный для итогового JAR-файла. Цель create-jar вызывает задачу jar, которая выглядит следующим образом. «jar destfile="${dist}/${jar-name}.jar" basedir="../../" includes=•**/*.class **/$fweb}/*.htrnl"» «fileset dirs"../../images"/> «/jar» Создание JAR-фдйла с помощью Ant | 107
Атрибут destf lie элемента jar задает местоположение и имя создаваемого JAR- файла. Здесь используется свойство jar-name, чтобы пользователь мог выполнить этот файл Ant из командной строки и при необходимости передать новое имя JAR-файла в качестве параметра. ant -Djar-name=mynew jar.j ar Помните, что значения свойств, задаваемые с помощью переключателя -D, заменяют значения этих же свойств, заданные внутри сборочного файла. Атрибут basedir задачи jar определяет каталог верхнего уровня файлов, которые будут включены в JAR. Например шаблон ../../ означает «подняться вверх на два ката- лога относительно базового каталога данного проекта»; другими словами, подняться на два каталога вверх от каталога, в котором находится данный сборочный файл Ant. Атрибут includes имеет два шаблона, разделенных пробелом (для разделения можно использовать и запятую). Эти шаблоны предназначены для отбора файлов для включения в JAR. Первый шаблон определяет включение всех файлов с расширением .class, находя- щихся в нуле или более каталогов, внутри каталога, заданного в basedir. Таким образом, JAR-файл будет содержать все файлы классов Java из всех подкаталогов каталога из basedir; JAR включит любые вложенные каталоги, в которых будут найдены файлы классов. Второй шаблон (**/${web}/* .html) берет все подкаталоги каталога, задан- ного свойством web и включает в JAR все файлы с расширением .html. И еще раз повторю, что в JAR-файл будут включены все вложенные директории, в которых будут найдены HTML-файлы. И наконец, элемент fileset, вложенный в задачу jar, берет все содержимое ката- лога ../../ и включает его в JAR, но не включает туда сам каталог ./images. Чтобы включить не только содержимое, но сам каталог images на верхний уровень JAR, необ- ходимо переписать задачу j аг следующим образом: <jar destfile="${dist}/${jar-name}.jar" basedir="../../" includes=“**/*.class **7${web}/*.html **/imagee/*.gif*/> Здесь в атрибут includes добавлен третий шаблон (**/images/* .gif), который выбирает из всех каталогов images, вложенных в каталог, заданный в basedir, все GIF- файлы. Сами каталоги images также включается в JAR. — Тку Шаблон ** часто используется в элементах Ant, он означает ноль или более каталогов. 108 | Глава 4. Использование Apache Ant
Манифест , Если в задаче jar отсутствует атрибут manifest, то в JAR-файле будет сформирован файл META-INF/MANIFEST.MF. Этот манифест по умолчанию выглядит следующим образом: Manifest-Version: 1.0 Created-By: Apache Ant 1.5.1 Если вы хотите задать местоположение собственного файла манифеста (например для подписи JAR-файла или указания файла, содержащего метод main() в исполняемом JAR), используйте атрибут manifest задачи jar. Значением необязательного атрибута manifest может быть местоположение файла манифеста или имя другого JAR-файла, который юбавлен с помощью вложенного элемента fileset. Если это J AR-файл, дан- ная задача ищет манифест META-INF/MANIFEST.MF в нем. См. также Рецепт 4.1 по скачиванию и установке Ant; рецепт 4.2 по созданию целей Ant; рецепт 43 по созданию пути к классам для файла Ant; рецепт 4.4 по компиляции сервлета при п< »мощи Ant; рецепты 4.7 и 4.8 по запуску и остановке Tomcat с помощью Ant; рецепты 2.1 и 2.6 ло развертыванию с помощью Ant web-приложения; руководство по Ant, раздел по задаче property: http://ant.opache.org/manual/CoreTasks/property.html', руководство по Ant, сег- мент по целям: http://ant.apache.Org/manual/using.html#targets', индексную страницу руково- дства по Ant: http://ant.apache.org/nianual/index.html', проект Apache Ant: http://ant.apache.org. I 4.7 Запуск с помощью Ant приложения на Tomcat Задача Создать файл Ant для запуска web-приложения на Tomcat. Решение Используйте поддерживаемую Tomcat задачу StartTask, с помощью которой Ant может управлять сервером Tomcat. Обсуждение Tomcat, являющийся контейнером для сервлетов и JSP, включает встроенное web- приложение «Менеджер», которое можно использовать для запуска, остановки, развертывания и выполнения других административных задач в отношении web-приложе- ний. Путь к контексту этого приложения: /manager. ___________________ i__________________'____, Запуск с помощью Ant приложения на Tomcat | 109
Tomcat версии 4 (и более поздних) включает Java-классы, позволяющие разработчикам Использовать приложение «Менеджер» из сборочных файлов Ant. Преимущество исполь- зования из Ant приложения «Менеджер» в том, что в этом случае не требуется кон- фигурировать файл conf/server.xml, чтобы сделать web-приложение перезагружаемым динамически (см. рецепт 2.2). Кроме того, можно запускать и останавливать отдельное web-приложение, не затрагивая других приложений Tomcat. Документация по «Менеджеру» находится в http://jakarta.apache.org/tomcat/tomcat-4.l- doc/printer/manager-howto.html. Ниже представлена последовательность запуска Tomcat из Ant. 1. Убедитесь в наличии JAR-файла, необходимого для задачи запуска Tomcat: <Инстал- ляционный-католог-Anr^/lib/catalina-ant.jar. При необходимости скопируйте этот файл из каталога <инсталляц1юнный-каталог-Тотса1>/зегуегЛ1Ь в свой каталог <Инсталля- ционный-катсъ1ог-Апг>/НЬ (известный K3X.ANT_H0MEAib). 2. Убедитесь, что база данных пользователей Tomcat включает имя пользователя, которому назначена роль manager. Запускать и останавливать web-приложение с помощью инструмента «Менеджер» могут лишь пользователи-администраторы. Отображение пользователей и паролей на рбли задается в файле conf/tomcat-users.xml. Только пользова- • тель с ролью manager может использовать инструмент «Менеджер». Вот пример соответ- ствующей записи в файле conf/tomcat-users.xml. «user usemame="doug" passwords "_1968dgw" roles="manager,dbadmin"/> 3. В файле Ant, используя элемент taskdef, определите пользовательскую задачу и присвойте ей имя. В примере 4.8 этой задаче присваивается имя start, и это имя затем используется в цели, предназначенной для запуска Tomcat. 4. Выполните этот файл Ant из командной строки, для чего перейдите в каталог с этим файлом и напечатайте ant. Пример 4.8 показывает элемент taskdef, определяющий задачу start, за которым следует цель, запускающая заданное приложение Tomcat. Пример 4.8. Запуск Tomcat при помощи файла Ant •«project name="My Project" defaults"start-tomcat" basedir="."> «taskdef names"start” classnames"org.apache.catalina.ant.StartTask" /> <1— импортируем свойства задающие имя и пароль пользователя, url, и путь к контексту —> «property file*"global.properties" /> «target name-*” start -tomcat"' descriptions"Starts the Web application"» «echo messages"Starting the default application ${ context-path}..."/> «start 110 | Глава 4. Использование Apache Ant
url»"${url}" userndst-" >" $ {usernams) " password»"$(password)" path»"/$(context-path}" /> , </target> </project» Задача start имеет четыре атрибута, значения которых в примере 4.8 устанавливаются в файле global.properties. Ниже приведен этот текстовый файл, содержащий четыре пары ймя/значение, которые импортируются в файл Ant с помощью задачи property. <property file="global.properties- /> Файл globaLproperties размещается в том же каталоге, что и сборочный файл Ant. Вот его содержимое. url=http://localhost:8080/manager usemame=bruce f password=brucel957 context-path=home Свойство url задает URL «Менеджера» Tomcat, username и password определяют пользователя, которому в базе данных пользователей присвоена роль manager, свойство context-path задает путь к контексту web-приложения, которое вы запускаете, и сам файл Ant добавляет к этому пути символ слеш (Г). Другой способ передачи значений свойств в файл Ant - указать их в командной строке. —ЦА* ant -Dusername=bruce -Dpassword=brucel957 -Durl=http://localhost:8080/manager -□context -path=home Значения свойств из командной строки замещают те значения, что были заданы в задаче property. Выполните данный файл Ant, для чего перейдите в каталог, где он находится, и напечатайте в командной строке ant или ant -buidfile <имя командного файла». Ниже приведена такая командная строка и вывод результатов ее работы. Н:\book\cookbook\code\chap4>ant .-buildfile start.xml Buildfile: start.xml start-tomcat: [echo] Starting the default application home... [start] О1Г- Started application'at context path /home BUILD SUCCESSFUL Total. time: 4 seconds Запуск с помощью Ant приложения на Tomcat | 111
Когда приложение остановлено, оно недоступно для web-пользователей (см. рецепт 4.8). Когда приложение запущено вновь, оно может нормально принимать запросы. Приложение «Менеджер» Tomcat может инициировать многие другие обще- yJV 4 ж административные задачи, например развертывание приложений (см. рецепт 2.6). См. также Описание приложения «Менеджер» Tomcat hftp://jakarta.apache.org/tomcat/tomcat-4.1- doc/manager-howto.html', рецепт 4.1 по скачиванию и установке Ant; рецепт 4.2 по соз- данию целей Ant; рецепт 4.3 по созданию пути к классам для файла Ant; рецепт 4.4 по ком- пиляции сервлета при помощи Ant; рецепты 4.5 и 4.6 по созданию WAR и JAR файлов; рецепт 4.8 по остановке Tomcat с помощью Ant; рецепты 2.1 и 2.6 по развертыванию с помощью Ant web-приложения; руководство по Ant, раздел дю задаче property: http:// ant.apache.org/manual/CoreTasks/property.html-, руководство по Ant, сегмент по целям: http:/ /ant.apache.org/manual/using.html^argets', индексную страницу руководства по Ant: http:// ant.apache.org/manual/index.htmh, проект Apache Ant: http://ant.apache.org. \ 4.8 Остановка Tomcat с помощью Ant Задача С помощью Ant остановить определенное web-приложение. Решение В файле Ant, с помощью элемента taskdef определите соответствующую задачу и Java-класс org. apache. catalina. ant. StopTask. / Обсуждение В ходе разработки может потребоваться остановить web-приложение, работающее на Tomcat, например, для того чтобы добавить новые сервлеты или записи в дескрипторе развертывания, а затем снова запустить его. чтобы внесенные изменения начали дейст- вовать. В случае отсутствия настройки conf/server.xml, делающей данное приложение динамически перезагружаемым (см. рецепт 2.2), для остановки одного web-приложения без ущерба для остальных, можно использовать соответствующую цель Ant. Этот процесс - противоположность процессу запуска приложения (рецепт 4,7), при этом приложение прекращает работу До тех пор, пока его не запустят вновь. 112 | Глава 4. Использование Apache Ant
Класс org.apache;catalina.ant.StopTask обеспечивает связь между Ant и приложением «Менеджер» Tomcat. «Менеджер» - встроенное web-приложение (путь к контексту /manager), которое можно использовать для администрирования, других web- приложений. Следующие четыре шага, знакомые вам по рецепту 4.7, необходимы для использова- ния задачи stop. . 1. Убедитесь в наличии JAR-файла, необходимого для остановки Tomcat: <Инсталля- ционный-каталог-Ап1>/ИЬ/са1аНпа-ап1./аг. При необходимости скопируйте этот файл , из каталога <инсталляционный-каталог-Тотса1>/зегуег/Ш> в свой каталог <Инстал- ляционный-каталог-Ап1>Л1Ь (известный KaxANT^HOMEAib). 2. Убедитесь, что база данных пользователей Tomcat включает имя пользователя, которому назначена роль manage г (см. шаг 2 рецепта 4.7, если Требуются детали). 3. В примере 4.9, с помощью элемента taskclef этой задаче присваивается имя stop и это имя затем используется в цели, предназначенной для остановки Tomcat 4. Выполните файл Ant из командной строки, для чего перейдите в каталог с этим фай- лом и напечатайте ant или ant -buildfile «имя сборочного файла>.' Пример 4.9. Использование Ant для остановки web-приложения «project name="My Project” default""stop-tomcat* basedir-"."> «taskdef naiue»"stop" classname»"erg.apache.catalina.ant.StopTark" /> <! — импортируем свойства задающие имя и пароль пользователя, url, и путь к контексту —> «property file""global.properties" /> «target name"”stop-tomcat" description""Stops the Web application”» «echo message""Stopping the application $(context-path}..."/> «stop url»"$(url}" username" " $ {username} " password""${password}" path"”/${context-path}" /> «/target» ' «/project» Элемент taskdef определяет для сборочного файла задачу под названием stop. Эта задача используется далее в сборочном файле. «stop url=" $ {url}" usemame=" $ {username}" password"" $ {password}" path""/${context-path}" /> Остановка Tomcat с помощью Ant | 113
Значения свойств в примере 4.9 извлекаются в задаче property, из файла global, properties (файл свойств, находящийся в том же каталоге, что и сборочный файл). Эти свойства представляют: • имя и пароль пользователя, которому в conf/tomcat-users.xml присвоена роль manager* • URL приложения «Менеджер» (например, http://localhost:8080/manager); • путь к контексту останавливаемого web-приложения. Приложение «Менеджер» Tomcat может инициировать множество других административных задач, например развертывание приложений (см. рецепт 2.6). См. также Описание приложения «Менеджер» Tomcat http://jakarta.apache.org/tomcat/tomcat-4.l- doc/manager-howto.html; рецепт 4.1 по скачиванию и установке Ant; рецепт 4.2 по соз- данию целей Ant; рецепт 4.3 по созданию пути к классам для файла Ant; рецепт 4.4 по ком- пиляции сервлета при помощи Ant; рецепты 4.5 и 4.6 по созданию WAR и JAR файлов; рецепт 4.7 по запуску Tomcat с помощью Ant; рецепты 2.1 и 2.6 по развертыванию с помощью Ant web-приложения; руководство по Ant, раздел по задаче property: http:// ant.apache.org/manual/CoreTasks/property.html; руководство по Ant, сегмент по целям: http:/ /ant.apache.org/manual/using.htmVhargets; индексную страницу руководства по Ant http:// ant.apache.org/manual/index.html; проект Apache Ant: http://ant.apache.org. 114 | Глава 4. Использование Apache Ant
. . , i: .. . . ГЛАВА5 Различные форматы страниц JSP • = "j f 5.0 Введение Данная глава описывает два способа работы с JSP, которые слегка выходят за рамки обычного подхода. Первый способ - прекомпиляция JSP для превращения ее в исходный код сервлета* Второй - разработка JSP в формате XML-документа. Прекомпиляция JSP Прекомпиляция (предварительная компиляция) JSP включает использование предоставляемого сервером инструмента командной строки для преобразования страницы JSP в файл с классом сервлета. Страница JSP преобразуется в сервлет, часто называемый классом реализации JSP (JavaServer Page implementation class), до того как она начнет обрабатывать какие-либо НТГР-вапросы В спецификации JSP стадия, на которой контейнер JSP преобразует синтаксис страницы JSP в сервлет, называется фазой трансляции (translation phase). В Tomcat, если вы хотите посмотреть, как выглядит класс реализации JSP, получаемый после преобразования, обратитесь к каталогу <инсталчяционный-каталог-ТотсаГ>/ыогк/51апс1а1опе/<имя хоста>/<имя ыеЬ-приложения>, где <имя хоста> - localhost или другое имя хоста, где работает Tomcat, <имя у\>еЬ-приложения> - это также и имя контекста, которое обычно выглядит так: examples, ROOT или storefront. Указанный каталог содержит файлы с расширением Java, такие, как default-jsp. java. Это файлы с исходным Java-кодом, которые затем компилируются в файл классов и после выполняются как сервлеты, и отвечают на запросы. К причинам, побуждающим разработчиков прекомпилировать страницы JSP, относятся: 1. желание избежать ощутимой задержки при поступлении первого запроса от web- . контейнера, во время которой компилятор JSP преобразует исходный код JSP в сервлет; 2. возможность посмотреть исходный Java-код класса реализации JSP и, воз- можно,, поработать над ним в редакторе интегрированной среды разработки сервлетов (IDE). ( И в Tomcat, и в WebLogic для прекомпиляции JSP может использоваться инструмент, запускаемый из командной строки. В рецепте 5.4 показано, как в web. xml странице JSP поставить в соответствие ее класс реализации. 115 \
JSP в формате XML-документа Заключительные рецепты данной главы описывают создание JSP в виде XML-файлов. Спецификация JSP, версии 1.2 и версии 2.0 описывает создание и использование JSP в формате XML-документов. Это значит, что помимо создания JSP в обычном синтаксисе их можно кодировать в виде правильных XML-документов. Согласно спецификации, JSP- документ - это XML-документ с определенным пространством имен. Контейнер JSP определяет, что имеет дело с JSP-документом, а не с обычной страницей JSP, по крайней мере, одним из трех способов. 1, В файле web.xml элемент j sp-property-group имеет дочерний элемент is-xml. (Элемент j sp-property-group является одним из элементов конфигурирования JSP, которые предлагает добавить в web.xml спецификация JSP версии 2.0.) 2. Сам файл имеет расширение Jspx. 3. Страница имеет корневой элемент j sp: root. В рецепте 5.5 показано, как выглядят эти файлы. Спецификация JSP назывет представление страницы JSP в виде XML-документа XML- представлением (XML view). XML-представление генерирует контейнер JSP во время фазы трансляции. XML-представление может использоваться подклассом javax.servlet, jsp. tagext.TagLibraryValidator для синтаксического анализа JSP с целью проверки правильности использования пользовательских тегов, перед тем как контейнер наконец преобразует JSP в класс реализации страницы (в сервлет). Процесс генерации XML- представления и сохранения полученного XML-файла описан в рецепте 5.6. Существуют, в частности, следующие причины создавать JSP в виде XML-файлов (JSP-документов). 1. Web-контейнеры способны взаимодействовать с JSP-документами, входящими в web- приложение, то есть web-приложение может включать XML-файлы вместо страниц JSP с традиционным синтаксисом. Таким образом, JSP-документы можно интегрировать с прочим XML-содержимым (XHTML-файлами, масштабируемой векторной графикой (SVG) и XML-файлами, связанными с транзакциями web-сервисов). 2. Для работы с JSP-документами можно использовать редакторы XML. 3. С JSP-документами можно использовать другие XML-технологии, например XSLT, SOAP, SAX и DOM. 116 | Глава 5. Различные форматы страниц JSP
5.1 Прекомпиляция JSP в Tomcat Задача Используя Tomcat 4.1.x, преобразовать JSP в сервлет. Решение Воспользуйтесь инструментом командной строки JspC, находящимся в <инсталляци- оннъ'й-каталог-ТотсаГ>/Ьй1. Обсуждение Использование инструмента JspC, запускаемого из командной строки - первый шаг в прекомпиляции JSP на Tomcat. Для Unix этот инструмент предоставляется в форме сценария оболочки - jspc.sh, для Windows - в форме командного файла jspc.bat, он создает исходные Java-файла с классами реализации страниц JSP. Затем эти итоговые файлы .java компилировать в классы сервлетов, используя javac или другой компилятор с Java. Таким образом, прекомпиляция JSP - процесс, состоящий из двух шагов, и имеет смысл автоматизировать его с помощью командного файла. Однако разберемся сначала с тем, как использовать утилиту JspC. Командному файлу запуска JspC под Windows \<инсталляционный-каталог-Тотсаг>/ bin/jspc.bat) требуется, чтобы переменная окружения JASPER_HOME содержала путь к инсталляционному каталогу Tomcat. Значение этой переменной устанавливается с помощью следующей командной строки. set JASPER_HOME=k:\jakarta-tomcat-4.1.12 Для запуска утилиты JspC перейдите в каталог %JASPER±HOMEc/tJ>in и напечатайте следующую команду (указав свои собственные значения путей). jspc -d H:\book\cookbook -webinc H:\book\cCokbook\map.xml -webapp h:\book\cookbook\dist Здесь переключатель -d задает каталог, в который необходимо поместить сгенерирован- ные файлы с исходным кодом, переключатель -webinc задает имя автоматически, генерируемого файла, в котором JspC создает элементы servlet и servlet-mapping для получаемых файлов сервлетов. Если вы компилируете страницу с именем precomp.jsp, эти элементы для отображения будут выглядеть так, как показано в примере 5.1. Пример 5.1. Отображение сервлета для прекомпилированной страницы JSP <servlet> <servlet-naine>org. apache. j sp .precorap_j sp</servlet-name> <servlet-class>org.apache.jsp.precomp_j sp</servlet-class> </servlet> Прекомпиляция JSP в Tomcat | 117
<servlet-mapping> <servlet-name>org.apache.jsp.precomp_j sp</serVlet-name> <url-pat tem> /precomp. j sp< /url -pattern> </servlet-mapping> После этого данные элементы можно скопировать и вставить в дескриптор развертывания web.xml своего приложения. Переключатель -webapp задает каталог web-приложения, который должен иметь под- каталог /WEB-INF, содержащий файл web.xml вашего приложения. JspC находит в указан- ном каталоге верхнего уровня web-приложения все файлы .jsp и транслирует их в файлы с исходным кодом сервлетов, вместе со страницами JSP из вложенных подкаталогов. Полученные в итоге файлы Java размещаются в каталоге, заданном в переключателе -d. В отличие от -webinc, переключатель -webxml создает полный файл web.xml, в который включены вновь созданные сервлеты и отображения для этих сервлетов. Другие возмож- ности JspC описаны в http://cvs.apache.Org/viewcvs/-checkout~/jakarta-tonicat-4.0/jasper/doc/ jspc.html. Далее необходимо откомпилировать сгенерированные исходные файлы. Для того чтобы выполнить оба шага за один раз, рекомендую использовать командный файл. В примере 5.2 приведен командный файл Windows, генерирующий исходные файлы сервлетов и затем, с помощью javac, компилирующий их. Пример 5.2. Использование командного файла для прекомпиляции JSP под Tomcat @echo off jspc -d H:\book\cookbook\classes -webinc H:\book\cookbook\map.xml -webapp h:\book\cookbook\dist set PRECLASSPATH=%CATALINA_HOME%\common\lib\servlet.jar; %CATALINA_HOME%\common\lib\jasper-runtime.jar;%CLASSPATH% javac -classpath %PRECLASSPATH% -d ./classes *.java Сохраните этот текст в текстовом файле, например с именем precomp.bat. Перейдите в каталог, содержащий данный командный файл, и напечатайте precomp. Файл выполнит команду JspC для всех .jsp файлов, находящихся ниже каталога web-приложения h:\bookx cookboolddist. Поскольку используется переключатель -webinc, команда создает фрагмент XML, содержащий элементы servlet и servlet-mapping. Если не было ошибок, преобразованные файлы сохраняются в каталоге h:\boohcookbooldclasses. Затем создается переменная окружения PRECLASSPATH, подключающая компо- ненты servlet.jar и jasper-runtime.jar, вместе с любыми каталогами или JAR, являющимися частью существующей переменной окружения CLASSPATH. Компонент servlet.jar необходим во время компиляции для импорта следующих пакетов Java: • javax.servler; • javax.servlet.http; ' • javax.servlet.jsp. 118 | Глава 5. Различные форматы страниц JSP
Добавление jasper-runtime.jar необходимо для импорта пакета org. apache. j asper. runtime. Под Windows, для успешного выполнения данного командного файла, необхо- димо значением переменной окружения JASPER-HOME сделать инсталляционный каталог Tomcat. Сценарий, выполняющий те же задачи в Unix, приведен в примере 5.3. Данный сценарий запускает находящийся в каталоге /Ып сервера Tomcat файл jspc.sh, преком- пилирующий все файлы JSP, которые JspC найдет в текущем каталоге. Полученные файлы .java сценарий сохраняет в каталоге ./classes. Пример 5.3. Сценарий оболочки для прекомпиляции JSP #!/bin/sh.. $CATALINA_JiOME/bin/jspc.sh -d ./classes -webinc ./map.xifii -webapp ./; PRECLASSPATH=$CATALINA_HOME/common/lib/servlet. jar: $CATALINA_HOME/common/ lib/jasper-runtime.jar; export PRECLASSPATH; javac -classpath $PRECLASSPATH -d ./classes ./classes/*.java См. также Рецепт 5.3 по протоколу прекомпиляции; рецепт 5.4 по отображению компилирован- ных JSP в web.xml\ раздел по прекомпиляции JSP книги Hans Bergsten «JavaServer Pages» (O'Reilly); главу JSP. 11.4 спецификаций JSP версии 2.0. 5.2 Прекомпиляция JSP в WebLogic Задача Прекомпилировать JSP на сервере WebLogic. Решение Воспользуйтесь Java-утилитой weblogic.jspc, инсталлируемой вместе с сервером WebLogic. Обсуждение В WebLogic имеется собственная утилита для прекомпиляции JSP: weblogic.jspc. Эта утилита - часть файла JAR, находящегося в <UHcmajuixyuoHHbiu-Kamaxo2-WebLogic>/ weblogic700/serverflib/weblogic.jar. При прекомпиляции страниц JSP с помощью weblogic, jspc эта утилита помещает итоговые файлы классов в указанный ей каталог. В примере 5.4 показан простой командный файл для Windows NT, прекомпилирующий страницу example, jsp в класс реализации. Прекомпиляция JSP в WebLogic | 119
Пример 5.4. Прекомпиляция JSP с помощью weblogic.jspc @echo off , ' set WLCLASSJ?ATH=k: \bea\weblogic700\server\lib\weblogic.jar;%CLASSPATH% java -cp %WLCLASSPATH% weblogic.jspc -d .\classes example.jsp Во второй строке формируется значение переменной окружения WLCLASSPATH. Это значение включает путь к weblogic.jspc и значение переменной CLASSPATH. В следующей строке полученный комбинированный путь используется для запуска weblogic.jspc. Переключателе -d определяет место сохранения итоговых файлов классов, в данном случае это каталог classes находящийся в каталоге с командным файлом и файлом example.jsp. В результате генерируется файл jsp_servlet._ ^example.class с Java-классом (включается имя ' пакета). Если вы не указали пакет для компилируемого сервлета, то по умолчанию в качестве имени пакета используется j sp_serviet (см. пример 5.6). В примере 5.5 пока- зан сценарий оболочки, написанный для Mac OS, который прекомпилирует JSP с помощью среды WebLogic. Пример 5.5. Прекомпиляция страниц JSP с помощью weblogic.jspc и сценария оболочки #!/bin/sh WLCLASSPATH=/Users/bruceper/java/weblogic_jar/weblogic. jar: $CLASSPATH; export WLCLASSPATH; java -cp $WLCLASSPATH weblogic.jspc -d /Users/bruceper/books/cookbook/code/chap5/classes newfile.jsp ' В отличие от утилиты JspC в Tomcat, weblogic.jspc компилирует файл с синтаксисом страницы JSP в файл класса за одну операцию. Тогда как использование JspC ** f £ из командной строки требует последующего запуска компилятора (например, j avac) для компиляции файлов .java в файлы классов. При использовании weblOgic. jspc компиляция выполняется автоматически. Командный файл для Windows, приведенный в примере 5.6, для всех страниц JSP, найденных в web-приложении, указанном переключателем -webapp, задает пакет jsps- ervletcookbook. Пример 5.6. Использование weblogic.jspc для прекомпиляции всех страниц JSP web-приложения 6echo off set WLCLASSPATH=k i^beaXweblogic?00\server\lib\weblogic.jar;%CLASSPATH% java -cp %WLCLASSPATH% weblogic.jspc -d .\classes -package jspservletcook- book -compileAll -webapp h:/home В примере 5-7 показан сценарий оболочки, выполняющий ту же работу в Unix. Пример 5.7. Прекомпиляция всех страниц JSP web-приложения с помощью сценария оболочки #1/bin/sh WLCLASSPATH=7Users/bruceper/java/weblogic_j ar/weblogic. jar: $CLASSPATH; export WLCLASSPATH; 120 | Глава 5. Различные форматы страниц JSP
Обратите внимание на следующий набор инструкций из приведенного примера. -compileAll -webapp h:/home Переключатель —compileAll вместе с аргументом -webapp просит weblogic.jspc декомпилировать все файлы JSP, найденные в web-приложении, размещенном в каталоге h:/home, включая JSP-файлы из вложенных подкаталогов. Это web-приложение находится r формате «развернутых каталогов» (не архивировано в WAR-файле). В примере 5.6 откомпилированные классы записываются в K3Lrasior\classes^spservletcookbook. См. также Рецепт 5.3 по протоколу прекомпиляции; рецепт 5.4 по отображению компилирован- ных JSP в web.xml-, раздел по прекомпиляции JSP книги Hans Bergsten «JavaServer Pages» (O'Reilly); главу JSP.l 1.4 спецификации JSP версии 2.0. 5.3 Прекомпиляция JSP с помощью протокола прекомпиляции Задача Вы хотите использовать «протокол прекомпиляции», являющийся частью специфи- кации JSP, для прекомпиляции одного или нескольких файлов JSP. Решение Направьте контейнеру JSP запрос, включающий параметр jsp_precompile. * ' Обсуждение Спецификация JSP версий 1.2 и 2.0 требует от контейнеров JSP поддержки параметра запроса jsp_precompile. Данный параметр подразумевает прекомпиляцию запраши- ваемой страницы JSP. В Tomcat это работает следующим образом: 1. Запросите страницу JSP, которую хотите декомпилировать, добавив к URL параметр jsp_precompile, например http://localhost:8080/home/url_rewrite.jsp?jsp_ргесот- pile=true. Контейнер JSP не станет выполнять запрошенную страницу, он только преком- пилируетее В результе запроса, сделанного из браузера, в браузере отобразится пустая страница. Прекомпиляция JSP с помощью протокола прекомпиляции | 121
2. Если JSP-файл с синтаксисом страницы JSP еще не был скомпилирован или если после компиляции в него были внесены изменения, Tomcat создаст для этой страницы в каталоге <инсталляционный-каталог-Тотса1>Л^огк новые файлы - один с исходным текстом на Java, другой -* с Java-классрм. Для JSP-файла с именем url_rewrite.jsp Tomcat создаст файлы с именами url_rewriteJsp.java и url_rewrite_jsp.class. Подразумевается, что запрос (С параметром isp_precompile (без части «=true») эквивалентен запросу с параметром j sp_precompile=true. * •' В Tomcat протокол прекомпиляции создает как файл java, так и результат его л компиляции - класс реализации страницы. Инструмент JspC (см. рецепт 5.1) ' '* f $ позволяет создать лишь файл Java/ Описываемый протокол лучше всего использовать совместно с каким-либо инструмен- том автоматизации, способным создавать HTTP-запросы, например с компонентом Jakarta Commons HttpClient. Это позволит автоматизировать процесс прекомпиляции множе- ства JSP страниц, послав несколько НТТРтапросов из единственной Java-программы. См. также Рецепты 5.1 по использованию Tomcat-утилиты JspC\ рецепт 5.2 по прекомпиляции на сервере WebLogic; рецепт 5.4 по отображению откомпилированных страниц в web.xml' 1 лаву 7 по отправлению HTTP-запросов из сервлетов или JSP; домашнюю страницу компо- нента Jakarta Commons HttpClient: http://jakarta.apache.org/commons^ttpdrcnt/; раздел по прекомпиляции JSP книги Hans Bergsten «JavaServer Pages» (O’Reilly); главу JSP. 11.4 спецификации JSP версии 2.0. 5.4 Отображение страницы JSP на соответствующий ей класс реализации страницы Задача Имеется прекомпилированная страница JSP, необходимо в дескрипторе развертывания задать отображение обращений к этой странице на соответствующей ей класс реализации. Решение V Скопируйте элементы servlet и servlet-mapping, автоматически сгенерирован- ные утилитой JspC, и вставьте их в web.xml. Создайте в каталоге WEB-INF/classes своего приложения необходимые каталоги, связанные с пакетом и поместите в этот же каталог . прекомпилированные станины JSP. 122 | Глава 5. Различные форматы страниц JSP
Обсуждение Прекомпиляция JSP позволяет убрать из web-приложения все файлы с синтаксисом JSP и Оставить только итоговые файлы с классами сервлетов. После этого, используя элемент servlet-mapping файла web.xml, .ложно отобразить URL в стиле ссылки нгг JSP (например, default.jsp) на откомпилированные классы сервлетов. Вот как решается эта задача. 1. Прекомпилируйте страницы JSP (см. рецепты 5.1 и 5.2), включая компиляцию исход- ных Java-файлов в файлы классов с помощью javac или другого компилятора. 2. Скопируйте автоматически сгенерированные утититой JspC элементы servlet- mapping и servlet-mapping в дескриптор развертывания (если используется Tomcat) или добавьте эти элементы в web.xml вручную (если используется WebLogic или иной контейнер). 3. Удостоверьтесь, что элемент url-pattern в элементе servlet-mapping содержит имя файла в сти те JSP, например default.jsp, или отображение расширений, например *.jsp. 4. Поместите класс или классы, включая связанные с пакетом каталоги, в WEB-INF/ classes или в JAR-файл, находящийся в WEB-INF/lib. Когда web-пользователь запросит URL, заданный в элементе servlet-mapping класса реализации страницы, web-контейнер направит этот запрос к данному классу сервлета. Пример 5.8 демонстрирует конфигурацию сервлета для прекомпилированнои страницы JSP. Пример 5.8. Записи web.xml, относящиеся к прекомпилированнои JSP <servlet> <servlet-hame>org.apache.j sp.precomp_j sp</servlet-name> <servlet-class>org. apache, jsp-. precomp_jsp</servlet-ciassV </servlet> <servlet-mapping> <servlet-name>org. apache. j sp .precomp_j sp< Zserviet-name> <url-pattern>/precomp.j sp</urlxpattern> </servlet-mapping> В web-приложении структура каталогов для этого’ класса будет выглядеть примерно так: /WEB-INF/classes/org/apache/jsp/precompJsp.class. Если путь к контексту web-прило- жения /home, то пользователи moi у г обращаться к этому классу реализации JSP (скрытому сервлету) с помощью (JRL типа http://localhostr8080/home/precomp.jsp. См. также Рецепты 5.1-5.3; главу JSP.11.4 спецификации JSP версии 2.0. Отображение страницы JSP на соответствующий ей класс реализации страницы | 123
„ 5.5 Создание JSP в виде JSP-документа «с нуля» Задача Создать JSP-документ с помощью редактора XML. Решение Откройте редактор XML и создайте JSP используя только XML-элементы. Обсуждение JSP-документ - это ссылающийся на определенное пространство имен, корректно сформированный XML-файл, содержащий стандартные действия JSP (например, jsp: include и jsp: useBean), пользовательские действия (например, пользовательские теги JSTL) и XML-эквиваленты директив JSP. В табл. 5.1 приведены XML-эквиваленты общих директив JSP. Для создания JSP используйте такой редактор XML, с помощью которого можно проверить корректность полученного документа. Для того чтобы JSP-документ можно было поместить на выполнение в контейнер JSP, он должен быть корректным XML-документом. Табл. 5.1. XML-эквиваленты директив JSP Директива Пример page <%@ page import="java. util.Date" %> Эквивалент в JSP-документе <jsp:directive, page import="java. util.Date" /> include <%& include file="footer.html" %> <j sp: direc tive. incl ude file-"footer.html" /> taglib <%0 taglib uri="WEB- TNF/tlds/xml gen.tld" prefix=”t" .%> <jsp:root jsp:id="0" xmlns: jsp="http://java.sun.com/JSP/Page" version-"2.0” xmlns:t="urn:jsptld: /WEB-INF/tlds/xml_gen.tld"> В JSP 1.2 Единственным способом определения того, что страница JSP сформирована в XML-формате, было наличие корневого элемента j sp: root. Однако в JSP 2.0 2 добавилось несколько дополнительных опций - теперь JSP-документ можно * отличить от страницы JSP не XML-формата по наличию в дескрипторе развертывания элемента jsp-property-group, по расширению файла .jspx или по корневому элементу j sp: root. В данном рецепте сравнивается простая страница JSP и ее XML-эквивалент, затем сравнение повторяется после добавления пользовательского тега и выражения, вычисляемого на этапе выполнения (в атрибут JSP-элёмента). В примере 5.9 приведен простой файл с синтаксисом страницы JSP, показывающий местное время сервера. 124 | Глава 5. Различные форматы страниц JSP
Пример 5.9. Простой файл с синтаксисом страницы JSP <%@page contentType="text/html"%> <%@page import="java.util.Date"%> <html> <headxtitle>Welcome to the Web</titlex/head> <body> <h2>Welcome to the Web</h2> The' server's local time is <%=new Date() %>. </body> </html> Данная страница JSP содержит две директивы и JSP-выражение, Отображающее строку с датой и временем в браузере. Копируя код из этой страницы и вставляя его в редакторе XML в новый файл, с заменой не XML конструкций на элементы XML, можно преобразо- вать эту страницу в JSP-документ. В примере 5.10 приведен JSP-документ, эквивалентный странице из примера 5.9. Рис. 5.1. Простая страница JSP до преобразования в XML Пример 5.10. Простой JSP-документ с корректным XML-форматом < j sp:root xmlns:jsp="http: / / java.sun.com/JSP/Page" version="2.0"> <jsp:directive.page contentType="text/html"/> 4 < j sp:directive.page import="j ava.util.Date"/> <html> • <head><title>Welcome to the Web</titlex/head> <body> <h2>Welcome to the Web</h2> ' The server's local time is <jsp:expression>new Date()</jsp:expression>. </body> </html> </jsp:root> Создание JSP в виде JSP-документа «с нуля» | 125
Код из примера 5.10, вместо традиционных директив JSP, имеющих недопустимый в XML синтаксис элементов с <%@, включает элементы j sp: directive .page. Все, «го в странице JSP, имеет ограничители в стиле <%, не может использоваться в JSP-документе, в противном случае документ не пройде г Проверку на корректность формата XML. В примере 5.11 приведена более сложная .страница JSP, с директивой taglib, задающей библиотеку тегов ядра из JSTL 1.0; на этой странице также использован код на языке выражений (Expression language - EL). Кроме того,.здесь имеется элемент jsp: useBean, устанавливающий областью видимости переменной dateString из java, util. Date данную страницу. .. Пример 5.11. Страница JSP, требующая сложного преобразования в XML <%@page contentType="text/html"S> у <%@ .taglib uri="http://java. sun. сот/jstl'/core” prefix="c" %> <html> ' I-? . i5 <head>s;title>Welcbrne to the Web</title></head> <body> <h2>Welcome to the VJeb</h2> Hello, <c:out value="$ {param, firstName} ${param. last Name}"/><br><br> <jsp:useBean id="dateString" class="java.util-Date"/> The time is <c:out value="${dateString}" />.<brxbr> The value of 10 + 24 +35 = <c:out value="${10 + 24 + 35}" /> </body> </html> В примере 5.12 представлена та же страница, преобразованная в JSP-документ. Пример 5.12. JSP-документ, ссылающийся на библиотеки тегов (taglib) _ <j sp:root xmlns:j sp="http://java.sun.com/JSP/Page" xmlns:c="http://java.sun.com/jstl/gore" version="2.0"> <jsp:directive.page contentType="text/html"/> , <html> *r <head><title>Welcome to the Web</titlex/head> <body> <h2>Welcome to the Web</h2> <jsp:text>HeJlo </jsp:text> <c:out value="$ {param. firstName} $ {param. lastName}"/><brx/brxbrx/br>! <jsp:useBean id="dateString" class-?java.util.Date"/> <jsp:text>The time is </jsp: text xc: out value="${dateString}" />. <brx/brxbr ></br> <jsp:text>The value of 10 + 24 + 35 = </jsp:text> <^c:out value="${10 + 24 + 35}" /> ) </body> </html> </jsp:root>> ’ , 126 | Глава 5, Различные форматы стрг ниц JSP t
В JSP-документе любые библиотеки тегов можно подключать как атрибуты пространства имен, как это сделано в элементе jsp: root, приведенном ниже. < j sp:root xmlns:j sp="http://java.sun.com/JSP/Page * xmlns :c?=*http: //java.sun.com/jstl/core" version="2.0"> Элемент j sp: text можно использовать для хранения в JSP-документе любых шаб- лонных данных. Стандартные действия JSP (например, jsp:useBean) и пользователь- ские теги (например, с: out) можно использовать в JSP-документе с тем же синтаксисом, что и для традиционной страницы JSP. j На рис. 5.2 показано отображение JSP-документа из примера 5,12 в браузере. К этой странице мОжно обратиться, используя URL - http:/flocalhost:8080/home/example_xml2. jsp ?firstName=Bruce&lastName=Perry. t Рис. 5.2. Вид JSP-документа из примера 5.11 в браузере А вот как выглядит исходный код HTML, если в меню браузера выбрать «Вид -> в виде HTML» (с некоторыми корректировками для улучшения читаемости). <htmlxheadxtitle>Welcome to the Web</titlex/head> <body> <h2>Welcome to the Web</h2> Hello Binice Perry<br/xbr/> The time is Mon Feb 10 16:20:05 EST 2003 .<br/xbr/> The value of 10 + 24 + 35 = 69 </body></html> См. также Рецепт 5.6 по генерированию XML-представления страницы JSP; главу JSP.6 (JSP-доку- менты) спецификации JSP версии 2.0, главу JSP.10 (XML-представление) спецификации JSP версии 2.0.' Создание JSP в виде JSP-документа <с нуля» | 127
5.6 Генерирование XML-представления страницы JSP Задача Автоматически сгенерировать XML-представление страницы JSP. Решение Создайте пользовательский тег и класс TagLibraryValidator, с помощью которых можно вывести XML-представление страницы JSP в файл. Обсуждение XML-представление - это представление страницы JSP в формате XML, которое генерируется контейнером JSP в фазе трансляции, промежуточная стадия перед тем, как контейнер преобразует JSP в класс реализации страницы (в сервлет). Класс TagLibrary- Validator может использовать XML-представление для проверки корректности исполь- зования в JSP пользфвательских тегов, перед тем как JSP превратится в сервлет. XML- представление очень похоже на JSP-документ (страницу JSP в формате XML), создавае- мый разработчиком вручную для включения в web-приложение. Согласно спецификации JSP 2.0 различия между этими двумя XML-файлами заключаются в следующем. • В XML-представлении развернуты все директивы include, а в соответствующих фрагментах JSP-документа эти директивы могут присутствовать. • В XML-представлении каждый XML-элемент снабжен атрибутом j sp: id. • В XML-представлении элемент jsp;root добавляется в качестве корневого Элемента документа, если документ еще не имеет элемента j sp: root. • В XML-представлении добавляется элемент jsp:directive,раде (если его не было) t атрибутом pageEncoding и значение атрибута pageEncoding устанав- ливается в «UTF-8». • В XML-представлении добавляется элемент j sp: directive. раде (если его не было) с атрибутом contentType и значение атрибута contentType устанавли- вается в соответствии с главой JSP.4.2 «Кодировки символов в ответе не запрос» спе- цификации JSP 2.0 («text/xml» для JSP-документа). Разработчика на Java могут добавлять к web-приложениям подклассы класса j avax. servlet.jsp.tagext.TagLibraryValidator в качестве инструментов проверки использования в приложении пользовательских тегов. Контейнер JSP (в Tomcat такой кон- тейнер называется Jasper) создает XML-представленйе страницы JSP и передает его в TagLibraryValidator для синтаксического анализа и верификации XML-элементов. 128 | Глава 5. Различные форматы страниц JSP
Полезно проверить XML-представление страницы JSP, чтобы отладить класс TagL- ibraryValidator, используемый вами в библиотеке пользовательских тегов, или чтобы открыть JSP в редакторе XML и оценить ее синтаксис с точки зрения XML. Вот хороший способ (с примесью хакерства) автоматической генерации файла с XML- представлением страницы JSP. Он заключается в использовании объекта javax. serv- let . jsp.tagext.PageData, который автоматически возвращает XML-представле- ние страницы JSP в виде объекта java. io. Inputstream. Необходимо следующее. 1. Создайте класс, расширяющий класс javax.servlet.jsp.tagext.TagLib- raryValidator. Подобные классы верификации используются для проверки корректности применения пользовательских тегов и детально описаны в главе 23. 2. Переопределите метод TagLibraryValidator. validate (String prefix, String uri, PageData page) так, чтобы записать XML-представление из параметра PageData в файл. 3. Создайте простейший пользовательский тег, расширяя javax.servlet.jsp tagext. TagSupport. Этот тег «пометит» страницу JSP, чтобы ее XML-представ- ление можно было вывести в файл. Тег должен включать атрибут «filename», из которого созданный вами класс верификации возьмет Имя файла для записи XML- представления. Этот тег выглядит примерно следующим образом: <t:toxml filenames"myxml_view" /> 4. Создайте для этой библиотеки тегор файл дескриптора библиотеки тегов (Tag Library Descriptor - TLD), задав в качестве верификатора этой библиотеки созданный вами класс верификации. <validator> <validator-class> com.j spservletcookbook.ToXmlValidator </validator-class> <description> Saves XML views of JSP pages to the specified directory. < /description </validator> 5. Поместите оба класса (TagLibraryValidator и TagSupport) в каталог 'WEB-INF/ classes web-приложения или в JAR-файл, находящийся в WEB-INF/lib (примеры из данного рецепта подразумевают первый из форматов, а не размещение классов в JAR). 6. Поместите файл TLD в каталог WEB-INF/tlds. 7. Добавьте в дескриптор развертывания WEB-INF/web.xml элемент taglib, соответ- ствующий вашим тегу и TLD. Наличие в web.xml элемента taglib не является необходимым для JSP версий 1.2 и 2.0, поскольку контейнер JSP автоматически проводит поиск файлов с расширением .tld в каталоге WEB-INF, как и в каталоге МЕТА -INF JAR-файлов приложений. 5-1545 Генерирование XML-представления страницы JSP | 129
8. Создайте файл свойств, содержащий путь к каталогу, который вы хотите использо- вать для автоматически генерируемого XML-представления. Сохраните этот файл свойств в WEB-INF/classes, используя соответствующие имена пакетов. Этот файл свойств используется, чтобы избежать трудоемкой записи абсолютного пути к ката- логу в коде класса верификации. 9. Поместите созданный пользовательский тег в файл JSP, XML-представление которого требуется получить в файле. В примере 5.13 приведена страница JSP с пользовательским тегом. Пример 5.13. Генерирование XML-представления страницы <%@ taglib uri="/toxml_view" prefix="tH %>, <html> , / <head> <title>Test tld</title> </head> <body bgcolor="#ffffff"> Hello, this page is using the toxml tag to look at its XML View. <t:toxml filename=,'iny_xmlview"/> </body> </html> Элемент с тегом t: toxml - пустой элемент, сигнализирующий классу верификации о необходимости генерировать файл, содержащий XML-представление. Итоговый файл будет назван my_xmlview.xml (класс верификации добавит расширение .xml). Этот тег не оказывает никакого влияния на внешний вид или поведение страницы JSP. Следующий ниже фрагмент дескриптора развертывания показывает элемент taglib, задающий URI, используемый в директиве taglib. Элемент taglib дескриптора развертывания также задает местоположение файла TLD (WEB-INF-/tlds/xml_gen .tld). <taglib> <taglib-uri>/toxml_view</taglib-uri> <taglib-location>/WEB-INF/tlds/xml_gen.tld</taglib-location> </taglib> В примере 5.14 показан файл TLD для нашей библиотеки тегов, задающий класс верификации и простейший пользовательский тег (маркер), используемый в примере 5.13. Я не привожу код тега toxml, поскольку в нем нет ничего интересного, кроме того, что он содержит переменную-член типа string, с названием filename. Основное назначение этого тега - инициировать работу класса верификации Контейнер JSP создает по одному экземпляру класса верификации для каждой библиотеки тегов, подключающее класс верификации. 130 | Глава 5. Различные форматы страниц JSP
Пример 5.14. Файл TLD для пользовательского тега, используемого для получения XML-представ- ления <?xml version="1.0" encodings“ISO-8859-1" ?> <!DOCTYPE taglib PUBLIC "—//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_l_2.dtd"> <taglib> ^«tlib-version*1.0</tlib-version* <jsp-version*l.2</jsp-version* <short-name*Validator test</short-name> <description>Validator test«/description* «validator* <validator-class> com.j spservletcookbook.ToXmlValidator «/validator-class* «description* Saves XML views of JSP pages to the specified directory.. <Jdescription* </validator* <tag> <name> toxml</name* <tag-class*c6m.jspservletcookbook.ToXml</tag-class* <body-content>EMPTY</body-content* «description* This tag demonstrates the production of JSP XML view files. </description* <attribute> <name> f i lename< /nartie* «required*true«/required> <rtexprvalue*false</rtexprvalue* «description* This attribute provides the filename.«/description* x. «/attribute* «/tag* «/taglib* 5* Генерирование XML-представления страницы JSP I 131
Класс верификации com. jspservletcookioook. ToXmlValidator выполняет метод validate когда загружена страница JSP использующая тег toxml. Как класс верификации узнает, где сохранить файл, содержащие XML-представление страницы? Путь к каталогу хранения он извлекает из файла свойств, который приводится ниже. Такой подход позволяет лицам, использующим пользовательский тег, изменить каталог хранения XML-представления, не вмешиваясь в исходный код класса верификации. Файл свойств размещается в том же каталоге, что и класс верификации. Путь к этому файлу свойств - 'WEB-INF/classes/comJjspservletcookbook/vahdator.properties. directory=h: /home/kmlviews Имя файла для хранения берется из самого тега. <t: toxml filenames "my_xml view" /> Таким образом, полный путь к файлу с XML-представлением выглядит так: h:/home/ xmlviews/my_xmlview.xml. При создании файла с XML-представлением класс верификации добавляет к имени расширение xml. Перед этим верификатор извлекает имя файла из тега toxml. используя для синтаксического разбора входного потока из объекта javax. servlet .jsp. tagext. PageData синтаксический анализатор SAX. Теперь у вас есть все необходимое, за исключением очень важного класса верификации, он приводится в примере 5.15. Метод validate для чтения значения свойства direc- tory (каталог) использует объект/ java.util.ResourceBundle. Метод validate получает имя файла используя вспомогательный класс,'приведенный в примере 5.16. Затем этот метод генерирует XML-представление страницы JSP, используя java.io.Input- Stream, возвращаемый из PageData. getlnputStream (). Пример 5.15. Класс верификации, предназначенный для генерирования XML-представления import j avax.servlet.jsp.tagext.TagLibraryValidator; import javax.servlet.jsp.tagext.ValidationMessage; irrport j avax. servlet .jsp. tagext. PageData ; import j ava.io.*; import java.util.ResourceBundle; import java.util.MissingResourceExceptiOn; inport java.util.Date; public class ToXmlValidator extends TagLibraryValidator { /** Creates new ToXmlValidator */ public ToXmlValidator() { } public ValidationMessage[] validatefjava.lang.String prefix, java.lang.String uri,PageData page){ ValidationMessage(] vam = null; 132 | Глава 5. Различные форматы страниц JSP
try{ ResourceBuridle bundle = ResourceBunble.getBundle("com.j spservletcookbook.Validator"); String director^ = bundle.getString("directory"); String fileName = getFilename(page); //throw an Exception if the directory is invalid if (directory.== null). throw new Exception ( "Received a null directory for the XML view file."); //throw an Exception if the filename is invalid if (fileName -= null) c. throw new IOException( "Received a null filename for the XML view file."); File file = new File(directory + ”/" + fileName + ".xml"); FileWriter writer = new FileWriter(file); BufferedReader in ч new BufferedReader ( new InputStreamReader(page.getInputStrearn())); String line = ""; //write the XML view to the specified file while ((line = in.readLineO) != null ){ writer.write(line); } in.closeO; < writer.close(); } catch (lOException io){ f //return a validation message ValidationMessage vmsg = new ValidationMessage(null,io.getMessage()); vam = new ValidationMessage[1]; vam[0].= vmsg; return vam; } catch (MissingResourceExdeption mre){ //return a validation message ValidatioriMessage vmsg = hew ValidationMessage (null, mre. getMessage ()) ; vam = new ValidationMessage[1J; vam[0] = vmsg; return vam; } catch (Exception e){ //return a validation message ValidationMessage vmsg = new Генерирование XML-представления страницы JSP | 133
ValidationMessage(null,e.getMessage()>; vam = new ValidationMessage[1] ; vam[0] = vmsg; return vam; } //return empty array vam = new ValidationMessage[0]; return vam; } private String getFilename(PageData pacje) throws Exception { try{ < ValidateHandler handler = new ValidateHandler(); return handler.getFilename(page); } catch (Exception e){ throw e; } } } В примере 5.16 приведен вспомогательный класс ValidateHandler, который используется нашим верификатором для получения из пользовательского тега имени файла. Этот класс делает один проход по XML-представлению (до того как оно записы- вается в файл) и извлекает из атрибута filename элемента toxml находящееся там имя файла. Вся работа по синтаксическому разбору XML производится этим классом за сценой, а верификатор получает имя файла Простым вызовом метода. ValidateHandler handler = new ValidateHandler(); return handler.getFilename(page); Класс ValidateHandler для разбора XML, получаемого ,c помощью javax. servlet -jsp. tagext. PageData. getlnputStream () использует следующие интерфейсы прикладных программ: Java API для обработки XML (Java API for XML processing - JAXP) и простой API для XML (Simple API for XML - SAX). Класс Vali- dateHandler необходимо поместить в каталог WEB-INF/classes (или в JAR-файл, в WEB-INF/lib), чтобы web-приложение (класс ToXmlValidator) смогло его найти. Вместо SAX можно использовать любые другие.компоненты, обеспечивающие ана- логичную функциональность (синтаксический разбор XML). Если вы решили использо- вать JAXP, а ваш web-контейнер еще не содержит необходимые компоненты JAXP, то для полной установки JAXP добавьте в каталог V/EB-INF/lib следующие JAR-файлы: jaxp-api.jar, dom.jar, sax.jar, xalan.jar, xerceslmpl.jar и xsltc.jar. Эти компоненты можно скачать как часть Java Web Services Developer Pack (http://java.sun.com/webservices/web- servicespack.htmiy, библиотеки JAXP включены и в Java 1.4.x. 134 | Глава 5. Различные форматы страниц JSP
Пример 5.16. Вспомогательный класс, расширяющий класс defaultHandler, для извлечения имени файла из атрибута пользовательского тега import org.xml.sax.Attributes; import org.xml.sax.SAXParseException; import org.xml.sax.SAXExcept ion; import org.xml.sax.helpers.DefaultHandler; _mport javax.xml.parsers.SAXParserFactory; import j avax.xml.parsers.FactoryConfigurationError; import j avax.xml.parsers.ParserConfigurationExcfeption; import javax.xml.parsers.SAXParser;. import j ava.io.JOException; import javax.servlet.jsp.tagext.PageData; public class VaiidateHandler extends DefaultHandler { private String fileName = public void startElement(String nameSpaceuri, String sname, String qname, Attributes attrs)( forfint i=0; i<attrs. getLength (.); i++) if("filename".equals(attrs.getLpcalName(i))) this.fileName=attrs.getValue(i); } public String getFilename(PageData page) throws FactoryConfigurationError, ParserConfigurationException, SAXException, lOException { try{ f SAXParserFactory factory = SAXParserFactory.newlnstance() ; factory.setNamespaceAware(true); SAXParser saxparser = factory.newSAXParser(); saxparser.parse(page.getInputStream(),this); } catch (FactoryConfigurationError fe){ throw fe; } catch (ParserConfigurationException pee){ throw pee; x } qatch ( SAXExcepztion se) { / throw se; } catch( java.io.IOException io){ t ' throw io; } finally { return this.fileName; } } Генерирование XML-представления < границы JSP | 135
public void error(SAXParseException e) throws SAXParseException { throw e; } } XML-представление, генерируемое для страницы JSP из примера 5.13, показано в примере 5.17 (добавлено несколько переносов строк для удобочитаемости). Смотрится не очень хорошо, зато теперь вы знаете, как выглядит XML-предствление! 'Весь HTML-код рассматривается как шаблонные данные, и заключен г элемент J sp: text и секции CDATA. Два XML-элемента jsp:root и t:toxml получили в XML-представлении последовательные идентификационные номера, указанные в атрибуте isp: id. Эти иден- тификаторы могут использоваться классом TagLibraryValidator для выдачи деталь- ных сообщений, относящихся к XML верифицируемой страницы. Пример 5.17. XML-представление JSP из примера 5.13 I V <jsp:root jsp:id=*0' xmlns:jsp="http://java.sun.com/JSP/Page' version="1.2' xmlns: t=" / toxml_view" > < jsp: textx![CDATA[]]></jsp:text> <jsp:text><! [CDATA[<html>] ]></jsp: text:> <jsp:te^t><![CDATA[<head> ]]></jsp:text> <jsp: textx! [CDATA [<title>Test tld] ] ></jsp: text> <jsp: textx! [CDATA[</title>] ]x/jsp: text> <jsp:textx! [CDATA[</head>] ]x/jsp:text> <jsp:textx! [CDATA[<body bgcolor="#ffffff">Hello, this page is using the toxml tag to look at its XML View.]]></jsp:text> <t:toxml jsp:id="l" filenames"my_xmlview"/> <jsp:text><! [CDATAf] ]x/jsp:text> < j sp: textx! [ CDATA [ < /body> ] ] >< / j sp: text> 4 <jsp: textx! [CDATA[</html>] ]x/jsp: text> </jsp:root> у См. также Рецепт 5.5 по созданию страницы JSP в форме JSP-документа «с нуля»; главу JSP.6 (JSP-документы) спецификации JSP версии 2.0; главу JSP.10 (XML-представление) спе- цификации JSP версии 2.0. 136 | Глава 5. Различные форматы страниц JSP
ГЛ\ВА6 Динамически подключаемое содержимое страниц JSP и сервлетов 6.0 Введение Сервлеты и JSP часто содержат общие для некоторой организации фрагменты информации - логотип, товарный знак, панель навигации и т. п. Для подключения такой информации web-приложения используют механизм импорта, позволяющий централизованно хранить и изменять содержимое, без необходимости вносить измене- ния во всех фрагментах кода, где эта информация используется. Часть подобной информации постоянна и редко подвергается изменениям (например, логотип организа- ции). Другая часть более динамична, меняется часто и непредсказуемо, например текст приветствия, который необходимо локализовать для каждого отдельного пользователя. В обоих случаях вам необходима уверенность, что сервлет или JSP могут развиваться независимо от подключаемого ими содержимого и что данная реализация сервлета или JSP при необходимости корректно обновит подключаемое содержимое. В этой главе приводятся рецепты включения содержимого в сервлеты и JSP, которые можно использовать в следующих условиях. • Когда подключаемая информация обновляется при каждом запросе пользователя. • Когда подключаемая информация содержит два и более уровней вложенности, например, когда включаемый файл в Свою очередь подключает другой фрагмент информации и т. д. • Когда для смены подключаемого сервлетом элемента информации желательно использовать дескриптор развертывания - аккуратный и не подверженный ошибкам способ подключения содержимого, которое довольно часто прихо- дится настраивать и изменять. • Когда требуется импортировать ресурсы, находящиеся за пределами web-прило- жения. Рецепт 6.1 описывает, как импортировать ресурс каждый раз, когда сервлет обрабатывает запрос. 137
Подключение ресурса при каждой обработке запроса Задача Требуется включать в сервлет Информацию из внешнего файла каждый раз, когда сервлет обрабатывает запрос. Решение Используйте в методе doGet() сервлета метод javax.servlet.RequestDis- patcher . include (request, response), подключающий внешний файл,, Обсуждение . J 1 • Метод doGet () класса javax.servlet .http.HttpServlet инициирует меха- низм подключения, когда web-контейнер получает запрос GET для данного сервлета. -*Л- При использовании данного подхода реализуйте метод doPost () сервлета так, чтобы он вызывал doGet (request, response). • В примере 6.1 приведен сервлет, импортирующий в методе doGet () шаблон с авторским правом (copyright) с помощью метода javax. servlet .RequestDis- patcher .includO(). Пример 6.1. Включение содержимого в методе init () сервлета, расширяющего класс HttpServ- let package com.j spservletcookbook; import j avax.servlet.*; import jaVax.servlet.http.*; public class IncludeServlet extends HttpServlet { public void doGet(fittpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException { response.setContentType("text/html"); j ava.io.PrintWri ter out = response.getWriter(); out ’. printin (" <htrftl> H) ; out.printIn("<head>"); out.printin("<title>Include Servlet</title>“) ; out.printIn("</head>"); 138 | Глава 6. Динамически подключаемое содержимое страниц JSP и сервлетов
•d out.printin("<body>"); out.printIn("<hl>Welcome To Our Universe</hl>"); out.println("Imagine the rest of the page here.<br><br>"); //Включаем информацию об авторском праве RequootDicpatcher dispatcher и request.getRequestDispatcher( */copyright"); dispatcher.Include(request, response); out.printlp("</body>"); out.printlnft</html>n); }//doGet ) В примере 6.1 сервлет получает объект Request Dispatched'путем вызова метода javax.servlet.ServletRequest.getRequestDispatcher(). В данном случае методу getRequestDispatcher()в качестве параметра передается путь к сервлету, содержащему импортируемый ресурс: /cvpyright. Этот путь в web.xml отображается на сервлет Copyright, показанный в примере 6.2. Пример 6.2. Импортируемый сервлет Copyright public class Copyright extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.lOException { java.io.Printwriter out = response.getWriterO; out.printin("Copyright&copy; 2003-2004 EmbraceAndExtend Corp."); } } Сервлет Copyright выводит строку текста, включающую код символа авторского права (&сору), чтобы этот символ корректно отображался в итоговом HTML. Когда импортирующий сервлет вызывает метод include (), данный текст с авторским правом вставляется в место, определяемое положением этого вызова. I .....Т"1 Сервлет может импортировать и HTML-страницу, а не' только результат вывода JSP или сервлета. Если вы импортируете описанным выше способом HTML, убедитесь, что импортируемый текст не нарушит вашу страницу HTML, например повторением HTML-тегов или из-за ошибки закрытия определенного тега. На рис. 6.1 показано отображение в браузере страницы, сгенерированной сервлетом IncludeServlet. Рецепт 6.2 описывает, как конфигурировать импортируемые ресурсы с помощью внешнего файла конфигурации, например web.xml. Подключение ресурса при каждой обработке запроса | 139
Вас* Refresr Home Welcome To Our Universe Imagine the rest of the page here Copyright© 2003-2004 EmbraceAndExtend Corp Local intranet iather.com L 5g] Welcome toSparhawkJ 'Search Favorites Рис. 6.1. Страница сервлета IncludeServlet в браузере Джейсон Хантер, написавший технический обзор этой книги, указывает, что многие прибегают к созданию предварительно формируемых (в offline) статичных f v (HTML) файлов, тогда как содержимое большинства сайтов использует включения, например импорт заголовков и нижних колонтитулов для страниц этих сайтов. В большинстве случаев сервер обрабатывает запросы статичных файлов намного эффективнее, чем запросы к динамическим страницам (таким, как JSP, подключающим другие ресурсы). См. главу 3 «Servlet Best Practices» книги «Java Enterprise Best Practices» (O’Reilly) См. также % Рецепты 6.2 и 6.3 по включению ресурсов в сервлеты; рецепты 6.4 и 6.7 по использо- ванию jsp:include, директивы include, а также по включению ресурсов в JSP- документы или XML-файлы; главу SRV. 14.2.5 спецификации сервлетов версии 2.4; главу JSP.5.4 спецификации JSP версии 2.0 по j sp: include; главу JSP. 1.10.3 специфи- кации JSP версии 2.0 по директиве include. 140 | Глава 6. Динамически подключаемое содержимое страниц JSP и сервлетов
6.2 Использование внешней настройки включения ресурса в сервлет Задача Требуется для настройки ресурсов, включаемых в сервлет, использовать внешний файл конфигурации (например, web.xml). Решение Используйте параметры инициализации включающего сервлета'это позволит осущест- вить внешнюю настройку механизма подключения, а затем подключайте ресурсы с помощью метода javax. servlet. RequestDispatcher. include (request, response). Обсуждение Может потребоваться периодически Менять ресурс, подключаемый сервлетом, без необ- ходимости изменять и перекомпилировать код сервлета. Подобные изменения можно произ- водить, изменяя параметры инициализации сервлета в web.xml. С помощью этой стратегии можно менять как местоположение файла с ресурсом, так и способ извлечения ресурсов (Например, из базы данных). Меняя содержимое элемента param-value можно заставить сервлет импортировать требуемый ресурс. В примере 6.3 показан сервлет, скон- фигурированный на подключение файла privacy.jspf. Этот файл содержит стандартное зая- ление, часто включаемое в web-приложения, о неразглашении информации, предос- тавляемой пользователями. Пример 6.3. Задание подключаемого ресурса с помощью элемента ini t-param сервлета <servlet> <servlet-name>PrivacyServlet</servlet-name> <servlet-class>com.jspservletcookbook.IncludeServlet-</servlet-class> < ini t -param> <param-name>included-resource</paranr-name> <param-yalue>privacy. j spf</param-value> <init-param> </servlet> В примере 6.4 представлен метод doGet () сервлета PrivacyServlet. Метод прлучает значение параметра инициализации included-resource (privacy.jspf) и затем подключает необходимый JSP-сегмент. Использование внешней настройки включения ресурса в сервлет | 141
Пример 6.4. Подключение ресурса, заданного параметром инициализации public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException { response.setContentType("text/html"); java.io.Printwriter out = response.getWriter(); out.printIn("<html>"); out.printIn("<head>"); out.printlnf"<title>Include Servlet</title>"); out.printIn("</head>"); out.printIn("<body>"); \ out.printlnf"<hl>Welcome To Our Universe</hl>"); out.printIn("Imagine the rest of the page here.<br><br>"); //Подключаем информацию о конфиденциальности //на основе значения init-param String includeRes • (String) getInitParameter( "included-resource"); //Получаем объект RequestDispatcher //на основе значения init-param RequestDispatcher dispatcher request» getRequestDispatcher(includeRes); dispatcher.include(request, response); out.printIn("</body>*); out.printIn("</html>*); } J В примере 6.4 сервлет получает объект RequestDispatcher на основе значение элемента init-param. Ниже представлен этот код. //Переменная includeRes содержит значение "privacy.jspf" // полученное из init-param RequestDispatcher dispatcher = request.getRequestDispatcher(includeRes); Затем с помощью метода dispatcher, include (request, response) в ответ на запрос подставляется выводная информация из privac.jspf. JSP-сегмент, подключаемый серйлетом PrivacyServlet показан в примере 6.5. Содержимое этого сегмента JSP содержит ряд тегов H'tML, не противоречащих HTML, сформированному включающей страницей. Пример 6.5. Сегмент JSP, включаемый в сервлет с помощью RequestDispatcher <%@page errorPage="/error.j sp"%> <pxstrong>Parker River Net Solutions Privacy Policy</strongx/p> <p>Any personal information you provide to us regarding Web- or software- development services or shareware software, such as your name, address,- tele- phone number, and e-mail address, will not be released, sold, or rented to any entities dr individuals outside of Parker River Net Solutions.</p> 142 | Глава 6. Динамически подключаемое содержимое страниц JSP и сервлетов
Включаемые сегменты или страницы не должны устанавливать или менять заголовки ответа на запрос, и любые попытки установить тип содержимого из подключаемого сервлета или JSP, например <%@ page content*Type=" text/xml'* %> будут игнорироваться. Все включаемые JSP задают страницу ошибки (error page), состоящую из тегов форматирования HTML и текста. На рис, 6.2 показано, как выглядит страница, формируемая сервлетом PrivacyServlet в браузере. Рис. 6.2. Web-страница с включенным сегментом JSP Можно несколько изменить пример 6.4, чтобы задать ресурс, подключаемый по умолчанию, на тот случай, если необходимый параметр инициализации сервлета по ошибке пропущен в дескрипторе развертывания (web.xml). В случае такой ошибки метод getlnitParameter возвращает null и в случае совпадения использует в операторе включения значение по умолчанию. См. также Рецепт 6.3 по включению ресурсов, имеющих вложенные включения; рецепты 6.4 - 6.8 по включению ресурсов в страницы JSP; главу SRV. 14.2.5 спецификации сервлета 2.4; главу JSP. 1.10.3 спецификации JSP 2.0 по включению файлов в JSP. Использование внешней настройки включения ресурса в сервлет | 143
6.3 Включение в сервлет ресурсов с несколькими уровнями вложенности Задача Включить в сервлет ресурсы, которые в свою очередь включают сервлеты, JSP или HTML-страницы. Решение Для подключения файла ресурсов верхнего уровня воспользуйтесь методом javax. servlet. RequestDispatcher.include (reQuest, response). Убедитесь, что в web.xml правильно сконфигурированы страницы ошибок - на случай возникновения исключительной ситуации в одном из импортируемых файлов «глубокого залегания». Обсуждение Хотя это не является наилучшим архитектурным решением, можно включить в сервлет ресурс, который в свою очередь включает другой ресурс и т. д. Это напоминает матрешку. Вы открываете верхнюю половинку матрешки и находите там матрешку меньших размеров, вложенную в первую. И здесь уже не кажутся странными мысли об очень слож- ных web-страницах, использующих HTML-фреймы, табличные теги, содержащие заго- ловки и нижние колонтитулы, и где все эти сегменты страницы содержат сторонний специализированный контент, получаемый с помощью механизма включения. Один из подключаемых файлов, находящийся на некоторой глубине вложенности, может возбу- дить исключение или некоторым образом испортить цепочку включений. Поэтому необхо- димо позаботиться о том, чтобы web-приложение имело соответствующим образом сконфигурированную страницу ошибки, которая отображала бы информацию о ресурсе, по вине которого возникла проблема, хотя это скорее помогает в отладке приложения, чем является профессиональным способом защиты от возникновения ошибок. В данном рецепте приводится пример сервлета, имеющего три уровня вложенности включаемых ресурсов, ^тот сервлет включает другой сервлет - Level2, который включает JSP level3.jsp, а эта страница, в свою очередь, включает сервлет Level4. На рис. 6.3 пока- зано, что увидит в браузере пользователь, обратившийся к этому сервлету com. j spserv- letcookbook. Multipleinc. Код сервлета приведен в примере 6.6. Этот сервлет отвечает за вывод текста первого уровня («Hello from Level 1»), а затем каждый из включаемых ресурсов дополняет содержимое ответа на запрос. 144 | Глава б. Динамически подключаемое содержимое страниц JSP и сервлетов
' Рис. 6.3. Три файла, подключаемых к одной web-странице Пример 6.6. Внешний сервлет package com.j spservletcookbook; Import j avax.servlet.*; import j avax.servlet.http.*; public class Multipleinc extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, / j ava.io.lOException { response.setContentType("text/html") ; java.io.Printwriter out = response.getWriter()? out.printIn(<html>"); ' out;. print In (" <head>") ; out.printin("<title>Multiple Includes</title>"); out.printin("</head>"); out.println("<body>"); out.printin("<hl>Hello from Level l</hl>"); out.printin("This text is displayed at Level 1."); RequestDispatcher dispatcher request. getRequestDispatcher("ZIevel2" ) ; Включение в сервлет ресурсов с несколькими уровнями вложенности | 145
I dispatcher.include(request, response); out.printIn(“</body>"); out.printIn("</html>"); } } Код RequestDispatcher dispatcher = request.getRequestDispatcher("/level2"); dispatcher.include(request, response); включает вывод сервлета, отображаемого на путь Aevel2, его код показан в примере 6.7 (только метод doGet ()). Пример 6.7. Сервлет первого уровня включения public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IGException { java.io.Printwriter out = response.getWriter(); out.println("<h2>Hello from Level 2</h2>"); out.println("This text is included at Level 2:"); //Include the JSP file named "level3.jsp" try{ RequestDispatcher dispatcher request.getRequestDispatcher( •/level3.jsp"); dispatcher.include(request, response); } catch (Exception se){ String context_path * (String) request.getAttribute( "javax. servlet. include. context_path"); String servlet_path (String) request.getAttribute( "javax.servlet.include.servlet_path"); String errMessage new StringBuffer( "Exception raised during Level2 servlet include:<br>"). append("Context path: "+context_path+"<br>"). append("Servlet path: "+servlet_path).toString(); throw njw ServletException (errMessage) i ) ) Сервлет из примера 6.7 дописывает в формируемый ответ на запрос свой текст, а затем подключает level3.jsp, как и внешний сервлет, используя для этого объект j avax. serv- let .RequestDispatcher. Сервлет Level2, кроме этого, использует блок try/catch и атрибуты объекта request (запрос), предназначенные для обработки исключений, которые могут возникнуть во время операций включения. 146 | Глава 6. Динамически подключаемое содержимое страниц JSP и сервлетов
В соответствии со спецификацией JSP API, включаемые ресурсы имеют доступ к пяти атрибутам запроса (объекта request): • javax.servlet.include.request_uri • javax.servlet.include.context_path • javax.servlet.include.sen let_path • javax.servlet.include.path_info • javax.servlet.include.query_string В блоке catch сервлет Level2 получает значения двух из этих атрибутов запроса. String context_path = (String) request.getAttribute(•javax.servlet.include.pontext_path"); String servlet_path = (String) request.getAttribute("javax.servlet.include.servlet_path"); Затем в этом же блоке catch сервлет Level2 возбуждает новое исключение Servlet- Exception и включает в состав сообщения об ошибке полученные значения атрибутов. Эту информацию об исключении, возникшем в ходе операции включения, отображает страница ошибок, сконфигурированная для данного web-приложения. Конфигурация с границы ошибок в web.xml выглядит примерно следующим образом: * \ <error-page> <except ion-t,ype> javax.servlet.ServletException </exception-type> <location>/error</lpcation> </error-page> Путь “/error” отображается на" сервлет, выводящий информацию, связанную с исключением. В примере 6.7 путь к контексту был пустым, а путь к сервлету - /level2. Отображение страницы ошибок в браузере показано на рис. 6.4. В качестве сервлета, генерирующего исключение, указан сервлет верхнего уровня (Multipleinc), поскольку именно он ини- циировал механизм включения, который привел к исключению ServletException. В примере 6.8 показан файл JSP (level3.jsp), импортируемый сервлетом начального уровня вложенности. &awilevel3.jsp представляет собой следующий уровень включаемого содержимого. Включение в сервлет ресурсов с несколькими уровнями Вложенности | 147
Рис. 6.4. Отображение информации об исключении, возникшем в ходе включения Включаемые сервлеты не вызывают метод java.io.PrintWriter.close(), поскольку это не позволит внешнему сервлету поместить в состав ответа на запрос что-то еще после того как отработает цепочка включений. Внешний сервлет (Multipleinc из примера 6.6) вызывает Printwriter. close () в самом конце, после окончания включения вложенных ресурсов. Пример 6.8. Включаемый JSP-файл level3.jsp <%@page errorPage="/error"%> <h3>Hello from Level 3</h3> This text is included at Level 3. <jsp:include page="/level4"/> И, наконец, файл JSP с помощью стандартного действия j sp: include импортирует текст, возвращаемый сервлетом, который отображен на путь flevel4. Сервлет Level 4 делает то же, что остальные сервлеты - пишет символьные данные в объект Print- Writer, поэтому его код не приводится. Причина всей этой пирамиды - проде- монстрировать, как файлы ресурсов разных, типов могут образовывать цепочки вложенных включений. Внешний сервлет включает сервлет номер два, тот включает JSP-файл, который в свою очередь включает текст, возвращаемый третьим сервлетом. Первый включаемый сервлет заключает код подключения своих ресурсов в блок try, чтобы перехватить любые прерывания, возбуждаемые включаемым файлом JSP. 148 | Глава 6. Динамически подключаемое содержимое страниц JSP и сервлетов
См. также Рецепт 6.1 по использованию механизма включения RequestDispatcher; рецепт 6.2 по заданию включаемого ресурса с помощью файла конфигурации; рецепты 6-4 - 6.8 по включению ресурсов в страницы JSP; главу SRV. 14.2.5 спецификации сервлета 2.4; главу JSP.1.1O.3 спецификации JSP 2.0 по включению файлов в JSP; главу 9 по заданию страниц ошибок B^web-приложениях. 6.4 Включение в JSP редко изменяемых ресурсов Задача ' Требуется включить в JSP ресурсы, которые не подвержены частым изменениям (например, фрагменты страницы, представляющие заголовок или нижний колонтитул). Решение Поместите на страницу JSP директиву include и присвойте включаемому сегменту JSP расширение .jspf. Обсуждение Страницы JSP часто составляются из фрагментов, представляющих панель навигации, заголовок (элементы страницы, находящиеся в верхней части web-страницы), нижний колонтитул (элементы, появляющиеся в нижней части) и тело с основным содержанием. Поскольку все страницы одного web-приложения или сайта могут использовать единую панель навигации, панель помещается в отдельный файл, и используется всеми web-компо- нентами, которым она требуется. Если вам необходимо импортировать на страницу JSP некоторый статичный (неизменяемый) сеТмент JSP, используйте директиву include. <%@ include file="/WEB-INF/jspf/navbar.jspf" %> Если ваша JSP-страница является JSP-документом, то есть выполнена в синтаксисе XML (см. главу 5), употребите следующую форму директивы include. <jsp:directive.include file="/WEB-INF/jspf/navbar.. jspf" /> Если значение атрибута file начинается с «/», то это путь относительно контекста, то есть путь относительно каталога web-приложения, включающего страницу JSP, использующую эту директиву. Для приведенных выше директив это означает «из корневого каталога web-приложения взять файл/WEB-INF/jspf/navbar.jspf». Включение в JSP редко изменяемых ресурсов | 144
Если значение атрибута file элемента include не начинается с «/», то это путь относительно страницы, то есть путь относительно страницы JSP, использующей данную директиву include. Приведенная ниже директива include включает файл из каталога segments, расположенного в том же каталоге, что и включающая страница JSP. <%@ include file="segments/navbar.jspf" %> Директива include включает текст или код включаемого сегмента во время фазы трансляции, когда JSP преобразуется в сервлет. Этот механизм включения - более эффективный способ импорта текста или кода (например, HTML-тегов или директив taglib), которые в противном случае вам' пришлось бы печатать на странице JSP до ее преобразования в сервлет. •» Разница между директивой include и стандартным действием jsp:include в том, что директива include импортирует реальный текст или байты * । включаемого сегмента, тогда как стандартное действие j sp: include посылает запрос к включаемой странице и затем включает уже динамически формируемый ответ на запрос. См. рецепт 6.5. Пример 6.9. Включение сегмента JSP в страницу JSP во время трансляции <%враде contentType="text/html"%>• <%е include file«"/WEB-INF/jepf/taglib-inc.jepf" %> <html> <head> <title>Main Content</title> </head> <body> <hl>Here is the main content</hl> This web application is using the following Servlet API: <c:out value="${pageContext.servletContext.majorVersion}"/>.<c:out value= * $ {pageContext. servletContext .minorversion}" /xbrxbr» <jsp:useBean id="timeValues" class="java.util.Date"/> <c:set targets"${timeValues}" values * ${pageContext.session.creationTime}* property^"time"/> The session creation time: <fmt:formatDate'value="${timeValues}" type="both" dateStyle= "medium" /xbrxbr> The toxml tag will create an XML view of this page. <t; toXml filenames * include-xmlview" /> </body> </html> 150 | Глава 6. Динамически подключаемое содержимое страниц JSP и сервлетов
Во второй стоке примера 6.9 подключается сегмент JSP с именем taglib-inc.jspf. Этот сегмент содержит директивы taglib, ответственные за доступность JSTL и возмож- ность использования на исходной странице пользовательских (нестандартных) тегов. Страница taglib-inc.jspf приведена в примере 6.10. Пример 6.10. Сегмент JSP, содержащий директивы taglib <%@ taglib uri="http://jaya.sun.com/jstl/core" prefix="c" %> <%@ taglib uri="http://java. sun. com/jst'l/fmt" prefix="fmt" %> <%(a taglib un,= "/toxml_view" prefix="t" %> Директива include включает эти три директивы taglib в исходную страницу, как если бы вы напечатали их на странице вручную, после чего контейнер JSP преобразует исходную страницу в сервлет. Три директивы taglib делают возможным использова- ние следующих тегов из примера 6-9. • c:out • c:set • fmt:formatDate • t:toXml ' *’ Спецификация JSP 2.0 рекомендует файлам с незаконченным кодом JSP, предназначенным для включения в другие файлы, присваивать расширение .jspf, ' f $ что означает «фрагмент JSP». Однако спецификация 2.0 называет эти фрагменты «сегментами JSP», чтобы не путать их с интерфейсом javax.servlet.jsp. tagext. JspFragment. Этот интерфейс — часть API расширения тегов. На рис. 6.5 показано, как данная страница JSP выглядит в браузере. Эта страница показывает версию API сервлетов, используемую web-контейнером, время создания javax. servlet.http.HttpSession (отформатированное с помощью JSTL-тега frnbf ormatDate) и пользовательский тег, описанный в рецепте 5.6. Этот тег вызывает генерирование XML-представления содержащей его страницы и сохранение соз- данного XML-файла под именем, указанным в атрибуте filename. Тег вставлен, чтобы показать способы включения разных видов директивы taglib. I См. также Рецепт 6.5 по использованию стандартного действия jsp:include; рецепт 6.7 по включению сегментов JSP в XML-файлы; рецепт 6.8 по включению содержимого, находящегося вне контекста JSP; главу JSP. 1.10.3 спецификации JSP 2.0 по включению файлов в JSP; главу 23 по тегам JSTL. -----------д------1-------j---------------- Включение в JSP редко изменяемых ресурсов | 151
Here is the main content This web application is using the"following Servlet API: 2.3 The session Creation time Mar 21.2003 2 36:47 PM The toXml tag wi II create an XML vi ew of thi s page. I : ' F], Puc. 6.5. Страница JSP с включенным сегментом JSP, содержащим директивы taglib 6.5 Включение содержимого в JSP при каждой обработке запроса Задача Требуется включать содержимое в страницу JSP каждый раз, когда она получает запрос, а не тогда, когда JSP преобразуется в сервлет. Решение Используйте стандартное действие j sp: include. Обсуждение Действие jsp:include включает ресурс в страницу JSP каждый раз, когда та получает запрос, что делает j sp: include гораздо более динамичным механизмом, чем директива include (см. рецепт 6.4). При использовании jsp:include включаемые сегменты JSP имеют доступ к объектам request, session и application исход- ной страницы и ко всем атрибутам, которые имеют эти объекты. Используйте действие jsp:include в любом месте файла, где необходимо импортировать ресурсы (например сегменты JSP) из этого же web-приложения. 152 | Глава 6. Динамически подключаемое содержимое страниц JSP и сервлетов
* *' Пользовательское действие import, являющееся частью ядра JSTL, может импортировать ресурсы из других web-приложений или даже из другого места t £ Интернета. См. рецепт 6.8. Пример 6.10 показывает страницу JSP, получающую информацию, введенную в форму, от другой страницы того же web-приложения. Получающая страница, для подключения сегментов, содержащих заголовок и нижний колонтитул, в свои верхнюю и нижнюю части, использует j sp: include. Чтобы продемонстрировать возможности подключаемого сегмента по доступу к информации о запросе и сеансе родительской страницы, сегмент с заголовком отображает (с помощью приветственного HTML-тега title) введенное в форму имя пользователя, которое хранится в параметрах запроса fname и Iname. В подвале отображается идентификатор сеанса, первое имя пользователя (first name) и последнее имя пользователя (last name). HTML-страница с формой для ввода первого имени, последнего имени и адреса электронной почты пользователя, показана на рис. 6.6. Рис. 6.6. HTML-форма Предположим, что страница с формой содержит код JavaScript, проверяющий правильность введенной информации. Когда пользователь нажимает кнопку Submit, информация, введенная в форму, передается к странице /solutions.jsp с помощью следующего HTML-тега. <form method=post action="/solutions.jsp"> Включение содержимого в JSP при каждой обработке запроса | 153
В примере 6.11 показана страница solutions.jsp, включающая два сегмента JSP: header.jspf (заголовок) и footer.jspf (нижний колонтитул). Сегмент header.jspf содержит HTML-тег head и помещает введенное в форму имя пользователя в тег title, вложен* ный в тег head. Сегмент footer.jspf для примера, повторяет имя пользователя и показы- вает идентификатор его сеанса, получаемый от JSP-объекта session. Спецификация JSP 2.0 рекомендует держать эти файлы в каталоге WEB INF/jspf. Пример 6.11. Подключение двух сегментов и отображение введенных в форму данных <%@page contentType="text/html"%> <html> <jsp: include page-"/WEB-INF/jspf/header,jspf" /> <body bgcdlor="white"> <table widths"660" border="0" summary="A,two-column table in which resides a logo and navigation bar"> <trxtd valign="top"> Organization image goes here...<p> <u>Main</u> </td> ) <td aligns"right" valign="top"> Navbar goes here... </tdx/trx trx td valign="top" aligns"center" colspan="2"> <table border="0" summary= "A nested table for aligning body content"> <trxtdxh2>Thanks for registering at this site</h2x/tdx/tr> <trxtd>Here is the info you submitted:</tdx/tr> <trxtd>Name: ' <%= request.getParameter("fname") %> <%= request.getParameter("lname") %></tdx/tr> <trxtd>Email : <%= request. getParameter (" eaddress") %>- < / tdx / trx /1 able> < / tdx / tr>< trx td>< / tdx / tr> </table> > <table widths"660” border="0" summary= "A table containing a footer navigation bar."> <tr><td valign="top" aligns"center"> <jsp:include pages "/WEB-INF/ jspf /footer, jsp" /> ( ««. * if </tdx/tr> 1 </table> </body> </html> / 154 | Глава 6. Динамически подключаемое содержимое страниц JSP и сервлетов
В примере 6.12 приведен сегмент header.jspf. Пример 6.12. Сегмент, содержащий заголовок страницы, включаемый директивой jsp: include <HEAD> t <META name="author" content= "Bruce W. Perry, author®jspservletcookbook.com"> <META name="keywords" content= "Java, JSP, servlets, databases, MySQL, Oracle, web development*» <TITLE>Parker River: Thanks For Visiting <H" request.gotParamstor("fnama") \> roquest.getParameter("Inane") H> </TITLE» <. </HEAD> Все, что делает этот сегмент, - включает имя пользователя в тег title. В примере 6.13 приведен импортируемый сегмент footer.jspf. $тот сегмент также отображает имя пользо- вателя, а кроме того, отображает идентификатор (ID) сеанса, причем перед обращением к методу HttpSession.getld() проверяется, что объект javax. servlet .http. HttpSession не null. Пример 6.13. Сегмент JSP с нижней частью страницы (подвалом), подключаемый с помощью jsp: include Thanks for visiting request.gotParameter("fname") 4> <4» roquest.getParameter("Inane") %><br> Session ID: <4 if (request. getSessionO ! null) <%» <4" request.getSession().getXd() %> <H } else (*> Unknown <4 } %> <brxbr> <a href="/index.html">Main</a» | <a href="/service.html">Services</a> | <a hrefs*/sitemap.html"»Site Map</a» | <a href®"/resources.html"»Resources</a> | <a href«"/contacts.html">Contact Us</a»| <a href="/prns_privacy.html">Privacy</a> На рис. 6.7 показан вид страницы solutionsjsp в браузере. ** • При использовании jsp:include изменения во включаемых файлах сразу же отражаются во включающей странице. А если вы измените страницу, включаемую * f директивой include, эти изменения не отразятся на включающей странице до тех пор, пока вы не внесете какие-либо изменения во включающую страницу, что заставит контейнер JSP перекомпилировать ее. \ Включение содержимого в JSP при каждой обработке запроса | 155
Рис. 6.7. Отображение в браузере сегментов с заголовком и нижней частью страницы См. также Рецепт 6.4 по директиве include; рецепт 6.7 по включению сегментов JSP в XML- файлы; рецепт 6.8 по включению содержимого, находящегося вне контекста JSP; главу JSP. 1.10.3 спецификации JSP 2.0 по включению файлов в JSP; главу 23 по тегам JSTL. 6.6 Использование внешнего файла конфигурации для включения ресурсов bJSP Задача Требуется динамически включать в JSP тот или иной файл, основываясь на значении из файла конфигурации. 156 | Глава 6. Динамически подключаемое содержимое страниц JSP и сервлетов
Решение Используйте стандартное действие jsp:include. Файл, который необходимо включить, задайте как значение свойства во внешнем файле свойств или как параметр конфигурации в дескрипторе развертывания. Обсуждение Использование внешней настройки для задания файла, включаемого в JSP. позволяет изменять имя и/или путь включаемого файла, не трогая код JSP. Кроме того, при исполь- зовании jsp:include включающую страйицу не нужно перекомпилировать, чтобы отразить какие-либо изменения во включаемом файле - web-pecjypc включается в JSP при обработке каждого запроса. Если в файле конфигурации вы укажете другой файл, ответ от включаемого ресурса добавится к ответу включающей JSP во время следующего запроса. Различие между стандартным действием j sp: include и директивой include *4» д в том, что последняя включает байты или содержимое импортируемого файла *• ? £ до того, как JSP будет откомпилирована (во время фазы трансляции). Если * . впоследствии включаемый сегмент изменится, изменения не отразятся на JSP, пока сама JSP не будет изменена, что заставит контейнер JSP (например, JSP-контейнер Jasper из Tomcat) перекомпилировать JSP. В примере 6.14 показана JSP, использующая для задания включаемого файла внеш- ний файл свойств.. Пример6.14. Использование java. util.ResourceBundle.getBundleO для включения файла, заданного с помощью внешнего файла конфигурации <%@page contentType="text/html"%> <%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <html> <% java-util.ResourceBundle bundle = java.util.ResourceBundle. get Bundle ("com. j spservletcookbook. include") j String segment bundle.getString("external~include");%> <jsp:include page="<%=segment %>"'/> <body> <h2>Welcome to our Portal Home <c:out value="${param.fname}" /> <c:out value="${param.Iname)" /></h2> <jsp:useBean id="datestring" class="java,.util.Date"/> The time is <c:out value="${datestring}" />.<br><br> </body> </html> Использование внешнего файла конфигурации для включения ресурсов в JSP | 157
В примере 6.14 включается сегмент JSP, путь к которому задан в свойстве exter- nal-include. Это свойство описано в обычном текстовом файле include.properties и выглядит примерно следующим образом: external-include=WEB-INF/ j spf/header_tag.j sp Файл include.properties хранится в WEB-INF/classes/com/jspservletcookbook. Когда ваш сервлет или JSP пытается добраться до списка свойств, вызывая статический метод ! £ j ava .util. ReseourceBundle. getBundle (" cbm. j spservletcookbook. '* include"), getBundle автоматически заменяет символы точка «.» символом «/» и добавляет к концу этой строки «.properties» (в нашем примере будет осуществлен поиск com/jspservletcookbook/include.properties). Код примера сохраняет полученные значения в переменной segment типа String. String segment = bundle.getString("external-include"); После этого переменная segment, задающая путь к файлу с подключаемым сегментом, содержит значение WEB-INF/jspf/header_tag.jsp. Включение выполняется с помощью JSP- выражения <%=segment %> на месте значения атрибута раде элемента j sp: include. <jsp:include page="<%=segment %>"/> 9 Во время работы этой страницы JSP, ответ от включаемого файла включается в ту часть страницы, где находится стандартное действие jsp:include. В примере 6.15 показано содержимое включаемого файла header_tag.jsp. Пример 6.15. Содержимое сегмента header_tag.jsp , <%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <HEAD> <МЕТА name="author" contents "Bruce W. Perry, author®jspservletcookbook.com"> <META name="keywords" contents "Java, JSP, servlets, databases, MySQL, Oracle, web development"> <TITLE>Parker River: Thanks For Visiting <c:out values"${param.fname}"/> <c:out values«${param.Iname}"/> </TITLE> </HEAD> Это законченный HTML-тег HEAD, включающий два вложенных тега - МЕТА и TITLE. Если вы обратитесь к включающей странице с запросом следующего вида: http://localhost: 8080/home/externalIncludeJsp?fname=Mister&lname=Beaii, то возвращаемое от сегмента JSP содержимое - реальный текст, который контейнер JSP подставит вместо тега j sp: include в вывод - выглядит примерно так, как показано в примере 6.16. 158 | Глава 6. Динамически подключаемое содержимое страниц JSP и сервлетов /
Пример 6.16. Вывод, выдаваемый при использовании jsp:include <HEAD> <МЁТА name—'1 author" content= "Bruce W. Perry, author©jspservletcookbook.com"> <META name="keywords" content= "Java, JSP, servlets, databases, MySQL, Oracle, web development"> <TITLE>Parker River: Thanks For Visiting Mister Bean </TITLE> </HEAD> Включаемый сегмент обрабатывает параметры запроса fnanfe и Iname из строки запроса: fname=Mister&lname=Bean и включает их значение в тег TITLE. Вид страницы extemallnclude.jsp в браузере показан на рис. 6.8. dfflE 3 Parker River Thanks Foi Visiting Mister Bean - Microsoft Internet Explorer Refresh^ Back hltp://localhost8080/home/externalfnclude.isp?fname«Misterttlnafne=Bean Welcome to our Portal Home Mister Bean The time is Mon Mar 31 12:43:33 EST 2003. I intranet' Puc. 6.8. Вид в браузере страницы JSP, использующей для включения другого сегмента JSP стандартное действие jsp: incl ude Использование внешнего файла конфигурации для включения ресурсов в JSP | 15
• •’ В данном примере подключаемый сегмент содержит такую директиву taglib, что необходимо использовать теги с: out из JSTL 1.0. Если вы используете JSTL 1.1, " f д* то атрибут URI должен иметь значение http://java.sun.com/jsp/jstl/core. <%@ taglib ' uri«"http://java.sun.com/jstl/core" prefix="c" %> Вы также можете передать параметры на обработку во включаемый сегмент* <jsp:include page="<%=segment %>"> <jsp:param name=*role" value="comedian"/> </jsp:include> ' Если вместо указания пути к включаемому файлу вы хотите использовать параметр контекста в дескрипторе развертывания, добавьте о web.xml элемент context-param (см. пример 6.17). Пример 6.17. Элемент context-рагат, задающий путь к включаемому файлу <context-param> <param-narae>external-include</param-name> <param-value>WEB- INF/ jspf /header_tag. j sp</param-value> </context-param> > . Во включающей странице JSP моркно получить значение контекстного параметра следующим образом. <jsp:include page="<%=application.get!nitParameter("external-include")%>"/> В результате JSP подставит в качестве значения атрибута раде элемента jsp: include путь WEB-INF/jspf/header_tag.jsp. См. также Рецепт 6.4 по директиве include; рецепт 6.7 По включению сегментов JSP в XML- файлы; рецепт 6.8 по включению содержимого, находящегося вне контекста JSP; главу JSP. 1.10.3 спецификации JSP 2.0 по включению файлов в JSP; главу 23 по тегам JSTL; следующую web-страницу о том, как метод getBundle возвращает определенные типы ResourceBundles: http://java.sun.eom/j2se/l.4.1/docs/api/java/util/ResourceBundle. html#getBundle(java. lang.String, java.util.Locale, jaya.lang. ClassLoader). 160 | Глава 6. Динамически подключаемое содержимое страниц JSP и сервлетов
6.7 Включение фрагмента XML в JSP-документ Задача Необходимо включить в JSP-документ файл с фрагментом XML, то есть включить страницу JSP, выполненную в синтаксисе XML. Решение Если необходимо, чтобы включение выполнялось при каждом запросе JSP, исполь- зуйте стандартное действие j sp: include. Если необходимо осуществить включение во время фазы трансляции, используйте элемент j sp: directive. include. Обсуждение Поскольку JSP-документ является правильным XML-файлом, для включения в него сегментов JSP можно использовать два XML-элемента: jsp:include и jsp:direc- tive. include. JSP-докуменг - это страница JSP, выполненная в синтаксисе XML, с соблюдением всех правил XML, иными словами, страница состоит из элементов и атрибутов XML, а также содержимого отдельных элементов XML. Такой JSP-документ затем размещается в корневом каталоге web-приложения (это стандартное местоположе- ние, но можно самостоятельно задать другое место для страниц JSP), и JSP-контсйнер транслирует этот XML-файл в сервлет. Одной из причин использования JSP-документов является интеграция JSP с другими XML-технологиями (XHTML, SVG, SOAP и т. п.). Рецепт 5.5 описывает JSP-документы подробнее. В примере 6.18 показана страница JSP из примера 6.14, выполненная в виде JSP-документа, здесь для включения файла WEB-INF/ ispf/header_tagjspf используемся директива j sp: include. Пример 6.18. JSP-документ, использующий для включения файла директиву jsp:include <jsp:root xmlns:jsp="http?//java.sun.com/JSP/Page" xmlns:c="http://java.sun.com/j s11/core" xmlns= “http: / /www. w3. org/1 99 9/xhtml" vers ion=" 2.0" > <j sp:directive.page contentType="text/html"/> <html> ' । / <jвр:include page«"WEB-INF/jspf/header_tag.jspf" /> <body> <h2>Welcome to our Portal <c:out value=" $ {param, f name} " /><jsp:text> </jsp:text> <c:out value="${param.Iname}• /></h2> *-1545 Включение фрагмент? XML в JSP-документ | 161
<jsp:useBean id="dateString" class="java.util.Date"/> <jsp:text>The time is </jsp:text> <c:out value="${dateString}" <br /><br /> </body> </html> </jsp:root> В примере 6.18 страница JSP включает текст, возвращаемый от headerjag.jspf. При использовании jsp: include сам включаемый файл не обязательно должен быть правильным XML-документом, главное, чтобы он возвращал текст, являющийся правиль- ным XML и корректно состыкующийся с включающим JSP-документом. Спецификация JSP 2.0 рекомендует давать сегментам JSP, включаемым в страницы JSP или JSP-доку^енты, расширение 'jspf. Кроме того, одним из способов отделить JSP-документы от обычных страниц JSP является присвоение JSP-документам расширения .jspx (при использовании web.xml по версии 2.4 спецификации сервлетов). Tomcat 4.1.x будет .компилировать и выполнять файлы с таким расширением как страницы JSP, если вы добавите в conf/web.xml следующие элементы servlet-mapping. < s er vl e t -mappijig> <servlet-name>jsp</servlet-name> <ur1-pattern> *.j spf</url-pa11ern> </servlet-mapping> <servlet-mapping> <servlet-name>jsp</servlet-name> <url-pattern>*. jspx</url-pattern:» </servlet-mapping> В примере 6.49 приведен включаемый файл header_tag.jspf. Он имеет собственную директиву taglib, чтобы теги, включенные в TITLE и связанные с JSTL, вырабатывали правильные значения из параметров запроса fname и lname. Когда к включающей странице поступает запрос http://localhost:8080/home/x617.jspx?fname=Bruce&lname=Perry текст, возвращаемый данцым сегментом JSP, включаемым посредством j sp: include, показывает комментарии, приведенные в нижней части примера 6.19. Пример 6.19. Включаемый файл header_tag.jspf <%@ taglib uri="http://java.sun.com/jstl/core" ptefix="c" %> <HEAD> <META name="author" content= > "Bruce W. Perry, author®jspservletcookbook.com"/> <META name="keywords" content- "Java, JSP, servlets, databases, MySQL, Oracle, web development"/> <TITLE>Parker, River: Thanks For Visiting <c:out value="${param.fname}"/> <c:0ut value="${param.lname}"/> 162 | Глава 6. Динамически подключаемое содержимое страниц JSP и сервлетов
</TITLE> </HEAD> <!--исходный тексту возвращаемый от header_tag.jspf <HEAD> <META name="author" content= "Bruce W. Perry, author©jspservletcookbook.com"/> <META name="keywords" content= "Java, JSP, servlets, databases, MySQL, Oracle, web development"/> <TITLE>Parker River: Thanks For Visiting / Bruce Perry </TITLE> </HEAD> —> На рис. 6.9 показано, как итоговый документ выглядит в браузере. Рис. 6.9. Вид JSP-документа в браузере Для включения можно также использовать элемент j sp: directive. include, включающий содержимое до того, как JSP-документ будет преобразован в сервлет, тогда как jsp:include производит включение уже во время выполнения. Чтобы изменить пример 6.17 для использования jsp:directive.include, замените элемент jsp: include. <jsp:directive.include f ile=“WEB-INF/jspf/header_tag.jspf" /> В данном случае включаемое содержимое не должно иметь синтаксических форм, не принадлежащих языку XML, например директив taglib, поскольку включаемый код включается напрямую в JSP-документ, когда последний преобразовывается в сервлет. Включение фрагмента XML в JSP-документ | 163 6*
Альтернативный подход заключается в использовании в XML секций CDATA, чтобы обернуть слова и символы. Которые в противном случае нарушили бы ** f jfr корректность синтаксиса XML-документа. Секции CDATA выглядят следующим ’ образом: <![CDATA[ ...]]> При использовании jsp:directive.include, для корректной компиляции JSP, необходимо удалить из верхней части кода из примера 6.19 директиву taglib. А для того чтобы теги с: out из включаемого сегмента все еще работали, необходимо проследить за наличием во включающем JSP-документе атрибута xmlns, делающего доступным элементы ядра JSTL, как это сделано в верхней части примера 6.18. Основное правило использования двух механизмов Включения заключается в следующем: если включаемый сегмент будет часто изменяться, причем включающая Страница должна оперативно реагировать на эти изменения, используйте jsp: include. Если включаемый сегмент относительно постоянен, используйте j sp: directive. include. См. также Рецепт 6.4 по директиве include; рецепт 6.5 по стандартному действию jsp: include; рецепт 6.8 по включению содержимого, находящегося вне контекста JSP; главу JSP. 1.10.3 спецификации JSP 2.0 по включению файлов в JSP; главу 23 по тегам JSTL. 6.8 Включение содержимого, находящегося за пределами контекста JSP Задача Требуется включить сегмент JSP, находящийся за пределами контекста включающего файла. Решение Используйте тег ядра JSTL - с: import. Обсуждение Тег с: import дает авторам страницы JSP большую гибкость в подключении ресурсов, находящихся как внутри, так и вне создаваемого web-приложения. Тег с: import позво- ляет странице импортировать ресурсы: J64 | Глава 6. Динамически подключаемое содержимое страниц JSP и сервлетов
• из-за границ web-контейнера, при помощи абсолютного URL (например, http://java. sun.com/api)’, • из другого контекста в пределах того же web-контейнера. Допустим, ваш домен имеет центральный репозиторий подключаемого содержимого, находящийся по адресу http:// www.mydomain.com/warehouse. Тогда страница JSP, инсталлированная в контекст /cus- tomer может импортировать ресурс из контекста /warehouse при помощи тега <с: import ur'l="7cataiog_header. jspf" context="/warehouse" />; • из собственного контекста, наподобие j sp: include. Данный рецепт содержит примеры импорта ресурсов из-за пределов контекста импортирующей страницы JSP. В примере 6.20 импортируется сегмент JSP с именем header_tag.jsp из контекста /dbproj. Атрибут url задает вкЯючае^ый ресурс, атрибут context объявляет контекст из которого JSP импортирует этот ресурс. Чтобы исполь- зовать тег с: import, JSP должна содержать директиву taglib следующего вида. <%в taglib uri="http://java.sun.com/jstl/core" prefix="c" %> В примере 6.20, во второй строке, включается сегмент taglib-inc.jspf с группой тегов taglib. Пример 6.20. Использование тега с: import для импорта по внешнему URL <%t?page contentType=" text/html" %> <%@ include file="/WEB-INF/jspf/tagljb-iric.jspf" %> <html> ' r - <c:import url«"/header_tag.jspf* context-"/dbproj" /> <bpdy> , . ; , . <h2>welcome to our Portal <c:but valuer" ${param.fname}" 7o <c:out yalue^“$(param.Iname}" /> </h2> <jsp:useBean id="datestring" class="java.util.Date"/> The time is <c:out value="${datestring}" />. <br /><br /> </body> </html> ' Тег c: import вставляет текст, генерируемый /dbproj/headerjag.jsp в ту часть кода, где располагается этот тег. Путь к контекрту /dbproj представляет другое (по отношению к импортирующей JSP) web-приложение (другой контекст). Верхняя часть импортирующей страницы выглядит теперь, благодаря HTML, созданному в импортируемом файле, следующим образом: <html> <HEAD> <МЕТА name="author"‘content= "Bruce W. Perry, author@jspservletcookbook.com"/> <META name="keywords" content= Включение co зержимого, находящегося за пределами контекста JSP | 165
"Java, JSP, servlets, databases, MySQL, Oracle, web development"/> <TITLE>Parker River: Thanks For Visiting Mister Bean </TITLE> </HEAD> <body> <!—далее идет продолжение страницы... --> При использовании Tomcat, во избежание исключения при попытке импорта ресурсов из другого контейнера для страницы JSP, использующей с:import, в файле conf/server.xml должен находиться элемент context со следующей парой атрибут/значение. ; crossContext="true" <!—по -умолчанию "false"—> В примере 6.21 импортируется описание протокола НТТР/1.1 (предложения для обсуж- дения (RFC) 2Q68). В этом примере тип содержимого указан как «text/plain», поэтому браузер не будет пытаться отобразить этот текст как HTML, что может сделать текстовые файлы неудобочитаемыми. Затем в примере 6.21 используется директива taglib, для того, чтобы в JSP можно было использовать тег с: import. Тег с: import задает местополо- жение импортируемого текстового файла с помощью абсолютного URL: http://www.ietf. org/rfc/rfc2068. txt. Пример 6.21. Использование с: import для импорта текстового ресурса, заданного с помощью абсолютного URL <%@page contentType="text/plain"%> <%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <c:import url=;"http://www.ietf.org/rfc/rfc2068.txt" /> Если JSP использует c: import для доступа к сомнительному ресурсу (когда сервер, получивший запрос на ресурс, отвечает HTTP-кодом возврата 403), тег с: import вызовет исключение и компиляция JSP завершится неудачно. С тегом с:import можно использовать вложенные в него теги с:param. В примере 6.22 импортируется файл header_tag.jspf и ему передаются на обработку два параметра запроса: fname и Iname. Директива taglib в верхней части примера 6.22 позволяет использовать в остальной части кода теги с: import и с: param. Пример 6.22. Передача значений параметров с помощью с: param <%@ taglib uri="http://java.jsun.com/jstl/core" prefix=“c" %> <html> <c:import url="WEB-INF/jspf/header_tag.jspf" > <c:param name=nfhame" value»"Mister"/> <c:param name»"Iname" value»"Bean"/> 166 | Глава 6. Динамически подключаемое содержимое страниц JSP и сервлетов
</с:import* <body> <h2> Далее идет продолжение страницы...</h2> </body> </html> Файл header_tag.jspf берет значения переданных параметров и помещает их в привет- ствие, формируемое в теге TITLE. HTML, получаемый в результате этого импорта пока- зан в примере 6-23. Пример 6.23. Значения параметров запроса отображаются в выходном HTML <html> » <HEAD> <• <МЕТА name="author" contents "Bruce W. Perry, author@jspservletcookbodk.com"/> <META name=" keywords" contents "Java; JSP,.servlets, databases, MySQL, Oracle, web development"/> <TITLE>Parker River: Thanks For Visiting Mister Bean </TITLE* </HEAD> <body> <h2> Далее идет продолжение страницы ...</h2> </body> </Html> См. также . Рецепты 6.1-6.3 по включению ресурсов в сервлет; рецепты 6.4-6.7 по использованию include и jsp:include, и включению ресурсов в JSP-документы или XML-файлы; главу 23 по использовании > JSTL 1.0; главу JSP.5.4 спецификации JSP 2.0 по j sp: include; главу JSP1.10.3 спецификации JSP 2.0 по директиве include. Включение содержимого, находящегося за пределами контекста JSP | 167
ГЛАВА 7 Обработка данных от web- формы в сервлетах и JSP 7.0 Введение Каждому разработчику знаком сценарий, когда клиент заполняет web-форму и отсылает введенную информацию на обработку в программу, работающую на стороне сервера. В ряде случаев для отправки НТТР-зацроса программе, работающей на стороне сервера, используется метод POST. В методе POST данные пересылаются на сервер в теле запроса^ а не в строке запроса, «прицепом» к URL (как в методе GET). Рассмотрим HTML-тег form из примера 7.1. _ Пример 7.1. HTML-тег form для пересылки данных методом POST <form method=POST асt£on="/project/controller"> <b>User Name:</b> <input type="text" name="username" size="20"> <br><br> <b>Department:</b> <input type="text" name="department" size=" 15" ><brxbr> <b>Email:</b> <input type=*'text* name=" email" size= »15"><br><br> <input type="submit" values"Submit"> </form> Когда клиент нажимает на кнопку «submit», чтобы отослать введенную информацию, формируется текст запроса, начало которого выглядит примерно следующим образом: POST /project/OOntroller HTTP/1.1 Accept: image/gif, image/х-xbitmap, image/jpeg, image/pjpeg, applica- tion/msword, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/pdf, */* Referer: http://Iqcalhost:8080/project/login.jsp Accept-Language: en-us Content-Type: application/x-www-form-urlencoded 168
Немного далее, спустя несколько заголовков, следует тело запроса, содержащее вве- денные данные. username=Bruce+W+Perry&password=bw^pl9 б 8 JSP и сервлеты осуществляют лексический разбор данных, переданных с помощью POST, совершенно незаметно для разработчика. И это - тема нескольких следующих рецептов. Затем мы обсудим, как использовать сервлеты и JSP для отправки данных методом POST, когда они фактически исполняют роль клиента, а не выступают в роли программы на стороне сервера. 7.1 Обработка HTTP-запроса POST в сервлете Задача Требуется обработать данные, являющиеся частью запроса POST. Решение Используйте в |методе doPost сервлета методы ServletRequest.getParame- ter(String nar^e), getParameterMap(), getParameterNames () или get- ParamterValues(String name). Обсуждение Когда клиент посылает HTTP-запрос POST, метод service сервлета вызывает метод doPost сервлета. Далее у разработчика сервлета есть четыре разных метода, которые она может вызвать, чтобы добраться до присланных данных, что делает процесс обработки довольно простым. Если клиентское приложение использует метод GET, чтобы переслать сервлету данные в составе строки запроса, сервлету потребуется в методе doGet () осуществить вызов. doPost(request,response); Пример 7.2 демонстрирует обработку данных, посланных посредством POST, с помощью метода get Parameter (String name), а также с помощью метода getPa- rameterMap (), возвращающего java .util .Мар (карту). Этот объект содержит ключи и значения параметров. Метод getParameterNames!) возвращает java.util .Enu- meration - перечисление с именами параметров. Вы можете по очереди перебирать имена из этого перечисления, передавая их в метод getParameter(String name). Другой метод объекта ServletRequest - getParameterValues (String name) - воз- вращает массив строк (String), содержащий все значения, присланные в параметре с указанным именем (если значение всего одно, возвращается массив, содержащий всего одну строку). На рис. 7.1 показан вид в браузере вывода сервлета PostHandler после того, как пользователь заполнил и отослал форму из примера 7.1. Обработка HTTP-запроса POST в сервлете | 169
Рис. 7.1. Сервлет отображает пары имя/значение параметров, переданных от формы Пример 7.2. Использование методов ServletRequest.getParameter и getParameterMap для обработки присланных данных import j avax.servlet.*; import javax.servlet.http.*; import java.util.Map; import j ava.util.Iterator; import java.util.Map.Entry; public class PostHandler extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException { /* Использование ServletRequest.getParameter(String name), getParameterMap(), getParameterNames(), или getParameterValues() в методе сервлета doPost */ String name = request.getParameter("username"); String depart request.getParameter("department"); String email = request.getParameter("email"); response.setContentType("text/html"); java.io.Printwriter out = response.getWriter(); out.printin("<html>"); out.printIn("<head>"); 170 | Глава 7. Обработка данных от web-формы в сервлетах и JSP
I out .printin ("<title>Welcome</title>’'); out.printin("</head>M); out.printIn(“<body>"); out.printIn("<hl>Your Identity</hl>"); out.printIn( "Your name is: " + ( (name null || name, equal s ("'*)) ? "Unknown" : name)); out. print In (" <brxbr> ") ; out.printIn( "Your department is: " + ( (depart null || depart.equals("")) ? "Unknown" : depart)); »• out. printin (" <brxbr> *) ; out.printIn( "Your email address is: " + ( (email = null || email.equals("")) ? "Unknown" : email)); out.printIn("<h2>Using ServletRequest.getParameterMap</h2>"); Map param_map request. getParameterMapO ; if (param_map -= null) throw new ServletException( "getParameterMap returned null in: ".+ getClass().getName()); //перебор java.util.Map и отображение присланных //значении параметров //ключи объектов Map.Entry имеют тип String; значения //имеют тип String[], //то есть массив сорок Iterator iterator param_map.entryset().iterator(); * while(iterator.hasNext()){ Map.Entry roe» (Map.Entry) iterator .next (); out.println(me.getKey() + ": "); String (J arr (String!)) me.getValueO; for(int i=0;i<arr.length;i++){ out.printIn(arr[i]); ' //в случае нескольких значений, после значения //ставится запятая (кроме последнего) if (i > 0 && i I" arr.length-1) out.printin(", "); }//end for out .printin ("<brxbr>"); Обработка HTTP-запроса POST в сервлете | 171
}//end while out.printin("</body>"); out.printIn("</html>"); } public void doGet(HttpServletRequeSt request, HttpServletResponse response) throws ServletException, java*.io.lOException { doPost(request,response); } } ' ‘.r/i '•> it Получение значения параметра сводится к вызову метода request .getParame- ter(<имя параметра»). Затем, как в коде примера 7.2, можно осуществить проверку значения, чтобы напечатать корректные данные. out.printIn("Your name is: " + ( (name c= null || name.equals(""J) ? "Unknown" : name)); Если переменная name равна null или пустой строке, сервлет печатает «Unknown», в противном случае он печатает значение имени. Существует несколько шаблонов проектирования для проверки данных, введенных в форму, которыми вы можете вос- пользоваться, в том числе серверный сценарий JavaScript и компонент JavaBean для проверки. Обработка типа java. util .Мар (карта) сложнее и требует больше кода. Сервлет получает карту параметров, вызывая метод ServletRequest. Map, param_map = request.getParameterMap() Далее код получает java.util, Iterator от java.util .Set, возвращаемого от Map. entrySet (). Объект Set содержит объекты Map. Entry, являющиеся парами ключ/значение и представляющие имя и значение параметров. Сервлет, для организации цикла по именам и значениям параметров, использует итератор. Iterator iterator = param_jnap. entrySet().iterator(); while(iterator.hasNext()){ Map.Entry me = (Map.Entry) iterator.next(); out.printIn(me.getKey() + ": "); // Возвращаемое значение-массив строк String(] arr = (String[]) me.getValue(); for(int i=0;i<arr.length;i++){ out.printin(arr[i]); // в случае нескольких значений, после значения Г! Ставится запятая (кроме последнего) if (i > 0 && i !.= arr.length-1) out.printIn(", "); 172 | Глава 7. Обработка данных от web-формы в сервлетах и JSP
,}//end for out.printIn("<br><br>"); }//end while Если такой способ обработки присланных данных покажется слишком замысловатым, то оставьте getParameterMap() для приложений, созданных для работы с ниц, например для работы с компонентом JavaBean проверки, принимающим карту (Мар) в качестве параметра конструктора или метода. См. также Рецепт 7.2 по обработке запроса POST в JSP; рецепт 7.5 по передаче (POST) данных от сервлета; рецепт 7.7 по использованию сервлета для добавления параметра в строку запроса; документацию по ServletRequest API: http://java.sun.eom/j2ee/l.4/docs/api/ index.html. 7.2 Обработка HTTP-запроса POST в JSP Задача > ' • Требуется создать страницу JSP, обрабатывающую данные, передаваемые от прило- жения клиента с помощью метода POST. Решение Для перебора имен и значений параметров используйте JSTL-тег с: f orEach. Обсуждение JSTL делает процесс получения данных, присланных методом POST, достаточно простым. В примере 7.3 приведена страница JSP, содержащая некоторый шаблонный текст и JSTL-теги для отображения присланной информации. JSTL-тег с: f orEach перебирает присланные данные, используя неявно созданный JSTL-объект param. Объект param содержит типы java.util .Map.Entry, каждый из которых содержит пару ключ/ значение, представляющую имя и значение параметров, например «department=Develop- ment». Использующие язык выражений (Expression Language (EL)) конструкции * $ {map_ entry, key}" или " ${map_entry. value)" эквивалентны вызову методов Map. Entry. getKey () и getValue (). Возвращаемые ими значения передаются тегу с: out для отображения на HTML-странице. На рис. 7.2 показано, как эта страница будет выгля- деть в браузере, если в JSP переданы данные, введенные в форму из примера 7.1. Чтобы иметь возможность использовать JSTL 1.1, в элементе taglib атрибут uri должен иметь значение http://java.sun.com/jsp/jstl/core. Обработка HTTP-запроса POST в JSP | 173
Пример 7.3. Перебор присланных данных с помощью JSTL <%@page contentType="text/html"%> <%® taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <html> <headxti tie» Post Data Viewer</titlex/head> <body> <h2>Here is your posted data</h2> <c:forEach var=,,map_lentryn items'- "$ {param} "> <strong»<c:out value="${map_entry.key}" /»</strong»: <c:out value= "${map_entry.value} " /xbrxbr» </c:forEach» </body> , </html> \ i При использовании тегов JSTL .обязательно удостоверьтесь в наличии соответ- ствующей директивы taglib. В примере 7.3 taglib обеспечивает работу всех пользова- тельских тегов с префиксом «с» (например, с: forEach). В главе 23 объясняется, как установить JSTL в web-приложение, создавать различные пользовательские теги и использовать EL. Рис. 7.2. JSP отображает присланные пары имя/значение 174 | Глава 7. Обработка данных от web-формы в сервлетах и JSP
Если вы хощте получить значения параметров без использования тега с: f orEach* используйте фрагмент кода, приведенный в примере 7.4. Этот код отображает значения параметров в случае, когда имена параметров известны разработчику (так обычно и бывает). Пример 7.4. Отображение значений отдельных параметров с Ломощью с: out <h2>Here is your posted data</h2> <strong>User name:</strong>: <c:out value=“${param.username}"/> <brxbr> <strong>Department:</strong>: <c:out value="${param.department}"/> <strong>Email:</strong>: <c:out value="${param.email}"/> Подстановка этого кода в JSP приведет к такому же отображению в браузере, как и то, что приведено на рис. 7.2. *• Спецификация JSP 2,0 позволяет использовать EL в шаблонном тексте, то есть без необходимости использовать JSTL-тег с: out. См. также Рецепт 7.2 по обработке запроса POST в JSP; рецепт 7.3 по заданию значений свойств компонента JavaBean из данных, введенных в форму; рецепт 7.4 по присвоению ' значения параметра атрибуту, принадлежащему определенной области видимости; рецепт 7.6 по передаче данных (POST) от JSP; главу 23 по использованию JSTL. 7.3 Установка свойств компонента JavaBean в JSP Задача Требуется установить значения свойств компонента JavaBean из данных, введенных в форму. Решение Используйте стандартное действие jsp:setProperty, с атрибутом property, установленным в «*», и атрибутом класс, установленным в полностью квалифицирован- ное имя класса компонента JavaBean. Установка свойств компонента JavaBean в JSP | 175
Обсуждение Стандартное действие j sp: setproperty имеет встроенный метод для авто- матического отображения значений, введенных в форму на поля (переменные) компо- нента JavaBean. Имена введенных параметро в должны корреспондироваться с Именами методов-установщиков значений свойств (setter) компонента JavaBean. В примере 7.5 показана страница setBean.jsp, получающая данные от HTML-формы. <fonp method=post action="http://localhost:8080/home/setBean.jsp"> i Сначала страница JSP создает объект типа com. jspservletcookbook.UserBean. Затем с помощью jsp:setProperty устанавливаются значения свойств компонента JavaBeap. Значение атрибута name элемента j sp: SetProperty соответствует значению атрибута id элемента jsp:useBean. Атрибут'property элемента jsp: setProp- erty просто устанавливается в «*». Пример 7.5. Страница setBean.jsp, присваивающая свойствам компонента UserBean значения, введенные в форму <%@page contentType= " text/h>tml"%> <%@ taglib uri="http://java.sun.com/jstl/cbrfe" prefix="c" %> <jsp:uscBoan id="userB" class""com. jspservletcookbook.UserBean" > <jsp:setProperty name" "userB" property»"*" /> </jsp:useBean> <html> <headxtitle>Post Data Viewer</title></head> <body> <h2>H'ere is your posted data</h2> <strong>User name</strong>: <d:out value= "${userB. username}" /><brxbr> <strong>Department</strong>: <c: out value=" $ {userB. department}" /><brxbr> <strong>Email</strong>: <c:out valufe="${userB.email)" /> </body> •> </html> В примере 7.5, для отображения на странице в браузере значений свойств компо- нента JavaBean, используется JSTL-элемент с: out. Атрибут value элемента с: out для получения значения свойства использует EL, например ’’${userB.email)". Такой синтаксис эквивалентен вызову метода getEmail () объекта UserBean. В примере 7.6 показан компонент UserBean, использующий соглашение по имено- ванию JavaBean, чтобы убедиться, что значения его свойств можно корректно устанав- ливать и извлекать. Отображение этих значений в браузере показано на рис. 7.3. 176 | Глава 7. Обработка данных от web-формы в сервлетах и JSP
Put. 7.3. Отображение введенных в форму данных посредством Java Bean t , - f I Действие jsp:setProperty, так, как оно используется в данном рецепте, устанавливает значения свойств компонента JavaBean, определяя соответствие имен параметров именам методов-установщиков значений свойств компонента JavaBean (setter). Если у компонента JavaBean имеется поле с именем «Username», то должен существовать параметр с точно таким же именем «Username», а метод- установщик значения поля должен называться "setUsername (String name)" (если поле имеет тип String) и никак иначе. Будьте осторожны, имена чувствительны к регистру символов! Пример 7.6. Инкапсуляция присланных данных в компоненте JavaBean package com.jspservletcookbook; public class UserBean implements java.io.Serializable! String username; String email; String department; public UserBeanOf) public void setUsername(String .username){ if(_usemame != null && „username. length () > 0) username = „username; else username = "Unknown"; ) Установка свойств компонента JavaBean в JSP | 177
public String getUsername(){ if(username != null) return username; v else return "Unknown";} public void setEmail(String _email){ if(„email != null && „email.length() >0) , email = „email; else email = "Unknown"; } ; public String getEmail(){ if(_email != null) return email; / else return "Unknown";} public void setDepartment(String „department){ if(„department != null && „department.length() > 0) department = „department; x else department = "Unknown"; } public String getDepartment(){ if(department J= null) return department; else return "Unknown"; } } В рецепте 7.2 показано, как использовать компонент JavaBean для проверки коррект- ности введенных в форму данных См. также Рецепт 7.2 по обработке запроса POST в JSP; рецепт 7.4 по присвоению значения параметра атрибуту, принадлежащему определенной области видимости; рецепт 7.6 по передаче данных (POST) от JSP; главу 23 по использованию JSTL. 178 | Глава 7. Обработка данных от web-формы в сервлетах и JSP
7 А Присвоение в JSP значения параметра формы атрибуту, принадлежащему определенной Области видимости Задача Требуется атрибуту, имеющему областью видимости запрос, сеанс или приложение, присвоить одно из значений, введенных в форму. Решение Сначала для присвоения свойствам компонента JavaBean значений, введенных в форму, используйте стандартные действия j sp: useBean и j sp: setProperty. После этого с помощью пользовательского JSTL-тега с: set присвойте атрибуту проверенное в компо- ненте JavaBean введенное значение. Обсуждение Некоторые web-приложения могут проверять корректность введенных в форму дан- ных, например комбинацию e-mail/пароль, после чего проверенное значение присваива- ется атрибуту, имеющему областью видимости запрос, сеанс или приложение. Эффективным способом обработки введенных в форму данных является использование компонента JavaBean, чьей целью является проверка этих данных на соблюдение ряда бизнес-правил или соответствие внешнему источнику данных, например базе данных. Если данные корректны, приложение создает, например, атрибут сеанса, инициа- лизируемый этим значением. Если введенные данные некорректны, то логическая переменная в компоненте JavaBean устанавливается в false. Страница JSP, которой посылаются введенные в форму данные, мойсет проверить эти значения, Перед тем как обрабатывать их как корректные. В примере 7.7 показан компонент JavaBean ClientValidator, имеющий три поля: email, password и valid. Этот компонент используется страницей JSP для проверки введенных в форму данных, перед тем/ к^к страница присвоит эти данные атрибутам с областью видимости - запрос. Пример 7.7. Компонент JavaBean ClientValidator package com.j spservletcookbook; public class ClientValidator implements java.io.Serielizable{ String email; String password; boolean valid; Присвоение в JSP значения параметра формы атрибуту | 179
public ClientValidator(){ this.valid=filse;} public boolean isValid(){ f /* С помощью объекта доступа к данным (Data Access Object)проверяется email и пароль. Если данные корректны, this.valid устанавливается в true*/ this.valid=true; return valid; } t public void setEmail(String „email){ , if(„email != null && „ernai 1.length()'> 0) email = „email;, else / email = "Unknown"; } public String getEmail(){ return email; ' } public void setPasswOrd(String „password){ if («password != null && „password.length() >0) password = „password; else- paSsword = "Unknown"; } public String getPassword(){ return password; } 7 .} Страница JSP, использующая компонент ClientValidator приведена в примере 7.8. Сначала с помощью j^sp: useBean создается экземпляр компонента. Затем полям (свойст- вам) компонента присваиваются присланные значения (e-mail и пароль). После этого значение свойства isValid проверяется на true с помощью следующего JSTL-кода. <o:if test="${isValid)"> JSP присваивает значения двум атрибутам с областью видимости - запрос. Теперь эти атрибуты доступны странице, на которую переадресуется данный запрос. Атрибуты с областью видимости сеанс доступны из сервлетов и JSP, связанных с этим же сеансом (см. главу 11). Область видимости «приложение» распространяется на контекст (web- Ттриложение). 180 | Глава 7. Обработка данных от web-формы в сервлетах и JSP
Если требуете» задать значения атрибутам с областью видимости сеанс или 4 приложение, замените код примера 7.8 на следующий код. —__<с: set var=" email" value= ** $ {chk. email}". 'scope»"session" /> <c:set var="password" value="${chk.password}" scope»"session" J> , или: <c:set var="email" value="${chk.email}" scope»"application" /> <c:set var="password" value="${chk.password}" scope="application" /> Пример 7.8. Страница validChk.jsp, использующая компонент JavaBean для верификации данных, введенных в форму <%@page contentType="text/html"%> <%© taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <jsp:useBean id«-"chk" class» "com. j spservletcookbook. Cl ientValidator" > <jsp:setProperty name»"chk" property»"*" /> </jsp:useBean> <%— получаем корректные значения от компонента ClientValidator —%> <с:set.var»"isValid" value»"${chk.valid}" /> <c:if test»"§{isValid}"> <c:set var»"email" value»"${chk.email}" scope»"request" /> <c:set var»"password" value»"${chk.password}" scope»"request" /> </c:if> <html> <head><title>Client Checker</titlex/head> <body> f <h2>Welcome</h2> <strong>Email</strong>: <c:out value»"${email}" /><brxbr> <strong>Password</strong>:i. <c:out value»"${password}" /> </body> </html> См. также . .t Рецепт 7-2 пр обработке запроса POST в JSP; рецепт 7.3 по заданию значений свойств компонента JavaBean из данных, введенных в форму; рецепт 7.6 по передаче данных (POST) от JSP; главу 23 по использованию JSTL. Присвоение в JSP значения параметра формы атрибуту | 181
7.5 Передача данных (POST) от сервлета Задача Требуется переслать из сервлета параметры и их значения в виде запроса POST. Решение Для автоматизации отправки данных (POST) другим программам используйте компо- нент HttpClient (из Jakarta Commons) и его класс PostMethod. \ * Обсуждение Компонент HttpClient из Jakarta Commons позволяет разработчику замаскировать в своем JAVA-коде особенности работы web-браузеров, например отправки GET или POST HTTP-запросов, а также ^использование HTTPS для защищенного обмена. Как написано в домашней странице этого полезного компонента, HttpClient «обеспечивает эффек- тивную, отвечающую современным требованиям, со множеством возможностей, реали- зацию клиентской стороны для большинства самых последних стандартов и рекомендаций по HTTP» (http://jakarta.apache.org/commons/httpclient/). HttpClient распространяется под лицензией Apache Software. В данном рецепте описано использование HttpClient для отправки данных другой работающей на стороне сервера программе с помощью HTTP-метода POST. Для начала скачайте HttpClient с сайта Jakarta (http://jakarta.apache.org/commons/httpclient/down- loads.html). Затем распакуйте дистрибутив и поместите содержащийся там JAR-файл в каталог WEB-INF/lib своего web-приложения. Во время написания этих строк был дос- тупен JAR-файл Release 2.0 Alpha 3: commons-httpclient-2.0-alpha2.jar. После инсталля- ции вы можете начать использовать классы этого компонента в своих сервлетах и компонентах JavaBean. В примере 7.9 приведен сервлет, посылающий данные странице JSP: http://localhost: 8080/home/viewPost.jsp. Файл viewPost.jsp со страницей, отображающей присланные дан- ные, показан в примере 7.3. Обратите внимание на классы из пакета org.apache, commons. httpclierit, которые импортируются в верхней части сервлета. » Пример 7.9. Сервлет, посылающий с помощью HttpClient данные странице JSP package com.jspservletcookbook; import javax.servlet.*; import j avax. servlet. http. * ; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpStatus; import org. apache. commons. httpclient. methods. PostMethod; 182 | Глава 7. Обработка данных от web-формы в сервлетах и JSP
import org.apache.commons.httpclient.NameValuePair; public class ClientPost extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.lOException { HttpClient httpClient « new HttpClient( ) ; PostMethod postMethod » new PostMethod ( "http://localhost:8080/home/viewPost.jsp"); NameValuePair[] postData { new NameValuePair("username", "devgal"), < new NameValuePair ("department", ' development”), new NameValuePair("email", "devgalGyahoo.com") }; //в версии 2.0 betal появился метод //PostMethod.setRequestBody(NameValuePair[]) i //а метод addParameters удален postMethod.addParameters(postData); httpClient.executeMethod(postMethod); , //отображаем ответ на метод POST z 1 response.setContentType("text/html"); java.io.Printwriter out = response.getWriterO; //Код возврата (HTTP Status Code) "200 OK" if (postMethod.getStatusCode() HttpStatus.SC_OK) { out.printIn(postMethod.getResponseBodyAsString()); } else ( n out.printIn("The POST action raised an error: " + postMethpd.getStatus- LineO); }' //освобождаем соединение, использованное методом postMethodireleaseConnection(); } '• public void doGet(HttpServletRequest iequest, HttpServletResponse response) throws ServletException, java.io.lOException { doPost(request,response); i } } Передача данных (POST) от сервлета | 183
Приведенный код посылает странице JSP, которая будет обрабатывать данные, три пары имя/значение (с именами username, department и email). HttpClient принимает возвращаемый в результате выполнения метода POST текст, и его можно отобразить в этом же сервлете. Если в ответ на запрос POST ожидается текст большого объема, то вместо метода getResponseBodyAsString () нужно использовать метод HttpMe):hodBase. getResponseBodyAsStreamf). Последний (метод getResponseBodyAsStream ()) возвращает объект java, io. Inputstream. Пример 7.9 создан на основе примеров кода, приведенных на web-сайте компонента HttpClient. Рис. 7.4 показывает результат запроса сервлета ClientPost в браузере. Рис. 7.4. Отображение текста, возвращаемого в ответ на отправку сервлетом данных См. также Рецепт 7.1 по обработке запроса POST в сервлете; рецепт 7.7 по использованию сервлета для добавления параметра в строку запроса; страницу компонента HttpClient (Jakarta Commons): http://jakartajapache org/commons/httpclient. 184 | Глава 7. Обработка данных от web-формы в сервлетах и JSP
7.6 Пересылка данных методом POST из JSP Задача Требуется переслать параметры и их значения в составе HTTP-запроса POST из JSP. Решение Самым простым является старый способ - использовать HTML-тег form и кнопку Sub- mit (представить). Если требуется послать данные динамически (не полагаясь на нажатие пользователем кнопки), используйте компонент JavaBean, инкапсулирующий код работы с HttpClient, описанный ь рецепте 7.5. Обсуждение Самый простой способ инициировать метод POST из JSP - задать шаблонный HTML- текст, приведенный в примере 7.1, с HTML-тегом form, когда пользователь заполняет форму данными и отсылает их, нажав кнопку Submit Поскольку типичная форма была уже приведена в примере 7.1, здесь я покажу компонент JavaBean, позволяющий странице JSP динамически посылать данные другому процессу, также выполняющемуся на стороне сервера. Пример 7.10 демонстрирует страницу jspPost.jsp, использующую вспомогательный класс PostBean для отправки набора параметры/значения другой странице JSP. Получающая страница, viewPost.jsp, обрабатывает параметры, посылаемые ей объектом PostBean, и возвращает некоторый тек^т, который отображает JSP из примера 7.10. Исходная страница передает классу PostBean параметры, которые необходимо отправить, в виде java.util .Мар. Свойство url объекта PostBean задает место назначения отправляемых данных (адрес, которой в ином случае вы поместили бы в атрибут action HTML-тега form). Сначала код. <jsp:setproperty name="postBean" property="parameters" value="<%= request. getParameterMap() %>" /> с помощью метода HttpServletRequest. getParameterMap () получает карту параметров (Map), которые были переданы странице jspPost.jsp, а затем передает эту карту классу PostBean для дальнейшей пересылки. Пример 7.10. Страница JSP, передающая параметры и значения динамически < %@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> < %— создаем экземпляр класса PostBean, если он еще не создан —%> <jsp:useBean id="postBean" class="com.jspservletcookbook.PostBean" /> < %— присваиваем свойству parameters объекта PostBean значение типа Map (карта) - -%> Пересылка данных методом POST из JSP | 185
<jsp:setProperty name*"postBean" property*"parameters* value*"<%= request, getParameterMap()4>" /> <jsp:setProperty name*"postBeanM property*"url" value*"http://localhost: 8080/home/viewPost.jsp" /> <%— Отсылаем параметры и отображаем ответный текст —%> <jsp:getProperty name*"postBean" property*"post"/> В примере 7.11 показан класс Post Bean, используемый страницей JSP для посылки данных. Этот компонент JavaBean, для отправки HTTP-запроса POST, использует компо- нент HttpClient (из Jakarta Commons). Сама отправка происходит в методе PostBean, get Post (), который посылает параметры и возвращает текстовый ответ от получающего сервлета (в данном случае от viewPost.jspY Поскольку данный метод компонента JavaBean носит имя get Post (), то в соответствии с соглашением JavaBean об именовании методов, возвращающих значения свойств, из JSP к нему можно обращаться следующим образом: сjsp:getProperty name="postBean" property="post"/> Вышеприведенная строка кода затем заменяется возвращаемым значением типа String. Пример 7.11. Компонент JavaBean, пересылающий данные методом POST, для использования в сервлетах и JSP package com.j spservletcookbook; Import java.util.Map; import java.util.Iterator; import java.util.Map.Entry; T import org.apache.commons.httpclient.HttpClient; irnnort org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.methods.PostMOthod; , import org. apache. commons. httpclient. MameValuePair; import org.apache.commons.httpclient.HttpException; public class PostBean implements java.io.Serializable { private Map parameters; private String url; public PostBean(){ } public void setparameters(Map param){ if (param != null) parameters = param; } public Map getParameters(){ 186 | Глава 7. Обработка данных от web-формы в сервлетах и JSP
return parameters; } ' public void setUrl(String url) ( if (url != null && !(url.equals(""))) this.url=url; ) public String getUrl(){ return url; } public String getPost() throws java.io.IOException,HttpException{ c. if (url == null || url.equals("") || parameters == null) throw new IllegalStateExceptionf "Invalid url or parameters in PostBean.getPost method."); String retumData = "" ; HttpClient httpClient new HttpClient(); PostMethod postMethod » new PostMethod(url); //преобразуем Map, переданный ж компонент к типу NameValuePair[] NameValuePair!] postData * getParams(parameters); //в версии 2.0 betal•появился метод //PostMethod.setRequestBody(NameValuePair(]) //а метод addParameters удален postMethod.addParameters(postData); httpClient.executeMethod(postMethod); //Код возврата (HTTP Status Code) "200 OK” if (postMethod.getStatusCode() HttpStatus.SCJDK) ( retumData» postMethod. getResponaeBodyAsString (); } else { retumData» "The POST action raised an error: " + postMethod.getStatus£ine(); } //освобождаем соединение, использованное методом postMethod.гeleaseConnection(); return retumData; }//end getPost private NameValuePair[] getParams(Map map){ Пересылка данных методом POST нз JSP | 187
NaxneValuePair [] pairs new NaroeValuePair[map.size() ]; //Используем итератор, чтобы поместить пары имя/значенио //из карты (Мар) в массив Iterator iter map.entryset().iterator(); • int 1 0; while (iter.hasNoxt()){ Map.Entry me (Map.Entry) iter.next(); //Map.Entry.getValue() возвращает массив String[] pairs[i] new NamaValuePair( ' (String)me.getKey()<((String[]) me.getValue())[0]); i++; } return pairs; }//end getParams } Отображаемый результат выглядит так, как показано на рис. 7.5, поскольку здесь для отображения пар имя/значение, передаваемых в JSP, также используется viewPosj.jsp. Повторюсь, если вы хотите использовать JSP для динамической имитации HTML-формы, очень неплохая идея - делегировать механизм отправки данных компоненту JavaBean, и тогда JSP, как ей и положено, останется компонентом презентации, и к тому же создан- ный компонент JavaBean можно использовать повторно в других приложениях. См. также у . , •» г Рецепт 7.2 по обработке запроса POST в JSP; рецепт 7.3 по заданию значений свойств компонента JavaBean из данных, введенных в форму; рецепт 7.8 по использованию JSP для добавления параметра в строку запроса. 188 | Глава 7. Обработка данных от web-формы в сервлетах и JSP
Рис. 7.5. Отображение параметров, добавленных перенаправляющей страницей JSP 7.7 Использование сервлета для добавления параметра в строку запроса Задача Вы хотите использовать сервлет, чтобы добавить один или несколько параметров к строке запроса и затем перенаправить этот запрос к месту конечного назначения. Решение , / Для получения существующей строки запроса используйте API HttpServletRe- quest. Затем добавьте в нее несколько новых параметров и перенаправьте запрос с помощью javax. servlet .RequestDispatcher. Обсуадение Сервлет из примера 7.12 просто берет любую существующую строку запроса и добавляет к ней дополнительные параметры. Затем он посылает расширенную строку запроса, вызывая RequestDispatcher. forward. Использование сервлета для добавления параметра в строку запроса | 189
Пример 7.12. Добавление параметра к строке запроса с помощью сервлета import j avax.servlet.*; > import javax.servlet.http.*; public class QueryModifier extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.lOException { //returns null if the URL does not contain a query string String querystr = request.getQueryString(); if (querystr != null){ t querystr querystr + "&inspector-name«Jen&inspedtor-emailnJenniferqOyahoo.com”; } else { T querystr = " inspector-name®Jen&inspector-emaileJenniferqdyahoo. cbm" ; } RoquestDispatcher dispatcher « request.getRequestDispatcher("/viewPost.jsp?"+querystr); dispatcher.forward(request,response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.lOException { doGet(request,response); } } • • Метод HttpServletRequest.getQueryString() возвращает строку запроса без открывающего «?». - iff.* first=Bruce&last=Perry&zipcode=01922 Если вы хотите получить URL запроса, предшествующий строке запроса, без символа «?», используйте HttpServletRequest.getRequestuRL(), который возвращает результат типа java. lang. StringBuf f еУ. ч См. также < Рецепт 7.1 по обработке запроса POST в сервлете; рецепт 7.5 по посылке (POST) дан- ных от сервлета. 190 | Глава 7. Обработка данных от web-формы в сервлетах и JSP
7.8 Использование JSP для добавления параметра к строке запроса Задача Вы хотите использовать JSP, чтобы добавить один или нескольких параметров к строке запроса и затем перенаправить запрос к месту назначения. Решение Используйте стандартные действия j sp: forward и j sp: papain. Обсуждение Чтобы добавить один или нескольких параметров и перенаправить запрос другому компоненту, требуется просто добавить в JSP четыре строки. Действие j sp: forward добавляет любые j sp: param к существующим параметрам, когда перенаправляет этот текст обрабатывающему компоненту, см. пример 7.13. Пример 7.13. Добавление параметров и перенаправление в JSP <jsp:forward page="/viewPost.jsp” > ' <jsp:param name="inspector-name" value="Jen"/> <jsp:param name="inspectdr-email" value="jenniferq@yahoo.com"/> </j sp:forward> Если обратиться к этой странице с помощью следующего URL: http://localhost:8080/home/addParam.jsp?first=Bruce&last=Perry&zip=01922 то три оригинальных параметра (first, last и zip) сохраняются, когда действие jsp: forward добавляет два дополнительных параметра (inspector-name, inspec- tor-email) и перенаправляет страницу. В данном примере страница обрабатывается страницей viewPost.jsp, приведенной в примере 7.3. Запрошенная из браузера страница addParam.jsp перенаправляет запрос с пятью параметрами к странице viewPost.jsp. Резуль- тат отображается в браузере так, как показано на рис. 7.5. См. также Рецепт 7.2 по обработке запроса POST в JSP; рецепт 7.3 по заданию значений свойств компонента JavaBean из данных, введенных в форму; рецепт 7.6 по передаче данных (POST) от JSP. Использование JSP для добавления параметра к строке запроса | 191
7.9 Использование фильтра для чтений значений параметров - Задача Вы хотите использовать фильтр для перехвата и чтения данных, введенных в форму. Решение Для получения значения параметров в фильтре, используйте различные методы get- Parameter программного интерфейса (API) ServletRequest. Обсуждение Класс фильтра, создаваемого для сервлета, должен реализовывать интерфейс javax. servlet .Filter. Это означает, что этот класс Filter реализует методы doFilter (request, response) и destroy () этого интерфейса. Метод doFil- ter содержит «тропинку» к значениям параметров фильтруемого сервлета. Параметр ServletRequest метода doFil ter имеет методы get Parameter, getParame- terMap, getParameterNames и getParameterValues, позволяющие фильтру подсмотреть параметры (и их значения) запроса к этому сервлета. Но сначала необходимо отобразить созданный фильтр на требуемый сервлет. Приве- денная ниже цепочка из web.xinl отображает объект Filter на сервлет по имени Viewer. <•—здесь идут элементы context-param —> <filter> <filter-name>ParamSnoop</filter-name> <filter-class>com.jspservletcookbook.ParamSnoop</filter-class> </filter> < f i 1 ter-mapping» < fi1ter-name>ParamSnoop</fi1ter-name> <servlet-name>Viewer</servlet-name> </filter-mapping» <!—продолжение web.xml —> Поместите класс фильтра в каталог WEB-INF/classes своего web-приложения или внутрь JAR-файла находящегося в WEB-INFAib. Во время своего старта контейнер сервлетов создает по экземпляру каждого фильтра, объявленного в web.xml. Затем, при запросе пользователя к любому из сервлетов, на которые отображен данный фильтр, контейнер выполняет фильтр (вызывая его метод doFilter). Таким образом, фильтр ParamSnoop может проинспектировать запрос к сервлету Viewer до того, как сервлет обработает этот запрос. 192 | Глава?. Обработка данных от web-формы в сервлетах и JSP
Согласно спецификации сервлетов версии 2.4, глава SRV.6.2.1: «для каждой , * виртуальной Java-мащиньг, выполняемой на контейнере, создается только 4 t по одному экземпляру фильтра, объявленного в дескрипторе развертывания». В примере 7.14 доступ к параметрам перехватываемого запроса осуществляется с помощью вызова метода ServletRequest .getParameterMap!). Однако вы можете использовать для этого и другие методы ServletRequest API, например getParam- eterStringName. Метод getParameterMap!) возвращает карту java, util .Мар имен и значений параметров, которые можно извлечь из карты с помощью итератора j ava. ut i 1.1 terator и его метода next (). •Метод Map.entrySet () возвращает java.util .Set, из которого можно j получить Iterator, вызвав метод Set .iterator (•). В этом случае метод It era tor. next () возвращает объекты Map. Entry, содержащие пары ключ/ значение, представляющие имя и значение параметров. В примере 7.14 также показано, как извлечь из карты параметров пары имя/значение параметра и запротоколировать их с помощью метода ServletContext. log (). Пример 7.14. Подглядывание за значениями параметров запроса сервлета package com.j spservletcookbook; import j avax.servlet.*; k import j avax.servlet.http.*; import java.util.Map; import java.util.Iterator; import java.util.Map.Entry; public class ParamSnoop implements Filter { private FilterConfig config; /** Создание нового экземпляра ParamSnoop */ public ParamSnoop!) { < } public void init(FilterConfig filterCoiifig) throws ServletException! this, config = ijil terConf ig(; ) public void doFilter! ServletRequest request, ServletResponse response^, Filterchain chain) throws java.io.IOException, ServletException { Map paramMap request.getParameterMap!); ServletContext context « config.getServletContext!); /* Используем метод ServletContext.log для протоколирования 7 Использование фильтра для чтения значений параметров | 193
имен/значений параметров */ , context.log("doFilter called in: " + config.getFilterNameO + " on " + (new java.util.Date())); context.log("Snooping the parameters in request: " + ((HttpServletRequest) request).getRequestURI()); i Iterator iter paramMap.entrySet().iterator(); while (iter.hasNext()){> Map.Entry me (Map.Entry) iter.nextO; cont ext. log ((String) me. getKey() + + ((String[]) me.getValue())[0]); } ; //послать запрос дальше, к Следующему фильтру //или к сервлету назначения chain.doFilter(request,response); } public void destroy(){ /♦вызывается перед удалением экземпляра фильтра из обслуживания в web-контейнере*/ } } Единственной причиной использования метода ServletContext. log () было желание отобразить результат инспекции параметров запроса. Ниже приводится пример протокола Tomcat, находящегося в каталоге <Tomcat-mstallation-directory>/logs, в который выведены два параметра, переданные в запросе к сервлету (last и first). Иными словами, из браузера был сделан запрос http:/Aocalhost:8080/home/ viewer?first-Bruce&last=Perry. 2003-04-13 17:13:33 doFilter called in: ParamSnoop on Sun Apr 13 17:13:33 EDT 2003 2003-04-13 17:13:33 Snooping the parameters in request: /home/viewer 2003-04-13 17:13:33 last: Perry 2003-04-13 17:13:33 first: Bruce • I См. также Рецепт 7.1 по обработке запроса POST в сервлете; рецепт 7.7 по использованию сервлета для добавления параметра в строку запроса; главу 19 по фильтрации запросов и ответов; главу SRV.6 спецификации сервлетов версии 2.4 по фильтрам. 194 | Глава 7. Обработка данных от web-формы в сервлетах и JSP
ГЛАВА8 , I Выгрузка файлов 8.0 Введение Чтобы дать возможность пользователю выгрузить файл из своей файловой системы для обработки на сервере, на web-сайтах, используется HTML-тег form. Элемент input, вложенный в тег form, имеет атрибут type, которому для выгрузки файла необходимо присвоить значение file. Теги form и input имеют синтаксис, описан- ный в рецепте 8.1. HTTP-запрос на выгрузку файлов использует тип контента «multipart/form-data». HTTP-сообщение, которое пользователь посылает на сервер, нажав на vfreb-странице клавишу подтверждения ввода, включает в себя описательные заголовки и тело каж- дого из выгружаемых файлов. Каждый из выгружаемых файлов отделяется от других заданным шаблонным ограничителем (см. значение заголовка Content-Туре в примере 8.1). В примере 8.1 показан, в урезанном виде, запрос с содержимым типа "multipart/form-data", включающий с себя три очень небольших выгружаемых файла. Чтобы сделать пример компактнее, я удалил некоторые значения из заголовка Accept этого запроса. Пример 8.1. Сообщение с HTTP-запросом, включающим три выгружаемых файла POST /home/upload.jsp HTTP/1.1 Accept: image/gif, image/х-xbitmap, ima^e/jpeg, image/pjpeg ... Referer:.http://localhost:8080/home/interact.html Accept-Language: en-us Content-Type: multipart/form-data; boundary^----------------------- 7d33cllc6018e Accept-Encoding: gzip, deflate ' User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0) Host: localhost:9000 Content-Length: 541 Connection: Keep-Alive Cache-Control: no-cache Cookie: JSESSIONID=7F6154184FFF3DiAE345ElF2FFFlA22E -----------------------------7d33cllc6018e 195 7*
' Content-Disposition: form-data; name="filel"; filename»nH:\home\filel.txt" Content-Type: text/plain This is file 1. ----------------------------7d33cllc6018e Content-Disposition: form-data; name="file2"; filename*"H:\home\file2.txt" Content-Type: text/plain This is file 2. \ ----------------------i-----7d33cllc6018e Content-Disposition: form-data; name="file3"; filename*"!!:\home\file3.txt” Content-Type: text/plain This is file 3. ' _ ----------------------------7d33cllc6018e— В HTTP-запросе каждый из выгружаемых файлов отделен шаблонным ограничителем. -------------__---7d33cllc6018e Каждый файл имеет заголовки Content-Disposition и Content-Туре., Эти простые текстовые файлы, выгружаемые на сервер, состоят лишь из одной строки, чтобы дать вам представление о том, как выглядит данный вид HTTP-запроса. Более подробная информация о механизме выгрузки файлов содержится в RFC 1867: http:// www.ietf.org/rfc/rfcl867. txt. 8.1 Подготовка HTML-страницы для выгрузки файлов Задача Неоходимо создать HTML-страницу, позволяющую пользователю указать файл своей файловой системы, который требуется выгрузить на сервер. / Решение Используйте НТЭДЬ-тег form с атрибутом enptype, установленным в «multipart/ form-data». Используйте тег input, вложенный в тег form, с атрибутом type, установ- ленным в «file».. Обсуадение Код HTML, предназначенный для выгрузки файлов, должен включать в себя ряд необ- ходимых вещей. Тег form задает сервлет (или другой компонент, работающий на стороне сервера), который будет обрабатывать выгружаемый файл, указанный в атрибуте action этого тега. Чтобы выгрузка работала, атрибут method должен быть установлен в POST (не GET). Атрибут enc type тега form должен иметь значение «multipart/form-data». 196 | Глава 8. Выгрузка файлов »
Пользователь вводит файл, предназначенный для выгрузкй с помощью тега input с атрибутом type равным «file», который на форме выглядит как текстовое поле. Атрибут name однозначно идентифицирует каждый конкретный тег input, что приобретает важ- ное значение, когда HTML-код предполагает выгрузку более одного файла (см. замечание в конце данного рецепта). Без какого-либо дополнительного вмешательства сервер сохраняет у себя выгруженные файлы под их исходными именами. Атрибут accept предназначен для ограничения типов файлов, которые пользователь может выбрать для выгрузки (например, только MIME-типы «application/pdf»), однако этот атрибут плохо поддерживается некоторыми браузерами. При отображении HTML-кода из примера 8.2 браузеры автоматически показывают кнопку Browse. При нажатии на эту кнопку браузер открывает стандартное для файловой системы окно выбора файла, с помощью которого пользователь < Может выбрать файл для выгрузки. Пример 8.2. Простой НТМЪкод для выгрузки файла <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>Please Choose The File</title> </head> <body bgcolor="#ffffff"> <table border»"0"><tr> <form actions"/home/servlet/com.j spservletcookbook.UploadServlet" method»"post" enctype*"multipart/form-data"> <td valign="top"xstrong>Please choose your document:</strongxbrx/td> <td> <input type="file" name=”filel"> <brxbr> </tdx/tr> <trxtdxinput type»"submit" value»'Upload File"x/tdx/tr> </form> <7table> </body> f </html> /• После выбора файла, в текстовом поле выводится полный путь к выбранному файлу. Рис. 8.1 показывает внешний вид этой HTML-страницы в браузере. На рис. 8.1 показано поле input после того, как пользователь выбрал файл. Браузер автоматически заполняет это текстовое поле значением полного пути к выбранному файлу. Чтобы можно было выгрузить более одного файла, включите несколько* тегов ' input с разными значениями атрибута name. Браузер свяжет кнопку Browse * с каждым из них. Подготовка HTML-страницы для выгрузки файлов | 197
Рис. 8.1. HTML-страница для выгрузки файла в сервлет См. также Рецепт 8.2 по использованию для выгрузки файлов библиотеки com.oreilly. serv- let; рецепт 8.3 по выгрузке одного файла; рецепт 8.4 по выгрузке нескольких файлов; рецепт 8.5 по управлению именами файлов; рецепт 8.6 по использованию JSP для выгрузки файлов; домашнюю страницу com.oreilly.servlet: http://www.servlets.com/cos/index. html, RFC 1867 по выгрузке файлов с помощью формы: http://www.ietf.org/rfc/rfcl867.txt. 8.2 Использование библиотеки com.oreilly.servlet Задача Для выгрузки файлов вы хотите воспользоваться классами com.oreilly.servlet, разработанными постоянным автором издательства O’Reilly Джейсоном Хантером. * ♦’ Библиотека Джейсона Хантера берет на себя всю основную работу по выгрузке файлов. Я использую здесь эту библиотеку (конечно, с разрешения автора), поскольку она делает работу по выгрузке красиво, а кроме того, нет необходимости * заново изобретать и без того совершенное колесо. Решение Скачайте дистрибутивный ZIP-файл с http://www.servlets.com/cos/index.html. Добавьте входящий в дистрибутив файл cos.jar в каталог WEB-INF/lib своего web-приложения. Убедитесь, что не нарушаете лицензионное соглашение, используя данную библиотеку. 198 | Глава 8. Выгрузка файлов
Обсуждение JAR-файл cos.jar включает в себя пакеты com.oreilly. servlet и срт. oreilly. servlet .multipart. Эти пакеты содержат несколько классов, в том числе классы, имя которых начинается с «Multipart», которые можно использовать в сервлете для выгрузки файла. * *' Архив cos.jar также включает ряд других интересных и полезных классов, предназначенных для использования в сервлетах, однако приводимые здесь * f рецепты посвящены только выгрузке файлов. Загрузите с сайта http://www.servlets.com/cos/index.html последнюю версию ZIP-файла с дистрибутивом. Этот ZIP-файл содержит cos.jar, который необходимо поместить в каталог V'EB-INF/classes ваше] о приложения. Впоследствии вы можете импортировать необходимые классы в свой сервлет. inport com.oreilly.servlet.MuitipartRequest; import com. oreilly. servlet .multipart. FiTeRenamePolicy; Но перед тем как вы интегрируете эти классы в свой код, внимательно прочитайте лицензионное соглашение по их использованию: http://www.servlets.com/cos/license.html. В последующих рецептах данной главы предполагается, что cos.jar у вас уже есть и содержащиеся в нем классы доступны web-приложению. Если вы не сделаете необходимые шаги по обеспечению доступности этих классов в ваших web- приложениях, ни один из приведенных в главе примеров не будет работать правильно. См. также Рецепт 8.1 по подготовке HTML-кода для выгрузки файлов; рецепт 8.3 по выгрузке одного файла; рецепт 8.4 по выгрузке нескольких файлов; ’ рецепт 8.5 по управлению именами файлов; рецепт 8.6 по использованию JSP для выгрузки файлов; домашнюю страницу com,.oreilly, servlet: http://www.servlets.com/cos/index.html’, RFC 1867 по выгрузке файлов с помощью формы: http://www.ietf.org/rfc/rfcl867.txt. Использование библиотеки com.oreilly.servlet | 199
8.3 Выгрузка одного файла Задача Требуется создать компонент, способный принимать выгружаемый клиентом файл и сохранять его в локальном каталоге. Решение Создайте сервлет, использующий класс com.preilly.servlet.MultipartRe- quest из созданного Джейсоном Хантером архива cos.jar. Обсуждение Класс MultipartRequest включает несколько перегружаемых конструкторов. Один из них, используемый в примере 8.3, принимает в качестве параметров объект javax. servlet .http.HttpServletRequest, путь к каталогу, где вы хотите сохранить выгружаемые файлы, и предельно допустимый размер этих файлов. В примере 8.3, если клиент выгружает файл размером более 5 Мб, сервлет UploadServlet возбуждает исключение java. io. lOException. Вы можете сделать так, как сделано в примере 8.3: позволить обработать это исключение в элементе error-page файла web.xml, созданном для исключений lOException, или использовать для обработки ошибок в сервлете блок ~ try/catch. Объявление страниц ошибок в web-приложении описано в гл^ве 9. После создания экземпляра класса MultipartRequest, этот объект сразу присту- пает к выгрузке файла, то ест^ь для выгрузки вам не придется вызывать какие-либо методы. Сервлет из примера 8.3 инициирует выгрузку файла и затем отображает имя выгружаемого файла (файлов). Пример8.3. Сервлет, использующий классMultipartRequest package com.j spservletcookbook; import javax.servlet.*; import j avax.servlet.http.*; import com.oreilly.servlet-MultipartRequest; import java.util.Enumeration; public class UploadServlet extends HttpServlet { private String webTempPath; 200 | Глава 8. Выгрузка файлов
public void init(){ , webTempPath = getServletContext().getRealPathf"/") + “data"; } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException { //предельный размер файла - 5Мбайт MultipartRequest mpr new MultipartRequest( ? request,webTempPath,5 * 1024 * 1024); Enumeration enum mpr.getFileNames(); response,petContentType("text/html"); ,. java.io.PrintWriter out•= response.getWriter(); out.printIn("<html>"); out.printIn("<head>"); out.printin("<title>Servlet upload</title>"); out.println("</head>"); out.printIn("<body>"); 4 for (int i 1; enum.hasMoreElements();!++) out.printIn("The name of uploaded file " + 1 + " is: ” + mpr.getFilesystemName((String) enum.nextElement()) + "<brxbr>"); out.printin("</body>"); out.printlnf"</html>"); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException { throw new ServletException ("GET method used with " + getClassO ,getName()+"; POST method required."); ' } } Путь к каталогу сохранения файла генерируется с помощью вызова j avax. servlet. ServletContext.getRealPath("/"), который дает абсолютный путь к корневому каталогу web-приложения (например, h:\home\). После этого к нему добавляется имя ката- лога, в котором будет сохранен файл (data). Имя каталога сохранения также можно указывать, Используя внешний файл конфигурации, например с помощью элемента context-param a web.xmL Подробности см. в рецепте 8.6. 1 ...""3 ' " "" ---- Выгрузка одного файла | 201 I
Метод MultipartRequest. getFilesystemName (StringNaxne) возвращает имя выгружаемого файла в файловой системе клиента. На сервере его можно сохранить под этим же именем, а можно переименовать, использовав другой конструктор класса MultipartRequest, принимающий в качестве параметра объект FileRenamePol- icy. Этот конструктор выглядит следующим образом: MultipartRequest(javax.servlet.http.HttpServletRequest request, java.lang.String saveDirectory, int maxPostSize, \ ' FileRenamePolicy policy) Существует несколько версий конструктора класса MultipartRequest, имеющих параметр FileRenamePolicy, все они используются для переименования выгружаемых файлов (см. рецепт 8.5). Сервлет из примера 8.3 возбуждает исключение ServletExcep- tion, если к нему обратились с помощью метода GET, который неприменим для выгрузки файлов. См. также Рецепт 8.1 по подготовке HTML-кода для выгрузки файлов; рецепт 8.2 по использо- ванию библиотеки com.oreilly.servlet; рецепт 8.4 по выгрузке нескольких фай- лов; рецепт 8.5 по управлению именами файлов; рецепт 8.6 по использованию JSP для выгрузки файлов; домашнюю страницу com.oreilly.servlet: http://www.serv- lets.com/cos/index.html-, RFC 1867 по выгрузке файлов с помощью формы: http://www.ietf. org/rfc/tfcl867.txt. 8.4 Выгрузка нескольких файлов Задача Требуется выгрузить сразу несколько файлов клиента и обработать каждый из полученных файлов. Решение Используйте класс Mui tipart Parser из созданного Джейсоном Хантером архива cos.jar. Обсуждение Класс Mui tipart Parser позволяет сервлету последовательно обрабатывать каж- дый раздел (содержащий один файл) из составного (multipart) HTTP-запроса с выгружае- мыми файлами, получаемого сервером. 202 | Глава 8. Выгрузка файлов
Класс Mui tipart Parser также можно использовать для обработки нескольких файлов как единого целого. Однако Mui tipartParser дает возможность I* £ обрабатывать каждую часть в отдельности (например, сохраняя ее в базе даннух) * в ходе разбора многофайловой выгрузки. Кроме того, при обработке запроса сервлет может узнать тип содержимого, размер и имя файла. С помощью данного класса сервлет может произвести основные проверки, например подсчитать количество выгруженных файлов, а также узнать, заполнил ли пользователь все предложенные ему для загрузки файлов поля input. HTML-файл из рецепта 8.5 был изменен таким образом, чтобы позволить пользова- телю выгрузить из своей файловой системы три разных файла (см. рис. 8.2). Рис. 8.2. HTML-форма для выгрузки трех файлов Эта форма создана путем включения в HTML трех тегов input с атрибутом type="file". <input type="file" name="filel"xbrxbr> <input type="file" name=" file2 "><brxbr> <input type=“file" name="file3"> Сервлет из примера 8.4 обрабатывает загрузку нескольких файлов, импортируя из архива cos.jar три класса. Класс MultipartParser в примере 8.4 ограничивает размер выгружае- мых файлов 5 Мб, однако вы можете установить другое значение, передав в конструктор соответствующее значение параметра, и уменьшить или увеличить наибольший размер принимаемого файла, или оставить принятое по умолчанию значение - 1 Мб. Выгрузка нескольких файлов | 203
Документация по этому классу находится по адресу http://www.servlets.com/cos/ javadoc/com/oreilly/servlet/multipart/MultipartParser.html. --- В случае превышения одним из выгружаемых файлов заданного наибольшего размера, объект Mui tipart Parser возбуждает исключение java. io. lOException. Метод MultipartParser. readNextPart () возвращает тип Part (раздел) или null, если вход- ной поток не. содержит других разделов. Объект Part может быть объектом типа FilePart или объектом типа ParamPart, в зависимости от того, что он реально содержит. Объект ParamPart является оберткой для других параметров, которые может содержать HTML- форма, например «username» (имя пользователя). Объект FilePart имеет несколько мето- дов, предоставляющих информацию о выгружаемом файле, например, тип содержимого и имя файла. Метод FilePart. writeTo (java, io. File dir) сохраняет файл в задан- ном параметром dir каталоге и возвращает размер файла (тип long). Кроме того, объект FilePart может записывать в Outputstream, например: writeTo(jaya.io.Out- putstream out). Пример 8.4. Сервлет, обрабатывающий загрузку нескольких файлов package com.jspservletcookbook; import javax.servlet.*; import javax.servlet.http.*; . import com.oreilly.servlet.multipart.MultipartParser; import com.oreilly.servlet.multipart.Part; import com.oreilly.servlet.multipart.FilePart/" public class ParserServlet extends HttpServlet {. private String fileSavePath; , public void init(){ // save uploaded files to a 'data* directory in the web app fileSavePath “ getServletContext().getRealPath("/") .+ "data"; } ’ public void doPost(HttpServletRequest request, HttpServletRespbnse response) throws ServletException, java,io.lOException { response.setContentType("text/html"); java.io.Printwriter out = response.getWriter(); out.printIn("<html>"); out.printing"<head>"); out.printin("<title>File uploads</title>"); out.printIn(“</head>"); out.printin("<body>"); 204 | Глава 8. Выгрузка файлов
out.printIn("<h2>Here is information about any uploaded files</h2>"); try{ // наибольший размер файла - 5 MB MultipartParser parser new MuitipartParser( request,5 * 1024 * 1024); Part _part null; while ((_part parser.readNextPart()) ! null) { if (_part.ioFile()) { // получаем некоторую информацию о файле File Part fPart ж (FilePart) _part; * String name fPart.getFileName(); if (name ! null) { long fileSize fPart.writeTo( new java.io.File(fileSavePath)); out.printIn("The user's file path for the file: " + fPart.getFilePath() + "<br>"); out.printin("The content type of the file: " * fPart.getContentType()+ "<br>"); out. print In ("The file size: " +fileSize+ " bytes<brxbr>"); //переходим к следующему файлу, если он есть } else { out.printIn( "The user did not upload a file for this part."); } } else if (_part.isPuram()) { // если это не файл, а другой параметр, //например имя пользователя, делаем что-то иное } }// end while out. print In t" < /body> "); out.println("</html>") ; } catch (java.io.lOException ioe){ Z/error-page в дескрипторе развертывания //отображен на java.io.lOException throw new java.io.lOException( "lOException occurred in: " + getClass().getName()); Выгрузка нескольких файлов | 205
} }//doPost public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.lOException { throw new ServletException( "GET method used with " + getClass().getName()+. POST method required."); } На рис. 8.3 приведена страница, созданная сервлетом по итогам выгрузки файлов. Рис. 8.3. Сервлет отображает информацию о выгруженных файлах См. также I Рецепт 8.1 по подготовке HTML-кода для выгрузки файлов; рецепт 8.2 по использо- ванию библиотеки com.oreilly.servlet; рецепт 8.3 по выгрузке одного файла; рецепт 8.5 по управлению именами файлов; рецепт 8.6 по использованию JSP для выгрузки файлов; домашнюю страницу com.oreilly.servlet: http://www.servlets.com/cos/iiidex. html', RFC 1867 по выгрузке файлов с помощью формы: http://www.ietf.org/rfc/rfcl867.txt. 206 | Глава 8. Выгрузка файлов
8.5 Изменение имен файлов Задача Вы хотите изменять имена выгружаемых файлов, в соответствии с некоторой приня- той у вас политикой, во избежание конфликтов имен с существующими файлами. Решение Создайте класс, реализующий интерфейс com. oreilly. servlet .multipart. FileRenamePolicy, или воспользуйтесь ютассом DefaultFileRenamePolicy. • • Обсуждение Пакет com. oreilly. servlet .multipart содержит интерфейс FileRename- Policy, который можно использовать для проведения политики изменения имен выгружаемых файлов. Класс DefaultFileRenamePolicy переименовывает выгружаемые файлы, имена которых вступают в конфликт с существующими файлами, добавляя к их имени число. Например, если уже существует файл index.txt, то класс DefaultFileRenamePolicy присвоит первому выгружаемому файлу с таким же именем имя indcxl.txt, следующему выгружаемому файлу с этим именем - index2.txt и т. д. .Если вы хотите проводить собственную политику переименования, создайте класс, реализующий интерфейс FileRenamePolicy, затем реализуйте в этом классе метод rename (java. io. File f ile), инициирующий акт переименования. Приведенный ниже образец кода показывает использование конструктора класса MultipartRequest из примера 8.3. Здесь конструктору в качестве параметра переда- ется объект DefaultFileRenamePolicy. MultipartRequest mpr = new MultipartRequest( request,webTempPath,(5 * 1024 * 1024),new DefaultFileRenamePolicy()); He забудьте добавить в класс сервлета следующие операторы импорта. import com.oreilly.servlet.MultipartRequest; import com.oreilly.servlet.multipart.DefaultFileRenamePolicy; Как уже отмечалось, вы можете создать собственный механизм переименования, самостоятельно реализовав интерфейс FileRenamePolicy. В примере 8.5 приведен класс MyFileRenamePolicy, который переименовывает каждый выгружаемый файл, добавляя к концу существующего имени отметку времени. Отметка времени вычисля- ется следующим образом. ,// столько секунд прошло с 00:00:00 часов 1 января 1970 new java.util .Date () .getTimeO /1000 Изменение имен файлов | 207
Этот код переименовывает файл, сначала убирая расширение файла (если оно есть), затем добавляя строку (String) (с вычисленной числовой последовательностью) и снова возвращая прежнее расшир