This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
М а р т и н К. С о л о м о н Нирва М о р и с с о - Л е р у а Д ж у л и Басу
И з д а т е л ь с т в о "ЛОРИ"
Oracle Java Component Programming with KJB, CORBA and JSP Martin Is.. Solomon N irva Morriseau-I ,eroy Julie Basn (iopvrighl .Ml rights reserved Oracle I IporpaMMMpouainu.' па языке Java Мартин К. Соломон 1 Inpita Мориссо-Jlepva Лж\лн liacv 1 1ереводчнк И.Д|);Ш1111И[И1ШИ Научный редактор Д.Головко Корректоры Т.Килимник, 11Литвинова Верстка Л. Федякипой Copyright bv The •McGraw-Hill Companies. All rights reserved. Hxcept as permitted under the Copyright Act of l'.)76, no part of t his publication may he reproduced or (list rihuted in any form or by any means, or stored in a database or retrieval system, without the prior written permission of the publisher, or stored in a database or retrieval system without the prior written permission. ISBN 0-07 '21 27^7(> •:<•' Издательство "ЛОРИ". 2010 11:vi. N : OAl (03) Л P N : 070612 !-ШШ)7 г. ISBN <> 7 8 Г) - 8 Г)58 2 2 7f> - 2 Подписано в печать 01.01.2010 Формат 84х108/1(> Ь\'мага офсет N1 Гарнитура Пыо-Ьасксрвиль Печать офсетная 11еч.л. 18 Тираж 500 11,ена договорная Отпечатано в типографии О О О "Тиль-2004" 107023, Москва, ул. Электрозаводская, д. 21
П о с в я щ а ю книгу с в о е м у о д и н н а д ц а т и л е т н е м у с ы н у А л е н у М о р и с с о - Л е р у а и всем ч л е н а м с е м ь и , оказавшим мне
неоценимую поддержку.
Нирва Мориссо-Леруа Памяти моих родителей — Берты и Д ж о з е ф а Соломон. Т а к ж е п о с в я щ а ю книгу ж е н е Э б б и , прекрасным д о ч е р я м Рейчел Смит и Мишель Д е й з и Соломон и своему маленькому внуку Г а р р е т т у А л е к с а н д е р у С м и т у . Мартин К. Соломон В память о б а б у ш к е и д е д у ш к е . Т а к ж е п о с в я щ а ю книгу р о д и т е л я м С м р и т и Кана и С а н д ж и б у Б а с у , к о т о р ы е в с е г д а у ч и л и меня не забывать с в о ю м е ч т у . Джули Басу
Об авторах Нирва Мориссо-Леруа, обладательница степени MSCS, является администратором баз данных Огас1е8г и разработчиком приложений в Национальном административном университете океана и атмосферы (National Oceanic and Atmospheric Administration-University) Объединенного научного института моря и атмосферы Майами, связанном с отделом исследования ураганов (HRD — Hurricane Research Division) AOML. Она имеет более чем 16-летний опыт работы с информационными системами в качестве администратора баз данных Oracle, разработчика приложений и руководителя MIS и владеет языками Java, JDBC, SQLJ, SQL, Oracle PL/SQL и UNIX C/C++. Основные направления ее деятельности — определение потребностей пользователей, объектно-ориентированные анализ и проектирование, моделирование данных, анализ, проектирование, реализация реляционных и объектно-ориентированных БД и управление ими. Помимо этого, Мориссо-Леруа в совершенстве владеет тремя языками (французским, испанским и английским) и удостоена награды "Best Java Implementation" от НРСС (High Performance Computing and Communications) NOAA, полученной на NOAATech2000 в СилверСпринг (штат Мэриленд) 21 октября 1999 г. Обратиться к автору можно по адресу: [email protected]. Доктор Мартин К. Соломон является профессором кафедры разработки и изучения компьютерных технологий в Атлантическом университете Флориды. Основные аспекты его исследований: проектирование, реализация и теория систем баз данных, теория сложных вычислений и философские аспекты'вычислимости. Статьи по этим темам доктор Соломон публиковал в таких престижных журналах, как "ACM Transactions on Database Systems", "Communications of the ACM", 'Journal of Symbolic Logic" и "British Journal for the Philosophy of Science". Его профессиональные интересы затрагивают все стороны работы РСУБД Oracle, он регулярно ведет аттестационные курсы Oracle и часто публикуется в бюллетене "South Florida Oracle Users Group Newsletter". Обратиться к доктору Соломону можно по адресу: [email protected]. Джули Басу, доктор философии, возглавляет группу платформы Java в корпорации Oracle и в настоящее время готовит проект OracleJSP. Исследованиями и проектированием Oracle она занимается более 10 лет. Выпустила не один проект, связанный с интерфейсами программирования баз данных, финансовыми приложениями и кэшированием. Среди ее нынешних интересов web-приложения, XML и электронная коммерция. Джули опубликовала несколько статей на конференциях и в журналах для баз данных — подробнее об этом см. домашнюю интернет-страницу автора: www.jbasu.com. Ее адрес электронной почты: [email protected].
Предисловие Наше время не случайно называется информационным веком. Сегодня простым щелчком мышыо в web-браузере можно без труда обращаться к огромным объемам информации, распределенной по всей планете. Сердце информационной революции — Интернет. Он соединяет различные сети, территориально отдаленные друг от друга, значительно расширяя границы взаимодействия отдельных людей и коммерческих организаций. За последние несколько лет электронная коммерция на основе Интернета вступила в бурный рост. Товары продаются через Web, а покупатели напрямую общаются с продавцами. Прикладные программы самообслуживания, подобные тем, что позволяют выполнять банковские операции, не выходя из дома, значительно оптимизировали бизнес. Работа подавляющего большинства приложений электронной коммерции обеспечивается базами данных Oracle, обладающими высоким уровнем масштабируемости, надежности и доступности, а также отличной производительностью с точки зрения хранения и выбора данных с помощью языка SQL. Бум в электронной коммерции подстегнул разработку нового поколения приложений уровня предприятия, с помощью которых взаимодействие происходит по линии "организация-организация" или "организация-покупатель". Основным языком для построения подобных приложений стал Java. Причины его популярности: современная объектио-ориептироваппая модель программирования, переносимость среди различных платформ и безопасность операций с памятью. Кроме того, он предоставляет развитую структуру вспомогательных библиотек и инструментов. К примеру, в состав версии Java 2 Enterprise Edition входит средство Enterprise JavaBeans (EJBs), позволяющее строить защищенные и масштабируемые программные компоненты для бизнес-транзакций, а также сервлеты Java (Java Servlets) и страницы JavaServer Pages (JSPs), с помощью которых создаются динамические web-страницы. Такие ранее популярные модели распределенного программирования, как общая архитектура посредника объектных запросов (CORBA — Common Object Request Broker Architecture), также нашли отражение в Java, с помощью которого можно реализовывать компоненты CORBA. Знание основанных на Java прикладных программных интерфейсов и инструментов программирования крайне важно для разработчика Интернет-приложений. В Oracle сразу осознали важность модели Интернет-вычислений и вложили в Java значительные средства. В состав Ингернет-РСУБД Огас1е8г входит виртуальная машина Java (Java Virtual Machine) с высоким уровнем масштабируемости под названием Oracle8 г Jserver: она способна выполнять программы Java непосредственно в БД. JServer обеспечивает полнофункциональную поддержку Java 2 Enterprise Edition. Бизнес-компоненты Enterprise JavaBeans и CORBA выполняются в защищенном режиме в границах JServer, т.е. в непосредственной близости от бизнес-данных. Прикладной программный интерфейс (API) JDBC (Java Database Connectivity) и язык SQLJ (SQL, встроенный в Java) стандарта ANSI/ISO доступны не только на станции клиента, но и в JServer, что ускоряет обращение к SQL-данным в процессе работы. Вместе Огас1е8г и Java образую т самую мощную серверную платформу для развертывания защищенных приложений электронной коммерции, способных обслуживать сотни клиентов одновременно. Это именно та книга, которая позволит быстро и эффективно строить масштабируемые Интернет-приложения с использованием Java и Oracle. В первой части рассматривается стиль программирования на основе компонентов — очень эффективный метод написания модульных и удобных в обслуживании приложений, а также дается общий обзор процесса разработки приложений с помощью компонентов EJB, CORBA и JSP. В трех следующих подробно рассказано о EJB, CORBA и JSP. В начале каждой части дано краткое общее представление о том или ином компоненте, затем рассматриваются более частные вопросы программирования. Написана книга отлично,
и переходи ть от главы к главе очень просто, к тому же теория поясняется многочисленными примерами. Взятые из современной практики, они показывают, как с помощью компонентов Java грамотно разрабатывать приложения баз данных уровня предприятия в пошаговом режиме. Меня поразила широта и глубина тем, раскрываемых в этой книге, а также превосходная организация материала. Могу сказать, что поистине восхи ; щей ею. Уверен, что она послужит эффективным и по-настоящему незаменимым руководством тем, кто собирается разрабатывать приложения уровня предприятия с использованием OracleSai и Java. Дэвид А. Розенберг, вице-президент группы платформы Java корпорации Oracle
Благодарности Заслуга в создании нашей книги принадлежит многим людям, которым я хочу выразить особую признательность за поддержку, советы и отклики, полученные нами во время работы над этим проектом. Прежде всего Эдварду О. Гриффину — техническому руководителю из корпорации Oracle: ом помог мне в работе с новыми версиями OracleSi (1.6 и 1.7). А также Хосе Альберто Фернандесу, Брейдену Н. Макдэпиелу и своему бывшему соавтору Джеральду П. Момплезира — за превосходные технические замечания и предложения. Большое спасибо соавторам, Мартину К. Соломону и Джули Басу. Хочу поблагодарить доктора Марка Д. Пауэлла, эксперта в области атмосферы, и его группу H*WIND отдела исследования ураганов NOAA, доктора Джозефа Просперо из Университета Майами, Джереми Джадсопа, старшего редактора комплектования, Монику Фэлтисс, Памелу Вулф, Денниса Уивера и Росса Долла из редакции Osborne/McGraw-Hill и группу серверных технологий/разработки SQL} корпорации Oracle. Нирва Мориссо-Леруа Майами, Флорида Июль 2000 г.
Весьма благодарен Арчану Дюби и Цзюки Ли за помощь в тестировании программ, а также нашему техническому редактору Хосе Альберто Фернандесу за полезные предложения и рекомендации. Отдельное спасибо Джереми Джадсону (за его неоценимую поддержку), Памеле Вулф, Россу Доллу, Монике Фэлтисс и Деннису Уиверу, членам редакции Osborne/McGraw-Hill. Выражаю признательность жене Эбби за помощь в наборе текста и соавторам Нирве Мориссо-Леруа и Джули Басу за приятное и плодотворное сотрудничество. Наконец, большое спасибо замечательным системным администраторам: И. Серджу Джозефу, Манешу Нилаканте, Артуру Соузе, Марчело Мартинсу и Натану Картеру. Мартин К. Соломон Бока-Ратон, Флорида Июль 2000 г.
Спешу поблагодарить семыо и друзей за чуткость и поддержку. Особенно Индрани и Субхенду Чаудхури, деливших со мной хлеб-соль, а также сестру Джун Мухерджи и подругу Эне Сингх. Я благодарна Хосе Альберто Фернандесу, Алексу Ю и Брайану Райту из корпорации Oracle за глубокие технические рецензии и полезные рекомендации. Огромную помощь оказала мне редакция Osborne/McGraw-Hill: Джереми Джадсон, Памела Вулф, Росс Долл и Моника ФэлтиссХБыло приятно работать с соавторами Нирвой Мориссо-Леруа и Мартином К. Соломоном. Хочу особо поблагодарить Нирву за приглашение принять участие в этом проекте, умение вести за собой и постоянную великодушную помощь. Наконец, все мы глубоко признательны Томасу Кьюриану и Дэвиду Розенбергу из корпорации Oracle за финансирование нашей работы. Джули Басу Сан-Магео, Калифорния Июль 2000 г.
Введение Главная тема этой книги — разработка приложений баз данных на основе компонентов Java с использованием Enterprise JavaBeans (EJBs), CORBA и JavaServer Pages (JSPs). В частности, вы научитесь разрабатывать, внедрять и настраивать многоуровневые приложения БД с помощью реализаций JDBC и SQLJ. Несмотря на то что прикладные программы, здесь представленные, были созданы для работы в базах данных Oracle версий 8.хх и выше, с небольшими изменениями их можно использовать в любой основанной на SQL, т.е. "чистой" реляционной или объектно-реляционной системе управления БД (DBMS — Database Management System).
Схемы баз данных В центре нашего внимания будет создание приложений БД, работающих со схемами "чистой" реляционной и объектно-реляционной баз данных. "Purchase Order" (заказ па покупку) — это схема финансовой реляционной БД. Она является частью проекта базы данных, представленного в "Design ol'a Financial Administrative System Using Lhe Semantic Binary Model" (проект финансовой административной системы с использованием семантической двоичной модели). "Scientific Observation" (научные наблюдения) — это схема объектно-реляционной БД. Она является частью проекта научной базы данных, представленного в "Atmospheric Observations, Analyses, and The World Wide Web Using a Semantic Database" (наблюдение за атмосферой, анализ и World Wide Web с использованием семантической БД). Обе схемы представлены в книге "Огас1е8г SQL Programming", ОМН, 1999. Схемы Purchase Order и Observation были специально созданы для Атлантической океанографической и метеорологической лаборатории (AOML, Atlantic Oceanographic and Meteorological Laboratory) в Майами (штат Флорида) и для Лабораторий исследования окружающей среды (ERL, Environmental Research Laboratories) Национального управления океана и атмосферы (NOAA, National Oceanic and Atmospheric Administration), подразделения Министерства торговли США. В частности, схема Observation предназначалась отделу исследования ураганов (HRD — Hurricane Research Division) AOML и в настоящее время реализуется им как часть системы H*WIND, проводящей анализ ветра на поверхности воды в реальном времени для синоптиков Национального центра слежения за ураганами (NHC, National Hurricane Center) и группы связи (FEMA Hurricane Liaison Team) NHC.
SQL-сценарии создания финансовой схемы Purchase Order При создании схемы Purchase Order в базе данных Огас1е8г используйте такой SQL-сценарий createposchema. sql: -- Имя файла: poexample.sql -- Сценарием создаются все таблицы, ограничения и последовательности, -- необходимые для примера Purchase Order. -- В сценарии предполагается, что созданы пользователь БД и индекс с именем -- INDX. -- Убедитесь в том, что пользователю назначена временная табличная область. -- Применение: sqlplus пользователь/пароль -- SQL> @poexample.sql
Введение
set termout on set echo on spool poexample.log -- Из-за ограничений внешних ключей сначала нужно удалить эти -- таблицы. DROP TABLE DEPARTMENT_LIST CASCADE CONSTRAINTS; CREATE TABLE DEPARTMENT_LIST( departmentno NUMBER(5), shortname VARCHAR2(6), longname VARCHAR2(20)); DROP TABLE ACCOUNT_LIST CASCADE CONSTRAINTS; CREATE TABLE ACCOUNT_LIST ( accountno NUMBER(5), projectno NUMBER(5), departmentno NUMBER(5), PRIMARY KEY ( accountno )); DROP TABLE EMPLOYEE_LIST CASCADE CONSTRAINTS; CREATE TABLE EMPLOYEE_LIST( employeeno NUMBER(7), departmentno NUMBER(5), type VARCHAR2(30), lastname VARCHAR2(30), firstname VARCHAR2(30), phone VARCHAR2(10)); DROP TABLE CREDITCARD_LIST; CREATE TABLE CREDITCARD_LIST ( cardno VARCHAR2(15), employeeno NUMBER(7), expirationd&te DATE); DROP TABLE CHECKACCOUNT_LIST; CREATE TABLE CHECKACCOUNT_LIST( accountno NUMBER(5), employeeno NUMBER(7)); DROP TABLE VENDOR_LIST; CREATE TABLE VENDOR_LIST( vendorno NUMBER(6), name VARCHAR2(30), address VARCHAR2(20), City VARCHAR2(15), state VARCHAR2(15), vzip VARCHAR2(15), country VARCHAR2(15)); DROP TABLE PROJECT_LIST; CREATE TABLE PROJECT_LIST ( projectno NUMBER(5), projectname VARCHAR2(20), start_date DATE, amt_of_funds NUMBER, PRIMARY KEY( projectno )); DROP TABLE PURCHASE_LIST; CREATE TABLE PURCHASE_LIST ( requestno NUMBER(IO), employeeno NUMBER(7), vendorno NUMBER(6), purchasetype VARCHAR2(20), checkno NUMBER(11), whenpurchased DATE);
DROP TABLE LINEITEM_LIST; CREATE TABLE LINEITEM_LIST ( requestno NUMBER(10), lineno NUMBER(5), projectno NUMBER(5), quantity NUMBER(5), unit VARCHAR2(2), estimatedcost NUMBER(8,2), actualcost NUMBER(8,2), description VARCHAR2(30)); -- Добавим ограничения к таблицам ALTER TABLE DEPARTMENT_LIST ADD CONSTRAINT deptno_pk PRIMARY KEY(departmentno) USING INDEX TABLESPACE INDX; ALTER TABLE ACCOUNT_LIST ADD CONSTRAINT acc_deptno_fk FOREIGN KEY(departmentno) REFERENCES DEPARTMENT_LIST(departmentno); ALTER TABLE EMPLOYEE_LIST ADD CONSTRAINT employeeno_pk PRIMARY KEY(employeeno) USING INDEX TABLESPACE INDX; ALTER TABLE EMPLOYEE_LIST ADD CONSTRAINT emp_deptno_fk FOREIGN KEY(departmentno) REFERENCES DEPARTMENT_LIST(departmentno); ALTER TABLE CREDITCARD_LIST ADD CONSTRAINT cardno_pk PRIMARY KEY(cardno) USING INDEX TABLESPACE INDX; ALTER TABLE CREDITCARD_LIST ADD CONSTRAINT credit_employeeno_fk FOREIGN KEY(employeeno) REFERENCES EMPLOYEE_LIST(employeeno); ALTER TABLE CHECKACCOUNT_LIST ADD CONSTRAINT accountno_pk PRIMARY KEY(accountno) USING INDEX TABLESPACE INDX; ALTER TABLE CHECKACCOUNT_LIST ADD CONSTRAINT check_employeeno_fk FOREIGN KEY(employeeno) REFERENCES EMPLOYEE_LIST(employeeno); ALTER TABLE vendor_list ADD CONSTRAINT vendorno_pk PRIMARY KEY(vendorno) USING INDEX TABLESPACE INDX; ALTER TABLE Purchase_list ADD CONSTRAINT requestno_pk PRIMARY KEY(requestno) USING INDEX TABLESPACE INDX; ALTER TABLE LINEITEM_LIST ADD CONSTRAINT lineno_pk PRIMARY KEY(requestno,lineno,projectno) USING INDEX TABLESPACE INDX; -- Создадим последовательности DROP SEQUENCE deptno_SEQ; CREATE SEQUENCE deptno_SEQ
xiii
Введение
о
START WITH 200 INCREMENT BY 1; DROP SEQUENCE projectno_SEQ; CREATE SEQUENCE projectno_SEQ START WITH 300 INCREMENT BY 1; DROP SEQUENCE employeeno_SEQ; CREATE SEQUENCE employeeno_SEQ START WITH 100 INCREMENT BY 1; DROP SEQUENCE accountno_SEQ; CREATE SEQUENCE accountno_SEQ START WITH 1000 INCREMENT BY 1; DROP SEQUENCE cardno_SEQ; CREATE SEQUENCE cardno_SEQ START WITH 311200 INCREMENT BY 1; DROP SEQUENCE vendorno_SEQ; CREATE SEQUENCE vendorno_SEQ START WITH 400 INCREMENT BY 1; DROP SEQUENCE requestno_SEQ; CREATE SEQUENCE requestno_SEQ START WITH 500 INCREMENT BY 1; DROP SEQUENCE lineno_SEQ; CREATE SEQUENCE lineno_SEQ START WITH 1 INCREMENT BY 1; spool off
SQL-сценарии создания научной схемы Observation При создании схемы Observation в базе данных Огас1е8г используйте такой SQL-сценарий сreateobjschema.sql: -- Имя файла: obsexample.sql -- Сценарием создаются все таблицы, ограничения и -- последовательности, необходимые для примера Observation. -- В сценарии предполагается, что созданы пользователь БД и индекс INDX. -- Применение: sqlplus пользователь/пароль -- SQL> @obsexample.sql
set termout on set echo on spool createobjschema.log DROP DROP DROP DROP DROP DROP
TABLE PR0DUCT_LIST; TYPE PR0DUCT_TYPE; TABLE PASSED_OBSERVATION_LIST; TYPE PASSED0BSARRAY; TYPE PASSEDOBS; TABLE 0CEANIC_0BSERVATI0N_LIST;
Введение
DROP DROP DROP DROP DROP DROP DROP DROP DROP DROP
TYPE OCEANIC.OBSERVATION_TYPE; TYPE 0CEANIC_0BSERVATI0N; TABLE QC_EVENT_LIST; TYPE QUALITY_CONTROL_EVENT; TABLE ATMOSEVENT_LIST; TYPE ATMOSEVENT; TABLE SCIENTIST.LIST TYPE SCIENTIST; TABLE PLATFORM_TYPE_LIST; TYPE PLATFORM_TYPE;
CREATE TYPE PLATFORM_TYPE AS key_id NUMBER(8), type VARCHAR2(50), description VARCHAR2(50));
'CCT(
CREATE TABLE PLATFORM_TYPE_LIST OF PLATFORM_TYPE; CREATE TYPE SCIENTIST AS OBJECT( usr_id NUMBER(6), lastname VARCHAR2(20), firstname VARCHAR2(20), platform_id NUMBER, for_platform REF PLATFORMTYPE); CREATE TABLE SCIENTIST_LIST OF SCIENTIST; CREATE TYPE ATMOSEVENT AS 0BJECT( key_id NUMBER(8), when_t DATE, name VARCHAR2(30), type VARCHAR2(20), refkey NUMBER(8), transformedjto REF atmosevent); CREATE TABLE ATMOSEVENT_LIST OF ATMOSEVENT; CREATE TYPE OCEANIC_OBSERVATION AS OBJECT( latitude_deg NUMBER(10,4), longitude.deg NUMBER(10,4), windspeedjnps NUMBER(10,4), adj_windspeed_mps NUMBER(10,4), wind_di rection_deg NUMBER(6), pressure_mb NUMBER(6)) CREATE TYPE OCEANIC_OBSERVATION_TYPE AS 0BJECT( Obs.id NUMBER(8), when_t DATE, at_time CHAR(8), station_id NUMBER(6), produced_id NUMBER(8), produced_by REF PLATFORM_TYPE, obsobj OCEANICJDBSERVATION); -- Список всех наблюдений за океаном по дате, времени и типу -- платформы. CREATE TABLE OCEANIC_OBSERVATION_LIST OF OCEANIC_OBSERVATION_TYPE; -- Воспользуемся qc_id_seq для обновления QUALITY_CONTROL_EVENT qc..id CREATE TYPE QUALITY_CONTROL_EVENT AS OBJECT( qc_id NUMBER(8), when_t DATE, at_time CHAR(8), event_id NUMBER(8), for_event REF atmosevent, whom_id NUMBER(6), by_whom REF scientist);
Введение
О CREATE TABLE QC_EVENT_LIST OF QUALITY_CONTROL_EVENT; CREATE OR REPLACE TYPE PASSEDOBS AS 0BJECT( obsid NUMBER(8), when_t DATE); CREATE TYPE PASSEDOBSARRAY AS TABLE OF PASSEDOBS; CREATE TABLE PASSED_OBSERVATION_LIST( qcid NUMBER(8), when_t DATE, at_time CHAR(8), idobj passedObsArray) NESTED TABLE idobj STORE AS pobsid_list; ALTER TABLE POBSID_LIST STORAGE (MINEXTENTS 1 MAXEXTENTS 20); -- Теперь создадим ограничения ALTER TABLE PLATFORM_TYPE_LIST ADD CONSTRAINT PT_KEY_ID_PK PRIMARY KEY(KEY_ID) USING INDEX TABLESPACE INDX; ALTER TABLE SCIENTIST_LIST ADD CONSTRAINT SL_USR_ID_PK PRIMARY KEY(USR_ID) USING INDEX TABLESPACE INDX; ALTER TABLE ATMOSEVENT_LIST ADD CONSTRAINT AL_KEY_ID_PK PRIMARY KEY(KEY_ID) USING INDEX TABLESPACE INDX; ALTER TABLE OCEANIC_OBSERVATION_LIST ADD CONSTRAINT 0_0BS_ID_PK PRIMARY KEY(0BS_ID) USING INDEX TABLESPACE INDX; ALTER TABLE QC_EVENT_LIST ADD CONSTRAINT QC_ID_PK PRIMARY KEY(QC_ID) USING INDEX TABLESPACE INDX; ALTER TABLE QC_EVENT_LIST ADD CONSTRAINT qc_whom_id_fk FOREIGN KEY(whom_id) REFERENCES SCIENTIST_LIST(usr_id) ON DELETE CASCADE; ALTER TABLE PASSED_OBSERVATION_LIST ADD CONSTRAINT passed_id_pk PRIMARY KEY (passed_id) USING INDEX TABLESPACE INDX; ALTER TABLE PASSED_OBSERVATION_LIST ADD CONSTRAINT po_qc_id_fk FOREIGN KEY(qcid) REFERENCES QC_EVENT_LIST(qc_id) ON DELETE CASCADE; ALTER TABLE PASSED_OBSERVATION_LIST ADD CONSTRAINT passed_qcid_ukey UNIQUE(qcid) USING INDEX TABLESPACE INDX; ALTER TABLE PASSED_OBSERVATION_LIST MODIFY (qcid NOT NULL); ALTER TABLE PRODUCT.LIST ADD CONSTRAINT pr_id_pk PRIMARY KEY (id) USING INDEX TABLESPACE INDX; -- Теперь создадим последовательности
XV
-- последовательность key_id для PLATFORM_TYPE DROP SEQUENCE PT_key_SEQ; CREATE SEQUENCE PT_key_SEQ START WITH 1 INCREMENT BY 1; -- последовательность usr_id для SCIENTIST DROP SEQUENCE USERSEQ; CREATE SEQUENCE USERSEQ START WITH 1 INCREMENT BY 1; -- последовательность key_id для ATMOSEVENT DROP SEQUENCE atm_key_seq; CREATE SEQUENCE atm_key_seq START WITH 1 INCREMENT BY 1; DROP SEQUENCE OBSID_SEQ; CREATE SEQUENCE OBSID_SEQ START WITH 1 INCREMENT BY 1; -- последовательность qc_id для QUALITY_CONTROL_EVENT DROP SEQUENCE qc_id_seq; CREATE SEQUENCE qc_id_seq START WITH 1 INCREMENT BY 1; -- последовательность passed_id для PASSED_OBSERVATION DROP SEQUENCE passed_id_seq; CREATE SEQUENCE passed_id_seq START WITH 1 INCREMENT BY 1; -- Теперь создадим модуль (пакет) PL/SQL DROP PACKAGE OBSACTIONS; CREATE OR REPLACE PACKAGE OBSACTIONS AS -- Получим новый Obs_id FUNCTION getObsId RETURN NUMBER; PRAGMA RESTRICT_REFERENCES(getObsId,WNDS,WNPS, RNPS); -- Добавим новое наблюдение PROCEDURE insertObs(p_newobsid IN NUMBER, p_whent IN VARCHAR2, IN CHAR, p_attime IN NUMBER, p_ptlid IN NUMBER, p_latdeg p_londeg IN NUMBER, IN NUMBER, p_wsmps IN NUMBER, p_adjwsmps IN NUMBER, p_wddeg IN NUMBER, p_pmb p_stlid IN NUMBER); END OBSACTIONS; / CREATE OR REPLACE PACKAGE BODY OBSACTIONS AS -- Воспользуемся частной (private) функцией FindCurrTime, чтобы -- вычислить текущее время. Этот метод доступен только для -- функций и процедур, указанных в разделе тела модуля OBSACTIONS -- и аналогичен частному методу Java. FUNCTION FindCurrTime RETURN CHAR IS v_time CHAR(8);
BEGIN SELECT TO_CHAR(SYSDATE,'HH24MISS') INTO v_time FROM DUAL; RETURN v_time; EXCEPTION WHEN NO_DATA_FOUND THEN RETURN v_time; END FindCurrTime; Получим новый Obs_id
FUNCTION getobsld RETURN NUMBER IS p_obsid NUMBER; BEGIN SELECT OBSID_SEO.NEXTVAL INTO p_Obsid FROM DUAL; RETURN p_obsid; EXCEPTION WHEN OTHERS THEN RETURN p_obsid; End getObsId; Создадим объект типа Oceanic_observation Это частный (private) метод. FUNCTION OceanicObservation (p_latdeg p_londeg p_wsmps p_adjwsmps p_wddeg p_pmb
IN IN IN IN IN IN
NUMBER, NUMBER, NUMBER, NUMBER, NUMBER, NUMBER)
RETURN oceanic_observation IS Создадим тип oceanic_observation. v_obs oceanic_observation := oceanic_observation(p_latdeg,p_londeg, p_wsmps, p_adjwsmps, p_wddeg, p_.pmb); BEGIN RETURN v_obs; END OceanicObservation; Добавим новое наблюдение PROCEDURE insertObs(p_newobsid p_whent p_attime p_ptlid p_latdeg p_londeg p_wsmps p.adjwsmps p_wddeg p_pmb p_Stlid
IN NUMBER, IN VARCHAR2, IN CHAR, IN NUMBER, IN NUMBER, IN NUMBER, IN NUMBER, IN NUMBER, IN NUMBER, IN NUMBER, IN NUMBER) IS
v_date DATE := TO_DATE(p_whent,'DD-MON-YYYY"); v_time CHAR(8) := p_attime; v_newobsid NUMBER := TO_NUMBER(p_newobsid); v_platformref REF PLATFORM_TYPE; v_obs Oceanic_Observation := Oceanic_Observation(p_latdeg,p_londeg, p_wsmps,p_adj wsmps,p_wddeg,p_pmb); BEGIN Проверим входную дату p_whent IF v_date IS NULL THEN SELECT SYSDATE INTO v_date FROM DUAL; END IF; Проверим входное время IF v_time IS NULL THEN
v_time := FindCurrTime; END IF; Получим ссылку (REF) на platform_type SELECT REF(P) INTO v_platformref FROM platform_type_list P WHERE P.key_id = p_ptlid; Вставим новый объект INSERT INTO OCEANIC_OBSERVATION_LIST VALUES( v_newobsid, v_date, v_time, p_stlid, p_ptlid, v_platformref, v_obs ); -- зафиксируем результат; EXCEPTION WHEN NO_DATA_FOUND THEN NULL; WHEN OTHERS THEN NULL; END insertObs; END OBSACTIONS; DROP PACKAGE QCACTIONS; CREATE OR REPLACE PACKAGE QCACTIONS AS Получим новый qc_id FUNCTION GETNEWQCID RETURN NUMBER; PRAGMA RESTRICT_REFERENCES(GETNEWQCID,WNDS,WNPS,RNPS); Добавим новый QcSet PROCEDURE insertQcSet(p_newqcid IN NUMBER. p_whent IN VARCHAR2, p_attime IN CHAR, p_evtid IN NUMBER, p_whom_id IN NUMBER); -- Добавим новую строку в таблицу PASSED_OBSERVATION_LIST PROCEDURE insertQcSetObs(p_qcid IN NUMBER, p_obsid IN NUMBER); END QCACTIONS; CREATE OR REPLACE PACKAGE BODY QCACTIONS AS Выясним текущее время FUNCTION FindCurrTime RETURN CHAR IS v_time CHAR(8); BEGIN SELECT TO_CHAR(SYSDATE, 'HH24MISS-) INTO v_time FROM DUAL; RETURN v_time; EXCEPTION WHEN N0_DATA_F0UND THEN RETURN v_time; END FindCurrTime; FUNCTION GETNEWQCID RETURN NUMBER IS p_qcid NUMBER; BEGIN SELECT qc_id_seq.NEXTVAL INTO p_qcid FROM DUAL; RETURN p_qcid; EXCEPTION WHEN OTHERS THEN RETURN p_qcid; End GETNEWQCID; PROCEDURE insertQcSet(p_newqcid IN NUMBER, p_whent IN VARCHAR2, p_attime IN CHAR, p_evtid IN NUMBER, p_whom_id IN NUMBER) IS
Введение
О v_date DATE := TO_DATE(p_whent,'DD-MON-YYYY-); v_time CHAR(8) := p_attime; v_newqcid NUMBER := TO_NUMBER(p_newqcid); v_eventref REF atmosevent; v_scientistref REF scientist; BEGIN Проверим входную дату p_whent IF v_date IS NULL THEN SELECT SYSDATE INTO v_date FROM DUAL; END IF; Проверим входное время IF v_time IS NULL THEN v_time := FindCurrTime; END IF; Получим ссылку (REF) на atmosevent SELECT REF(P) INTO v_eventref FROM ATMOSEVENT_LIST P WHERE P.key_id = p_evtid; Получим ссылку (REF) на scientist SELECT REF(P) INTO v_scientistref FROM SCIENTIST_LIST P WHERE P.usr_id = p_whom_id; Вставим новую строку INSERT INTO QC_EVENT_LIST VALUES(p_newqcid,v_date,v_time,p_evtid,v_eventref, p_whom_id,v_scientist ref); EXCEPTION WHEN OTHERS THEN RAISE N0_DATA_FOUND; END insertQcSet; PROCEDURE insertQcSetObs(p_qcid IN NUMBER,p_obsid IN NUMBER) IS v_qcdate DATE; v_time CHAR(8); v_qcid NUMBER : = TO_NUMBER(p_qcid); v_obsdate DATE; v_obsid NUMBER := T0_NUMBER(p_obsid); v_cnt NUMBER; BEGIN Проверим p_qcid IF v_qcid IS NULL THEN RAISE N0_DATA_FOUND; END IF; Проверим v_obsid IF v_obsid IS NULL THEN RAISE N0_DATA_FOUND; END IF; Проверим, существует ли QcSet SELECT Q.when_t, q.at_time INTO v_qcdate, v_time FROM QC_EVENT_LIST Q WHERE Q.qc_id = v_qcid; Проверим, существует ли Obsid SELECT 0.when_t INTO v_obsdate FROM OCEANIC_OBSERVATION_LIST 0 WHERE O.obs_id = v_obsid; v_cnt := 0; Проверим, существует ли PASSED_OBSERVATION_LIST SELECT C0UNT(1) INTO v_cnt FROM PASSED_OBSERVATION_LIST P WHERE P.qcid = v_qcid; IF ( v_cnt = 0 ) THEN INSERT INTO PASSED_OBSERVATION_LIST VALUES(v_qcid, v_qcdate,v_time,PASSEDOBSARRAY()); END IF;
xix
Введение
INSERT INTO TABLE (SELECT P.idobj FROM passed_observation_list P WHERE P.qcid = v_qcid) VALUES(PASSEDOBS(v_obsid,v_obsdate)); EXCEPTION WHEN OTHERS THEN RAISE NO_DATA_FOUND; END insertQcSetObs; END QCACTIONS; /
Шрифтовые соглашения В этой книге приняты соглашения, по которым моноширинным шрифтом выделяются: • Классы: стандартный класс Java Java.lang.* • Типы данных (прописными литерами): тип данных REF CURSOR • Имена и расширения файлов (строчными литерами): файлы .class, расширение .ser • Функции и процедуры: insertQcSet(), function Get0bsld() • Имена таблиц баз данных (прописными литерами): PASSED_OBSERVATION • Ключевые слова Java в абзацах (строчными литерами полужирного начертания): public
О б р а т н а я связь с авторами Авторы с радостью примуг замечания и предложения читателей относительно качества и полезности этой книги. Ваши отклики для нас очень валены — высылайте их по электронной почте: Нирва Мориссо-Леруа Мартин К. Соломон Джули Басу
Получение примеров по сети Исходный программный текст и глоссарий можно найти на сайтах www.data-i.com и www.osborne.com. Программы, исходный текст которых присутствует там, указаны в файле с соответствующим именем, например Obslmp. sqlj.
Внимание ! Представленные здесь программы не нацелены на использование в каких бы то ни было приложениях, опасных по своей природе. Ответственность за принятие всех необходимых мер по безотказной работе подобных приложений, их дублированию, резервированию и безопасности использования полностью возложена на читателя.
О р е с у р с а х , используемых в д а н н о й книге На сайте издательства "Лори" (www.lory-press.ru) содержится ряд ресурсов, на которые в книге есть ссылки.
Программы Программы, содержащиеся в книге, находятся на сайте издательства "Лори" (www.l017-press.ru) в каталоге BookCode.zip. Это программы из следующих глав: Глава 1. Знакомство с распределенными вычислительными системами Глава 4. Разработка сеансовых зерен EJB
Введение
xxi с
Глава 5. Разработка сеансовых зерен: углубленное изучение Глава 6. Знакомство с CORBA Глава 7. Сеансы CORBA Глава 8. Управление транзакциями в CORBA Глава 9. Компоненты схемы Purchase Order Глава 10. Введение в программирование с использованием страниц JSP
Приложения ДЛЯ удобства на сайте издательства "Лори" (www.lory-press.ru) размещены электронные варианты следующих приложений к книге (для сервлетов, EJB, CORBA и JSP):
1
Для просмотра этих файлов нужно применять Adobe Acrobat Reader версии 3.0 или выше. Приложение А. Краткий справочник по сервлетам и общие сведения об API сервлетов Приложение В. Краткое описание API Enterprise JavaBeans Приложение С. Краткий справочник по Oracle8i CORBA для Java Приложение Е. Установка и конфигурирование web-серверов для работы с Oracle JSP Приложение F. Инструментальные средства Oracle8/ EJB и CORBA и поддержка JSP BjDeveloper
Примеры для JSP и сервлетов Примеры программ JSP и сервлетов находятся в каталоге jspsamples.zip сайта издательства "Лори" (www.lory-press.ru). Операции установки и выполнения этих программ описаны в README.txt.
Содержание ЧАСТЬ I
Общий обзор 1
Знакомство с распределенными вычислительными системами • • • 3 Компоненты: общее представление Что такое компонент
2
4 4
Программные компоненты: общее представление Преимущества компонентов и программных компонентов Распределенные вычислительные системы Распределенные объектные архитектуры Стандарты распределенных вычислительных систем Достоинства распределенных вычислительных систем Построение компонента в Java Класс ObsHelper Класс ObsException Интерфейс Observation Класс Obslmp: реализация с помощью JDBC Класс Obslmp: реализация с помощью SQLJ Класс Client Итоги
5 6 6 7 7 9 9 9 11 12 12 16 20 22
Знакомство с web-приложениями
23
Понятие web-cepeepa web-браузер Протокол HTTP Язык разметки HTML Генерация динамического содержимого на Web-страницах Модель сервлетов Знакомство с JavaServer Pages Архитектура web-приложений Упрощенная архитектура приложения Компонентная JSP-архитектура Использование библиотек тегов JSP Итоги
24 25 27 28 29 29 38 42 42 43 45 47
ЧАСТЬ II
Построение компонентов Enterprise JavaBeans 3
Знакомство с Enterprise JavaBeans (EJB)
51
Спецификация Enterprise JavaBeans (1.0) Цели проекта Enterprise JavaBeans Роли Enterprise JavaBeans Архитектура Enterprise JavaBeans Сервер Enterprise JavaBeans Контейнер Enterprise JavaBeans Компоненты приложения EJB Типы зерен EJB Домашний интерфейс EJB Удаленный интерфейс EJB Класс зерна уровня предприятия Дескриптор внедрения Enterprise JavaBeans Файл ejb-jar Клиентское приложение Управление транзакциями и безопасность в EJB
53 53 54 55 56 56 57 57 59 62 65 68 70 71 73
xxiv
Содержание о
4
Поддержка транзакций Поддержка распределения Поддержка безопасности Исключительные ситуации EJB Достоинства Enterprise JavaBeans Архитектура Oracle8/' JServer Основы 0racle8/ JServer Создание первого Enterprise JavaBean Итоги
73 74 74 74 75 76 76 81 92
Разработка сеансовых зерен EJB
93
Oracle8/ JServer: поддержка транзакций Еще раз о декларативных атрибутах транзакций Управление транзакциями Управление доступом Программные ограничения Разработка приложений баз данных с использованием сеансовых зерен Обзор JDBC-драйверов Oracle Подключение с помощью JNDI Итоги
5
94 95 96 100 102 • • • 103 103 105 132
Разработка сеансовых зерен: углубленное изучение
133
Управление зернами в сеансах связи с базой данных Клиентский объект, начинающий новый сеанс Серверный объект, начинающий новый сеанс Два клиента, обращающиеся к одному сеансу Серверный объект, обращающийся к тому же сеансу Серверный объект, управляющий продолжительностью сеанса Серверный объект, заканчивающий сеанс Ограничение транзакций Транзакция, ограниченная на стороне клиента (автономная программа Java) Транзакция, ограниченная на стороне сервера Построение транзакционного приложения Еще раз о транзакциях в EJB Требования пользователей Сеансовое зерно QcObsBean Сеансовое зерно QcSetBean Транзакционное приложение QcClient Итоги
Обзор CORBA 176 IDL 177 Компилятор IDL 177 Конструкции IDL 179 Внедрение и использование объектов CORBA 186 Программирование модуля IDL 186 Создание исходных файлов Java из файла IDL с помощью idl2java • • • • 187 Программирование Java-реализации серверного объекта 187 Компиляция файлов Java и загрузка созданных файлов классов в JServer • 187 Публикация имени серверного объекта CORBA 188 Программирование и компиляция клиента Java 189 Реализация серверного объекта CORBA с помощью JDBC 191 Механизм обратных вызовов CORBA 191 Клиентский объект обратного вызова 192 Серверный объект 192 Реализация клиентского объекта обратного вызова 192 Реализация серверного объекта 192
Содержание
xxv
7
Клиентская программа, обращающаяся к серверному методу обратного вызова Механизм привязки CORBA Активация посредников ORB и серверных объектов Активация ORB Активация серверного объекта Программирование спецификаций интерфейсов на Java Краткие сведения о некоторых важных инструментах loadjava dropjava publish remove Итоги
193 194 194 194 195 196 197 197 198 198 201 202
Сеансы CORBA
203
Службы соединений: ТТС и ПОР 204 Характеристики JNDI 204 JNDI-интерфейс Context 205 JNDI-класс InitialContext • • 205 CORBA-сеансы Oracle8/ 206 Прослушивающие процессы и диспетчеры базы данных 206 Синтаксис URL для служб и сеансов 207 Компоненты и классы URL 207 Управление сеансами 211 Запуск сеанса из серверного объекта 211 Запуск именованного сеанса со стороны клиента 212 Пример двухсеансовой программы 212 Пример программы с указателями URL, содержащими имена сеансов • • • 214 Управление продолжительностью сеанса и его завершение 216 Аутентификация 217 Способы аутентификации клиента 217 Права доступа к объектам базы данных 219 Клиенты не-JNDI 219 Итоги 220
8
Управление транзакциями в CORBA
221
Ограниченные возможности JTS 223 Ограничения транзакций и контекст транзакций 223 Интерфейсы службы транзакций 224 Методы службы транзакций Java 225 public static synchronized TransactionService getTSQ 225 public void begin() 225 public Control suspend() 226 public void resume( Control control ) 226 public void commit( boolean report_heuristics ) 226 public void rollback() 226 public void rollback_only() 227 public void set_timeout( int seconds ) 227 public Status get_status() 227 public String get_transaction_name() 227 Использование методов JTS в клиентских программных конструкциях CORBA- • 227 Пример ограничения на стороне клиента 228 Использование методов JTS в серверных программных конструкциях CORBA • • 230 Пример ограничения на стороне сервера 230 Компонент серверного объекта CORBA 233 accountlist.idl 234 AccountListlmpl.sqlj 235 Клиент CORBA для компонента AccountList 237 Пример с приостановкой и возобновлением транзакции 238 Клиент, обращающийся к компоненту EJB 239 Клиент CORBA, обращающийся к компоненту EJB и компоненту серверного объекта CORBA 241 JTA 243
xxvi
Содержание
о
9
Структура клиента с ограничением JTA на стороне клиента Пример ограничения JTA на стороне клиента Структура реализации серверного объекта с ограничением JTA на стороне сервера Итоги
243 244
Компоненты схемы Purchase Order
247
CORBA-компонент DepartmentList Требования пользователей DepartmentList Общий вид DepartmentList IDL-файл для DepartmentList Реализация серверного объекта для DepartmentList Клиент для DepartmentList CORBA-компонент EmployeeList Требования пользователей EmployeeList Общий вид EmployeeList IDL-файл для EmployeeList Реализация серверного объекта для EmployeeList Клиент для EmployeeList CORBA-компонент VendorList Требования пользователей VendorList Общий вид VendorList IDL-файл для VendorList Реализация серверного объекта для VendorList Клиент для VendorList CORBA-компонент ProjectList Требования пользователей ProjectList Общий вид ProjectList IDL-файл для ProjectList Реализация серверного объекта для ProjectList Клиент для ProjectList CORBA-компоненты PurchaseList и LineltemList Требования пользователей PurchaseList и LineltemList Общий вид PurchaseList и LineltemList IDL-файл для PurchaseList и LineltemList Реализация серверного объекта для PurchaseList Реализация серверного объекта для LineltemList Клиент для PurchaseList Итоги
Построение web-приложений с помощью страниц JSP 10
Введение в программирование с использованием страниц JSP • • 283 Основы JSP-программирования Элементы сценариев Неявные объекты JSP Написание Hello.jsp Выполнение Hello.jsp Заглянем внутрь Директивы JSP Директива page Директива include Вызов других страниц с JSP Тэг <jsp:include> Тэг <jsp:forward> Использование JSP-страниц вместе с сервлетами Вызов сервлета с JSP-страницы Вызов JSP из сервлета Особенности сред Sen/let 2.0 Обработка ошибок JSP JSP-реализация Oracle
Использование SQLJ в JSP Использование транслятора командной строки ojspc Итоги
309 311 314
Использование JSP вместе с зернами JavaBean
315
Разработка JSP-приложений с помощью компонентов JavaBean 316 Знакомство с JavaBean 316 Стандартные JSP-тэги для зерен JavaBean 318 Создание HelloBean.jsp с помощью UserNameBean 321 Использование зерен JavaBean с разными областями действия 322 Разработка JSP-приложения с контролем за сеансами 328 Выполнение операций над базой данных с помощью зерен JavaBean 333 Ввод информации в базу данных 333 Исполнение статических SQL-запросов 338 Исполнение динамических SQL-запросов 345 Зерна доступа к базам данных в Oracle JSP 1.1 349 Библиотека зерен Oracle JSP 349 Генерация XML-страниц с помощью JSP-страниц и зерен JavaBean • • • • 350 Оптимизация SQL-операций 353 Использование готовых JDBC-операторов 354 Пакетное обновление 355 Кэширование описателей операторов 355 Пулинг соединений 355 Кэширование результатов запроса 357 Итоги 358
12
Использование JSP вместе с EJB, CORBA и библиотеками тэгов • 359 Разработка web-приложений с помощью EJB-компонентов Сеансовое EJB для заказов Вызов OrderEJB из web-приложения Разработка web-приложений с помощью компонентов CORBAОбъект CORBA для заказов Вызов объекта CORBA из web-приложения Использование библиотек тэгов JSP Директива taglib SQL-тэги Тэги JML Реализация специального тэга Итоги
360 360 365 372 372 374 378 379 379 384 385 395
ЧАСТЬ V
Приложения А
Краткий справочник по сервлетам и общие сведения об API сервлетов Краткий справочник по сервлетам Написание сервлетов Компиляция сервлетов Внедрение сервлетов в Tomcat Вызов сервлетов Servlet API 2.2 Иерархическая структура классов Иерархическая структура интерфейсов Классы и интерфейсы
В
399 400 400 404 • • 405 405 406 407 407 408
Краткое описание API Enterprise JavaBeans
417
Краткий справочник по Enterprise JavaBeans Создание зерна уровня предприятия (сеансового зерна) Enterprise JavaBeans API Иерархическая структура пакета javax.ejb Иерархическая структура интерфейсов Пакет javax.ejb
418 418 424 424 424 424
xxviii
Содержание
О С
Краткий справочник по 0racle8i CORBA для Java
431
Программирование модуля IDL 432 Генерация исходных файлов Java из файла IDL с помощью idl2java 432 Программирование Java-реализации серверного объекта 433 Компиляция файлов Java и загрузка сгенерированных файлов классов в JServer 433 Публикация имени серверного объекта CORBA 434 Программирование и компиляция клиента Java 434 Выполнение клиента 435
D Краткий справочник по JavaServer Pages
Е
F
• •
437
Справочник по синтаксису JSP Директива page • • • Директива taglib Тэги include • • • Тэги JavaBean Комментарии Объявление переменных и функций Скриптлеты Выражения Тэг jspiplugin Тэг jsp:forward Справочник по JSP API Пакет javax.servlet.jsp Пакет javax.servlet.jsp.tagext
Установка и конфигурирование web-серверов для работы с Oracle JSP
447
Установка Oracle JSP в Tomcat Этапы установки Этапы конфигурирования Запуск сервера Tomcat Выполнение JSP-программ в Tomcat Установка и конфигурирование Java Web Server Этапы установки Этапы конфигурирования Выполнение JSP-программ в JWS Установка и конфигурирование Apache и JServ Этапы конфигурирования Выполнение JSP-программ в Apache/JServ Параметры конфигурации Oracle JSP
Инструментальные средства Oracle8i EJB и CORBA и поддержка JSP в JDeveloper
461
Инструментальные средства Oracle8/ EJB и CORBA Инструментальные средства Огас1е8/, используемые для EJB Инструментальные средства Огас1е8/, используемые как для EJB, так и для CORBA Инструментальные средства Oracle8i, используемые для CORBA Поддержка JSP в JDeveloper Создание нового приложения JavaServer Pages
Библиография
462 462 464 469 472 473
481
ЧАСТЬ I О О О —
Общий обзор
ГЛАВА 1
О
Знакомство с распределенными вычислительными системами
ГЛАВА 1
О ^ с н о в н а я тема книги — разработка клиентских и серверных компонентов Java с помощью реализаций JDBC и SQLJ. Первая из них позволяет встраивать динамический SQL в программы Java, а вторая — включать в программы Java статические SQL-конструкции. В статическом встраиваемом SQL все SQL-oneраторы, включаемые в программу, становятся известными во время компиляции, в то время как в динамическом встраиваемом, по крайней мере, часть их совершенно неизвестна до момента выполнения программы. Прочитав книгу, вы научитесь разрабатывать, внедрять и настраивать такие многоуровневые программные компоненты для БД, которые будут манипулировать информацией, находящейся на сервере данных Огас1е8г версий 8.1.5, 8.1.6 и новой 8.1.7. Они будут использоваться как простые бизнес-объекты, по, что особенно важно, внедряются с помощью таких компонентных моделей, как Enterprise JavaBeans (EJBs), CORBA, сервлеты Java, JavaBeans или JavaServer Pages (JSPs). Последние позволяют компаниям устанавливать одно и то же приложение на самые разные рабочие серверы и распределять таковое среди самых разных клиентов, в том числе автономных программ Java, клиентов EJB, CORBA, JSP, сервлетов и у\сЬбраузеров. В части I (главы 1 и 2) представлены новейшие тенденции разработки программных компонентов, основные принципы распределенных вычислительных систем и разработки web-приложений, в том числе сервлетов Java. В части II (главы 3-5) раскрываются основные понятия архитектуры Enterprise JavaBeans (EJB 1.0 и 1.1). Здесь строятся и развертываются в базе данных Огас1е8г простые и составные компоненты EJB для БД. В части III (главы 6-9) разрабатываются и внедряются Java-компоненты CORBA. Кроме того, создаются Java-клиенты CORBA, использующие компоненты EJB, которые будут построены в части II. В части IV (главы 10-12) описана разработка компонентов JavaServer Pages и JavaBean. В главе 12 с помощью расширяемого языка разметки (XML — Extensible Markup Language), JSP и сервлетов строятся клиентские приложения, которые будут пользоваться компонентами EJB и CORBA, построенными в частях II и III. Итак, темы настоящей главы: • Базовые понятия для компонентов • Базовые понятия для программных компонентов • Распределенные вычислительные системы • Основные строительные блоки компонента, использующего Java (в этом разделе с помощью реализаций JDBC и SQLJ строится простой компонен т Java). Предлагаем вам общий обзор самых современных тенденций разработки программных компонентов, а также основных принципов распределенных вычислительных систем.
Компоненты: общее представление Время крупных, монолитных систем уже уходит. Скорость этого процесса весьма велика, и циклы разработки сокращаются от нескольких месяцев до пары недель. Сегодня распространены укороченные процессы разработки, когда крупные и сложные приложения строятся из нескольких небольших "частей" — компонентов, которые разрабатываются за более короткое время.
Что т а к о е компонент Компонент (component) — это независимая программная единица уровня приложения, разрабатываемая не для конкретного приложения, а с определенной целыо. К программированию компонентов можно привлечь группу разработчиков, наделив каждого своими обязанностями, что, несомненно,
о
Знакомство с распределенными вычислительными системами
сэкономит время на разработку. Проектирование особенно крупных приложений нередко поручают даже нескольким организациям. Компонентный подход к программированию основывается на базовых понятиях теории ориентации на объекты. Хотя нередко термины "компонент" и "объект" используются как синонимы, компонент — это не объект. Объект (object) — это экземпляр класса, создаваемый во время выполнения программы. Компонент может быть классом, но обычно представляет собой совокупность классов и интерфейсов. На этапе выполнения программы компонент "оживает" при конкретизации его классов. Таким образом, на данном этапе компонент становится сетью объектов. Как правило, компоненты — это многократно используемые бизнес-объекты с заранее определенным режимом работы. Детали их реализации скрываются в интерфейсах, обособляющих и формирующих (инкапсулирующих) набор функциональных возможностей и соединяющих компоненты. Интерфейс (interface) — это набор именованных операций, которые могут вызываться клиентами. Более того, грамотно описанные интерфейсы определяют точки входа компонента, и доступ к нему осуществляется только через его интерфейс. При использовании компонентного метода поставщики услуг и клиенты взаимодействуют друг с другом через спецификацию интерфейса, которая становится посредником между двумя сторонами, позволяя им сотрудничать и работать совместно. В разделе "Построение компонента в Java" этой главы с помощью Java строится компонент Observation. В главе 4 функциональные возможности компонента Observation расширяются, и он развертывается в качестве зерна (Bean) уровня предприятия. На рис. 1.1 представлен общий вид компонента. Рис. 1.1. Состав компонента Я клиент, и мне нужно ввести новые детали наблюдения Клиент
Я могу ввести детали наблюдения интерфейс
Я могу ввести детали наблюдения в таблицу OCEANIC_OBSERVATION_UST базы данных реализация
При программировании с ориентацией на компоненты обращаются к различным их аспектам. Сам компонент можно построить при помощи любого языка программирования, конечно при условии, что последним поддерживаются интерфейсные соглашения, принятые для стандарта конкретного компонента. Во многих языках программирования, например COBOL, Object COBOL, С, С++, Pascal, Object Pascal, Modula 2, Eiffel или Smalltalk, нет достаточной поддержки инкапсуляции, полиморфизма, безопасности типов или комбинации этих характеристик. В настоящее время самым известным языком программирования с использованием компонентов является Java. С появлением программного продукта Java 2 Enterprise Edition (J2EE) от Sun Microsystems комбинация EJB, сервлетов и JSP формирует мощную платформу для построения приложений на основе компонентов.
Программные компоненты: общее представление Компоненты применяются в основном по двум причинам: из-за возможности многократного использования большим числом приложений и благодаря интерфейсам. Правильное применение интерфейсов может принести большую пользу, позволяя, например, строить самодостаточные единицы или одновременно и параллельно разрабатывать приложения. Компоненты лучше всего применять в процессе сборки приложений. Компонентный подход должен 2 Зак. 574
5
ГЛАВА 1
быть не революционным, а эволюционным. Собирая, т.е. объединяя заранее заготовленные компоненты, разработчики могут создавать новые конструкции. Сборные системы, состоящие из компонентов, называются программными компонентами (software components). "Программный компонент — это структурная единица с заранее оговоренными интерфейсами и исключительно явными контекстными зависимостями. Он может быть установлен автономно и включен в конструкцию посторонними" [European Conference on Object-Oriented Programming (ECOOP), 1996]. Изначально программные компоненты рассматривались по аналогии с аппаратными компонентами и микросхемами. Они совершенно самостоятельны, т.е. независимы от среды и приложения и при построении работоспособной системы взаимодействуют друг с другом посредством методов (операций), заявленных в их интерфейсах. Подробнее о программных компонентах мы поговорим в главе 5 при построении компонентного приложения, состоящего из трех зерен Enterprise JavaBeans.
П р е и м у щ е с т в а компонентов и программных компонентов • Независимость Компонент — обобщенная единица, не зависящая от приложения. • Многократное использование Это многократно используемые единицы. По сравнению с конкретными решениями конкретных проблем компоненты более общие, что допускает неоднократное их использование в самых различных контекстах. • Настройка Отдельные компоненты можно делать на заказ, удовлетворяя определенные потребности, а готовый — настроить так, чтобы он им соответствовал. • Компоновка Собрав несколько компонентов, можно сформировать работоспособную систему. • Простота модернизации и обслуживания Модернизация отдельных компонентов устраняет необходимость в объемной модернизации, обязательной в монолитных системах. • Прозрачность местонахождения Компоненты могут находиться в любом месте сети, на наиболее удобных для их функционирования компьютерах; это определяется функциями компонента. • Распределение С помощью таких стандартов распределенных вычислительных систем, как Enterprise JavaBeans, CORBA или Distributed Component Object Model/Component Object Model (DCOM/COM) корпорации Microsoft компоненты и программные компоненты молено распределить по всей сети предприятия.
Распределенные вычислительные системы Общей характеристикой современных корпоративных и правительственных сетей является их неоднородность (гетерогенность). Неоднородные системы представляют собой комбинацию множества ОС, разнесенных среди нескольких аппаратных (мэйнфреймы, рабочие станции, персональные компьютеры и др.) и программных компонентов. Распределение объектных вычислений — это метод построения программной инфраструктуры, объединяющей компоненты сети и позволяющей им взаимодействовать друг с другом. Рассмотрим, каковы основные принципы распределенных вычислительных систем и как последние связаны со специалистами по информационным технологиям, отвечающими за построение информационных систем, и системами управления БД, в частности с объектно-реляционной БД Огас1е8г (версий 8.1.5, 8.1.6 и 8.1.7), реализующей архитектуры компонентных моделей на сервере баз данных.
Знакомство с распределенными вычислительными системами
о
В основе всех архитектур распределенных вычислений лежит взаимодействие компыотерЪв. Новейшей разработкой в системах распределенных вычислений является распределение объектов, когда объекты (бизнес-логика и данные) разносятся по неоднородной сети: независимо от того, находятся ли они в различных адресных пространствах или на разных компьютерах, объекты кажутся частями единого целого. Термином "распределенные объектные вычисления" (distributed object computing) обозначаются те программы и приложения, которые удаленно вызывают другие программы, находящиеся в других адресных пространствах, а возможно, и па других компьютерах и / и л и в других сетях. Распределенные объектные вычисления — это основа вычислений, ставшая результатом постепенного сближения объектно-ориентированной технологии и технологии клиент/сервер. Более того, она обеспечивает взаимодействие и возможность многократного использования распределенных объектов, что позволяет разработчикам строить системы, собирая компоненты от разных поставщиков.
Распределенные объектные архитектуры Распределенные объектные системы служат фундаментом трехуровневой архитектуры, в которой логические схемы представления, или первый уровень, находятся на станции клиента, бизнес-логика — на среднем уровне, а база данных — на третьем. Распределенная объектная технология расширяет средний уровень, позволяя обращаться не только к одному прикладному объекту, но и к нескольким. В результате рождается новая архитектура, называемая N-ypoeневой (N-tier), или многоуровневой (multi-tier). В ней возможно сосуществование множества прикладных объектов (т.е. серверов баз данных, объектов Java RMI, EJB, CORBA, DCOM и др.), причем клиентские и серверные объекты взаимодействуют посредством специального протокола удаленного вызова методов (RMI, remote method invocation). Протокол RMI используется для удаленного вызова коммуникационных методов. Например, у каждой из моделей CORBA, Java RMI и Microsoft DCOM он свой. У любого прикладного объекта есть определенный интерфейс объектной оболочки, где заявляются услуги, предоставляемые объектом и особенно важно, что связь осуществляется только через этот интерфейс. В основе всех распределенных объектных протоколов лежит одна и та же базовая архитектура. Распределенные объектные архитектуры основаны на сетевом коммуникационном слое (уровне), состоящем из трех частей: объектного сервера (object server), скелета (skeleton) и изолятора (stub). Первый и второй располагаются, как правило, па среднем уровне, но в Огас1е8г находятся на третьем (т.е. на сервере баз данных). Изолятор размещается на машине клиента и обеспечивает межпроцессную связь клиентских и серверных объектов. Для клиента он выступает в роли посредника и несет ответственность за коммуникационные запросы первого, передаваемые объектному серверу через скелет. Изолятор и скелет отвечают за то, чтобы объектный сервер (который может находиться на среднем или третьем уровне) выглядел так, будто он работает в определенном месте. Пересылают данные из одного адресного пространства в другое изолятор и скелет с помощью двух процессов — упорядочения (marshaling) и обратного упорядочения (unmarshaling). "Во время упорядочения параметры вызова метода (в пространстве клиента) или возвращаемые значения (в пространстве сервера) упаковываются в стандартный формат для передачи" (См. книгу "Огас1е8г SQLJ Programming", Osborne/McGraw-Hill (далее OMcGH), 1999).
Стандарты распределенных вычислительных с и с т е м ДЛЯ распределенных объектных вычислений существует несколько стандартов: • Группа управления объектами (OMG, Object Management Group) в начале 1990 г. разработала общую архитектуру посредника объектных запросов (CORBA, Common Object Request Broker Architecture),
7
ГЛАВА 1
в основе которой лежит абстрактная модель, называемая архитектурой управления объектами (ОМА, Object Management Architecture), где для организации взаимодействия между клиентскими и серверными объектами и управления ими применяется посредник объектных1 запросов (ORB, Object Request Broker). Удаленное обращение осуществляется через протокол Internet Inter-ORB (НОР). Он дает возможность писать распределенные программы взаимодействия через Интернет на разных языках программирования. Объекты и интерфейсы CORBA определяются при помощи языка описания интерфейсов OMG (OMG IDL, OMG Interface Definition Language). Он позволяет взаимодействовать клиентским и серверным объектам, написанным на разных языках программирования. В число соответствий OMG IDL для языков программирования (Java, С, С++, Ada и COBOL) входят описания специфичных типов данных и интерфейсов для обращения к объектам CORBA. Объекты CORBA можно распределят!> на многие аппаратные платформы (рабочие станции UNIX, Windows NT и др.). CORBA описывается в главах 6-9. • Распределенная компонентная объектная модель (DCOM, Distributed Component Object Model), разработанная в Microsoft,— это компонентная технология распределения приложений в архитектуре Windows. Она основана на компонентной объектной модели (COM, Component Object Model), которая позволяет клиентам вызывать службы, предоставляемые согласующимися с СОМ компонентами (объектами СОМ). Объекты и интерфейсы СОМ определяются при помощи языка описания интерфейсов IDL (Microsoft Interface Definition Language), расширения стандарта DCE Interface Definition Language. • Удаленный вызов методов Java (RMI, Remote Method Invocation) от Sun JavaSoft позволяет объекту Java, функционирующему в одной виртуальной машине Java (JVM, Java Virtual Machine), вызывать методы другого объекта Java, функционирующего в другой JVM. В RMI с этой целью используется протокол JRMP (Java Remote Method Protocol). Кстати, способ, изначально задуманный для работы только в среде Java. В июне 1999 г. Sun выпустила спецификацию RMI over НОР (RMI-IIOP): будучи разработанной совместно Sun и IBM, она позволяет объектам Java взаимодействовать с объектами CORBA. Спецификацией RMI-IIOP поддерживаются и платформы JDK начиная с 1.1.6, и Java 2. • Компонентная архитектура JavaBeans от Sun JavaSoft позволяет разработчикам создавать клиентские компоненты, которые можно собирать при помощи визуальных построителей приложений (например, Oracle JDeveloper или Visual Cafe) и невизуальных средств. Подробнее о разработке компонентов JavaBean см. в главе 11. • Enterprise JavaBean (EJB) — это компонентная модель, позволяющая разработчикам распределять компоненты на сервере (на прикладных серверах и серверах баз данных). В приложениях EJB удаленный вызов соответствует спецификации RMI, но производители не ограничены транспортным протоколом RMI. Например, на сервере FJB в Огас1е8г в качестве транспортного протокола применяется RMI over ПОР. Серверные компоненты используются на прикладных серверах промежуточного программного обеспечения, где компоненты обслуживаются во время выполнения программы и доступны для удаленных клиентов. С появлением РСУБД Огас1е8г разработчики получили возможность сохранять объекты EJB и CORBA внутри базы данных. С помощью EJB разрабатываются и внедряются N-уровневые, распределенные и объектно-ориентированные приложения Java. Подробнее о ней см. главы 3-5.
Знакомство с распределенными вычислительными системами
О
Достоинства р а с п р е д е л е н н ы х вычислительных с и с т е м • Разбиение сложных прикладных программ на программные компоненты Следовательно, различные задачи можно распределять сразу среди нескольких разработчиков, получая несколько оперативных и независимых решений. • Упрощение модернизации и обслуживания Нередко обновление и обслуживание монолитных систем оказывается довольно дорогим и долгим. Программные приложения, моделирующие бизнес-объекты, более гибки, расширяемы, и применять их можно неоднократно. • Распределение программных компонентов среди компьютеров, наиболее подходящих для выполнения задачи Кроме того, программные компоненты могут использоваться несколькими приложениями. м И с п о л ь з о в а н и е объектных
оболочек
п р и о б р а щ е н и и к с т а р ы м систе-
мам Старые (унаследованные) системы — неотъемлемая часть нынешних. Объектные оболочки — объектно-ориентированные интерфейсы, окружающие старые сис темы,— позволяют последним в полной мере участвовать в работе информационных систем нового поколения, делая их доступными и разрешая связь с ними. Например, web-браузеры с CORBA или клиенты CORBA могут напрямую вызывать объектные оболочки, если, конечно, оболочки созданы с помощью OMG IDL.
Построение компонента в Java Компонент в Java строится с помощью базовых блоков. Более того, компонент Observation — простой бизнес-объект — разрабатывается с применением реализаций JDBC и SQLJ. Observation позволяет клиенту обращаться к базе данных Огас1е8г и вводить массив наблюдений за атмосферой океана в таблицу OCEANIC_OBSERVATION_LIST. Эта таблица является частью научной схемы наблюдений, представленной во введении. В главе 4 функциональные возможности этого компонента расширяются, и он внедряется в базу данных Огас1е8г в качестве компонента EJB. Компонент состоит как минимум из интерфейса и класса реализации, которые, работая в совокупности, создают некий функциональный набор. В частности, Observation состоит из: •
Интерфейса Observation
• Класса реализации Obslmp • Класса ObsHelper • Класса ObsException •
К л а с с а Client
На рис. 1.2 представлены основные строительные блоки компонента в Java. Прежде всего — описания классов ObsHelper и ObsException.
К л а с с ObsHelper Указанным классом реализуется интерфейс java. io. Serializable. В ObsHelper содержится несколько конструкторов, позволяющих создать несколько объектов ObsHelper в соответствии с конкретными потребностями. Экземпляры класса используются для прямого и обратного упорядочения данных, пересылаемых между приложением Client и классом Obslmp, который будет создан в последующих разделах этой главы. Вот описание ObsHelper: •
/*
Имя программы:
ObsHelper.java
** **
Назначение:
Серийный Helper-класс Java, используемый для передачи объектов параметров (OCEANIC,OBSERVATIONTYPE) между клиентами, компонентами EJB и CORBA.
**
9
ГЛАВА 1
package helpers; import java.io.Serializable; import java.math.BigDecimal; public class ObsHelper implements java.io.Serializable { // Переменные для элементов public BigDecimal obs_id = null; public String when_t = null; public String at_time = null; public BigDecimal station_id = null; public BigDecimal produced_id = null; public BigDecimal latitude = null; public BigDecimal longitude = null; public BigDecimal wdspd = null; public BigDecimal adj_wdspd = null;
Знакомство с распределенными вычислительными системами 38
public BigDecimal wddir = null; public BigDecimal pressure = null; // Опишем массив типа BigDecimal public BigDecimal[] idArray = null; // Конструктор по умолчанию public ObsHelperQ {
К л а с с ObsException В Java существует класс Throwable, характеризующий все, что можно установить в качестве исключительной ситуации, или исключения (exception). Базовым типом, устанавливаемым из любого стандартного метода библиотечного класса Java и пользовательских методов и подпрограмм этапа выполнения, является класс java. lang. Exception. Скорее всего, понадобится создать собственные исключительные ситуации, чтобы обозначить особые ошибки, которые могут возникнуть во время работы программы. Организовать собственный класс исключений можно с помощью существующего типа исключительных ситуаций, унаследовав его. ObsException — это пользовательский класс исключений, расширяющий класс java. lang. Exception. В главе 5 ObsException будет переопределен так, чтобы он унаследовал свойства java. rmi.RemoteException. Последний будет применяться в компонентах EJB для переноса исключительной ситуации из серверных объектов на станцию клиента. Вот описание класса ObsException: •
/*
Имя программы:
ObsException.java
Назначение:
Класс исключений, который должен передаваться из серверных объектов клиенту.
Ч package helpers; public class ObsException extends Exception { // Конструктор no умолчанию public ObsExceptionO { } // Конец конструктора // Конструктор с параметрами
ГЛАВА 1
public ObsException (String msg ) { super(msg); } // Конец конструктора с параметрами } // Конец класса ObsException
Интерфейс Observation Интерфейс (interface) определяется как совокупность именованных операций, у каждой из которых есть определенная сигнатура и, возможно, возвращаемый тип. Интерфейсом Java определяется набор методов или объявлений констант без реализации тел методов. Все объявления методов интерфейса Java автоматически являются абстрактными (abstract) и общими (public). В интерфейсе Observation заявлен один метод — insertObs(). При вызове приложением Client метод insertObs() возвращает вызывающему объект А г ray List, состоящий из объектов Obshelper. П р и в е д е м о п и с а н и е интерфейса Observation: •
Observation.java Название вашего продукта Copyright (с) 2000 Ваше имя Интерфейс Java, определяющий вызываемый метод insertObs() клиента.
// импортируем helper-классы import helpers.ObsHelper; import helpers.ObsException; import java.util.ArrayList; import java.sql.SQLException; public interface Observation { // Вставим объект ArrayList Наблюдений // в таблицу 0CEANIC_0BSERVATI0N_LIST // и возвратим объект ArrayList Идентификаторов // Наблюдений public ArrayList insertObs() throws SQLException, ObsException; } // Конец интерфейса Observation
К л а с с Obslmp: реализация с помощью JDBC В Java для реализации объявленного интерфейса в новом классе применяется конструкция implements. Поэтому при реализации интерфейса Observation воспользуемся ею в классе Obslmp. Когда мы создаем новый класс, реализующий интерфейс Java, первый должен реализовывать каждый метод второго. Интерфейсом Observation определяется лишь один метод, insertObs(), и его необходимо реализовать в классе Obslmp, для чего применим JDBC. В главах 4 и 5 эта реализация будет пересмотрена и расширена. В классе Obslmp описывается и реализуется несколько частных (private) методов Java, т.е. тех, что не могут вызываться клиентами, и один общий (public), который клиенты могут вызывать: •
Частный метод getNewObs() не может вызываться клиентами: он обращается к переопределяемому методу getNewObs (Connection conn), который, в свою очередь, генерирует новый идентификатор наблюдения. Данный метод возвращает вызывающему объект ObsHelper с идентификатором наблюдения.
Знакомство с распределенными вычислительными системами
О
• Частный метод getNewObs (Connection conn) вызывает PL/SQL-функцию ObsActions.get0bsld(), генерирующую новый идентификатор наблюдения. При вызове методом getNewObsO он возвращает вызывающему объект ObsHelper. Полное описание PL/SQL-модуля ObsActions дано во введении. insertObs (ObsHelper obs) вызывает PL/SQL-метод ObsActions. insertObs ( . . . ) , который вводит OCEANIC_OBSERVATION_TYPE в таблицу OCEANIC_OBSERVATION_LIST. Он возвращает вызывающему объект ObsHelper.
• Частный метод
• Общий метод ArrayList insertObs (ArrayList inObs) — единственный, вызываемый клиентами. Напомним, что он и единственный, описанный в интерфейсе Observation. Метод принимает объект ArrayList из о б ъ е к т о в ObsHelper в качестве входных д а н н ы х и в о з в р а щ а е т о б ъ е к т ArrayList
из идентификаторов наблюдений. Для этого он последовательно вызывает метод insertObs (ObsHelper obs).
• Частный статический ( s t a t i c ) метод connectDb() подключается к базе данных и возвращает вызывающему объект java. sql. Connection. Вот описание класса •
// // // // // // // //
Имя программы: Название: Версия: Авторское право: Автор: Описание:
Obslmp:
Obslmp.java Название вашего продукта Copyright (с) 2000 Ваше имя Класс реализации Java, реализующий вызываемый метод insertObsO клиента, заявленный в интерфейсе Observation.
package obsserver; // импортируем helper-классы import helpers.ObsHelper; import helpers.ObsException; // импортируем специфичное для приложения исключение import java.sql.SQLException; import java.sql.*; import oracle.sql.*; // Импортируем вспомогательные классы Java import java.math.BigDecimal; import java.util.ArrayList; public class Obslmp implements Observation { // Конструктор по умолчанию public ObsImpO { } // Конец конструктора // Этот метод НЕ вызывается клиентами. // Поэтому он не указан в интерфейсе // Observation. private ObsHelper getNewObs(Connection conn) throws SQLException, ObsException { // Создадим объект CallableStatement CallableStatement cstmt = null; try { // Подготовим строку символов (String) для вызова String sqlld = "{? = call OBSACTIONS.GETOBSID}";
13
14
ГЛАВА 2
О И Подготовим вызов с помощью объекта conn cstmt = conn.prepareCall(sqlld); // Объявим, что ? - это возвращаемое значение типа Integer cstmt.registerOutParameter (1, Types.INTEGER); // Получим новый obsid, выполнив запрос cstmt. executeO; // Сохраним результат запроса // в переменной anObsId. BigDecimal anObsId = new BigDecimal(cstmt.getInt (1)); // Возвратим объект ObsHelper, используя новый идентификатор return new ObsHelper(anObsId); } // Конец try
catch (SQLException e) { throw e; } // Конец catch // Выполним очистку. Этот метод гарантирует, что независимо // от происходящего в нем объект CallableStatement // будет всегда закрываться после обработки // finally { if ( cstmt != null ) cstmt.close(); } // Конец finallyO } // Конец getNewObs(conn) private ObsHelper insertObs(ObsHelper obs, Connection conn) throws SQLException, ObsException { // Создадим объект CallableStatement CallableStatement cstmt = null; try { // Подготовим строку символов для вызова // PL/SQL-процедуры OBSACTIONS.INSERTOBS() String sql = "{call OBSACTIONS.INSERTOBS(?,?,?,?,?,?,?,?,?,?,?)}"; cstmt = conn.prepareCall(sql); // Установим входные параметры // для PL/SQL-процедуры OBSACTIONS.INSERTOBS() cstmt.setlnt(1, obs.obs_id.intValueO); cstmt.setString(2, obs.when_t); cstmt.setString(3, obs.atjtime); cstmt.setlnt(4, obs.produced_id.intValueQ); cstmt.setlnt(5, obs.latitude.intValueO); cstmt.setlnt(6, obs.longitude. intValueO); cstmt.setlnt(7, obs.wdspd.intValue()); cstmt.setlnt(8, obs.adj_wdspd.intValueO); cstmt.setlnt(9, obs.wddir.intValueO); cstmt.setlnt(10, obs.pressure.intValueO); cstmt.setlnt(11, obs.station_id.intValueO); // Необходимо вызвать метод executeO объекта // CallableStatement. Если забудем его включить, возникнут // достаточно странные ошибки, cstmt. executeO; // Возвратим объект ObsHelper return new ObsHelper(obs.obs_id);
Знакомство с распределенными вычислительными системами
} // Конец try catch (SQLException е) { throw е; } // Конец catch // Выполним очистку finally { if ( cstmt != null ) cstmt.close(); } // Конец finallyO } // Конец insertObs(obs,conn) // Введем ArrayList из OCEANIC_OBSERVATION_TYPE public ArrayList insertObs(ArrayList inObs) throws SQLException, ObsException { int loopVar = 0; // Объявим массив объектов ObsHelper ArrayList returnArrayList = inObs; int arrayListSize = inObs.size(); Connection conn = null; try { // С помощью тонкого JDBC-драйвера Oracle // подключимся к базе данных conn = connectDb(); // Повторим действия и сохраним ArrayList // идентификаторов obs_id в returnArrayList while ( loopVar < arrayListSize ) { // Получим новый obs_id на каждом шаге ObsHelper anObsid = getNewObs(conn); // Перенесем объект ObsHelper в obs ObsHelper obs = (ObsHelper)inObs.get(loopVar); // Заменим obs.obs_id новым anObsid.obs_id obs.obs_id = anObsid.obs_id; // Вызовем insertObs(..), добавив новую строку // в базу данных, и возвратим новый // ObsHelper с новым obs_id. returnArrayList.add(insertObs ( obs, conn )); loopVar++; // Увеличим счетчик } // Конец while // Уменьшим объект ArrayList до его текущего размера returnArrayList.trimToSize(); // Возвратим ArrayList идентификаторов return returnArrayList; } // Конец try catch (SQLException e) { throw e; } // Конец catch // Выполним очистку finally { if ( conn != null ) conn.close(); } // Конец finallyO } // Конец insertObs(ArrayList inObs) // Этот метод вызывается всеми методами, которым нужно // подключиться к базе данных с помощью тонкого
// Подключимся к серверу базы данных data-i.com conn = DriverManager. getConnect.i.on( "jdbc:oracle:thin:@data-i.com:1521:ORCL", "scott", "tiger"); // Возвратим объект java.sql.Connection return conn; } // Конец connectDb() } // Конец класса Obslmp
Теперь, после построения компонента Observation, нужно скомпилировать исходные файлы Java. Обратите внимание на то, что для некоторых методов компонента в качестве входного параметра и возвращаемого типа использовался объект ArrayList. Тип ArrayList для Java описан в 1.2.x, поэтому для компиляции исходного программного текста следует пользоваться компилятором, соответствующим JDK 1.2.x. Если применять JDK 1.2.x нежелательно, замените тип ArrayList на любой массив Java или тип Vector. Для компиляции программ воспользуемся командой javac: •
// Естественно, установим собственный CLASSPATH. Javac -g helpers\*.java obsserver\*.java
Теперь опишем класс Obslmp с помощью SQLJ. T ВНИМАНИЕ! )
Следите за тем, чтобы исходный программный текст для реализаций JDBC и SQLJ не присутствовал в одном каталоге. При компиляции программы SQLJ компилятор генерирует исходный файл . java. Если реализация JDBC находится в том же каталоге, она будет перезаписана. Во избежание подобной ситуации исходный текст всех программ, представленных в книге, хранится в каталогах Jdbclmplementation и Sqljlmplementation. Указанные файлы можно скопировать на сайтах www.data-i.com или www.osborne.com.
К л а с с Obslmp: реализация с помощью S Q U Как и реализация JDBC, эта реализация будет пересмотрена и расширена в главах 4 и 5. Она очень похожа на ту, что строится через JDBC, однако имеет ряд незначительных отличий. • В SQLJ подключение к базе данных идет с помощью объектов соединения двух типов: интерфейс sqlj. runtime.ConnectionContext и класс sqlj. runtime, ref. DefaultContext. Экземпляр любого из них указывает на местонахождение сервера данных, на котором будет выполняться SQL-операция. С помощью следующего программного фрагмента подключаемся к БД: // Объявим переменную типа DefaultContext protected static DefaultContext localHostCtx; // Подключимся к базе данных. Метод Oracle.getConnection() // возвращает объект DefaultContext. localHostCtx = Oracle.getConnection ("jdbc:oracle:thin:@data-i.com:1521:ORCL", "scott","tiger",true);
Знакомство с распределенными вычислительными системами 44
• ДЛЯ реализаций JDBC, где вызываются хранимые функции или процедуры, в программе нужно устанавливать специальную среду. Если не указать любой из установочных операторов или попытаться выполнить их не в том порядке, что описан заранее, будут выданы сообщения об ошибках Java. В SQLJ функция просто вызывается. Например: ttsql [localHostCtx] returnld = {VALUES ObsActions.getObsId};
Обратите внимание на простоту оператора и особенно на то, что среда здесь не устанавливается. SQLJ-объект localHostCtx DefaultContext связывается с оператором при выполнении SQL-команды в базе данных. Более подробно о соединительных объектах SQLJ рассказано в главе 5 книги "Огас1е8г SQLJ Programming", OMcGH, 1999. • Вызывать процедуры в SQLJ так же просто, как и функции. Например: #sql [localHostCtx] { call ObsActions.insertObs( :IN obs_id, :IN when_t, :IN at_time, :IN produced_id, :IN latitude, :IN longitude, :IN wdspd, :IN adj_wdspd, :IN wddir, :IN pressure, :IN station_id)
};
Приведем описание класса •
// // // // // // // // // //
Obslmp
с помощью реализации SQLJ:
Имя программы: Obslmp.sqlj Имя программы: Obslmp.java Название: Название вашего продукта Версия: Авторское право: Copyright (с) 2000 Автор: Ваше имя Описание: Класс Java, который использует SQLJ для реализации вызываемого клиентами метода insertObs(), заявленного в интерфейсе Observation.
О public ObsImpO throws SQLException { // Подключимся к базе данных // с помощью SQLJ-объекта DefaultContext connectDb(); System.out.println("In ObsImpO, I got a connection"); } // Конец конструктора // Этот метод, который не могут вызывать клиенты, подключается // к БД и вызывает переопределяемый geLNewObs(), получая // новый obs_id. private ObsHelper geLNewObsO throws SQLException, ObsException { // Объявим переменную, int returnld; // Вызовем get0bsld() из PL/SQL-модуля ObsActions, чтобы // получить новый obs_id. try { // Для вызова PL/SQL-фуккции воспользуемся объектом // localHostCtx DefaultContext #sql [localHostCtx] returnld = {VALUES ObsActions.getObsId}; BigDecimal anObsid = new BigDecimal(returnld); // Возвратим объект ObsHelper с помощью нового идентификатора return new ObsHelper(anObsId); } // Конец try catch (SQLException e) { throw e; } // Конец catch catch (java.lang.NulLPointerException e) { throw e; } // Конец catch } // Конец getNewObs // Этот метод получает новый obs_id и добавляет новый // OCEANIC_OBSERVATION_TYPE в таблицу OCEANIC_OBSERVATION_LIST. private ObsHelper insertObs(ObsHelper obs) throws SQLException, ObsException { try { BigDecimal obs_id = obs.obs_id; String when_t = obs.when_t; String at_time = obs.at_time; BigDecimal produced_id = obs.produced_id; BigDecimal latitude = obs.latitude; BigDbcimal longitude = obs.longitude; BigDecimal wdspd = obs.wdspd; BigDecimal adj_wdspd = obs.adj_wdspd; BigDecimal wddir = obs.wddir; BigDecimal pressure = obs.pressure; BigDecimal station_id = obs.station_id; // Вызовем PL/SQL-процедуру OBSACTIONS.INSERTOBS() с помощью // объекта localHostCtx DefaultContext ttsql [localHostCtx] { call ObsActions.insertObs( :IN obs_id, :IN when_t, :IN at_time, :IN produced_id, :IN latitude, :IN longitude, :IN wdspd, :IN adj_wdspd, :IN wddir, :IN pressure, :IN station_id) }; // Возвратим объект ObsHelper return new ObsHelper(obs.obs_id);
Знакомство с распределенными вычислительными системами 46
} // Конец try catch (SQLException е) { throw е; } // Конец catch } // Конец insertObs(obs) public ArrayList insertObs(ArrayList inObs) throws SQLException, ObsException { int loopVar = 0; // Объявим массив объектов ObsHelper ArrayList returnArrayList = inObs; int arrayListSize = inObs.size(); try { // Повторим действия и сохраним ArrayList // из идентификаторов obs_id в returnArrayList while ( loopVar < arrayListSize ) { // узнаем новый obs_id на каждом шаге ObsHelper anObsid = getNewObsO; // Перенесем объект ObsHelper в obs ObsHelper obs = (ObsHelper)inObs.get(loopVar); // Заменим obs.obs_id новым anObsid.obs_id obs.obs_id = anObsid.obs_id; // Вызовем insertObs(..), добавив новую строку в БД, // и возвратим новый // ObsHelper с новым obs_id. returnArrayList.add(insertObs(obs)); loopVar++; // Увеличим счетчик } // Конец while returnArrayList.trimToSize(); // Возвратим ArrayList идентификаторов return returnArrayList; } // Конец try catch (SQLException e) { throw e; } // Конец catch } // Конец insertObs(ArrayList inObs) // Этот метод создает экземпляр SQLJ-объекта DefaultContext // и сохраняет объект в переменной localHostCtx. // Этот метод вызывается, когда клиент создает экземпляр // класса Obslmp. private static void connectDbO throws SQLException { // Создадим Default Context для определенного // хоста и подключимся к БД. localHostCtx = Oracle.getConnection ("jdbc:oracle:thin:@data-i.com:1521:ORCL", "scott","tiger",true); } // Конец connectDbO } // Конец класса Obslmp
Теперь нужно скомпилировать исходный программный текст реализации SQLJ. Более подробно о компиляции и выполнении программ SQLJ говорится в приложении F и в книге "Огас1е8г SQLJ Programming", OMcGH, 1999.
ГЛАВА 1
Для компиляции класса Obslmp воспользуемся такой командой: •
// Установим свой СLASSPATH sqlj-status Obslmp.sqlj
К л а с с Client Данный класс пользуется компонентом Observation, описанным в предыдущих разделах и выполняет следующие задачи: • Объявление глобальной переменной theObservationlnterface типа интерфейса Observation.
• Описание конструктора Client(). При конкретизации класса Client его конструктор создает экземпляр класса Obslmp и сохраняет объект в переменной theObservationlnterface. • Создание объекта ArrayList, состоящего из объектов ObsHelper. • Вызов метода insertObs(), заявленного в интерфейсе Observation и реализованного в классе Obslmp. Метод возвращает приложению Client объект ArrayList, состоящий из идентификаторов. • Вызов локального метода printObsIds (obsids) для вывода всех новых идентификаторов наблюдений, создаваемых компонентом. Приведем описание класса Client: •
V // Импортируем классы JDBC import java.sql.*; // Импортируем helper-классы import helpers.ObsHelper; import helpers.ObsException; // Сделаем интерфейс obsserver.Observation // видимым для приложения Client import obsserver.*; import java.sql.*; import oracle.sql.*; // Импортируем вспомогательные классы Java import java.math.BigDecimal; import java.util.ArrayList; public class Client { //Объявим переменную типа Observation protected Observation theObservationlnterface = null; // Конструктор public ClientO { // Получим экземпляр класса Obslmp и сохраним его // в переменной theObservationlnterface theObservationlnterface = new 0bslmp(); } // Конец конструктора public static void main (String args[]) throws Exception {
Знакомство с распределенными вычислительными системами
// Получим экземпляр класса Obslmp Client aClientApp = new ClientO; System.out.println("I got an Obslmp instance"); // Создадим объект ArrayList ArrayList obs = new ArrayList(2); System.out.println("I created an ArrayList object"); // Сохраним набор объектов ObsHelper в объекте obs ArrayList while (loopVar++ < 2) { BigDecimal obs_id = null; String when_t = "16-AUG-2000"; String at_time = "085500"; BigDecimal station_id = new BigDecimal(O); •BigDecimal produced_id = new BigDecimal(1); BigDecimal latitude = new BigDecimal(O); BigDecimal longitude = new BigDecimal(O); BigDecimal wdspd = new BigDecimal(O); BigDecimal adj_wdspd = new BigDecimal(O); BigDecimal wddir = new BigDecimal(O); BigDecimal pressure = new BigDecimal(O); // Создадим объект ObsHelper ObsHelper obsl = new ObsHelper(obs_id,when_t,at_time,station_id, produced_id,latitude,longitude, wdspd,adj_wdspd,wddir,pressure); // Введем объект ObsHelper в ArrayList obs.add(obsl); } // Конец while System.out.println("I going to call the insertObsO method"); // Вызовем метод insertObsO класса Obslmp и получим // объект ArrayList, состоящий из объектов ObsHelper, которые // представляют собой набор идентификаторов наблюдений. ArrayList obsids = aClientApp.theObservationlnterface.insertObs(obs); System.out.println("I called the insertObsO success!"); System.out.println("I going to call the local +" print0bslds() method"); // Отобразим наблюдения printObsIds(obsids); System.out.println("I called printObsIds"); } // Конец main public static void printObsIds(ArrayList obs) throws Exception { int loopVar = 0; int arraySize = obs.size(); System.out.println("I have Obsids, see size:" +arraySize); while ( loopVar < arraySize ) { // Считаем объект ObsHelper в объекте ArrayList ObsHelper anObsid = (ObsHelper)obs.get(loopVar); System.out.println("id: " +anObsid.obs_id); loopVar++; } // Конец while
о
21
ГЛАВА 1
} // // Конец printObsIds } // Конец класса Client
Т е п е р ь скомпилируем и в ы п о л н и м п р и л о ж е н и е Client: •
// Установим свой CLASSPATH // Во-первых, скомпилируем программу javac -g Client.Java // Во-вторых, выполним программу java Client
Итоги Итак, мы изучили основы компонентов, программных компонентов и распределенных объектных вычислительных систем. Были представлены главные распределенные объектные парадигмы: CORBA, DCOM, Java RMI и EJB. Мы создали простой компонент для приложения баз данных, обращающийся к БД Огас1е8г и вводящий массив типа OCEANIC_OBSERVATION_TYPE в таблицу OCEANIC_0BSERVATI0N_LIST. А в заключение написали приложение Client — автономную программу Java на основе компонента. В главе 2 речь пойдет о web-приложениях, которые генерируют динамическое содержимое, настраиваемое согласно индивидуальным потребностям. В частности, будуг описаны технологии Java Server Pages (JSPs) и сервлетов, генерирующих динамическое содержимое, легко переносимое с платформы на платформу.
ГЛАВА 2 Знакомство с web-приложениями
О
ГЛАВА 1
D m J предыдущей главе говорилось о различных моделях программирования для распределенных вычислений. В настоящей мы опишем составляющие и архитектуру web-приложеиий. Интернет породил целое поколение новых прикладных программ, позволяющих общаться через World Wide Web. web-ripoграммирование, начавшись с создания развлекательных приложений, быстро "посерьезнело" — и вот уже появились бизнес-приложения уровня предприятия, обладающие широкими функциональными возможностями, надежные и масштабируемые. Объем операций, выполняемых через Интернет (их называют обычно электронным бизнесом (e-business), или электронной коммерц/лей (е-сошшегсе)), за последние три года чрезвычайно вырос. Продукты рекламируются и сбываются непосредственно через так называемые web-витрины (store fronts), партнеры обмениваются бизнес-данными в электронном виде, а интенсивность торгового оборота растет благодаря приложениям самообслуживания, например программам банковских расчетов на дому. В этой области произошла настоящая революция, продолжающаяся и по сей день. Рассмотрим отдельные технологии электронного бизнеса. Новая модель электронного бизнеса была воплощена благодаря совершенствованию web-приложений, вызываемых с удаленного компьютера по сети одним щелчком по клавише мыши. Такие приложения поддерживают интерактивный ввод и представление данных через любой стандартный web-браузер. За удобными для пользователей экранами скрываются транзакционные бизнес-компоненты, взаимодействующие с базами данных, например Огас1е8г. В этой главе мы раскроем основные понятия и принципы работы web-приложений, а именно: • Понятие web-сервера, его работу с протоколом HTTP • Модели сервлетов для генерации динамических web-страниц • JavaServer Pages, алгоритм обработки web-страниц и преимущества их над сервлетами. • Компонентную архитектуру web-приложений.
построения
элегантных
и
мощных
Понятие web-cepeepa На абстрактном уровне web-сервер — это программа, принимающая запросы по сети, на основании параметров запроса выполняющая определенные логические схемы и возвращающая результаты клиентскому приложению. Запросы передаются, как правило, пользователем, который щелкает мышью на гиперссылках, или гиперсвязях (hyperlinks), web-страницы, отображаемой web-браузером. Ответ, генерируемый web-сервером, обрабатывается и отображается браузером. Общая схема взаимодействия web-сервера и web-браузера по сети представлена на рис. 2.1. web-сервер прослушивает (listens) сеть в порту на той машине, где функционирует. Стандартным механизмом передачи клиентских запросов и ответов сервера по Интернету или через частные внутренние сети (интранет) является протокол HTTP. Входящие HTTP-запросы, направляемые определенной машине или в определенный порт, обрабатываются конкретным web-сервером. На одной машине могут работать несколько web-серверов: пока они прослушивают сеть в разных портах, никакого конфликта не будет. При обработке HTTP-запроса web-серверу порой приходится выполнять самые разнообразные функции: считывать содержимое файлов, выполнять программы, считывающие данные в базе или записывающие их туда, и др. В частности, он может выполнить сервлет (servlet) Java, используя встроенный двигатель, или систему поддержки, сервлетов (servlet engine) и виртуальную машину Java (Java Virtual Machine), чтобы сгенерировать динамическое содержимое web-страниц. Например, HTTP-запросом может вызываться сервлет, выдающий приветствие и текущее время и динамически обрабатываемый на основании
Знакомство с web-приложениями
О Сеть
Клиент
Сервер
Общая схема web-cepeepa HTTP-запрос
реального времени вызова. Пример такого сервлета приведен ниже. Программы, выполняемые web-сервером, называются серверными приложениями (server-side). Самым популярным web-сервером на сегодня считается web-сервер Apache. Это программа с бесплатно распространяемым доступным исходным текстом, коллективно разрабатываемая множеством программистов по всему миру. Его можно бесплатно получить на сайте www.apache.org. Она быстро завоевала популярность благодаря простоте применения, гибкости, доступности для нескольких платформ (в том числе операционной системы Linux) и возможности обращения к исходному тексту в процессе отладки, web-сервер Apache написан на языке С и имеет расширяемую модульную архитектуру, позволяющую вводить в его состав другие функциональные модули. Вторым по значимости web-сервером считается информационный Интернет-сервер (IIS, Internet Information Server) корпорации Microsoft, обладающий набором мощных функциональных средств. Однако работает он в основном в системах Windows NT, и поэтому область его применения ограничена. Для генерации динамических web-страниц в IIS поддерживаются активные серверные страницы (ASPs, Active Server Pages). Аналогом ASPs на основе Java является технология JavaServer Pages компании Sun Microsystem. В отличие от базирующихся на Java технологий сервлетов и JSP языком создания сцена.риев для ASPs является JScripl или VBScript, а компонентной моделью — СОМ и DCOM. Доступ к БД в ASPs облегчают активные объекты данных (ADOs, Active Data Objects) от компании Microsoft, в то время как в JSP и сервлетах для той же цели служат API Java Database Connectivity (JDBC) или SQLJ (SQL, встроенный в Java).
web-браузер web-сервер работает совместно с web-браузером, предоставляющим интуитивно понятный пользовательский интерфейс для web-взаимодействия. Главной функцией последнего является отображение web-страниц, написанных на одном из языков разметки, например на HTML (Hypertext Markup Language — гипертекстовый язык разметки) или XML (Extensible Markup Language — расширяемый 51зьис разметки). На большинстве web-страниц присутствуют гиперссылки, которые связаны с универсальными указателями ресурсов (URLs, Universal Resource Locators), идентифицирующими другие web-рссурсы. Если щелкнуть на гиперссылке мышыо, браузер создаст запрос для базового URL. Общий формат URL таков: •
протокол имя_сервера[:номер_порта~\
имя_ресурса
25
ГЛАВА 1
Так, URL может иметь вид http://www.data-i.com, https://www.mybank. com:8080/accounts, mailto:[email protected] или ftp://www.myserver.com/aFile.txt. Первой частью URL является спецификация протокола, например http, https (secure HTTP — защищенный HTTP), mailto (протокол электронной почты) или ftp (file transfer protocol — протокол передачи файлов). Имя машины сервера может быть обозначено: • Числовым Интернет-адресом (IP-адресом), например 144.23.245.123, представляющим четыре байта 32-разрядного адреса машины. Адрес 127.0.0.1 представляет локальную машину, где функционирует браузер. Либо: • Символическим именем, например www.data-i.com. Специальное символическое имя localhost указывает обычно на локальную машину, где функционирует браузер. При желании после имени сервера можно указать номер порта, например 8080. Остальная часть строки URL идентифицирует ресурс на web-сервере на основе иерархической структуры каталогов, отделяя их символом / . Такое иерархическое имя интерпретируется web-браузером. Алгоритм доставки и место назначения запроса зависят от протокола, имени машины сервера и номера порта, указанных в URL. Например, URL следующего запроса идентифицирует страницу с именем examples/j sp/chapte г2/ WelcomeUser. jsp, которая должна быть доставлена через HTTP с локальной машины и из порта номер 8080: •
Браузер направляет HTTP-запрос (как правило, метод GET) по частной интранет или Интернет на web-сервер, который, как предполагается, функционирует на хосте и в порту, указанных в URL. web-cepBep интерпретирует входящий запрос и посылает обратно страницу в соответствии с URL запроса. HTTP-ответ обрабатывается и отображается браузером. Помимо текста, на возвращаемой странице часто содержатся указатели URL на другие ресурсы, например фото, схемы или рисунки. Браузер выявляет такие указатели на web-странице, а затем запрашивает их содержимое так же, как и в главном запросе. Кроме того, с web-cepeepa на машину клиента, где работает браузер, можно загрузить и более объемные аудио- и видеоданные с помощью соответствующих дополнительных программных конструкций. Кроме отображения текстовых и графических данных, большинство web-браузеров способны выполнять прикладные программы. Например, web-браузер Netscape Communicator имеет встроенную виртуальную машину Java (Java Virtual Machine) и запускает небольшие программы Java, апплеты (applets), загружаемые с web-сервера. В отличие от апплетов, которыми занимается клиентский браузер, сервлеты (см. ниже) — это программы Java, выполняемые виртуальной машиной Java на web-cepeepe. Кроме того, в браузерах, как правило, организуется "объектная модель документов", представляющая отображаемые страницы. Она позволяет работать с документом локально, при помощи клиентских языков создания сценария, подобных JavaScript или VBScript. Сегодня ведущими web-браузерами являются Netscape Communicator и Microsoft Internet Explorer. Они служат воротами в World Wide Web и в большинство интранет. Различные в деталях, все они используют стандартный протокол HTTP и язык разметки HTML. Если браузер соответствует общепринятым стандартам, взаимодействие с web-сервером не зависит от того, какой браузер применяется. Чаще всего при вызове сервлетов и страниц JSP как из Netscape Communicator, гак и из Internet генерируется одна и та же web-страница.
Знакомство с web-приложениями
О
27
Протокол НИР В основе web-общения лежит HTTP — Hypertext Transfer Protocol (протокол передачи гипертекста). Это главный протокол Интернета, вытесняющий более старые протоколы, такие как ftp и gopher. Простой и универсальный, он строится на связи запрос/ответ: запросом клиента HTTP генерируется ответ сервера, передаваемый обратно клиенту HTTP. Пара сообщений запрос/ответ иногда называется транзакцией (transaction) HTTP. Сообщения передаются посредством T C P / I P (Transmission Control Protocol/Internet Protocol — протокол управления передачей данных/протокол Интернета) — базового механизма пересылки информации для Интернета и большинства интранет-сетей. Сообщение HTTP состоит из заголовков и необязательного тела. Заголовки сообщения HTTP содержат различную информацию о данных, передаваемых в теле. Например, в заголовке Content-type указывается MIME-тип данных (скажем, HTML или XML), а в заголовке Content-length — число байтов в теле сообщения. Заголовки меняются в зависимости от того, является ли сообщение HTTP-запросом или HTTP-ответом.
HTTP-запрос Обычно HTTP-запрос передается набором URL запроса в окне браузера или щелчком мышью на гиперссылке на web-странице, отображаемой в тот момент браузером. Запрос можно сгенерировать и программным путем. В запросе указывается определенный метод, который подлежит выполнению web-сервером, например GET, POST, HEAD, PUT или DELETE. Они описываются в HTTP-спецификации. Наиболее часто используются два метода: GET и POST. С помощью первого, как правило, считываются страницы на web-cepBepe. В нем можно задавать параметры запроса в виде пар имя_параметра=значение_параметра в строке символов запроса (query string), добавляемой к URL запроса. Например, введя следующий URL, вы создадите HTTP-запрос GET с параметром запроса с именем user и значением Тага: •
Метод POST, напротив, посылает параметры в теле HTTP-запроса, и в URL запроса они не фигурируют. Он более удобен, чем GET, при загрузке больших объемов данных, например содержимого файла, или передаче конфиденциальной информации — номера или пароля банковского счета и т.п. POST обычно используется тогда, когда запрос модифицирует данные на сервере. Метод HEAD применяется реже, чем GET или POST. Он не имеет тела сообщения и предпочтителен, как правило, при передаче информации о состоянии, например даты изменения страницы (актуально для кэширования).
HTTP-ответ HTTP-ответ генерируется web-сервером в результате обработки HTTP-запроса. Он состоит из необязательных HTTP-заголовков и тела. Заголовки используются web-браузером для отображения содержимого тела. Так, если в заголовке Content-type указан text/html (наиболее часто применяемый MIME-тип для web-страниц), web-браузер обрабатывает HTML-теги (метки) в теле сообщения, форматируя содержимое страницы. В ответе могут присутствовать данные и других типов, например простой текст или двоичный код. Алгоритм отображения, который используется web-браузером, определяется данными, получаемыми в заголовке Content-type. В заголовке HTTP-ответа всегда содержится код состояния HTTP. Для разных результатов обработки запроса в HTTP описаны стандартные коды состояния. Например, код состояния 200 свидетельствует об успешном обслуживании запроса, а 500 — о внутренней ошибке сервера. Другим часто встречающимся кодом состояния HTTP является код 404, сообщающий о том, что web-сервер не может найти запрашиваемую страницу.
ГЛАВА 1
Язык р а з м е т к и HTML Протокол HTML работает в тесной взаимосвязи с языком разметки HTML. Отображение содержимого, подлежащего отображению на web-странице, в HTML основано на применении специальных тегов разметки со спецификациями HTML. Существуют теги разного предназначения, например для указания способа форматирования текста, для обработки данных, вводимых пользователем, для перехода от одной страницы к другой и др. Используются они, как правило, попарно — каждому начальному соответствует конечный, а текст, заключенный между ними, зависит от их действия. Например, тот, что находится между тегами <В> и В>, отображается жирным шрифтом. Для тегов характерно вложение в иерархической структуре. В качестве завершенного примера рассмотрим HTML-страницу, представленную в листинге 2.1. Листинг 2.1. HTML-страница
•
<TITLE> The Welcome Page
Welcome to Oracle 8i Java Components!
Hope you will enjoy reading the book!
В этом HTML-фрагменте теги и <TITLE> показывают, что в окне браузера нужно вывести название The Welcome Page. Затем тег отмечает начало р е а л ь н о г о с о д е р ж и м о г о страницы. Его атрибут BGCOLOR означает, что фоновым цветом страницы должен быть белый. Блок текста в границах тегов <Н1> и Н1> отображается как заглавие п е р в о г о уровня, причем "i" в строке символов Огас1е8г будет выделен курсивом, для чего служат теги <1> и 1>. Тег <Р> указывает на начало нового абзаца, а <В> — на представление текста жирным шрифтом, пока не встретится соответствующий конечный текст. Тег указывает размер шрифта. Начальные и конечные теги выделяют соответствующие разделы текста, web-страница, отображаемая браузером для файла Welcome, html, показана на рис. 2.2.
Welcome to Oracle 8i Java Components! Hope you will enjoy reading the book! i Document;
Done
•A* LU
:Л
Существуют теги, указывающие нумерованные и маркированные списки, цвета и шрифты текста, а также отображающие таблицы, рамки и формы. HTML-форма — важное средство, часто применяемое при построении интерактивных web-приложений. Это механизм получения данных от пользователя, для чего служат "входные окна" на web-странице, отображаемой браузером, куда пользователь вводит нужную информацию. Кроме того, в форме могут присутствовать кнопки, активизирующие выполнение определенных операций после ввода данных. Щелкнув мышью на одной из них, вы создадите новый HTTP-запрос к серверу. Запрос может вызывать серверную программу, например сервлет или JSP. О применении HTML-форм говорится в части IV этой книги. Помимо ввода и представления данных, в HTML поддерживается еще и перемещение со страницы на страницу. Одним из наиболее полезных тегов
Знакомство с web-приложениями
О
HTML является <А>, описывающий гиперссылку на URL для некоторых web-рссурсов. Этим простым, но удобным тегом па web-страницах реализуется мощное средство "щелчка и просмотра". Когда для атрибута href задана HTTP-ссылка (связь), <А> указывает браузеру сгенерировать HTTP-запрос, обращенный к указанному URL, когда пользователь щелкает мышыо па соответствующей ссылке. Страница, возвращаемая как HTTP-ответ, заменяет ту, что сначала отображалась в окне браузера. Это позволяет перемещаться по WWW (заниматься "web-ссрфингом") со страницы на страницу, причем они могут находиться на разных машинах, нередко в абсолютно разных частях света. Тесно взаимодействуя, HTTP и HTML произвели настоящую революцию в использовании Интернета.
Генерация динамического содержимого на web-страницах Сначала web-серверы работали с web-страпицами, содержащими лишь статичные данные, подобные HTML-файлам и изображениям. Однако вскоре этого оказалось недостаточно. Чтобы web-приложение нашло практическое применение, оно должно генерировать данные, специфичные для пользователя. Например, приложение по банковским расчетам на дому должно показывать состояние счета для конкретного номера, вводимого в HTTP-запросе. Всего лишь несколько лег назад единственным механизмом динамической обработки содержимого web-страниц был общий шлюзовый интерфейс (CGI, Common Cateway Interface). Сегодня доступны значительно усовершенствованные модели серверного программирования, но CGI по-прежнему поддерживается большинством web-серверов. С его помощью web-cepeep может выполнять серверные прикладные программы. Однако недостатком CGI является то, что для выполнения каждой запрошенной программы создается новый процесс, а это ухудшает масштабируемость. Вслед за CGI появились более эффективные, но специфичные для платформ технологии, подобные ISAPI от Microsoft или NSAPI от Netscape. В Active Server Pages от Microsoft реализован другой подход, по применение этого средства ограничено платформой Windows. В Netscape также поддерживается серверное средство сценариев — SSJS, использующее для генерации динамических web-страниц программные фрагменты JavaScript. На сегодня самыми популярными технологиями генерации динамического содержимого являю тся сервлеты Java и JavaServer Pages (JSPs). Основанные на Java, программы для сервлетов и JSP могут в полной мере использовать мощь, переносимость, безопасность, модульность и расширяемость объектно-ориентированной платформы Java. Об этих методах программирования, а также об их удобстве с точки зрения разработки серверных web-приложений говорится ниже. Архитектура JSP основана на сервлетах, и поэтому понимание принципов действия сервлетов важно при изучении JSP.
Модель сервлетов Опишем вкратце модели сервлетов. Сервлет (servlet) Java — это серверная программа, вызываемая web-сервером для обслуживания HTTP-запросов. Он работает в виртуальной машине Java (Java Virtual Machine) на web-сервере и обычно выполняет какие-то вычисления, генерируя содержимое HTTP-ответа. По сравнению с CGI и другими методами серверного программирования сервлеты лучше, потому что: • В отличие от программы CGI, при каждом вызове сервлета не создается новый процесс. Сервлеты вызываются, как правило, посредством потоков, обслуживающих отдельные HTTP-запросы. Число одновременно порождаемых потоков можно ограничить, что помогает избежать перегрузки сервера. • Это обычные программы Java, транслируемые в не зависящий от платформы байтовый код, и поэтому их можно автоматически переносить
29
ГЛАВА 1
на любую машину, где применяется Java. Работают они в области, защищенной границами виртуальной машины Java, и не могут быть причиной нарушения правил доступа к памяти и вызывать аварии сервера. • Серверы имеют полный доступ к мощным прикладным программным интерфейсам Java, таким как Enterprise Java Beans, Java Mail, JNDI и RMI. Технология сервлетов достаточно молода — спецификация Servlet 2.0 была окончательно одобрена в 1998 году. Тем не менее модель сервлетов и ее реализации быстро укрепились, в первую очередь благодаря их популярности среди web-разработчиков и энергичной поддержке со стороны производителей. Спецификация API Servlet 2.2 была опубликована в декабре 1999 г. Следующая версия API (2.3) создается во время написания данной книги так называемым Java-сообществом (JCP, Java Community Process), основанным компанией Sun Microsystems.
Написание простого сервлета Далее приведен пример простого сервлета HelloServlet, выдающего приветствие пользователю вместе с текущим временем. Этим примером иллюстрирует^ ся базовая структура сервлета и основные этапы обработки HTTP-запроса. Приведены и пояснения для разных этапов. •
/** Имя программы: ** Назначение:
HelloServlet.java Распечатка приветствия и текущего времени
public class HelloServlet extends HttpServlet { // (см. пояснение public void doGet (HttpServletRequest request, HttpServletResponse response) // (см. пояснение throws ServletException, IOException { PrintWriter out= response.getWriter(); // (см. пояснение response.setContentType("text/html"); // (см. пояснение out.println(""); // (см. пояснение 6 ) out. println("<TITLE>The Hello Servlet"); out.println(""); out.println("
Hello " + request.getParameter("user") + ", how are you?
"); // (см. пояснение 7 ) out. println("
The current time is " + new java. util.DateO); / / (см. пояснение 8) out.println("
Hope you have a nice day! "); out.println("
"); out.println(""); out.close(); // (см. пояснение 9)
}
2) 3) 4) 5)
}
Пояснения к HelloServlet. Java: 1. Первые два оператора import подключают библиотеки из спецификации сервлета, которые являются частью пакетов javax. servlet и javax. servlet. http, в первую очередь предназначенного для работы с основанными на HTTP сервлетами. Обратите внимание на префикс пакетов javax: он говорит о том, что данный пакет является частью расширенной структуры Java и не входит в состав базовых библиотек Java (префикс которых — java). Набор классов и интерфейсов пакетов javax. servlet и javax. servlet. http для спецификации Servlet 2.2 приведен в приложении А.
Знакомство с web-приложениями
о
2. Этот оператор объявляет класс HelloServlet. Как правило, сервлет расширяет абстрактный класс javax. servlet. http. HttpServlet, который описывает такие методы, как doGet(), doPost() и service(). Методы doGet(), doPost() и подобные им do. . . () класса HttpServlet предоставляют
стандартные реализации соответствующих методов HTTP-запроса. Один из них или несколько чаще всего переопределяется конкретным классом сервлетов, например HelloServlet. Метод service() выступает в роли диспетчера для соответствующих обработчиков запроса, например doGet() и doPost(). Он довольно редко переопределяется классами сервлетов. 3. Этот оператор описывает метод doGet (). У данного метода два аргумента: HTTP-объект request и HTTP-объект response типа HttpServletRequest и HttpServletResponse соответственно. Оба они описаны в пакете javax. servlet. http. При выполнении тела метода могут устанавливаться исключительные ситуации типа javax. servlet. ServletException или java.io.IQException.
4. Этот оператор извлекает объект PrintWriter — часть HTTP-объекта response. Объект PrintWriter используется для записи символьных данных, которые должны быть возвращены в качестве результата. 5. Этот оператор устанавливает MIME-тип генерируемой страницы. Типичные значения — text/html или text/xml, указывающие на HTML- или XML-содержимое. В значении можно задавать необязательную кодировку набора символов результата, например text/html; charset=koi8-r. Стандартной кодировкой набора символов является ISO-8859-1, называемая также Latin-1. 6. Этот оператор — тег , указывающий на начало генерируемой страницы. 7. Этот оператор извлекает значение параметра с именем из HTTP-объекта request, вызывая метод getParameter(), и выводит приветственное сообщение. 8. Этот оператор, создавая новый экземпляр класса java. u t i l . Date(), определяет текущее время и выводит его в ответе. 9. Этот оператор закрывает объект PrintWriter, указывая на окончание потока данных ответа. Выполнение HelloServlet. java Установите программу на своем web-cepeeре, следуя инструкциям, предлагаемым в приложении А. Процесс состоит из компиляции программного текста сервлета и размещения скомпилированного класса Java в нужном месте, доступном web-серверу, где и будет выполняться сервлет. Например, для сервера Tomcat, функционирующего на машине UNIX, сервлет можно установить в приложении examples — достаточно дать команду оболочки: •
# Сценарий UNIX для компиляции HelloServlet на сервере Tomcat javac -d ${TOMCAT_HOME}/webapps/examples/WEB-INF/classes \ -g -classpath ${TOMCAT_HOME}/lib/servlet.jar \ HelloServlet.java
Здесь предполагается, что переменная среды Т0МСАТ_Н0МЕ установлена как корневой каталог системы Tomcat. На рис. 2.3 показаны выходные данные, генерируемые при вызове HelloServlet вводом соответствующего URL, например: •
http://localhost:8080/examples/se rvlet/chapte r2.HelloSe rvlet?use r=Ta ra
Обратите внимание на то, что при описании класса сервлета в URL используется полное уточненное имя chapter2. HelloServlet. Параметру user строкой запроса URL присваивается значение Тага.
32
ГЛАВА 2
О Рис. 2.3. Выходные данные HelloServlet
The Hello Seivlet - Netscape £йе.
Edit
View
Back
£o
Communicator
Help
&
3
Й
4L
Mil.
г o'.'2:ii
Reload
Home
Search
Netscape
* Bookmarks
•та Print
Secuiily
Goto:|http7/localhosl !3080/e:
(TP"V/hat's Related
Hello Тага, how are you? The current time is Mon Aug 07 03:26:12 PDT 2000 Hope you have a nice day!
ЙР
|
j Document: Done
&,..Ш
:
Ш
Модель выполнения сервлета Теперь, после написания сервлета, нас интересует, каким образом он выполняется? Напомним, что сервлет — это обычный класс Java, т.е. его можно скомпилировать в виде байтового кода при помощи стандартного компилятора Java. Этап компиляции выполняется, как правило, вручную: другими словами, разработчик сервлета компилирует класс за отдельный шаг. Для страниц JSP (это будет показано ниже) этап компиляции автоматизирован. Сгенерированный класс нужно сделать доступным для вир туальной машины Java. Однако прежде чем сервлет заработает, необходимо выполнить ряд дополнительных операций. Например, нужно создать экземпляр класса сервлета. Возникает ряд важных вопросов. Будет ли обслуживать все HTTP-запросы один экземпляр класса сервлета или потребуется несколько экземпляров? Когда уничтожается экземпляр сервлета? Попробуем ответить на них. Двигатель сервлетов Двигатель (engine) сервлетов, называемый также контейнером (container) или исполнителем (runner) сервлетов,— это программа, выполняющая установленные сервлеты. Двигатель сервлетов отвечает за: • Создание и инициализацию экземпляров сервлетов • Вызов сервлетов, основанных на HTTP-запросах, и формирование HTTP-ответов из генерируемых выходных данных • Уничтожение экземпляров сервлетов и результатов их работы Процесс загрузки, создания, выполнения и, наконец, уничтожения экземпляра сервлета называется его жизненным циклом (life cycle). Различные стадии жизненного цикла сервлета представлены на рис. 2.4. Рис. 2.4. Жизненный цикл сервлета
Ф а з а загрузки
Вызов метода init()
Сервлет инициализирован
J
г Ф а з а обслуживания
Вызов метода service()
1г Ф а з а выгрузки
Вызов метода destroy()
Сервлетвыгружен 1
Обработка запросов
Знакомство с web-приложениями
О
Как правило, двигатель сервлетов создает один экземпляр класса сервлета, хотя порой используется пул экземпляров сервлетов. Точный момент создания экземпляра определяется конфигурацией web-cepeepa. Например, это возможно при запуске web-сервера или первом вызове сервлета через HTTP-запрос. Независимо от времени создания, двигателем сервлетов всегда вызывается метод init(), и только потом сервлет начинает обрабатывать запрос. Метод iпit () выполняет все логические процедуры инициализации, необходимые для обслуживания сервлетом клиентских запросов. Так, сервлет может установить в своем методе init() соединение с базой данных и пользоваться этим соединением для выполнения последующих SQL-запросов. Аналогичным образом метод destroyO сервлета всегда вызывается перед удалением экземпляра и служит для выполнения всех необходимых операций очистки, например завершения ранее установленного соединения с БД. После создания и инициализации экземпляр сервлета готов к обслуживанию запросов. При поступлении запроса для данного сервлета двигатель обычно порождает новый поток для обработки запроса. Поток вызывает метод service() класса сервлета. Чаще всего сервлеты расширяют класс javax. servlet. http. HttpServlet и реализация метода serviceO наследуется из этого суперкласса. Сигнатура метода serviceO такова:
Этот метод выступает в роли "диспетчера" — он определяет тип HTTP-запроса (например, GET или POST) и просто вызывает подходящий метод (doGet () или d o P o s t O ) для сервлета. Сигнатуры этих методов те же, что и у метода serviceO (см. пример метода doGet() для HelloServlet выше). Теперь посмотрим, что произойдет, если одновременно поступит несколько HTTP-запросов или если новый запрос придет во время обработки предыдущего. В этом случае двигатель сервлетов обычно использует другой поток выполнения, вызывая метод s e r v i c e O того же экземпляра сервлета, даже во время обработки первого запроса (рис. 2.5). В этой схеме подразумевается, что код обработки запросов в сервлете способен Рис. 2.5. Многопоточный доступ к одному экземпляру сервлета
HTTP-запрос 1 HTTP-запрос 2 НИР-запрос 3
Г Поток 11 I
1 1 1 Экземпляр сервлета
j
г 11
Поток 2
1 1 1 метод seijvice()
1 11
I I I Поток 3 I
1 1 1 |
- 1 11
HTTP-ответ 1 • HTTP-ответ 2 • НИР-ответ 3 •
Web-cepeep
33
34
О
ГЛАВА 2
обслуживать одновременное обращение со стороны нескольких потоков (исключением из этого правила является ситуация, когда классом сервлета реализуется интерфейс SingleThreadModel; см. следующий абзац). Следовательно, при написании сервлета нужно обязательно следить за тем, чтобы программный текст (код) был безопасен с точки зрения потоков. В Java для надлежащей защиты программ от конфликтов при многопоточном выполнении следует использовать оператор synchronized. В частности, нужно синхронизировать доступ к переменным экземпляров класса сервлета, например к переменной, представляющей соединение с базой данных. Нередко необходимо группировать некоторые операции, выполняемые над базой, делая их частью атомарной транзакции, соответствующей одиночному HTTP-запросу. Таким образом, доступ к соединению с базой данных нужно координировать среди нескольких потоков, обслуживающих разные HTTP-запросы. Запрет многопоточного доступа в некоторых случаях снижает производительность системы и эффективность обработки запросов. Так, при обслуживании отдельных транзакций для каждого запроса к базе данных весь код в методе doGet() или doPost(), возможно, придется синхронизировать, что приводит к последовательной обработке одновременно поступающих запросов. В подобных ситуациях для сервлета приемлем другой режим выполнения программ, называемый однопоточной (single-thread) моделью. В такой схеме (рис. 2.6) два запроса никогда одновременно не передаются одному и тому же экземпляру сервлета, и проблем с синхронизацией не возникает. Вместо этого двигатель создает для данного сервлета пул экземпляров и, обслуживая новый запрос, использует свободный экземпляр из этого пула. Подобная схема для сервлета допустима при реализации иктерфейса javax. servlet. SingleTh readModel — пустого интерфейса без методов, выступающего в роли простого указателя на альтернативный алгоритм выполнения программ. Сервлет, где реализован такой интерфейс, можно, без сомнения, считать безопасным с точки зрения потоков. Рис. 2.6. Выполнение сервлета в однопоточной модели
Знакомство с web-приложениями
с
Использование сеансов сервлетов По своей природе HTTP — универсальный протокол, не сохраняющий состояние. Другими словами, HTTP-запрос никак не связан с любым другим, даже если оба поступают от одного и того же клиента. Однако при взаимодействии web-приложений состояние часто должно сохраняться. Например, в web-приложении для банковских расчетов на дому нередко предусматривается регистрационная страница, где пользователь вводит номер и пароль своего счета, а эта информация необходима для следующего HTTP-запроса, когда пользователь запрашивает состояние счета. Другим известным примером взаимодействия с сохранением состояния являются сетевые магазины, когда пользователь собирает товары в вир туальную "корзину", заключающую в себе несколько запросов (см. главу 11). Все это требует ввода понятия сеанса (session), в котором, по существу, группируются серии запросов от одного клиента. Посмотрим, как организуется рабо та с сеансами. Каждый сеанс идентифицируется на сервере уникальным ключом. Ключ сеанса может содержаться в сообщении HTTP-ответа, сохраняться клиентом и вводиться в последующие запросы, обращенные к данному серверу, указывая текущий сеанс. Распространены три способа контроля над сеансами в сервлетах: • Через домашние данные • Путем перезаписи URL • Посредством встроенного в сервлеты API для контроля над сеансами Мы кратко опишем их ниже. Сеансы можно реализовывать и менее известными способами, которые выходят за рамки нашей книги. Заметим, что сеанс может быть завершен явно сервлетом или неявно по истечении времени сервером. По истечении срока действия сеанса его ключ становится недостоверным, даже если HTTP-запрос с данным ключом получен позже. Домашние данные (cookie) Это просто идентификационные данные сеанса, посылаемые клиенту в HTTP-заголовке Set-Cookie как часть сообщения HTTP-ответа. Сервлет может направить домашние данные явно, вызвав метод addCookie() объекта HttpServletResponse. Клиент вправе сохранить их и посылать во всех последующих запросах назад серверу для идентификации сеанса. Однако порой web-браузер не имеет поддержки домашних данных, либо пользователь явно запрещает их в браузере. В таких случаях применяе тся метод перезаписи (переадресации) URL. Перезапись URL При использовании этого метода все указатели URL, включаемые в ответ сервера, видоизменяются гак, чтобы нести информацию о ключе сеанса. Например, идентификатор пользователя добавляется к URL в виде строки запроса: •
Когда впоследствии пользователь щелкает мышью на гиперссылке HTTP на web-странице, отображаемой браузером, для ссылки применяется этот расширенный URL. Сервлет на другой стороне извлекает идентификатор сеанса из строки запроса URL. Этот метод неудобен тем, что в ответе приходится модифицировать все указатели URL, вводя ключ сеанса, а это дополнительная нагрузка на сервлет. Еще хуже то, что теряется конфиденциальность, поскольку идентификатор сеанса явно или неявно присутствует на генерируемой странице. Сеансовый API сервлетов В прикладном программном интерфейсе (API) сервлетов Java предусмотрена встроенная поддержка сеансов. С этим API должен работать любой web-браузер, поддерживающий сервлеты. С помощью данного API программист, создающий сервлеты, изолируется от всех деталей процесса слежения за сервлетами, реализуемого web-сервером; отправка домашних данных или перезапись URL могут происходить в фоновом режиме.
35
ГЛАВА 1
Посмотрим, как программист использует сеансовый API. Хранить и считывать данные, относящиеся к сеансу работы, призван объект HTTPSession — экземпляр типа javax. servlet. http. HttpSession, который можно извлечь из HTTP-объекта request, вызвав его метод getSession(boolean create). Если аргумент boolean метода getSession() истинен (t rue), для данного запроса запускается новый сеанс (при условии, конечно, что он уже не открыт). Если же вызвать getSession(false), возвращается значение null (при условии, что сеанс не существует). Сервлет, создающий сеанс, называется сервлетом с сохранением состояния (stateful). Сервлеты, не сохраняющие состояния (stateless), сеансами не пользуются. После извлечения объекта сеанса вызовом getSession() сервлет использует его для записи данных сеанса, например о соединении с БД или о корзине магазина. Затем к ним смогут обращаться все сервлеты, вызываемые в одном HTTP-сеансе. Данные хранятся и считываются в объекте session с помощью методов setAttribute() и getAttribute(). Например, в следующем программном фрагменте сервлета сначала получается объект session, инициализируется объект соединения с базой данных conn, а затем с объектом conn связывается атрибут сеанса с именем dbConnection: •
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Сначала получим объект session javax.servlet.http.HttpSession session request.getSession(true); // Инициализируем соединение с БД java.sql.Connection conn = ; // Сохраним сведения о соединении с БД в объекте session session.setAttribute("dbConnection", conn); }
те •
Впоследствии описатель соединения с базой данных можно считать в объекс помощью ключа dbConnection метода getAttribute():
Обратите внимание: считанный объект необходимо приводить к соответствующему типу. Существует также метод removeAttribute(St ring name) типа HttpSession, применяемый для удаления хранимого значения.
Контекст сервлетов В некоторых случаях web-приложению приходится сохранять не состояние сеансов, а состояние, связанное со всем приложением. Например, пул открытых соединений с БД порой нужно делать доступным всем сеансам web-приложения. Так из чего же именно состоит web-приложение? Это совокупность программ и ресурсов, выполняющих определенную задачу, например сообщение о расходах, web-приложение может состоять из статичных HTTP-страниц, логотипов и изображений, сервлетов и страниц JSP и таких программных компонентов, как JavaBeans и Enterprise JavaBeans, вспомогательных служебных классов и прочих ресурсов. Как правило, у каждого web-приложения на web-cepeepe свой маршрут. Так, создающее отчеты о расходах может находиться на сайте http://www.data-i.com/webexpense. Все указатели URL с этим префиксом ссылаются на программы и ресурсы в границах данного приложения. Такой маршрут называется корнем приложения (application root) и обычно уникален для того или иного web-приложения. В реализациях Servlet 2.2 каждому из них соответствует собственный экземпляр ServletContext. Объект ServletContext имеет тип javax. servlet. ServletContext. Описатель этого объекта могут считывать все сервлеты и страницы JSP приложения вызовом метода getServletContext(). В объекте ServletContext существует множество полезных методов для различных целей, в том числе призванных:
Знакомство с web-приложениями
О
• Получать сведения о web-сервере. Например, методы getServerInfo() и getMajorVersion() возвращают сведения о двигателе сервлетов и поддерживаемой версии. • Получать сведения о web-приложении. Например, getInitParameter() и getInitParameterNames() возвращают сведения о параметрах инициализации, связанных с объектом ServletContext. Метод getRealPath() возвращает сведения о реальном маршруте для данного виртуального маршрута, н а п р и м е р /welcome, html.
• Записывать сообщения в файл журнала методом 1од(). • Распределять данные по всему приложению. Данные с общим состоянием можно записывать в объект ServletContext, считывать в нем и удалять из него с помощью методов setAttribute(), getAttribute() и removeAttribute(). Они аналогичны соответствующим методам объекта HttpSession, о котором говорилось выше. • Получать объект RequestDispatcher для вызова других сервлетов и страниц JSP в web-приложении (см. главу 10). Полный набор методов объекта ServletContext приведен в приложении А. В следующем программном фрагменте показан пример вывода сведений о сервере, сохранения переменной с именем connPool в атрибуте контекста с именем dbConnectionPool и занесения информации в журнал: •
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext scontext = getServletContext(); PrintWriter out = response.getWriter(); out.println("Here is my server information:" + scontext.getServer!nfo());
scontext.setAttribute("dbConnectionPool", connPool); scontext.log("Database connection pool created."); }
Реализации сервлетов web-сервером Apache активно используется двигатель сервлетов Apache JServ. web-cepeep Apache и двигатель сервлетов JServ применяются в прикладном Интернет-сервере Oracle (iAS, Oracle Internet Application Server) версии 1.0. Однако JServ, где реализован лишь интерфейс Servlet 2.0, вытесняется такими двигателями, как Tomcat, который поддерживает API Servlet 2.2. Тем не менее иметь представление о JServ весьма полезно, поскольку он активно используется во многих средах. Apache JServ состоит из двух отдельных компонентов, один из них написан на языке С, а другой — на Java. С-компонент называется mod_jserv и соединяет web-сервер Apache с Java-компонентом, который и есть настоящий двигатель сервлетов. Стандартом для API Servlet 2.1 является web-cepeep Java (Java Web Server) компании Sun Microsystems, который появился в составе инструментария разработки JavaServer Web Development Kit (JSWDK). Эта реализация вытесняется проектом Tomcat — совместной разработкой Apache Software Foundation и Sun Microsystems. Tomcat — это стандартная система для спецификации Servlet 2.2. Существуют и другие двигатели сервлетов от других производителей, например JRun от Allaire. В Огас1е8г редакции 8.1.7 двигатель сервлетов Oracle Servlet Engine функционирует в границах БД. В нем реализован API Servlet 2.2 и работает виртуальная машина Java, встроенная в Огас1е8 г. Достоинство функционирования программ сервлетов и JSP внутри БД — их выполнение в непосредственной близости от SQL-данных (с использованием серверного Огас1е-драйвера JDBC) в защищенной среде базы.
37
ГЛАВА 1
Знакомство с JavaServer Pages Технология JavaServer Pages (JSP) встроена в описанную выше модель сервлетов и основана на смешивании программных конструкций Java со с татичными шаблонами HTML или XML. Логические схемы Java призваны генерировать динамическое содержимое страницы, а язык разметки — структурировать и представлять данные. Главная цель проекта JSP — строго отделить текст HTML или XML от программ Java специально для web-дизайнеров, которые незнакомы с программированием на Java. С такой целью в спецификации JSP предусмотрены встроенные средства компонентного программирования при помощи JavaBeans и библиотек тегов. Краткий обзор средств дан в следующем разделе, а более подробный рассказ см. в части IV. Технология JSP достаточно нова, но уже получила широкое распространение в среде прикладных web-дизайнеров, в промышленности и быстро развивается. Последняя версия спецификации JSP 1.1 появилась в ноябре 1999 г., а следующая (1.2) разрабатывается во время написания этой книги. В настоящее время JSP поддерживается web-продуктами нескольких производителей, в том числе Oracle. В основе web-сервера Oracle Internei Application Server (iAS), увидевшего свет в июне 2000 г., лежат web-сервер Apache и двигатель сервлетов Jserv. В состав iAS входит собственная реализации JSP компании Oracle. С Oracletfi версии 8.1.7 интегрирован двигатель Servlet 2.2 и JSP 1.1, выполняющий программы JSP и сервлетов непосредственно в БД (с использованием внутренней виртуальной машины Java). Стандартные реализации для спецификаций JSP 1.1 и Servlet 2.2 предоставляются сервером Tomcat, который разрабатывается Apache Software Foundation (www.apache.org) в тесном сотрудничестве с Sun Microsystems и другими промышленными партнерами. Ранее стандартная реализация JSP 1.0 была выпущена в Sun Microsystems как часть Java Web Server (JWS) и JavaServer Web Development Kit (JSWDK). Инструкции по установке JSP-двигателя Oracle с двигателями сервлетов JServ, JWS и Tomcat приведены в приложении Е.
Базовая программа JSP Пример простого сервлета HelloServlet был приведен в предыдущем разделе. В нем считывалось имя пользователя, передаваемое в качестве параметра HTTP-запроса, и выводились приветствие и текущая дата. Изменение сервлета на JSP поможет понять, в чем разница между двумя моделями программирования. Соответствующая JSP-программа выглядит так: •
<Н2><1>...Информация баннера... 1>Н2>
Файл Imports, jsp предназначен для хранения общих операторов импорта, например: •
На рис. 10.3 показан результат, получаемый в браузере после исполнения Staticlnclude. jsp. Обратите внимание на то, что информация баннера размещается внизу страницы.
Вызов других страниц с JSP JSP-программа может вызывать другие страницы. Для этого применяются два функциональных тэга: • Тэг <jsp: include>, который вызывает другую страницу, а затем возвращает управление вызывающей JSP. • Тэг <jsp: forward>, который передает управление другой странице и закрывает вызывающую JSP.
297
298
ГЛАВА 10
——О Рис. 10.3. Выходные данные после исполнения Staticlnclude.jsp
S t a l i o l n c l u d e JSP - N e t s c a p e £ile Ц
Edit
View
go
^'Bookmarks
^
Communicator Jk-
Н И И
(Help
Go to: | http: //localhost:8080/examples/jsp/chapter1O/Staticlnclude.jsp
"
"
T ] . ^ j l T What's Related
Hello! The current time is: Wed Jun 21 22:15:33 PDT2000
... Here goes the banner infonnation...
IfifR^-r
~
j Document: Done"
~
'
Ш
\
Эти тэги используются, как правило, для перехода от одной страницы к другой на основе динамических условий. В следующих примерах показано применение тэгов в приложении JSP.
Тэг <jsp:include> Тэг <jsp: include> используется для посылки HTTP-запроса с основной JSP на другую страницу. Подключаемой страницей может быть статический текст или HTML-файл, а также динамическая программа, например другая JSP или сервлет. Подключаемая страница обрабатывает запрос и обычно генерирует некие данные, которые вводятся в выходной поток как часть конечной страницы. Вызывающая страница возобновляет свое исполнение после завершения действия тэга include. Синтаксис тэга include: •
<jsp:include page ="includeURL." flush="true" />
Заметим, что синтаксис тэга include совместим с XML. У этого тэга два атрибута: page и flush. Атрибут page указывает относительный URL вызываемой страницы, который может задаваться в виде постоянной строки символов или вычисляться на этапе исполнения при помощи встроенного JSP-выражекия. Значением логического атрибута flush всегда должно быть true. Это значит, что буфер выходного потока основной JSP должен сбрасываться до передачи управления подключаемой странице. Сбрасывать буфер нужно обязательно, чтобы подключаемая страница могла вводить свои собственные выходные данные в нужную позицию HTTP-ответа. Приведем пример программы Dynamiclnclude. jsp, которая подключает выходные данные HTML-страницы IncludedHello. htm и JSP-программы Time, jsp, вызывая их при помощи тэга include: •
<%-- Имя программы: Dynamiclnclude. jsp -- Назначение: Вызвать другие страницы на этапе выполнения -%> <TITLE> The Dynamic Include JSP <% String includedHtml = "include/IncludedHello.htm"; %>
Обратите внимание: URL подключаемой HTML-страницы устанавливается динамически при помощи JSP-выражения, причем за основу берется значение, присваиваемое переменной includedHtml BjSP-скриптлете. В данном примере присваиваемое зцачение — это постоянная строка символов "include/IncludedHello. htm", но вообще его можно вычислять по динамическому условию. Возможность динамического определения URL подключаемой страницы является основным отличием тэга <jsp: include> от директивы include этапа трансляции (см. выше).
Л
Введение в программирование с использованием страниц JSP
299
О-
Файл IncludedHello. htm должен находиться в подкаталоге include относительно местоположения Dynamiclnclude. jsp. Создадим простой файл IncludedHello.htm:
•
< ! - - Имя программы: IncludedHello. htm - - Назначение: Распечатать статический текст --! > <Н2> Hello! How are you? <Р><В> I am Lhe IncludedHello HTML page.
The current time i s :
Судя no URL страницы, используемому в тэге include, файл Time, jsp должен находиться в том же каталоге, что и файл основной JSP. На странице Time, jsp содержится следующий программный текст: •
<%-- Имя программы: Time.jsp --%> <%= new j a v a . u t i l . D a t e ( ) %>
Если теперь указать в браузере URL для Dynamiclnclude. jsp, к выходной странице подключится содержимое файла IncludedHello.htm, за которым будет следовать текущее время, вычисляемое программой Time. jsp. Отметим, что подключаемая JSP будет автоматически преобразовываться перед вызовом, если, конечно, она не была преобразована заранее. Типичный результат вызова Dynamiclnclude. jsp, отображаемый браузером, показан на рис. 10.4. Рис. 10.4.
Hello! H o w are y o u ? 1 am the IncludedHello HTML page. The current time is: Wed Jun 21 23:03:47 PDT 2000 У М Н
|Document: Done
a, a.
I | -jj
В примере не показано, но стоит сказать, что в JSP-приложении разрешается применять несколько уровней функции include. Это может стать для читателя поводом попробовать свои силы в программировании. В некоторых приложениях необходимо вводить дополнительную информацию в HTTP-запрос перед его отправкой на обработку подключаемой странице. Для этого в спецификации JSP 1.1 предусмотрен специальный тэг <jsp:param> (в JSP 1.0 этот тэг недоступен). Его используют для указания дополнительных параметров запроса в виде пар имя=значение, которые добавляются к исходному HTTP-объекту request вызывающей JSP. Синтаксис тэга <jsp: param>:
В качестве упражнения читатель может написать JSP с использованием дополнительных параметров запроса для вызова подключаемой страницы.
Тэг <jsp: forward> Синтаксис функционального тэга для передачи запроса:
300
ГЛАВА 10
О •
<jsp:forward раде="передаваемый_11Я1." />
Результатом работы этой функции являются отправка HTTP-запроса по URL указанной страницы и прекращение исполнения текущей страницы. Страница, которой переходит управление, может быть статическим HTMLили текстовым файлом, а также программой JSP или сервлетом. Если вызывающая JSP уже записала какие-то данные в выходной буфер, то перед передачей запроса буфер очищается. Для добавления параметров к HTTP-запросу перед его передачей применяются вложенные тэги <jsp: param>, для чего используется синтаксис, схожий с тем, что был приведен выше для тэга <jsp: included Рассмотрим страницу Forward, jsp, иллюстрирующую концепцию передачи запроса: •
<% } f i n a l l y { i f (dctx != n u l l ) dctx.closeO; } } %> Enter an Employee Number: < ! - - (см. пояснение 8) -->
П о я с н е н и я к программе SQLJQuery. jsp: 1. Эта директива page объявляет об использовании SQLJ на JSP. В следующих двух строках также применяется директива page — для импорта необходимых классов SQLJ. 2. Этот скриптлет извлекает значение параметра с именем empno из объекта request. Если значение этого параметра не равно null, JSP исполняет SQL-запрос. 3. Этот оператор является частью главного JSP-скриптлета и описывает явный объект DefaultContext, представляющий SQLJ-соединение с базой данных. В SQLJ поддерживается понятие стандартного соединения (соединения по умолчанию) для исполнения SQL-конструкций, но его не следует применять в программировании с использованием JSP или сервлетов. Дело в том, что в исполняющей системе SQLJ соединение по умолчанию представляется в виде статической переменной, и одновременно выполняющиеся сервлеты и JSP-страницы, работающие в одной и той же виртуальной машине Java, будут перезаписывать эту статическую переменную, так как она одна. Выйти из этой ситуации можно, воспользовавшись для исполнения SQL-операторов явным объектом DefaultContext, как показано в данной программе.
Введение в программирование с использованием страниц JSP
О-
4. Этот оператор Java инициализирует SQLJ-объект как соединение с базой данных. Обратите внимание на то, что для соединения с учетной записью jspuser/jsp используется драйвер JDBC-OCI. 5. Это статический SQL-запрос, написанный на SQLJ. В нем в качестве контекста соединения для исполнения запроса используется dclx. Параметр запроса empno в конструкции WHERE применяется для считывания информации о соответствующем служащем в таблицах EMPLOYEE LIST и DEPARTMENT_LIST. Выбираемые данные помещаются в три переменные Java: job, deptName и empName, которые были объявлены ранее в этом скриптлете. 6. Этот HTML-оператор выводит значение переменной empName, присвоенное ей в предыдущем SQL-запросе. В следующих двух строках HTTPтекста отображаются соответственно рабочие обязанности и название отдела.
7. Этот оператор Java используе тся для перехвата всех исключительных ситуаций SQL, которые могут устанавливаться в программном тексте SQLJ. Блок catch распечатывает информацию об исключительной ситуации. За ним следует блок f i n a l l y , закрывающий ранее открытый контекст соединения. 8. Этот оператор указывает на начало сегмента HTML-формы. Он применяется для получения номера служащего от пользователя по мере ввода данных на экране. Впоследствии этот параметр используется в SQL-запросе. Обратите внимание: в качестве номера служащего по умолчанию в форме указан номер 111. На рис. 10.10 показан результат, выдаваемый браузером после вызова SQLJQuery. jsp без параметров. Если ввести помер служащего в текстовом окне и щелкнуть мьпвыо па кнопке Ask Oracle на экране, программа SQLJQuery. jsp будет вызвана с параметром запроса empno, установленным в значение 111. Это вызовет передачу SQL-запроса в базу данных, и браузер отобразит выходную страницу, представленную на рис. 10.11.
Использование транслятора командной строки ojspc В двигателях JSP поддерживается автоматическое преобразование установлен^ ных JSP-страниц при их вызове. Это очень удобно при разработке приложений JSP. Однако в процессе внедрения приложений JSP нежелательно, чтобы JSP преобразовывалась при ее первом вызове конечным пользователем. Преобразование JSP отнимает значительное время и может замедлить реакцию приложения в сравнении с ранее скомпилированными страницами. Следовательно, после разработки приложения было бы полезно заранее транслировать JSP-страницы, чтобы избежать их преобразования на этапе исполнения. Именно для этого в JSP-реализации Oracle существует инструментальное средство трансляции ojspc, выполняемое из командной строки. Познакомимся с синтаксисом и параметрами этого инструмента. Выходные данные после исполнения SQLJQuery.jsp без параметров
ш
ГГТпТх!
The SQLJQueiy J S P - N e t s c a p e
Eile
j|
£dit
View
£o
t a t ^Bookmarks
Communicator -A
Help
Go to:|http7/,localhost:3080/'eKamples/'isp/chapter10/SQLJQijeiy|sp
Щ р Г What's Related
Hello, I can do a S Q L J query to get employee data...
Enter an Employee Number:
|Пг 'RH
A s k Oracle
[Document: Done
m
S)
311
312
ГЛАВА 10
О Рис. 10.11. Результат запроса данных о служащем 111 при помощи SQLJQuery. j s p
ItA / Hello, I can do a SQLJ query to get employee data...
I
Employee #111 Details: Name Job Department
Mistik., Sheila Registered Nurse Oncology
Enter an Employee Number:
ill ЯМ
Ask Oracle
[Document: Done
"iL-sfe
л
Команда ojspc — обычный сценарий оболочки UNIX (и командный файл в Windows), который вызывает Java-ioiacc oracle, jsp. tools. Jspc. Этот класс является частью JSP-библиотек Oracle. Для применения данного инструмента нужно, чтобы в переменной среды CLASSPATH были указаны эти библиотеки, а также библиотеки сервлетов. Кроме того, при преобразовании с помощью ojspc файлов . sql j sp нужно убедиться в том, что JDBC-классы ( c l a s s e s 1 1 1 . z i p и л и c l a s s e s 1 2 . z i p , ч т о о п р е д е л я е т с я и с п о л ь з о в а н и е м J D K 1.1
либо JDK 1.2) и SQLJ-библиотеки (translator.zip) доступны в CLASSPATH. Синтаксис вызова ojspc: •
ojspc [параметры]
список_файлов
В средах оболочек UNIX разрешается указывать трафаретные символы в списке исходных файлов. Допустимыми расширениями исходных файлов являются .jsp, .sql jsp, .sqlj и .java. Файлы .sql jsp могут содержать в своем составе SQL-операторы в обозначении #sql. Для таких файлов транслятор JSP автоматически вызывает транслятор SQLJ. Во время SQLJ- и JSP-трансляции ссылки на типы определяются при помощи всех файлов SQLJ и Java, указанных в командной строке. Помимо этого, инструмент ojspc вызывает компилятор Java (по умолчанию javac), чтобы создать непосредственно байтовый код; автоматическая компиляция генерируемого текста отключается параметром -noCompile.
Для вывода перечня параметров ojspc применяется команда: •
ojspc -help
Основными параметрами являются: • -addclasspath. Этот параметр задает дополнительные элементы CLASSPATH для Java-компиляции генерируемого текста. Если не указан, используется системная установка CLASSPATH. • -appRoot. Этот параметр определяет корневой каталог приложения для файлов, подключаемых статически при помощи относительных для приложения указателей URL JSP-директивой include. В Oracle JSP версии 1.0 этот параметр назывался -includePath, в версии 1.1 он был переименован в -appRoot. Значением по умолчанию является текущий каталог. • -d, -dir. Этот параметр определяет выходной каталог для генерируемого байтового кода. По умолчанию байтовый код помещается в текущий каталог.
Введение в программирование с использованием страниц JSP
О-
• -extres. Этот флаг указывает на то, что для статического текста в JSP-источнике нужно генерировать файл внешнего ресурса. Флаг удобен в работе, если тело метода Java имеет длину около 64 Кбайт, что является системным ограничением (напомним, что в генерируемом тексте статический текст размещается в методе _jspService()). Кроме того, это ускоряет процесс Java-компиляции, так как постоянные с троки символов помещаются в файл внешнего ресурса. • -noCompile. Этот флаг указывает на то, что компилировать генерируемый текст не нужно. Впоследствии можно самостоятельно скомпилировать сгенерированные файлы, возможно, компилятором, отличным от стандартного javac. • -packageName. Этот параметр указывает имя пакета для генерируемого класса. Обычно имя класса соответствует маршруту к странице, по которому JSP установлена на web-сервере. Таким образом, для JSP-страницы, установленной в подкаталоге examples/jsp/chapter10 каталога документов web-сервера, во время предварительной трансляции с помощью ojspc нужно было бы указать имя пакета examples, jsp. chapterlO. Именно так JSP-двигатель Oracle отображает маршруты к страницам в URL запроса на имена пакетов Java. Точной схемы такого отображения в спецификации JSP нет, и она определяется реализацией. •
-S-napaMerp_sqlj. Этот параметр применим только по отношению к JSP-страницам с программными конструкциями SQLJ и используется для указания параметров транслятора SQLJ. За префиксом -S должно следовать имя SQLJ-параметра, символ пробела, а затем значение параметра (если оно есть).
• -srcdir. Определяет каталог, где будут размещены генерируемые исходные файлы. Не путайте этот параметр с описанным выше параметром -d, который задает местонахождение генерируемого байтового кода. • -verbose. Этот флаг используется для получения подробной информации об этапах трансляции. • -ve rsion. Этот флаг отображает номер версии библиотеки Oracle JSP. Приведем несколько примеров, иллюстрирующих использование инструмента ojspc. Заметим, что для отделения параметра от его значения (если оно есть) применяются пробелы. Строковые значения для таких параметров, как имена пакетов и маршруты к каталогам, следует заключать в двойные кавычки, и помните о регистре символов. Для имен параметров регистр символов не учитывается. Для получения информации об этапах трансляции во время компиляции JSP-файла Foo. jsp введем следующее: •
ojspc -verbose Foo.jsp Для компиляции файлов Bar. jsp и Query, sql jsp введем:
•
ojspc Bar.jsp Query.sqljsp Маршруты к исходным файлам можно указывать либо относительно текущего каталога, в котором вызывается ojspc, либо как абсолютные в файловой системе. По умолчанию выходным каталогом для генерируемых классов является текущий каталог, откуда вызывается ojspc. Местоположение генерируемых исходных файлов и компилируемого байтового кода можно изменить с помощью параметров -d и -srcdir:
О
ojspc -d _pages -srcdir /home/mywebpages *.jsp Параметры транслятора SQLJ устанавливаются с помощью флага -S. Например, чтобы транслятор SQLJ считывал параметры из файла sqlj. properties, нужно ввести:
313
314
ГЛАВА 10
О •
ojspc -S-props sqlj.properties Query.sqljsp
Полный перечень параметров ojspc приведен в "Oracle JSP Developer Guide and Reference, Release 8.1.7".
Итоги В этой главе описаны элементы сценариев и другие компоненты программирования на Java. Было показано, насколько прост процесс написания и исполнения JSP-программ. Двигатель JSP автоматически преобразует, загружает и выполняет JSP-страницы, позволяя быстро разрабатывать web-приложения. Объявления, скриптлеты и выражения JSP позволяют без труда вводить программные конструкции Java в JSP-страницы и динамически генерировать разделы web-страниц. JSP-директива page используется для передачи информации, связанной со страницей, например кодировки символов, транслятору JSP. Существуют специальные атрибуты errorPage и isErrorpage директивы page, применяемые для обработки ошибок этапа выполнения JSP. JSP-директива include служит для подключения содержимого других страниц статически на этапе компиляции. Кроме того, рассматривалось применение стандартных функциональных JSP-тэгов <jsp: include> и <jsp: forward>, позволяющих вызывать с
JSP-страницы другие программы JSP и сервлеты. Было показано, как с помощью интерфейса RequestDispatcher вызывать JSP-страницы и другие web-ресурсы из сервлета. В заключение были описаны JSP-реализация Oracle и ее свойства, которые дополняют функциональные возможности, полностью соответствующие спецификации JSP. В большинстве JSP-реализаций Java — единственный язык сценариев. В JSP-реализации Oracle в JSP-скриптлетах можно использовать и конструкции SQLJ, что упрощает процесс создания программ для работы с базами данных. Для предварительной трансляции JSP-страниц перед внедрением предлагается транслятор командной строки ojspc. Теперь вы умеете создавать JSP-страницы с использованием элементов сценариев, объявлений, выражений и неявных объектов JSP, которые определяют содержимое страниц динамически, исходя из параметров запроса, вводимых посредством HTML-форм. Кроме того, вы должны понимать, каким образом в процессе трансляции и исполнения JSP генерируется выходная страница. В этой главе было показано, как создавать JSP-страницы, вызывающие другие JSP-страницы, HTML-страницы и сервлеты, а также сервлеты, вызывающие JSP-страницы. Была создана JSP, которая выполняет статический запрос, обращенный к базе данных Oracle, и освещен вопрос предварительной трансляции программных файлов JSP с помощью транслятора командной строки ojspc. Овладев основами JSP-программирования, мы можем перейти к написанию web-страниц. В следующей главе показано, как с помощью компонентов JavaBean четко отделять в JSP-программах статический текст от динамического содержимого. Рассказывается о таких тэгах, связанных с зернами, как <jsp: useBean> и <jsp: setProperty>, которые являются стандартными тэгамиJSP,
облегчающими создание зерен JavaBean и работу с ними и с их свойствами. Приемы программирования JSP, о которых говорилось в настоящей главе, можно объединять с компонентами JavaBean, создавая многоцелевые web-приложения, компактные и модульные, простые в написании и обслуживании.
ГЛАВА 11
О—
ИспользованиеJSP вместе с зернами JavaBean
316
ГЛАВА 11
О D
предыдущей главе были представлены базовый синтаксис и свойства JSP. В этой главе говорится о применении JSP-страниц в компонентном программировании совместно с зернами JavaBean. Вы узнаете об основных концепциях зерен JavaBean и о том, как грамотно использовать базу данных Oracle в работе с компонентами JavaBean. Кроме того, описывается процесс генерации XML-текста при помощи JSP-страниц и зерен JavaBean. Вы изучите, как: • Применять компонент JavaBean с помощью соответствующих встроенных JSP-тэгов • Разрабатывать сеансовое JSP-приложение, использующее "корзину" для ввода заказа • Исполнять операции обновления базы данных, которые основаны на данных, вводимых пользователем в HTML-формах • Исполнять статический SQL-запрос с помощью SQLJ для взаимодействия с базой данных • Исполнять динамические SQL-запросы с помощью JDBC и форматировать результаты запроса в виде HTML-таблицы • Генерировать XML-текст из результатов SQL-запроса • Оптимизировать производительность доступа к базе данных с помощью пулинга соединений на уровне приложения
Разработка JSP-приложений с помощью компонентов JavaBean Фундамент JSP был создан для работы с модульными и многократно используемыми программными компонентами, такими как зерна JavaBean. Применение зерен JavaBean в JSP позволяет четко отделять в HTML программные конструкции Java, генерирующие динамическое содержимое, от логики представления информации. Удобно то, что программные конструкции Java, вычисляющие динамическое содержимое, молено разместить в одном или в нескольких зернах JavaBean, которые "вставляются" в JSP для упрощения манипуляции данными. Такое разделение позволяет программисту Java создавать вычислительные логические схемы в компонентах JavaBean, а web-дизайнеру формировать вид представления информации. Впоследствии компоненты можно объединить надлежащим образом на JSP-странице. В этом разделе рассказывается о том, как создавать простые компоненты JavaBean и применять их в JSP-программах, используя компактный и эффективный синтаксис.
Знакомство с JavaBean JavaBean — это класс Java с определенной структурной схемой. Схема имеет хорошо описанную семантику, что позволяет определять структуру JavaBean через анализ внутренней организации его скомпилированного класса при помощи API отражения (reflection) Java. Главные требования, предъявляемые к JavaBean, таковы: • Оно должно быть общим (public) классом Java. • Оно должно содержать общий конструктор без аргументов. • Оно может обладать одним или несколькими свойствами (properties), или атрибутами, работа с которыми организуется посредством общих методов доступа (accessor). Свойства зерна реализуются обычно как частные (private) переменные Java или поля, а методы доступа используются для присвоения и для считывания их значений. По умолчанию методы доступа связываются с соответствующими
Использование JSP вместе с зернами JavaBean
о
свойствами на основе простого соглашения по именованию: методами доступ а д л я с в о й с т в а , о б ъ я в л е н н о г о как i n t х, я в л я ю т с я getX() и s e t X ( i n t newX). Та-
кие правила проектирования обеспечивают простоту разработки приложений, а также динамическое определение свойств зерна во внешних средах, куда оно встраивается, например в графических инструментах разработки или как компонента в JSP. Помимо свойств, в JavaBean, как и в любом другом классе Java, описываются еще и методы. Не забывайте о том, что JavaBean — это обычный класс Java с набором специальных характеристик. Еще одной важной характеристикой зерна является его способность реагировать на события (event) окружающей среды, для чего реализуются интерфейсы приемника (прослушивающего процесса) событий (event listener). Например, зерно, обращающееся к базе данных с запросом, требует, чтобы при завершении ITTTP-сеанса базовый курсор закрывался. Зерно будет получать уведомление о событии завершения, если зарегистрируется в списке объектов, заинтересованных в данном событии (см. ниже раздел "События и интерфейсы приемников событий"). В редких случаях приходится использовать в зерне нестандартные имена для методов доступа или какую-то нестандартную структурную схему. Фундамент зерен JavaBean достаточно гибок для того, чтобы создать такое JavaBean, но после этого необходимо сформировать специальный класс дескриптора (descriptor) зерна, предоставив информацию о его структуре. Имя класса дескриптора образуется добавлением суффикса Beanlnfo к имени класса зерна, причем класс дескриптора должен реализовывать интерфейс java. beans. Beanlnfo, который содержит методы для получения необходимой информации об атрибутах, методах и событиях для JavaBean. За дополнительными сведениями обращайтесь к литературе по JavaBean, например к книге "Developing JavaBeans" Роберта Ингландера, издательство O'Reilly Press. В примерах этой книги соблюдаются стандартные правила именования get и set для методов доступа JavaBean.
Создание простого JavaBean В качестве первого шага создадим простое зерно UserNameBean, которое обладает единственным свойством userName со строковым значением, представляющим имя пользователя. Методы доступа этого свойства описываются в соответствии со стандартным соглашением по именованию. Базовая структура этого зерна-компонента представлена на диаграмме (см. рис. 11.1). Рис. 11.1.
setUserName(String newName)
Структура компонента UserNameBean
String getUserName()
Ниже приводится программный текст этого зерна — класс UserNameBean с ча-
с т н ы м п о л е м userName и м е т о д а м и getUserName() и setUserName(String newName)
для считывания и присвоения значения этого свойства. Здесь описан дополнительный метод noUser(), возвращающий true, если имя пользователя — null или пустая строка символов. package mybeans; public class UserNameBean { private String userName = ""; public String getUserName() { return userName;
}
317
318
ГЛАВА 10
О public void synchronized setUserName(String newName) { userName = newName;
}
public boolean nollserQ { return ((userName == n u l l ) | | (userName.equals( " " ) ) ) ;
}
}
В этой программе класс UserNameBean помещен в пакет mybeans. Указывать имя пакета для JavaBean необязательно, как, впрочем, и для любого другого класса Java. Явного конструктора здесь нет, т.е. для класса используется конструктор по умолчанию. Напомним, что JavaBean — обычный класс Java с набором дополнительных правил, определяющих его структуру, поэтому при его написании соблюдаются обычные правила синтаксиса и семантики Java. Заметим также, что для свойства зерна, используемого в JSP, совсем не обязательно указывать оба метода get и set; какой из методов доступа может быть опущен, зависит от способа использования свойства. Обычно метод set защищается от многопоточного доступа объявлением его как синхронизированного (synchronized) метода. Зерно компилируется так же, как любой другой класс Java. Для использования зерна в JSP-приложении класс зерна необходимо установить на web-cepeepe (см. приложение А).
Стандартные JSP-тэги для зерен JavaBean После написания JavaBean его можно ввести B J S P при помощи стандартных тэгов. В спецификации JSP описаны три встроенных тэга, упрощающих работу с зернами: •
<jsp:useBean>
•
<j s p : s e t P r o p e r t y >
•
<jsp:getProperty>
Эти тэги применяются для интеграции HaJSP-страиицах логики Java зерен со статическим HTML-текстом. Теперь посмотрим, каковы синтаксис и семантика этих тэгов и как их грамотно использовать в JSP-приложениях. Тэг < j s p : u s e B e a n > Этот тэг указывает на то, что определенное зерно используется на JSP-странице. Общий формат тэга: •
<jsp:useBean id="переменная" другие_атрибуты
/>
К другим атрибутам, помимо прочих, относятся class и scope. Наиболее часто используются атрибуты id, scope и class. Атрибут class описывает полностью определенное имя класса для JavaBean; в д а н н о м с л у ч а е — mybeans. UserNameBean.
Атрибут id описывает идентификатор Java для экземпляра зерна. С помощью этого идентификатора можно ссылаться на экземпляр зерна в той области действия Java, в которой присутствует тэг < j sp: useBean>. Например, следующий оператор JSP-программы указывает на то, что она использует экземпляр к л а с с а з е р н а mybeans. UserNameBean: •
Здесь идентификатор userBean определяет имя экземпляра зерна. Согласно правилам области действия переменных в Java, можно написать выражение или скриптлет Java, где фигурирует данный идентификатор, например: •
<%= userBean.getUserName() %>
Атрибут scope необязателен, но довольно важен. Он определяет время жизни (lifetime) компонента-зерна, используемого на JSP-странице, т.е. продолжительность его существования в качестве программной переменной. Этот атрибут может иметь одно из четырех значений:
Использование JSP вместе с зернами JavaBean
•
page
•
request
•
session
•
application
о ;
Значение по умолчанию для scope — page. Рассмотрим подробнее каждое из этих четырех значений: • page. Во время исполнения оператора <jsp: useBean> JSP-контейнер просматривает объект page в поисках экземпляра зерна с таким же идентификатором. Если такого зерна не обнаруживается, создается новый экземпляр зерна, который связывается с объектом page при помощи идентификатора, указанного атрибутом id. В этом правиле поиска предполагается, что обращаться к зерну с областью действия page на других страницах, вызываемых с данной JSP, нельзя; это относится, например, к страницам, вызываемым посредством тэгов <jsp: include> и <jsp: forward> (см. главу 10). При повторном вызове этой JSP тот же самый идентификатор будет ссылаться на совершенно иной экземпляр зерна. •
request. Эта область действия похожа на область действия page с тем важным отличием, что экземпляр зерна связывается с HTTP-объектом request. Следовательно, к зерну с областью действия request можно обращаться и на другой странице, вызываемой (подключаемой или новой управляющей) с текущей JSP. Идентификатор зерна с областью действия request должен быть уникален среди всех страниц, обрабатывающих один и тот же ITTTP-запрос.
• session. В этом случае экземпляр зерна связывается с объектом session и существует во время HTTP-сеанса, в котором вызывается данная JSP. При исполнении гэга <jsp: useBean> в объекте session создается экземпляр зерна, если, конечно, его там еще нет. Идентификатор зерна с областью действия session должен быть уникален среди всех страниц, вызываемых в границах одного и того же HTTP-сеанса. Зерна с областью действия session часто используются в приложениях с контролем за сеаисами, например в таких, где реализуется функция "корзины магазина". Пример подобного зерна приводится ниже. • application. Эта область действия похожа на другие, но связывает экземпляр зерна с объектом application (см. главу 10). При ее использовании экземпляр зерна становится доступен всем страницам, которые исполняются в одной и той же виртуальной машине Java и являются частью одного и того же web-приложения, в качестве текущей JSP. Помимо атрибутов, у тэга <jsp: useBean> может быть и тело, содержащее другие JSP-тэги и скриптлеты для работы с экземпляром зерна. Например: •
<jsp:useBean id="userBean" class="mybeans.UserNameBean" > I n i t i a l value of user name i s : <%= userBean.getUserName() %>
Тэг <jsp:setProperty> Стандартный тэг <jsp: setProperty> применяется для установки свойств компонента JavaBean, используемого на JSP-странице. Общий формат этого тэга: •
где имя_зерна — идентификатор экземпляра JavaBean, описываемый обычно в т э г е < j s p : useBean> в ы ш е н а J S P . К о н с т р у к ц и я в ы р а ж е н и е _ д л я _ с в о й с т в м о ж е т записываться в одном из следующих четырех форматов: •
property ="имя_свойства". В этом формате указывается имя одного свойства JavaBean, а его значение устанавливается на основании значения соответствующего параметра HTTP-объекта request. Другими словами,
320
ГЛАВА 10
О
метод set этого свойства будет вызываться со значением соответствующего параметра запроса в качества аргумента. Например, чтобы установить свойство userName ранее описанного UserNameBean на основании соответствующего параметра HTTP-запроса, нужно ввести: <jsp:setProperty name="userBean" property="userName" />
• property="*". Это сокращенное выражение говорит о том, что свойства JavaBean будут устанавливаться на основании значений соответствующих параметров запроса путем сопоставления их имен. Другими словами, анализируется каждый параметр HTTP-объекта request, и при наличии соответствующего свойства зерна его метод set вызывается со значением параметра запроса в качестве аргумента. • property ="имя_свойства" рагат-"имя_параметра". Этот формат используется для указания пары свойство-параметр запроса. Свойству зерна присваивается значение указанного параметра запроса вызовом соответствующего метода set со значением параметра в качестве аргумента. Например, если в HTTP-объекте request для представления имени пользователя применяется другой идентификатор, скажем, newName, то для присвоения значения свойству userName зерна значения параметра нужно указать: <jsp:setProperty name="userBean" property="userName" parameter="newName" />
• ргорег1у="имя_свойства" value="Hoeoe_значение". Этот формат используется для присвоения указанного значения данному свойству зерна. Новое_значение может быть постоянной строкой символов или JSP-выражением, вычисляемым во время запроса.
Тэг <jsp:getProperty> Этот оператор выводит значение указанного свойства JavaBean. Результатом его является вызов метода get свойства, преобразование выданного значения в строку символов и запись ее в объект out (представляющий поток ответа). Общий формат этого тэга: •
Здесь атрибут name ссылается на идентификатор зерна, ранее определенный в тэге < j sp: useBean> в границах JSP, а атрибут property указывает свойство этого зерна. Например, для отображения свойства userName зерна UserNameBean нужно ввести: •
Возникает вопрос: а нужен ли вообще тэг < j sp: getРroperty>? Ведь, по всей видимости, такой же эффект будет иметь выполнение эквивалентного JSP-выражения. Например, можно переписать предыдущий оператор, и результат будет таким же: •
<%= userBean.getUserName() %>
В чем лее отличие этих двух операторов? В некоторых случаях использование тэга <j sp: getProperty> является более гибким способом получения значения свойства. Так, иногда для методов доступа зерна применяются нестандартные имена (как указано в классе дескриптора Beanlnfo), которые неизвестны JSP-программисту. Настоящее имя метода доступа, соответствующего указанному свойству, выясняется во время JSP-трансляции при внутреннем анализе класса зерна и соответствующего класса дескриптора зерна. В такой ситуации удобно применять тэг <jsp: getProperty>. Кроме того, можно изменять имена методов доступа без модификации JSP-программы.
Использование JSP вместе с зернами JavaBean
о
Индексируемые свойства Имя индексируемого свойства связывается с несколькими значениями. Индексируемое свойство объявляется как массив, например: •
private S t r i n g f ] phones;
В спецификации JavaBean описывается стандартная структурная схема для методов доступа индексируемых свойств. Методы доступа могут обладать дополнительным атрибутом — целочисленным индексом массива, что позволяет обращаться к отдельным значениям массива. Методы доступа set и get могут иметь и другой вид и применяться ко всему массиву. Например, следующие сигнатуры методов — это стандартная схема доступа для объявленного выше свойства phones: •
public public public public
S t r i n g [ ] getPhones(); void setPhones(String[] newPhones); String getPhones(int index); void setPhones(int index, String newPhones);
В спецификации JSP 1.1 поддерживаются индексируемые свойства в стандартном тэге <jsp:setProperty>. В качестве примера предположим, что индексируемое свойство phones объявлено как часть экземпляра зерна addrBean. Для установки и получения значений этого индексируемого свойства на JSP можно воспользоваться следующими операторами: •
<% S t r i n g [ ] thePhones = new String[]{"123-4567 ', "456-7890"}; %> <jsp:setProperty name="addrBean" property="phones" value="<%= thePhones %>" /> <%=addrBean.getPhones(0)%>,<%=addrBean.getPhones(1)%>
Создание HelloBean. jsp с помощью UserNameBean Теперь создадим JSP, на которой используется описанный выше компонент UserNameBean. Эта JSP с именем HelloBean. jsp по существу выполняет ту же самую функцию, что и программа Hello, jsp из главы 10, с тем отличием, что в HelloBean. jsp используются JavaBean и стандартные JSP-тэги зерен, а не программные конструкции Java в JSP-скриптлетах. Приведем текст этой JSP : •
< ! - - Имя программы: HelloBean. р -- Назначение: Сохранить считать имя пользователя при помощи компонент?; UserNameBean и распечатать приветствие. - - >
<jsp:useBean id="nameBean" class="mybeans.UserNameBean"/> < ! - - (см. пояснение 2) -> <jsp:setProperty name="nameBean" property="*" /> <TITLE> The HelloBean JSP < ! - - - (см. пояснение 3) -->
Hello <%= nameBean.getUserName() %> !
The current time i s <%- new j a v a . u t i l . D a t e ( ) %>. Have a nice day!
Please type in your user name: < ! - - (см. пояснение 4) -->
321
322
ГЛАВА 10
О Пояснения к HelloBean. jsp:
1. Тэг <jsp: useBean> объявляет, что JSP исиользует экземпляр класса зерна
mybeans. UserNameBean, и с в я з ы в а е т е г о с и д е н т и ф и к а т о р о м nameBean. П о -
скольку область действия не указана, предполагается, что применяется область действия по умолчанию — page. 2. Этот оператор устанавливает для свойства userName экземпляра nameBean значение соответствующего параметра запроса. Заметим, что для описания свойства зерна, соответствующего параметру HTTP-запроса, применяется сокращение "*". 3. В приветствии "Hello" значение свойства userName считывается из зерна с помощью метода доступа getUserName(). 4. В последней части JSP указана HTML-форма для ввода имени пользователем, после чего вызывается та же JSP (действие формы по умолчанию). Заметим, что в текстовом поле ввода формы указано имя userName. Это имя намеренно совпадает с именем свойства зерна, "связывая" параметры HTTP-запроса с атрибутами зерна. Другими словами, значение, вводимое в этом текстовом поле, становится частью HTTPзапроса, который затем используется для установки соответствующего свойства зерна посредством тэга <jsp: setProperty>.
Выполнение HelloBean.jsp Сначала установим исходный файл HelloBean.jsp на web-сервере, следуя инструкциям, приведенным в приложении Е. Кроме того, необходимо скомпилировать класс UserNameBean и установить его на web-сервере. В приложении Е эти операции описаны для разных web-серверов. Например, для сервера Tomcat, функционирующего в системе UNIX, молено воспользоваться сценарием оболочки, представленным в листинге 11.1, и скомпилировать класс зерна, поместив его в подкаталог webapps/examples/WEB-INF/classes корневого каталога Tomcat. Листинг 11.1. Сценарий оболочки buildbeans.sh для компиляции класса UserNameBean •
После компиляции зерна можно выполнить JSP при помощи браузера. При вызове страницы без параметров отображается приветственное сообщение без имени пользователя, текущего времени и формы для ввода имени пользователя. Теперь допустим, что мы ввели в текстовом окне экрана имя Р а т и щелкнули мышыо на кнопке "Enter name". В результате HTTP-запрос посылается на ту же JSP-страницу (как стандартное действие HTTP-формы), а для свойства userName экземпляра UserNameBean, связанного с JSP- страницей (это стандартная область действия экземпляра зерна), устанавливается указанное значение. Впоследствии это значение молено считать и отобразить с помощью метода nameBean. getUserName(). Результат, получаемый в браузере, приведен на рис. 11.2.
Использование зерен JavaBean с разными областями действия Теперь создадим JSP-прилолеение, использующее компоненты JavaBean с разными областями действия. В примере демонстрируется не только применение
Использование JSP вместе с зернами JavaBean
Рис. 11.2.
The HelloBean JSP
Выходные данные HelloBean.jsp после ввода значения Pam
File
£dit
View
fio
* Bookmarks
Netscape
Communicator .jfy.
323
о
Help
Go to: |http.7/localhost:8080/enamples/jsp/chaplet11 /HelloBean.jsp?username-Pam
( Ш * What's Related
Hello Pant! The current time Is Wed Aug 02 00:56:30 PDT 2000. Have a nice day! Please type in your user name: Enter name
EpR>="(
^
I Document: Done
a
^
ia
Ia
модульных зерен и их свойств, но и изменение продолжительности их существования путем изменения области действия. Приложение состоит из двух JSP-страниц: BeanScoping. jsp и BeanScopinglncluded. jsp. Вторая JSP вызывается с первой с помощью тэга <jsp: include> (см. главу 10), поэтому обе они исполняются как часть одного HTTP-запроса. Цель примера — показать, что к экземплярам зерна с областями действия request и session можно обращаться с подключаемой (или новой управляющей) JSP-страницы, в то время как зерно с областью действия page локально для JSP-страницы. Структура этого приложения представлена на рис. 11.3. Она включает в себя две JSP-страницы и используемые ими зерна-компоненты. Зерно запроса и сеансовое зерно совместно используются двумя страницами (посредством соответственно HTTP-запроса и ITTTP-сеанса), в то время как экземпляры страничного зерна для каждой JSP-страницы свои. Рис. 11.3.
использует
Компоненты приложения BeanScoping
использует
Подключаемая использует использует JSP-страница
радеВеап
BeanScoping.jsp
BeanScopinglncluded.jsp
Ниже следует текст программы BeanScoping.jsp, в которой используются три экземпляра одного класса UserNameBean с областями действия page, request и session. JSP можно разделить на четыре части: • В первой части создаются и устанавливаются свойства трех экземпляров зерна. • Во второй части значения свойств экземпляров распечатываются.
зерна
считываются и
• В третьей части подключается другая JSP как элемент того же самого HTTP-запроса. • В четвертой, заключительной, части содержатся формы для ввода данных, где указывается значение свойства userName зерен. •
< ! - - Имя программы: BeanScoping.jsp - - Назначение: Применить компоненты JavaBean с областями действия page, request и session. - - !
Printing bean properties... < ! - - (см. пояснение 2) --> <% i f (pageBean.noUserO) { / * имя пользователя не установлено в зерне с областью действия page * / %> No user name in page-scoped bean! <% } else { / * извлечем свойство имени пользователя из pageBean * / %> User name in pageBean: <%= pageBean.getUserName() %> <% } %> <% i f (requestBean. rioUser()) { / * имя пользователя не установлено в зерне с областью действия request * / %> No user name in request-scoped bean! <% } else { / * извлечем свойство имени пользователя из requestBean * / %> User name in requestBean: <%= requestBean.getUserName()%> <% } %> <% i f
(sessionBean.noUser()) / * имя пользователя не установлено в зерне с областью действия session * / %> No user name in session-scoped bean! <% } else { / * извлечем свойство имени пользователя из sessionBean * / %> User name in sessionBean: <%=sessionBean.getUserName()%> <% } %> {
Now printing output from an included page..
< ! - - (см. пояснение 3) --> <jsp:include page="BeanScopingIncluded.jsp" flush="true" /> < ! - - (см. пояснение 4) -->
Please enter your user name:
Использование JSP вместе с зернами JavaBean
о
Пояснения к BeanScoping.jsp: 1. В первой части JSP содержатся три тэга <jsp: useBean>, использующих разные экземпляры одного класса зерна с разными областями
действия: page, request и session. За каждым из т р е х о п е р а т о р о в <jsp: useBean>
следует тэг <jsp:setProperty>, устанавливающий свойства экземпляра зерна на основании соответствующего параметра HTTP-запроса (userName).
2. В этой части JSP считывается и отображается значение свойства каждого зерна. Если значением является null или пустая строка, что определяет вызывающий метод noUser() зерен, выводится сообщение об этом. В противном случае отображается значение свойства, извлеченное вызывающим методом доступа getUserName(). 3. Этот оператор подключает JSP-страницу
BeanScopinglncluded.jsp
(см. ниже).
4. В последней части JSP содержатся две HTML-формы: • Сегмент первой формы позволяет ввести имя пользователя, которое становится параметром HTTP-запроса GET после щелчка мыши на кнопке "Submit new user name". Вовсе не случайно, что имя текстового поля ввода совпадает с: атрибутом userName класса UserNameBean; совпадение имен — это механизм, "связывающий" параметр запроса со свойствами зерна на этой JSP. • Функция передачи второй HTML-формы вызывает ту же самую JSP, но с параметром userName. Задача этой функции — считать и повторно использовать значение userName, сохраненное в зерне с областью действия session из предыдущего вызова JSP. Ниже приводится текст программы BeanScopinglncluded. jsp, которая вы-
з ы в а е т с я г л а в н о й J S P - с т р а н и ц е й BeanScoping.jsp. С т р а н и ц а BeanScopinglnclu-
ded. jsp похожа на BeanScoping. jsp; главное их отличие в том, что подключаемая JSP-сграница не устанавливает никаких свойств зерна посредством тэгов <jsp: setProperty> и не содержит никаких HTML-форм для ввода данных. Она просто использует три соответствующим образом названных экземпляра с
о б л а с т я м и д е й с т в и я page, request и session так, ч т о з е р н а с о б л а с т я м и д е й с т -
вия request и session разделяются между данной страницей и главной страницей BeanScoping.jsp. Как показано на рис. 11.3, экземпляр зерна с областью действия page — это собственный локальный компонент страницы, который не разделяется между страницами. •
<jsp:useBean id="pageBean" class="mybeans.UserNameBean" scope="page" /> <jsp:useBean id="requestBean" class="mybeans.UserNameBean" scope="request" /> <jsp:useBean id="sessionBean" class="mybeans.UserNameBean" scope="session" /> <% i f (pageBean.noUser()) { / * имя пользователя не установлено в зерне с областью действия page * / %> BeanScopinglncluded.jsp: No user name in page-scoped bean!
326
ГЛАВА 11
О <% } else { / * извлечем свойство имени пользователя из pageBean */ %> BeanScopinglncluded.jsp: User name in pageBean: <5!= pageBean.getUserNameO 3J> <% } %>
<% i f (requestBean. noUserO) { / * имя пользователя не установлено в зерне с областью действия request */ %> BeanScopinglncluded.jsp: No user name in request-scoped bean! <% } else { / * извлечем свойство имени пользователя из requestBean */ %> BeanScopinglncluded.jsp: User name in requestBean: <%= requestBean.getUserName()X> <% } %> <% i f (sessionBean.noUser()) { /* имя пользователя не установлено в зерне с областью действия session */ %> BeanScopinglncluded.jsp: No user name in session-scoped bean! <% } else { / * извлечем свойство имени пользователя из sessionBean * / %> BeanScopinglncluded.jsp: User name in sessionBean: <3S=sessionBean. getUserName( )%> <% } %>
Выполнение JSP-страницы BeanScoping Посмотрим, как работает JSP-страница BeanScoping. На рис. 11.4 показан результат, выдаваемый браузером при вызове данной JSP в первый раз и без параметров запроса. В этом случае тэги <jsp: useBean> создают новые экземпляры трех зерен с надлежавщми областями действия. Однако соответствующего HTTP-параметра для их свойства userName нет, поэтому первоначально методы noUser() возвращают true. Таким образом, JSP распечатывает сообщения "no user name". Теперь предположим, что мы ввели в HTML-форме имя Rita и щелкнули мышью на кнопке "Submit new user name". Будет сформирован новый HTTP-запрос и созданы новые экземпляры страничного зерна и зерна запроса на главной странице BeanScoping. jsp. Если срок действия HTTP-сеанса не истек, используется тот же самый экземпляр сеансового зерна. Для свойства userName новых экземпляров страничного зерна, зерна запроса и того же самого сеансового зерна устанавливается входное значение Rita. Затем все РИС. 11.4. Начальные выходные данные BeanScoping. jsp
I
The BeanScoping JSP • Netscape File Edit View Go Communicatw Help
;ij
~ Bookmeks Jfr. *
Go to: |http7/localhost8060/eKsinple:/isp/chap(ef11/BeanScoping.jsp
Welcome to the BeanScoping JSP! No user name in page-scoped bean! No user name in request-scoped bean! No user name in session-scoped bean! Now printing output from an included page..
BeanScoplnglncludedjsp: No user name in page-scoped bean! BeanScoplnglncludedjsp: No user name in request-scoped bean! BeanScoplnglncludedjsp: No user name in session-scoped bean!
Please enter your user name: |
Submit new user name Use previous nama
^ • • • • • • п ш
|
Использование JSP вместе с зернами JavaBean
о
зерна главной страницы распечатывают имя пользователя, как показано в первой части рис. 11.5. В следующей части рисунка изображены выходные данные, генерируемые подключаемой страницей BeanScopinglncluded. jsp. Эта страница не устанавливает никаких свойств зерен, поэтому в этом страничном зерне имя пользователя отсутствует. Свойства же зерна запроса и сеансового зерна устанавливаются главной страницей, и значение имени пользователя надлежащим образом считывается в разделяемых экземплярах зерна и распечатывается подключаемой страницей. Выходные данные BeanScoping.jsp после ввода имени пользователя Rita
Go to: |://localho$t:8080/examples/jsp/'diapter11 /BcenScoping.i$p?useiName»Ritj| j J ( f j j l " What's Related
Welcome to the BeanScoping JSP! User name ill pageBean: Rita Username in ri:qu
BeanScopinglncIuded.jsp: No username in pagu-sroped bean! BeanScopinglncIuded.jsp: Username in requestBean: Rita BeanScopinglncIuded.jsp: Username in sessionBean: Rita
Please enter your user naine: Submit new user name Use previous name (Document: Done
Чтобы увидеть, каким образом сеансовое зерно сохраняет установки своих свойств во время вызова, нужно еще раз обратиться к той же JSP без параметров запроса, щелкнув мышыо на кнопке "Use previous name" (использовать предыдущее имя) до истечения срока действия HTTP-сеанса. Как показано на рис. 11.6, зерно с областью действия session сохранило значение своего свойства userName из предыдущего вызова, а в новых экземплярах страничного зерна и зерна запроса имя пользователя не установлено. Выходные данные BeanScoping.jsp после повторного вызова без параметров
$£ The BeanScoping JSP - Netec'apo ' 'V 0e
£dit У f i o T
Bookmarks
Yl
/
Communicator Help Jfo
Go to IhttpV/localhosCBOeO/examples/jsp/chapterl 1 /BeanScoping jsp?
ЕШЩ 'What's RelatedM
Welcome to the BeanScoping JSP! No user name in page-scoped bean! No user name in request-scoped beaut! User name in sessionBean: Rita Now printing output from an included page..
BeanScopinglncIuded.jsp: No user name in page-scoped bean! BeanScopinglncIuded.jsp: No user name in request-scoped bean! BeanScopinglncIuded.jsp: User name in sessionBean: Rita
Please enter your user name: Submit new user name Use previous name
S'RU" [
I Document: Done
Zl Я Jfc-jOLjtf». €3 n/LJ Л
328
ГЛАВА 10
О
Использование зерен JavaBean с областью действия application аналогично приведенному выше примеру. О кэшировании соединений с базой данных с помощью зерна с областью действия application рассказывается ниже в разделе "Пулинг соединений".
Разработка JSP-приложения с контролем за сеансами Теперь рассмотрим более сложный пример применения JavaBean в JSP, когда действия пользователя отслеживаются в конкретном HTTP-сеансе. Этот пример написан по образцу распространенного web-приложения — интерактивной системы ввода заказов. Предположим, что наша прикладная программа должна позволять: • Выбирать один или несколько товаров (пунктов ассортимента) в группе. • Помещать выбранные товары в корзину. • Добавлять и удалять товары из корзины, а также очищать корзину по мере выбора. • В конце процесса выбора товаров передавать заказ системе. При этом информация о заказе будет вводиться в таблицы базы данных. • Запрашивать характеристики заказа в базе данных. Рассмотрим этапы процесса разработки этого приложения с помощью JSP-страниц и зерен JavaBean.
Архитектура интерактивного приложения заказов Первый шаг — создание проекта компонентов JSP-приложения. Модульная архитектура интерактивного JSP-приложения заказов (Order Online) представлена на рис. 11.7. Три JSP-страницы — EnterOrder. jsp, InsertOrder. jsp и QueryOrder. jsp — будут служить пользовательским интерфейсом для интерактивных процессов выбора товаров, передачи заказов и изучения заказов соответственно. Корзина представлена компонентом cartBean. В нем будет содержаться текущий список выбранных товаров, и его будут совместно использовать страницы EnterOrder.jsp и InsertOrder. jsp. Страница InsertOr-
der. jsp имеет дополнительный компонент DBInsertBean, который будет исполнять SQL-операцию INSERT для записи переданного заказа в базу данных заказов на покупку. У страницы QueryOrder. jsp будет свой собственный компонент JavaBean — DBQueryBean. Этот JavaBean будет обращаться с запросами к базе данных заказов на покупку и считывать информацию о заказах. Архитектура приложения Order Online
База данных Purchase Order
Использование JSP вместе с зернами JavaBean
о
Создание к л а с с а Cart Bean Ha первом этапе программирования опишем зерно JavaBean с именем CartBean, чтобы смоделировать корзину. Оно будет управлять списком товаров, выбираемых пользователем, и обеспечивать выполнение операций добавления, удаления и очистки этого списка. Таким образом, текущее содержимое корзины будет меняться в зависимости от параметров HTTP-запросов, передаваемых пользователем в границах одного НТТР-сеанса. Ниже приводится программный текст класса CartBean. Для представления корзины используется экземпляр класса java. u t i l . ArrayList — нового служебного класса, описанного в JDK 1.2. В среде JDK 1.1 нужно модифицирова ть программу, воспользовавшись другим типом данных, например java. util. Vector. •
/ * * Имя программы: ** Назначение: ** »* * *
CartBean.java Реализовать компонент для корзины, в которую можно добавлять товары и из которой их можно удалять; кроме того, корзину можно очищать.
/
package mybeans; import j a v a . u t i l . A r r a y L i s t ; / / требует JDK 1.2 public class CartBean { / / (см. пояснение 1) private S t r i n g [ ] itemsSelected = null; / / выбираемые товары private String action = null; / / выбираемое действие / / (см. пояснение 2) private ArrayList itemsList = new ArrayListO; / / содержимое корзины / * метод для установки действия: добавить, удалить или очистить * / public synchronized void setAction (String newAction) { / / (см. пояснение 3) action = newAction; i f (action.startsWith("Clear")) { / / очистить корзину itemsList.clear();
}
}
/ * метод для обработки нового списка выбранных товаров * / public synchronized void setItemsSelected ( S t r i n g [ ] newltems) { / / (см. пояснение 4) i f (newltems != n u l l ) { / / какие-то товары выбраны for ( i n t i = 0; i < newltems.length; i++) { i f (action.startsWith("Add")){ / / добавить в корзину itemsList.add(newltems [ i ] ) ; } else i f (action.startsWith("Remove")) { / / удалить / / найти последний экземпляр этого товара в корзине i n t index = itemsList.lastlndex0f(newltems[i]); i f (index != -1) { itemsList.remove(index);// удалить из списка
}
}
}
}
}
/ / (см. пояснение 5) / * метод для получения текущего номера заказанных товаров * / public i n t countltemsO { return itemsList.size();
}
/ * метод для получения конкретного товара * / public Object getltem(int index) { return itemsList.get(index);
}
329
330
ГЛАВА 10
О / * метод для получения всего списка заказанных товаров * / public ArrayList getOrder() { return itemsList;
} } / / конец CartBean Пояснения к CartBean.java:
1. Зерно обладает двумя свойствами: itemsSelected и action. Свойство itemsSelected указывает на список товаров, выбранных пользователем на экране, а свойство action — на природу операции: добавление товаров, удаление товаров или очистка корзины. В зерне присутствуют методы set для обоих его свойств. Значения этих свойств только записываются, но не считываются извне, поэтому методы get отсутствуют. 2. Переменная itemsList указывает на текущее содержимое корзины. 3. Метод set Action () устанавливает значение атрибута action. Помимо этого, если действием является очисгка корзины ("Clear the cart"), вызывается метод itemsList.clear().
4. Метод setItemsSelected() исполняет логику установки содержимого корзины в зависимости от выбранного действия: • Если какие-то товары выбраны, а действием является добавление в корзину ("Add to cart"), в itemsList вносятся выбранные товары, для чего вызывается метод itemsList. add(). • Если какие-то товары выбраны, а действием является удаление из корзины ("Remove from cart"), из массива itemsList удаляется последний экземпляр каждого выбранного товара. 5. В зерне присутствуют три общих метода: countItems(), getltem() и getOrder(). Эти методы применяются соответственно для получения общего числа товаров, находящихся в тот момент в корзине, для получения товара в указанной позиции в списке и для получения списка товаров, накопленных в корзине. Эти методы используются в программе EnterOrder. jsp (см. ниже).
Создание программы EnterOrder. jsp Теперь создадим страницу EnterOrder. jsp, использующую описанный выше класс CartBean. Эта JSP будет интегрироваться в зерне с HTML-текстом представления и с логикой вычислений, управляя процессом размещения заказов. Ввод заказа в базу данных заказов на покупку управляется другой JSP с именем InsertOrder. jsp, которая приводится в следующем разделе. Программный текст EnterOrder. jsp: •
Пояснения к EnterOrder. jsp: 1. JSP использует ранее описанный класс CartBean с областью действия session. Два свойства этого зерна, action и itemsSelected, устанавливаются на основании параметров HTTP-запроса с именами action и item соответственно. 2. Страница состоит из двух сегментов HTML-форм. Первая форма содержит список товаров с флажками выбора, а также три функциональные кнопки "Add to cart", "Remove from cart" и "Clear cart". Щелчок мыши на этих кнопках устанавливает параметр запроса с именем action в соответствующее значение, и происходит обращение к той же самой JSP-программе (т.е. к EnterOrder. jsp) при помощи HTTP-метода GET. 3. Вторая форма состоит из одной кнопки передачи с именем "Submit my order". Если щелкнуть на этой кнопке мышью, форма направит HTTP-запрос на страницу InsertOrder. jsp. Предполагается, что этот запрос является частью того же HTTP-сеанса, в котором работает EnterOrder. jsp, поэтому другая JSP может обращаться в области действия session к тому же самому экземпляру CartBean. Значимость этого станет очевидной при написании программы InsertOrder. jsp. 4. В последней части страницы EnterOrder. jsp отображается список товаров, находящихся в корзине в текущий момент, для чего вызываются соответствующие методы экземпляра CartBean.
Выполнение приложения Order Online После установки на web-сервере файла EnterOrder. jsp и скомпилированного класса для CartBean. java (см. выше сценарий buildbeans. sh и операции установки в приложении А) можно вызвать программу EnterOrder. jsp при помощи соответствующего URL. На рис. 11.8 показан результат первого вызова этой страницы.
331
332
ГЛАВА 10
О Рис. 11.8. Начальные выходные данные EnterOrder. j s p
Теперь выберем с помощью флажков на экране товары "Book Shell" и "Office Desk", а затем щелкнем мышью на кнопке "Add to cart". На рис. 11.9 показаны выходные данные браузера после этих действий. Рис. 11.9. Выходные данные EnterOrder.jsp после выбора товаров
Аналогично можно удалить товары из корзины, выбрав нужные флажки, а затем щелкнув мышью на кнопке "Remove from cart". Если щелкнуть мышью на кнопке "Clear cart", то из корзины будут удалены нее товары. Чередова ть действия "Add to cart", "Remove from cart" и "Clear carl" можно сколь угодно часто, при условии, что срок действия НТТР-сеапса не истек между этими операциями.
Использование JSP вместе с зернами JavaBean
о
После того как выбор сделан, все готово к размещению заказа! Теперь можно щелкнуть мышыо на кнопке "Submit my order", после чего начнет действовать вторая HTML-форма, которая перейдет к странице InsertOrder. jsp. Ее мы создадим позже.
Выполнение операций над базой данных с помощью зерен JavaBean Выше рассказывалось о программировании процесса ввода заказа при помощи JSP и JavaBean корзины. В этом разделе рассматривается выполнение в JSP-приложении операций над базой данных. Будет реализован последний этап процесса ввода заказа — ввод нужной информации в базу данных Purchase Order. Программные конструкции JDBC или SQLJ можно вводить непосредственно в JSP, чтобы обращаться к базе данных. Однако наличие большого объема логических схем Java на JSP-странице не слишком удобно при программировании серьезного JSP-приложения. Основой компонентного программирования является модульность (см. главу 2). С этой точки зрения лучшим стилем программирования является размещение программных конструкций Java в отдельном компоненте JavaBean с последующим вызовом их с JSP-страницы. При этом обеспечивается четкое отделение логики Java для динамической обработки информации от статического HTML-текста. Теперь посмотрим, как обращаться к базе данных Oracle при помощи JavaBean и как ввести зерно в JSPприложение.
Ввод информации в базу данных В JSP-приложении Order Online запрос на передачу заказа, производимый операцией "Submit my order" HTML-формы, направляется на страницу InsertOrder. jsp, которая вводит характеристики заказа в базу данных Purchase Order. Создадим эту JSP, а затем JavaBean с именем DBInsertBean, которое исполняет SQL-операцию INSERT для данных, собранных программой EnterOrder. jsp.
Создание InsertOrder.jsp Ниже приводится текст программы InsertOrder.jsp и даются пояснения. Главное, что стоит отметить,— для обработки информации JSP использует два зерна JavaBean: • Экземпляр cartBean с областью действия session, созданный JSP-страницей EnterOrder. В этом зерне содержится список товаров, выбранных пользователем приложения Order Online. • Экземпляр DBInsertBean с областью действия page, который является локальным компонентом для данной JSP. Это зерно будет подключаться к базе данных Oracle и исполнять необходимые SQL-операции. •
<%-- Имя программы: InsertOrder.jsp -- Назначение: Страница для ввода заказа, созданного при помощи JSP-страницы EnterOrder, в базу данных Purchase Order. -%> < ! - - Воспользуемся зерном корзины с областью действия session --> <jsp:useBean id="cart" class="mybeans.CartBean" scope="session" /> < ! - - (см. пояснение 1) --> <TITLE> The InsertOrder JSP
Ready to Order!
< ! - - (см. пояснение 2) --> You have selected: <%= cart.getOrder() %> <% i f ((request.getParameter("DBInsert")) != n u l l ) { %>
Пояснения к InsertOrder.jsp: 1. Предполагается, что JSP-страница InsertOrder вызывалась с JSP- страницы EnterOrder после завершения процесса выбора товаров, так что экземпляр CartBean уже создан JSP-страницей EnterOrder, и для него установлена область действия session. Поэтому первый JSP^rar <jsp: useBean> JSP-страницы InsertOrder считывает в области действия session этот экземпляр CartBean и делает его доступным для остальной части программы. 2. Этот оператор распечатывает список товаров, находящихся в корзине в текущий момент. Для этого вызывается метод getOrder() экземпляра CartBean.
3. Второй тэг <jsp: useBean> исполняется по условию, только когда в HTTP-запросе присутствует параметр с именем DBInsert. Этот тэг создает экземпляр класса зерна mybeans. DBInsertBean (см. ниже) с идентификатором dblnsert. Зерно создается с областью действия page, поскольку операция, выполняемая над базой данных, не имеет смысла вне области действия этой JSP. Свойства экземпляра зерна dblnsert устанавливаются на основании параметров HTTP-запроса. 4. Следующее JSP-выражение вызывает метод processOrder() зерна dblnsert с заказом, считываемым в экземпляре CartBean, в качестве аргумента. Результат вызова этого метода отображается на экране. 5. Этот оператор очищает корзину, сбрасывая список покупок. 6. В последней HTML-форм:
части
JSP-страницы
используются
сегменты
двух
• В сегменте первой формы присутствуют два текстовых поля для ввода номера служащего (empNum) и номера проекта (projNum) заказа. Указав в этих полях необходимые данные, можно щелкнуть мышью на кнопке "Submit my order", чтобы еще раз вызвать ту же JSP, но с параметром DBInsert, установленным в HTTP-запросе. Как отмечалось выше, при наличии этого параметра заказ передается зерну dblnsert для обработки.
Использование JSP вместе с зернами JavaBean
о
• В сегменте второй формы полей ввода нет, но есть кнопка "Back to Order Entry", возвращающая пользователя к начальному экрану ввода заказа, для чего в форме вызывается EnterOrder. jsp.
Создание DBInsertBean. s q l j Назначением класса DBInsertBean является ввод списка выбранных товаров в базу данных Purchase Order. Следовательно, он должен выполнять необходимые операции над таблицами. Схема для этих таблиц описана во введении к книге. Для удобства воспроизведем таблицы PURCHASE_LIST и LINEITEM_LIST, имеющие отношение к этому классу: CREATE TABLE PURCHASE_LIST ( requestno NUMBER(10), employeeno NUMBER(7), vendorno NUMBER(6), purchasetype VARCHAR2(20), checkno NUMBER(H), whenpurchased DATE); CREATE TABLE LINEITEM_LIST ( requestno NUMBER(10), lineno NUMBER(5), projectno NUMBER(5), quantity NUMBER(5), unit VARCHAR2(2), estimatedcost NUMBER(8,2), actualcost NUMBER(8,2), description VARCHAR2(30));
Для приема данных, вводимых в форме JSP-страницы InsertOrder, в JavaBean должны существовать два свойства с именами empNum и projNum. Текст данного JavaBean приведен ниже. Оно написано с использованием программных конструкций SQLJ, что упрощает исполнение операций над базой данных. / * * Имя программы: ** Назначение:
DBInsertBean.sqlj Ввести заказ в таблицы базы данных заказов на покупку.
public class DBInsertBean { / / (см. пояснение 1) private String empNum = null; / / номер служащего private String projNum= null; / / номер проекта / / Метод для установки свойства empNum public synchronized void setEmpNum(String empNum) { this.empNum = empNum;
} / / Метод для установки свойства projNum public synchronized void setProjNum(String projNum) { this.projNum = projNum;
} private DefaultContext dctx = null; private i n t requestno;
/ / контекст соединения с базой данных / / номер запроса для заказа
/ / Метод для обработки переданного заказа
335
336
ГЛАВА 10
О / / (см. пояснение 2) public synchronized String processOrder (ArrayList order) { i f ((order == n u l l ) || (order.size() == 0)) { return ("No order items to i n s e r t ! " ) ;
}
try { / / Подключимся к базе данных / / (см. пояснение 3) dctx = Oracle.getConnection("jdbc:oracle:oci8:@", "jspuser", " j s p " ) ; / / Введем заказ в базу данных DBInsert(order); / / Ошибок нет! return ("Purchase order processed successfully! " + "Your request number is: " + requestno); } catch (SQLException e) { return ("SQL Error:" + e.getMessageO); } finally { / / Отключимся от базы данных try { dctx.close(); / / (см. пояснение 4) } catch (Exception e) {}
}
}
private void DBInsert(ArrayList order) throws SQLException { / / (см. пояснение 5) / / Сначала узнаем следующий порядковый номер запроса #sql [dctx] { SELECT requestno_seq.NEXTVAL INTO :requestno FROM DUAL }; / / Затем введем запрос в таблицу PURCHASE_LIST #sql [dctx] { INSERT INTO PURCHASE_LIST( requestno, employeeno, whenpurchased) VALUES( :requestno, :empNum, SYSDATE
)
};
/ / Теперь введем все пункты ассортимента из переданного заказа for ( i n t i = 0; i < order.size(); i++) { «sql [dctx] { INSERT INTO LINEITEM_LIST ( requestno, lineno, projectno, quantity, description
)
VALUES (:requestno, lineno_seq.NEXTVAL, :projNum.
1,
};
}
}
}
)
:(order.get
(i))
#sql [dctx] { COMMIT }; / / завершим ввод строк
Использование JSP вместе с зернами JavaBean
о
337
П о я с н е н и я к DBInsertBean.sqlj: 1. У DBInsertBean два с в о й с т в а : empNum и projNum. П р е д л а г а ю т с я м е т о д ы для
установки значений этих свойств. Значения этих свойств только записываются, но не считываются, поэтому методы gel отсутствуют. 2. Главный метод зерна — processOrder(), который принимает заказ типа java. u t i l . ArrayList в качестве аргумента. Заказ обрабатывается следующим образом: • Если товаров в заказе нет, метод немедленно возвращает соответствующее сообщение. • В противном случае он подключается к базе данных с помощью метода Oracle. getConnection(), вызывает метод DBInsert() для ввода заказа в базу данных и возвращает номер только что введенного заказа. Затем он отключается от базы данных. 3. Стоит сказать несколько слов по поводу установления соединения с баз о й д а н н ы х . М е т о д getConnection() к л а с с а oracle, sql j . runtime. Default-
Context вызывается для того, чтобы вернуть SQLJ-контекст соединения dctx. Этот контекст соединения явным образом используется в каждом последующем SQL-операторе при помощи синтаксиса #sql [dctx]. Причина применения явного контекста соединения в каждой SQL-операции весьма интересна и неочевидна. Вспомним, что одновременно с JSP-приложением могут работать несколько пользователей, применяющих одну и ту лее виртуальную машину Java web-сервера, и для ввода заказов они могут подключаться к базе данных одновременно. Ясно, что в такой ситуации устанавливать и использовать стандартный кон текст соединения SQLJ (который реализуется исполняющей системой SQLJ через статическую переменную), нельзя, так как пользователи будут мешать друг другу подключаться. Поэтому в SQLJ-onepamopax нужно всегда применять явный контекст соединения, чтобы избежать проблем при параллельной работе пользователей. 4. И последнее замечание относительно соединений с базой данных. В этом зерне соединение с базой данных открывается и закрывается для каждого передаваемого заказа. На практике открытие и закрытие соединений — довольно ресурсоемкие операции, и число их следует сводить к минимуму. Более того, подключение каждого НТТР-сеанса может привести к слишком большому числу открытых соединений, особенно если велико число пользователей, одновременно работающих с приложением Order Online. Во избежание этого можно применять пулинг соединений (connection pooling) для совместного использования соединений с базой данных (см. ниже раздел "Оптимизация SQL-операций"). 5. Метод DBInsert() использует SQLJ для выполнения следующих операций над базой данных: • Ввод одной записи в таблицу PURCHASE_LIST для запроса на покупку. Номер запроса извлекается из последовательнрсти запросов при помощи SQL-оператора SELECT INTO, считывающего следующий порядковый номер requestno_seq. NEXTVAL. • Ввод записей в таблицу LINEITEM_LIST для каждого товара из списка заказанных, для чего используется номер запроса, ранее выбранный в последовательности запросов. Номера в ассортименте генерируются в последовательности lineno_seq.
Выполнение I n s e r t O r d e r . j s p Сначала необходимо установить программу InsertOrder. jsp на web-сервере, следуя инструкциям приложения Е. Не забудьте скомпилировать программный текст DBInsertBean.sqlj и сделать скомпилированный класс доступным web-cepверу. После этого можно будет вызывать JSP-страницу InsertOrder при помощи кнопки "Submit my order" на странице EnterOrder. jsp приложения Order Online.
338
ГЛАВА 10
О
На рис. 11.10 показан начальный экран страницы InsertOrder. jsp, выводимый после выбора товаров "Book Shelf и "Office Desk" при помощи EnterOrder. jsp. & T h o InserlOider JSP - Netscape
Начальный экран JSP-страницы InsertOrder
ESe £dit View Qo Communicator Help * Bookmarks Jfr.
Y o u h a v e s e l e c t e d : [Book Shelf Of Gee Desk]
Please fill in the following information: Employee Number: | Submit Order
Project Numb e n
I
Back to Order Entry
|
m
Document: Done
itfHH
Если теперь ввести номер служащего и номер проекта в форму, отображаемую JSP-страницей InsertOrder, а затем щелкнуть мышыо на "Submit Order", то этими двумя параметрами запроса будет создан и инициализирован экземпляр класса DBInsertBean. Вызов метода processOrder() приводит к тому, что зерно исполняет над базой данных необходимые операции INSERT, и для успешного ввода заказа генерируются выходные данные, изображенные на рис. 11.11. В этот момент можно вернуться к JSP-странице EnterOrder, щелкнув мышью на кнопке "Back to Order Entry". Рис. 11.11. Конечный экран JSP-страницы InsertOrder после успешной передачи заказа
g t The InseilOrdei J S P - Netscape Eite Edit Wew Go Communicator IJelp
>4* Back
^ F'oiwaid
Reload
^^BooUarks-A"
Home
Search
(al Netscape
^ Print
i Security
Go Io:
Ш Step t j ^ ' W h a t ' s Rdated
Ready to Order! Y o u h a v e s e l e c t e d : [Book Shelf Office Desk]
Result of processing order: Purchase order processed successfully! Your request number is: 502
Back to Order Entry
HI)- [
|
| Document Done
Исполнение статических SQL-запросов Итак, мы ввели информацию в базу данных заказов на покупку. Теперь посмотрим, как исполнять статические SQL-запросы и отображать результаты, выдаваемые JSP-страницей. В частности, для выбора характеристик заказа на покупку в базе данных воспользуемся SQLJ-итератором. Но перед созданием программы обсудим базовые концепции, касающиеся событий и интерфейсов приемников событий. Подобные интерфейсы реализуются при помощи зерен JavaBean, что позволяет эффективно применять такие общие ресурсы, как соединения с базой данных.
Использование JSP вместе с зернами JavaBean
о
События и интерфейсы приемников событий Событие (event) — это общий термин Java для механизма уведомления, в котором задействованы различные компоненты Java-приложения. Так, щелчок кнопкой мыши — это событие. С помощью механизма уведомления о событиях любой объект Java может регистрировать свою заинтересованность в одном или нескольких событиях, генерируемых другими объектами. Потом он выполняет работу, называемую прослушиванием (listening) событий. Объекты, генерирующие события, называются источниками событий (event source), а объекты, уведомляемые о событиях,— приемниками событий (event listener). Основой механизма уведомления о событиях являются методы реализации, содержащиеся в интерфейсах приемников событий (event listener interface). Каждое событие соответствует конкретному методу интерфейса, который можно реализовать при помощи класса Java. Объект приемника событий регистрирует себя в источнике, разрешая уведомление о событиях. При возникновении того или иного события объект источника событий вызывает соответствующий метод для всех объектов, зарегистрировавшихся в качестве приемников данного события. Само событие представляется объектом события, в котором содержится ссылка на источник событий, и передается в качестве параметра вызываемому методу. На рис. 11.12 приведена диаграмма модели уведомления о событиях. Приемники события
Рис. 11.12.
Приемники события
Модель событий с источниками и приемниками событий
Уведомление о событии
Источник событий
Уведомление о событии
Заметим, что модель событий не специфична для зерен JavaBean, а является общим свойством языка программирования Java. Несколько классов и интерфейсов, поддерживающих модель событий, описаны Bjava-naiceTe java. u t i l . В качестве конкретного примера рассмотрим класс JavaBean с областью действия session. Это зерно может быть заинтересовано в уведомлении о своем сохранении (привязке) в HTTP-объекте session или удалении (отмене привязки) из него, чтобы иметь возможность управлять своими ресурсами, такими, как курсоры и соединения базы данных. Для этой цели в API сервлетов описывается интерфейс приемника типа javax. servlet. http. HttpSessionBindingListener, с о д е р ж а щ и й два метода: valueBoundO и valueUnbound() — с о
следующими сигнатурами: •
public interface HttpSessionBindingListener extends java.util.EventListener { public void valueBound(HttpSessionBindingEvent event); public void valuel)nbound(HttpSessionBindingEvent event);
} Этот интерфейс приемника событий можно реализовать при помощи JavaBean с областью действия session. Метод valueBoundO вызывается, когда зерно сохраняется в HTTP-объекте session, в составе операций, выполняемых тэгом <jsp:useBean> с областью действия session. Метод valuellnbound() вызывается, когда зерно удаляется из объекта session. Вызовы методов, выполняемые во время действия зерна DBQueryBean (см. ниже), показаны на рис. 11.13. Это зерно для своего уведомления о событиях,
340
ГЛАВА 10
О
имеющих отношение к сеансу, реализует интерфейс HttpSessionBindingListener. Предположим, что с помощью тэга <jsp: useBean> создается экземпляр зерна с областью действия session. Он автоматически привязывается к HTTP-объекту session (вызовом метода session.setAttribute()). Операция привязки приводит к вызову метода valueBoundO зерна через интерфейс приемника событий. После этого JSP-страница может обращаться к экземпляру зерна и вызывать такие его методы, как queryOrder(). При завершении HTTP-сеанса (например, методом session, invalidate()) или при явном удалении ссылки на зерно из сеанса (методом session. remove()) для зерна вызывается метод valueUnbound(). Кроме того, в зерне может присутствовать метод finalize(), вызываемый после уничтожения экземпляра зерна. Рис. 11.13. JavaBean с областью действия session, прослушивающее события сеанса
Для чего нужно реализовывать в зерне специальные сеансовые методы приемника? Почему бы ни закрыть соединение с базой данных методом finalize() зерна, который бы вызывался во время "уборки"? Обычно считается, что это проще программировать. Но это не так. Действие метода finalize() не вполне совпадает с действием методов приемника сеанса. Если быть более точным, то действие интерфейса приемника гораздо лучше определено по сравнению с методом finalize(). Естественно, после завершения НТТР-сеанса ссылка на зерно с областью действия session становится недоступной. Скорее всего, после этого будет проводиться очистка ("уборка") зерна, для чего вызывается метод finalize(). Однако частота очистки зависит от расходования оперативной памяти во всей виртуальной машине Java, где исполняется одно или несколько приложений. Таким образом, неясно, когда зерно будет очищаться на самом деле, и до этого момента соединение с базой данных будет оставаться открытым. С точки зрения эффективности работы, удерживать соединение в течение неизвестного времени недопустимо. Именно с этой целью в интерфейсах приемников HTTP-сеансов хорошо описаны с редства обратного вызова для уведомления о событиях.
Создание DBQueryBean. sqlj Теперь создадим зерно DBQueryBean, которое с помощью статического SQL-запроса считывает характеристики конкретного заказа в базе данных заказов
Использование JSP вместе с зернами JavaBean
о
на покупку. Это зерно реализует интерфейс приемника событий НТТР-сеанса, освобождая соединение с базой данных по завершении сеанса или по окончании срока его действия. SQL-запрос в DBQueryBean выполняется на основании свойства requestNum зерна, после чего результаты запроса форматируются для отображения в браузере. Следует сделать два важных замечания относительно логики этого зерна: • Оно реализует интерфейс javax.servlet. http. HttpSessionBindingListener и предназначено для использования в области действия session. • Оно помнит контекст SQLJ-соединения в течение HTTP-сеанса, применяя для этого переменную экземпляра dctx. Соединение с базой данных, представляемое переменной dctx, закрывается при вызове метода valuellnbound() приемника событий. Приведем текст программы DBQueryBean. sqlj: •
/ * * Имя программы: ** Назначение: **
DBQueryBean.sqlj Считать информацию о заказе из базы данных Purchase Order с помощью SQLJ.
public class DBQueryBean implements HttpSessionBindingListener { / / (см. пояснение 1) String requestNum = null; / / (см. пояснение 2) / / Метод для установки свойства requestNum public synchronized void setRequestNum(String requestNum) { this.requestNum = requestNum; result = null;
/ / результат запроса / / контекст соединения с базой данных
/ / Метод для считывания характеристик заказа public synchronized String queryOrder() { / / (см. пояснение 3) i f (result != n u l l ) / / такой запрос уже выполнялся, поэтому / / воспользуемся его результатом! return r e s u l t . t o S t r i n g O ; try { / / При необходимости подключимся к базе данных i f (dctx == n u l l ) dctx = Oracle.getConnection("jdbc:oracle:oci8:@", "jspuser", " j s p " ) ; / / (см. пояснение 4) / / Запросим заказ в таблицах базы данных DBQueryO; return r e s u l t . t o S t r i n g O ; / / Но не будем закрывать соединение с базой данных! } catch (SQLException е) { return("Error in querying: " + e.getMessageO);
}
}
/ / Объявление SQLJ-итератора для пунктов ассортимента
341
/ / (см. пояснение 5) #sql i t e r a t o r Lineltems ( i n t lineno, i n t projectno, i n t quantity, String description); private Lineltems l i = null; / / Метод для выбора заказа на покупку и данных о пунктах / / ассортимента для нового заказа private String DBQueryO { i n t empNum; String empName; try { / / (см. пояснение 6) #sql [dctx] { SELECT PURCHASE_LIST.employeeno, firstname || ' ' || lastName INTO :empNum, :empName FROM PURCHASE_LIST, EMPLOYEE_LIST WHERE requestno = :requestNum AND EMPLOYEE_LIST.employeeno = PURCHASE_LIST.employeeno
}; result = new StringBuffer(); result.append("Employee: " + empName + , number: " + empNum + "
"); / / Теперь запросим пункты ассортимента для заказа / / (см. пояснение 7) 4 ftsql [dctx] l i = { SELECT lineno, projectno, quantity, description FROM LINEITEM_LIST WHERE requestno = :requestNum
};
formatHTML() ; I i . c l o s e ( ) ; / / закроем итератор return r e s u l t . t o S t r i n g ( ) ; } catch (SQLException e) { return("Error on DB Query: " + e.getMessageO);
}
}
private void formatHTMLO throws SQLException { / / . ( с м . пояснение i f ( l i == n u l l / / ! l i . n e x t ( ) ) { result.append("
No matching rows.
\n"); return;
} / / Распечатаем заголовок таблицы с характеристиками заказа result.append("
\n"); result.append("
Line #
"); result.append("
Project #
"); result.append("
Quantity < / l x / T H > " ) ; result.append(" Description < / l x / T H > " ) ; do { / / Распечатаем данные для каждого заказанного товара result.append("
\n"); result.append("
" + l i . l i n e n o O + "
"); result.append("
" + l i . p r o j e c t n o O + "
"); result.append("
" + l i . q u a n t i t y O + "
"); result.append("
" + l i . d e s c r i p t i o n ( ) + "
"); result.append("
");
Использование JSP вместе с зернами JavaBean
о
} whiLe ( l i . n e x t O ) ; result.append("
");
} / / (см. пояснение 9) / / Метод, исполняемый при запуске НТТР-сеанса public void valueBound(HttpSessionBindingEvent event) { / / Здесь ничего не делаем! / / Соединение с базой данных будет открыто только при передаче запроса.
} / / Метод, исполняемый при выходе из НТТР-сеанса public synchronized void valueUnbound(HttpSessionBindingEvent event) { i f (dctx != null) { t r y { dctx.close(); } catch (SQLException e) {}
}
}
}
Пояснения к DBQueryBean.sqlj: 1 . DBQueryBean р е а л и з у е т интерфейс HttpSessionBindingListener и д о л ж н о вы-
зываться посредством тэга <jsp: useBean> с областью действия session. JSP-страница QueryOrder (см. ниже) использует экземпляр этого зерна с областью действия session.
2. DBQueryBean имеет одно свойство с именем requestNum, которое представляет номер запрашиваемого заказа. Метод setRequestNum() служит для установки значения этого свойства. Кроме того, данный метод сбрасывает результат любого ранее исполнявшегося запроса. 3. JSP-страница QueryOrder будет вызывать метод queryOrder() зерна, если пользователь укажет параметр поиска (т.е. номер заказа) в HTML-форме. Поэтому для минимизации продолжительности соединения зерно не подключается к базе данных с помощью своего метода valueBound(), который вызывается при создании зерна и его привязке к HTTP-объекту session. Вместо этого соединение с базой данных открывается методом queryOrder() при его первом вызове с номером запроса. Это соединение продолжает быть открытым в течение оставшегося срока действия зерна, что определяется длительностью НТТР-сеанса. Другой возможный подход — поместить тэг < j sр: useBean> в условг ..> логическую конструкцию, исполняемую только при первом вводе номера запроса, и открыть соединение с базой данных при создании экземпляра зерна. 4. Этот оператор устанавливает контекст SQLJ-соединения с номои;ыо драйвера JDBC-OCI. 5. Этот оператор объявляет указанный SQLJ-итератор для считывания информации о пунктах ассортимента. 6. SQLJ-оператор SELECT INTO используется для считывания номера и имени служащего, соответствующего заказу. 7. Экземпляр итератора Lineltems заполняется соответствующим SQL-запросом с помощью значения свойства requestNum. 8. Метод formatHTML() форматирует результаты запроса в виде HTML- таблицы с соответствующими заголовками столбцов. 9. Обратите внимание на то, что зерно реализует два метода интерфейса HttpSessionBindingListener: valueBoundO и valueUnbound(). М е т о д value-
BoundO вызывается при создании зерна и его связывании с НТТР-сеансом. Однако совсем не обязательно, чтобы этот метод выполнял какието действия, так как соединение с базой данных открывается только при передаче запроса. Метод valueUnbound() закрывает соединение с базой данных, если значение не равно null.
343
344
ГЛАВА 11
О С о з д а н и е QueryOrder. j s p
Теперь можно написать программу QueryOrder. jsp, н которой используется описанный выше класс DBQueryBean. Область действия этого зерна — session, т а к как о н о р е а л и з у е т интерфейс HttpSessionBindingListener.
Программный
текст JSP-страницы приводится ниже, причем важные его участки выделены жирным шрифтом. Вам должны быть понятны общие закономерности JSP-логики. HTML-форма применяется для получения от пользователя номера запроса. Если номер не равен null, вызывается метод queryOrder() экземпляра DBQueryBean, отображая характеристики конкретного заказа. •
<%-- Имя программы: QueryOrder..jsp -- Назначение: Ввести номер заказа и запросить его характеристики в базе данных заказов на покупку. <jsp:useBean id="queryBean" class="mybeans.DBQueryBean" scope="session" /> <jsp:setProperty name="queryBean" property="reguestNum" /> <TITLE> The Query Order JSP <% String requestNum = request.getParameter("requestNum"); i f (requestNum l= n u l l ) { X>
Details of order number: <%= requestNum %>
<X = queryBean.queryOrder() X> <% } %>
Enter an order number:
Выполнение QueryOrder. jsp Необходимо установить на web-сервере JSP-программу QueryOrder и скомпилированный класс DBQueryBean (см. приложение Е). После этого можно будет вызывать JSP, указывая соответствующий URL. На рис. 11.14 представлены выходные данные запроса для заказа №502, полученные с помощью JSP-стран и ц ы QueryOrder.
Результат считывания заказа посредством QueryOrder. jsp
LlDlxl £te
View £o
£ommuriicatof
ЫФ
• ••"•'ll'r'-fft ..,•!/•
~
Details of order number: 502 Employee: Sheila Mistik , number: 111
Enter an order number: Submit Query
|
Использование JSP вместе с зернами JavaBean
О Исполнение динамических SQL-запросов В примере с QueryOrder. jsp SQL-запрос статичен. Другими словами, во время разработки программы известно, какие столбцы каких таблиц нужно считывать и какими условиями поиска пользоваться в SQL-операторе SELECT. В некоторых приложениях до этапа выполнения программы доступна не вся информация. В этих случаях необходимо применять API JDBC, так как в SQLJ исполняются только статические SQL-запросы и операции обновления. Напомним, что конструкции SQLJ и JDBC способны взаимодействовать друг с другом, поэтому в приложении их можно смешивать в любых комбинациях. В этом разделе мы напишем JavaBean, использующее JDBC для выполнения динамического SQL-запроса. Это зерно, создаваемое как класс DynamicQueryBean, будет применяться в качестве компонента в программе AnyQuery. jsp для динамического исполнения любого SQL-запроса, указываемого в HTML-форме. Сначала разработаем JavaBean, а затем напишем страницу AnyQuery. jsp, вызывающую это зерно.
С о з д а н и е DynamicQueryBean. j a v a Функцией этого зерна запросов является исполнение любого запроса, обращенного к базе данных Purchase Order. Текст программы приводится ниже, причем важные участки выделены жирным шрифтом. Заметим, что это зерно, как и созданная в предыдущем разделе программа DBQueryBean. sqlj, реализует интерфейс HttpSessionBindingListener. Таким образом, данное зерно будет использоваться в области действия session на JSP-странице и закрывать свое соединение с базой данных при завершении НТТР-сеанса. Главное, на что стоит обратить внимание в программе DynamicQuerybean,— это общий способ форматирования результата SQL- запроса в HTML-таблице. Данную функцию выполняет метод formatResult(), принимающий результирующее множество JDBC и генерирующий HTML-таблицу с соответствующими заголовками и строками. Более детально логика этого метода представлена в тексте программы. •
/ * * Имя программы: DynamicQueryBean.java ** Назначение: Выполнить динамический JDBC-запрос к базе ** данных Purchase Order. package mybeans; import java.sql.*; import javax.servlet.http.HttpSessionBindingListener; import javax.servlet.http.HttpSessionBindingEvent; public class DynamicQueryBean implements HttpSessionBindingListener public void DynamicQueryBean() { } private String query = ""; / / (см. пояснение 1) private String result = null; / / (см. пояснение 2) public synchronized void setQuery(String newQuery) { result = null; query = newQuery;
} / / Главный метод для получения результата запроса public String getResult() throws SQLException { / / (см. пояснение 3) i f (result != n u l l ) return result; } else return (runQuery(J); private Connection conn = null; private synchronized String runQueryO { / / (см. пояснение 4) try {
346
ГЛАВА 12 О i f (conn == null) { DriverManager.registerDriver( new oracle.jdbc.driver.OracleDriver()); conn = DriverManager.getConnection("jdbc:oracle:oci8:@", "jspuser", "jsp");
}
Statement stmt = corin.createStatement(); ResultSet rset = stmt.executeQuery (query); result = formatResult(rset)); i f (rset!= null) rset.closeO; i f (stmt!= null) stmt.closeO; return result; } catch (SQLException e) { return ("
SQL error for query:'
" + query + " " + e + "
\n");
}
}
private String formatResult(ResultSet rs) / / (см. пояснение 5) throws SQLException { StringBuffer sb = new StringBuffer(); i f (rs == null 11 ! rs.nextO) { sb.append("
No matching rows found.
\n"); return sb.toStringO;
}
sb.append("
\n"); ResultSetMetaData md = rs.getMetaDataO; i n t numCols = md.getColumnCountO; for ( i n t i=1; i<= numCols; i++) { sb.append("
" + md.getColumnLabel(i) + "
");
}
sb.append("
\n"); for ( i n t i = 1; i <= numCols; i++) { sb.append("
"); Object obj = rs.getObject(i); i f (ooj != n u l l ) sb.append(obj.toStringO); sb.append("
");
}
}
Sb.append("
"); } while (rs.nextO); sb.append("
"); return sb.toStringO;
/ / Метод, исполняемый при запуске сеанса public void valueBound(HttpSessionBindingEvent event) { / / Здесь ничего не делается. Зерно создается только при передаче запроса.
}
/ / Метод, исполняемый при выходе из сеанса public synchronized void valueUnbound(HttpSessionBindingEvent event) {
}
try { i f (conn != n u l l ) conn.closeO; / / (см. пояснение 6) } catch (SQLException e) { }
Использование JSP вместе с зернами JavaBean
о
П о я с н е н и я к DynamicQueryBean. j a v a : 1. З е р н о DynamicQueryBean и м е е т одно с в о й с т в о с и м е н е м query. Э т о свойство п р е д с т а в л я е т т е к с т и с п о л н я е м о г о S Q L - з а п р о с а и у с т а н а в л и в а е т с я пользователем в HTML-форме. 2. Л о к а л ь н а я п е р е м е н н а я result с о д е р ж и т результат, в о з в р а щ а е м ы й пред ы д у щ и м з а п р о с о м (если з а п р о с и с п о л н я л с я ) . Э т о з н а ч е н и е к э ш и р у е т с я зерном, чтобы его м о ж н о было п о в т о р н о использовать при исполнен и и т а к о г о ж е з а п р о с а . С л е д о в а т е л ь н о , м е т о д setQuery() д е л а е т к э ш и р о в а н и ю копию результата недостоверной, устанавливая для нее значение null. 3 . М е т о д getResult() — э т о о б щ и й метод, к о т о р ы й в ы з ы в а е т с я д л я исполн е н и я запроса и выдачи результата, ф о р м а т и р о в а н н о г о в виде HTMLтаблицы. Метод возвращает кэшированный результат запроса, если тот доступен (остался от предыдущего исполнения с тем же параметром з а п р о с а ) , и л и в ы з ы в а е т м е т о д runQueryO з е р н а . 4. М е т о д runQueryO — частный м е т о д , к о т о р ы й с о д е р ж и т р е а л ь н ы й т е к с т п р о г р а м м ы и с п о л н е н и я з а п р о с а . С п о м о щ ь ю J D B C о н о т к р ы в а е т соедин е н и е с б а з о й д а н н ы х (если о н о е щ е н е о т к р ы т о ) , а з а т е м , п о с л е получения описателя о п е р а т о р а для соединения, исполняет запрос, создавая результирующее множество данных. Результирующее множество форм а т и р у е т с я м е т о д о м formatResult(). 5. М е т о д formatResult() и н т е р е с е н с т о ч к и з р е н и я п р о г р а м м и р о в а н и я . О н принимает результирующее множество J D B C в качестве аргумента и форматирует строки в виде HTML-таблицы. Сначала он проверяет, не пусто л и р е з у л ь т и р у ю щ е е м н о ж е с т в о . Если э т о так, о н в о з в р а щ а е т сообщ е н и е о т о м , ч т о н и о д н о й с т р о к и н е н а й д е н о ; в п р о т и в н о м случае о н , в ы з ы в а я м е т о д getColumnLabel() о б ъ е к т а ResultSetMetadata JDBC-apryм е н т а ResultSet, о п р е д е л я е т и м е н а с т о л б ц о в , в о з в р а щ а е м ы х з а п р о с о м . Используя эти имена, он создает заголовок HTML-таблицы. Затем он о б р а б а т ы в а е т каждую с т р о к у р е з у л ь т и р у ю щ е г о м н о ж е с т в а и ф о р м а т и рует их в виде HTML-таблицы, п р и м е н я я соответствующие HTML-тэги и вызывая метод toStringO для каждого выбираемого объекта. 6 . Н а к о н е ц , п о с л е з а в е р ш е н и я Н Т Т Р - с е а н с а м е т о д valueUnboundO интерфейса HttpSessionBindingListener з а к р ы в а е т о п и с а т е л ь J D B C - с о е д и н е н и я .
Создание AnyQuery. j s p П р о г р а м м н ы й т е к с т э т о й J S P - с т р а н и ц ы п р и в о д и т с я н и ж е . О т м е т и м , ч т о в прог р а м м е используется класс DynamicQueryBean с о б л а с т ь ю д е й с т в и я session и ч т о е г о с в о й с т в о query у с т а н а в л и в а е т с я н а о с н о в а н и и т е к с т а SQL-запроса, вводимого в т е к с т о в о й о б л а с т и H T M L - ф о р м ы . J S P п р о в е р я е т , указан л и в H T T P - з а п р о се п а р а м е т р с и м е н е м query, и, е с л и э т о так, в ы з ы в а е т м е т о д getResult() з е р н а DynamicQueryBean для и с п о л н е н и я запроса и выводит о т ф о р м а т и р о в а н н ы й результат. В т е к с т о в о й области содержится з а п р о с по умолчанию, с к о т о р о г о м о ж н о н а ч а т ь работу. Если п о л ь з о в а т е л ь в в о д и т н о в ы й з а п р о с , з а п р о с п о у м о л ч а н и ю з а м е н я е т с я текущим. •
<%-- Имя программы: - - Назначение:
AnyQuery.jsp Принять и исполнить любой пользовательский запрос, обращенный к базе данных заказов на покупку, отобразив результаты в виде HTML-таблицы.
String query = request.getParameter("query"); i f (query != null) { %>
Result of your query:
<%= queryBean.getResultO %> } %>
<%
Hello! Here you can execute any query on the Order database.
Please enter your query below:
Выполнение AnyQuery. jsp Н а р и с . 11.15 п о к а з а н р е з у л ь т а т п е р в о г о в ы з о в а с т р а н и ц ы AnyQuery. jsp. Н а экр а н е п р и с у т с т в у ю т т е к с т о в о е о к н о д л я ввода з а п р о с а , а т а к ж е з а п р о с п о умолч а н и ю , о б р а щ е н н ы й к т а б л и ц е EMPLOYEE_LIST б а з ы д а н н ы х з а к а з о в па покупку.
Рис. 11.15. Начальные выходные данные AnyQuery. jsp
Hello! Here you can execute any query on the Order database. Please enter your query below:
S E L E C T f i r s t n a m e || ' ' || lastname e m p l o y e e n o AS "Employee ff", deptno AS "Depart ft" FROM E H P L O Y E E _ L I S T WHERE 1азСname LIKE 1 A* 1 ORDER BY lastname
u 0s R R
AS
Submit Query
| Document: Done
М о д и ф и ц и р у е м з а п р о с п о у м о л ч а н и ю : и з м е н и м у с л о в и е п о и с к а в констр у к ц и и WHERE о п е р а т о р а SELECT на lastname LIKE М%. П о с л е щ е л ч к а м ы ш и на к н о п к е "Submit Query" в ы з ы в а е т с я м е т о д getResultO з е р н а DynarnicQueryBean. Э т о т м е т о д п р и п о м о щ и J D B C и с п о л н я е т т е к с т з а п р о с а , в в е д е н н ы й но в х о д н о м о к н е . Результат ф о р м а т и р у е т с я в виде H T M L - т а б л и ц ы и п о с ы л а е т с я о б р а т н о браузеру (см. р и с . 11.6). З а м е т и м , ч т о з а п р о с п о у м о л ч а н и ю в т е к с т о в о м о к н е заменен м о д и ф и ц и р о в а н н ы м запросом, который был передан.
Использование JSP вместе с зернами JavaBean
Рис. 11.16. Выходные данные AnyQuery.jsp после исполнения запроса
349
о
The AnyQueiy JSP - Netscape Efle Edit i:|
View
Qo
l ^ J f " Bookmaiks
Communicator J^
Help
Go lo: |htlp7/localhost:8080/examples/jsp/chap(er11/AnyQuery. jsp
Hello! Here you can execute any query on the Order database. Please enter your query beluw:
S E L E C T f i r s t n a m e || 1 1 || lastname e m p l o y e e n o AS " E m p l o y e e ft", d e p t n o AS "Depart ff" FROH EMPLOYEE_LIST W H E R E lastname LIKE 'H%' O R D E R BY lastname
AS
U
Submit Query
1йР|=Ф=|
!Document: Done
"'
Pl.vjfe:
Si^
ШЭ
J >«£
Зерна доступа к базам данных в Oracle JSP 1.1 В O r a c l e J S P 1.1 п р е д л а г а е т с я н а б о р з е р е н доступа к базам д а н н ы х — з а р а н е е построенных компонентов, исполняющих SQL-операции в web-приложении. Н и ж е о п и с ы в а ю т с я э т и з е р н а и с о з д а е т с я J S P - с т р а н и ц а , и с п о л ь з у ю щ а я подобное з е р н о для исполнения SQL-запроса и генерации результатов в XML.
Библиотека зерен Oracle JSP В б и б л и о т е к е зерен O r a c l e J S P с о д е р ж а т с я ч е т ы р е з е р н а J a v a B e a n . И х м о ж н о создавать и применять в разных областях действия JSP-страницы при помощи тэга <jsp: useBeanX Д л я с о е д и н е н и я с б а з о й д а н н ы х и и с п о л н е н и я SQL-операции они используют JDBC, однако многие детали SQL-исполнения скрываются з е р н а м и , и в результате ф о р м и р у е т с я и н т е р ф е й с связи с б а з о й д а н н ы х , б о л е е п р о с т о й , чем J D B C . Н а п р и м е р , зерно для у п р а в л е н и я с о е д и н е н и я м и м о ж е т авт о м а т и ч е с к и з а к р ы в а т ь с о е д и н е н и е с б а з о й д а н н ы х п р и в ы х о д е за п р е д е л ы обл а с т и с в о е г о д е й с т в и я (page, request, session или application). Т а к и м о б р а з о м , с о е д и н е н и е всегда з а к р ы в а е т с я н а д л е ж а щ и м о б р а з о м , и удается и з б е ж а т ь ошибок со с т о р о н ы п р о г р а м м и с т а . О д н о и т о ж е з е р н о с о е д и н е н и й м о ж н о использ о в а т ь в р а з н ы х о б л а с т я х д е й с т в и я , поскольку класс з е р н а р е а л и з у е т интерфейс oracle.jsp.event.JspScopeListener — о б щ и й м е х а н и з м п р и е м н и к о в с о б ы т и й , п о д д е р ж и в а е м ы й в O r a c l e J S P для р а з н ы х о б л а с т е й д е й с т в и я . В п а к е т е oracle, jsp. d b u t i l , в х о д я щ е м в с о с т а в б и б л и о т е к O r a c l e J S P 1.1 (ojsputil. jar), доступны следующие зерна: •
ConnBean И с п о л ь з у е т с я д л я у с т а н о в л е н и я п р о с т о г о с о е д и н е н и я с б а з о й д а н н ы х б е з пулинга с о е д и н е н и й .
•
ConnCacheBean И с п о л ь з у е т с р е д с т в а к э ш и р о в а н и я с о е д и н е н и й O r a c l e для э ф ф е к т и в н о г о р а з д е л е н и я с о е д и н е н и й с базой д а н н ы х среди нескольких п о л ь з о в а т е л е й .
•
DBBean П р и м е н я е т с я д л я и с п о л н е н и я з а п р о с а , о б р а щ е н н о г о к б а з е д а н н ы х , и д л я в ы в о д а р е з у л ь т а т о в и л и в в и д е H T M L - т а б л и ц ы , и л и с помощью XML.
350
ГЛАВА 12
О •
CursorBean М о ж е т в ы з ы в а т ь х р а н и м ы е п р о ц е д у р ы и и с п о л н я т ь S Q L - о п е р а т о р ы D M L (UPDATE, INSERT и DELETE), а т а к ж е S Q L - з а п р о с ы .
В с л е д у ю щ е м р а з д е л е г о в о р и т с я о п р и м е н е н и и DBBean. Э т о з е р н о м о ж е т подключаться к базе данных и исполнять SQL-операции. О н о э ф ф е к т и в н о управляет соединением, закрывая его автоматически п р и выходе из области с в о е г о д е й с т в и я . Д р у г и м п о л е з н ы м с в о й с т в о м DBBean я в л я е т с я в о з м о ж н о с т ь получения результата SQL-запроса в ф о р м а т е XML. Н и ж е предлагается обзор X M L , а з а т е м с о з д а е т с я J S P - с т р а н и ц а , и с п о л ь з у ю щ а я DBBean для г е н е р а ц и и XML-текста. З а т е м будет п р и в е д е н п р и м е р с т а н д а р т н о г о з е р н а ConnCacheBean, к о т о р о е и с п о л ь з у е т с я для у п р а в л е н и я р а з д е л я е м ы м пулом с о е д и н е н и й .
Генерация XML-страниц с помощью JSP-страниц и зерен JavaBean С п е ц и ф и к а ц и я JSP поддерживает создание XML-страниц при помощи страниц JSP. Д л я к а ж д о г о JSP-тэга существует о б о з н а ч е н и е , с о в м е с т и м о е с X M L (см. главу 10), п о э т о м у J S P - с т р а н и ц ы м о ж н о создавать, п р и м е н я я у д о б н ы е инструмент а л ь н ы е средства XML. В ы х о д н ы е д а н н ы е , г е н е р и р у е м ы е J S P - с т р а н и ц е й , т а к ж е могут б ы т ь XML-текстом. Ч т о ж е т а к о е X M L и д л я ч е г о е г о используют?
Общее представление о XML X M L р а с ш и ф р о в ы в а е т с я как Extensible Markup Language ( р а с ш и р я е м ы й я з ы к р а з м е т к и ) . О н о с н о в а н на с т а н д а р т н о м о б о б щ е н н о м я з ы к е р а з м е т к и (SGML, S t a n d a r d G e n e r a l i z e d M a r k u p L a n g u a g e ) , к о т о р ы й п р и м е н я л с я на. п р о т я ж е н и и р я д а л е т д л я с о з д а н и я д о к у м е н т о в о б щ е г о х а р а к т е р а . X M L — у п р о щ е н н ы й вар и а н т SGML, в к о т о р о м у с т р а н е н ы н е к о т о р ы е с л о ж н ы е с в о й с т в а . Т е м н е мен е е X M L в о м н о г о м с о х р а н и л м о щ ь SGML, будучи р а с ш и р я е м ы м (в о т л и ч и е от H T M L , который имеет предопределенный набор тэгов). Это значит, что в документе XML можно описать свои собственные тэги (называемые также элементами ( e l e m e n t ) ) и с и н т а к с и ч е с к и е п р а в и л а д л я н и х , в о с п о л ь з о в а в ш и с ь описанием типа документа (DTD, d o c u m e n t type d e f i n i t i o n ) . D T D м о ж н о прим е н я т ь д л я п р о в е р к и XML-документа на " о р г а н и з о в а н н о с т ь " и н а д о с т о в е р н о с т ь п р и п о м о щ и синтаксического анализатора ( p a r s e r ) X M L — п р о г р а м м ы , к о т о р а я с ч и т ы в а е т XML-документ и п р и м е н я е т с и н т а к с и ч е с к и е п р а в и л а п о отношению к конструкции элементов. Т э г и в X M L и с п о л ь з у ю т с я д л я о п и с а н и я и е р а р х и ч е с к о й с т р у к т у р ы докум е н т а , к о т о р а я м о ж е т и м е т ь п р о и з в о л ь н у ю глубину. Н а п р и м е р , з а к а з на покупку м о ж н о п р е д с т а в и т ь в X M L следующей с т р у к т у р о й с в л о ж е н и я м и : •
<employeeInfo> <employeeName> name <employeeNumber> 1234 1 XXX 123 <description> This item is for XXX purpose. 2 YYY 345 <description> This item is for YYY purpose.
Использование JSP вместе с зернами JavaBean
о
К а к в и д и м , XML-документ и м е е т и е р а р х и ч е с к у ю , и л и д р е в о в и д н у ю , структуру. Т э г "верхнего" у р о в н я п р е д с т а в л я е т э л е м е н т заказа н а покупку. О н з а в е р ш а е т с я с о о т в е т с т в у ю щ и м к о н е ч н ы м т э г о м . В э л е м е н т е зак а з а п р и с у т с т в у ю т д в а в л о ж е н н ы х э л е м е н т а , employeelnfo и i t e m L i s t , к о т о р ы е в свою очередь содержат другие субэлементы. Отметим, что элемент item п о в т о р я е т с я в т э г е i t e m L i s t д л я к а ж д о г о п у н к т а ( т о в а р а ) в з а к а з е н а покупку. Э л е м е н т т и п а q u a n t i t y — э т о п р о с т о е ц е л о е ч и с л о б е з с у б э л е м е н т о в . Т а к и е э л е м е н т ы н а з ы в а ю т с я листовыми (leaf), о н и х р а н я т р е а л ь н ы е д а н н ы е в X M L - д о к у м е н т е . Нелистовые ( n o n - l e a f ) э л е м е н т ы о п и с ы в а ю т структуру с в л о ж е н и я м и и могут с о д е р ж а т ь в н у т р и с е б я д р у г и е л и с т о в ы е и н е л и с т о в ы е элементы. В о т л и ч и е о т H T M L , XML-документ н е всегда с о д е р ж и т и н ф о р м а ц и ю ф о р м а т и р о в а н и я , т.е. в X M L н е т о п и с а н и я ш р и ф т о в и л и ц в е т о в , с п о м о щ ь ю котор ы х следует о т о б р а ж а т ь э л е м е н т . Э т о п о з в о л я е т о т д е л и т ь с о д е р ж и м о е о т с р е д с т в п р е д с т а в л е н и я . В о з н и к а е т в о п р о с : как ж е о т о б р а ж а е т с я XML-докум е н т б р а у з е р о м ? Д л я э т о г о с л у ж и т п р и л о ж е н и е таблиц стилей (style sheets) XSL. XSL р а с ш и ф р о в ы в а е т с я как Extensible Stylesheet Language ( р а с ш и р я е м ы й я з ы к т а б л и ц с т и л е й ) , и его с п е ц и ф и к а ц и я д о п о л н я е т стандарт XML. XSL — м о щ н ы й инструмент преобразования и ф о р м а т и р о в а н и я древовидной структуры с п р а в и л а м и с о о т в е т с т в и я ш а б л о н а м , п р и м е н я е м ы й д л я о б р а б о т к и XML-элем е н т о в и для о п и с а н и я ф о р м а т а их в и з у а л ь н о г о п р е д с т а в л е н и я в б р а у з е р е . Благодаря своей гибкости и расширяемости, XML быстро завоевал огромную популярность. Т е п е р ь это стандарт W3C (World Wide Web Consort i u m — а с с о ц и а ц и я W o r l d W i d e W e b ; д о м а ш н и й с а й т www.w3.org). Т е х н о л о г и я X M L п р и м е н я е т с я все б о л ь ш и м и б о л ь ш и м ч и с л о м к о м п а н и й д л я с а м ы х разных целей: от представления структурированных данных до п р о т о к о л о в п е р е д а ч и с о о б щ е н и й . В н е в с я к о г о с о м н е н и я , в будущем е е и с п о л ь з о в а н и е будет р а с ш и р я т ь с я .
С о з д а н и е XMLQuery. j s p И н т е р е с н ы м а с п е к т о м п р и л о ж е н и й баз д а н н ы х я в л я е т с я с п о с о б reii' и а ц и и с т р у к т у р и р о в а н н о г о X M L - п р е д с т а в л е н и я р е з у л ь т а т о в SQL-запроса. В O r a c l e п р е д л а г а е т с я н е с к о л ь к о у т и л и т для п о д о б н о й X M L - г е н е р а ц и и и д л я р а б о т ы с XML-документами. XML-утилиты O r a c l e с к о м п о н о в а н ы в виде и н с т р у м е н т а р и я р а з р а б о т ч и к а O r a c l e X M L Developer's Kit (XDK), к о т о р ы й м о ж н о з а г р у з и т ь с web-сайта с е т и O r a c l e T e c h n o l o g y N e t w o r k ( t e c h n e t . o r a c l e . c o m / t e c h / x m l ) . В состав X D K в х о д я т с и н т а к с и ч е с к и й а н а л и з а т о р XML, X S L - п р о ц е с с о р и у т и л и т а O r a c l e XML-SQL д л я г е н е р а ц и и XML-данных и з р е з у л ь т и р у ю щ и х м н о ж е с т в J D B C . У т и л и т а O r a c l e XML-SQL и с п о л ь з у е т с я з е р н а м и доступа к базам д а н н ы х ( н а п р и м е р , DBBean) для п р о з р а ч н о г о п р е о б р а з о в а н и я SQL-результатов в XML, когда с к р ы в а ю т с я м н о г и е д е т а л и X M L - г е н е р а ц и и . Р а с с м о т р и м п р и м е р J S P - с т р а н и ц ы , г е н е р и р у ю щ е й XML-результаты д л я SQL-запроса п р и п о м о щ и DBBean. П р и в о д и м а я н и ж е J S P - п р о г р а м м а XMLQuery. jsp и с п о л ь з у е т э к з е м п л я р класса DBBean (см. в ы ш е ) с о б л а с т ь ю д е й с т в и я раде д л я и с п о л н е н и я з а п р о с а , вводим о г о в т е к с т о в о м о к н е в H T M L - ф о р м е . В а ж н ы е участки п р о г р а м м ы в ы д е л е н ы жирным шрифтом. •
<%-- Имя программы: XMLQuery.jsp - - Назначение: Сгенерировать XML-результаты для SQL-запроса. --%>
О <TITLE> XMLQuery JSP <% String query = request.getParameter("query"); i f (query != null) { %>
Result of your query in XML:
<% dbbean.connect(); / * подключимся к базе данных * / %>
<%= dbbean.getResultAsXMLString(query) %>
<% dbbean.close(); / * закроем соединение с базой данных */ } %>
Please enter your query below:
CTEXTAREA NAME="query" rows="8" cols="50"> <% i f (query != null ) { %> <%= query %> <% } else { %> SELECT firstname || ' || lastname AS "Name", employeeno AS "Employee #", deptno AS "Depart tt" FROM EMPLOYEE_LIST WHERE lastname LIKE 'A%' ORDER BY lastname <% } %>
З е р н о DBBean и м е е т т р и свойства: user, password и U R L , к о т о р ы е , как правил о , о б я з а т е л ь н ы для у с т а н о в л е н и я с о е д и н е н и я с б а з о й д а н н ы х . Э т и с в о й с т в а з а д а ю т с я о б ы ч н о в ы з о в а м и <j sp: setProperty> и л и , ч т о р е ж е , м е т о д а м и set напрямую. Если в п а р а м е т р а х з а п р о с а (request) е с т ь SQL-запрос (query), соединен и е с б а з о й д а н н ы х у с т а н а в л и в а е т с я п р и п о м о щ и м е т о д а dbbean. connect(). Д л я и с п о л н е н и я S Q L - з а п р о с о в п р и м е н я ю т с я два м е т о д а э т о г о з е р н а с с и г н а т у р а м и : •
String getResultAsHTMLTable(String queryText); String getResultAsXMLString(String queryText); П е р в ы й м е т о д и с п о л н я е т з а п р о с и ф о р м а т и р у е т с т р о к и в в и д е HTML-таблицы (используя алгоритм, схожий с алгоритмом описанного выше зерна DynamicQueryBean). И м е н а и л и п с е в д о н и м ы S Q L - с т о л б ц о в с т а н о в я т с я з а г о л о в ками столбцов HTML-таблицы. Второй метод также исполняет запрос, но ф о р м а т и р у е т с т р о к и в XML-виде. И м е н а и л и п с е в д о н и м ы S Q L - с т о л б ц о в становятся тэгами XML. В п р о г р а м м е XMLQuery. jsp для и с п о л н е н и я з а п р о с а п о л ь з о в а т е л я над б а з о й д а н н ы х з а к а з о в на покупку в ы з ы в а е т с я в т о р о й м е т о д — getResultAsXMLString(), г е н е р и р у ю щ и й в ы х о д н ы е д а н н ы е X M L . В з а к л ю ч е н и е с о е д и н е н и е с б а з о й данн ы х з а к р ы в а е т с я м е т о д о м dbbean. close(). К р о м е т о г о , э к з е м п л я р DBBean закрывает с о е д и н е н и е а в т о м а т и ч е с к и (если о н о е щ е не з а к р ы т о ) , когда и с п о л н е н и е J S P - с т р а н и ц ы з а в е р ш а е т с я и о н в ы х о д и т из о б л а с т и с в о е г о д е й с т в и я .
Выполнение XMLQuery. jsp У с т а н о в и т е J S P - с т р а н и ц у на w e b - с е р в е р е и н е забудьте д о б а в и т ь б и б л и о т е к у o j s p u t i l . j a r из O r a c l e J S P 1.1, а т а к ж е xsu12. j a r (для J D K 1.2) и л и xsu111. j a r (для J D K 1.1) в CLASSPATH. П о с л е д н и е б и б л и о т е к и в х о д я т в с о с т а в O r a c l e X D K ( к о т о р ы й молено з а г р у з и т ь с с а й т а t e c h n e t . o r a c l e . c o m с е т и O r a c l e T e c h nology N e t w o r k ) , O r a c l e 8.1.7 и O r a c l e I n t e r n e t A p p l i c a t i o n Server. П р и в ы з о в е XMLQuery. jsp с о з д а е т с я H T M L - с т р а н и ц а с в с т р о е н н ы м в н е е XML-блоком. И с х о д н ы й текст с т р а н и ц ы , г е н е р и р у е м о й п р и и с п о л н е н и и XMLQuery. jsp. п р и в е д е н в л и с т и н г е 11.2, у ч а с т к и с X M L в ы д е л е н ы ж и р н ы м шрифтом.
Н а э т о й с т р а н и ц е , г е н е р и р у е м о й п р о г р а м м о й XMLQuery. j s p , о п е р а т о р огмс ч а е т н а ч а л о X M L - д а н н ы х . Э л е м е н т " в е р х н е г о " у р о в н я , ф о р м и р у е м ы й д л я р е з у л ь т а т а , п о у м о л ч а н и ю н а з ы в а е т с я R0WSET, а к а ж д а я в л о ж е н н а я с т р о к а — ROW. С т р о к и н у м е р у ю т с я п о п о р я д к у , д л я ч е г о и с п о л ь з у е т с я а т р и б у т пит э л е м е н т а ROW. Э т о р е ж и м р а б о т ы п о у м о л ч а н и ю с л у ж е б н ы х п о д п р о г р а м м O r a c l e XML-SQL. Б р а у з е р ( н а п р и м е р , N e t s c a p e 4.6), в о з м о ж н о , н е о т о б р а з и т какие-то и з XML-тэгов на г е н е р и р у е м о й с т р а н и ц е , т а к как н е п о н и м а е т о б о з н а ч е н и я XML. Д л я ф о р м а т и р о в а н и я XML-результата в в и д е H T M L - т а б л и ц ы д л я б р а у з е р а используются т а б л и ц ы с т и л е й XSL. Таблицу с т и л е й м о ж н о п р и м е н и т ь нескольк и м и способами. О д н и м из способов, п р и ч е м весьма удобным, я в л я е т с я использ о в а н и е с п е ц и а л ь н о г о т э г а <jml: transform> и з O r a c l e J S P 1.1 (см. главу 12).
Оптимизация SQL-операций В ы ш е г о в о р и л о с ь об э ф ф е к т и в н о м и с п о л ь з о в а н и и в w e b - п р и л о ж е н и и з е р е н JavaBean для п р о г р а м м и р о в а н и я о п е р а ц и й , в ы п о л н я е м ы х над базой данных. В настоящем разделе рассматриваются вопросы, и м е ю щ и е о т н о ш е н и е к производ и т е л ь н о с т и и с п о л н е н и я S Q L - о п е р а ц и й в web-среде.
353
354
—
ГЛАВА 11
О
Web-приложения уникальны тем, что нередко одновременно обслуживают тысячи запросов в реальном времени. Время реакции web-приложения крайне в а ж н о , поскольку о н о в з а и м о д е й с т в у е т с ч е л о в е к о м , к о т о р ы й с н е т е р п е н и е м ожидает ответа. Это уникальное требование предполагает, что для построения web-приложения должны использоваться особые методы проектирования. Обсудим ряд важных вопросов, связанных с производительностью, и методы п р о е к т и р о в а н и я , взяв за о с н о в у и с п о л н е н и е S Q L - о п е р а ц и й в web-среде.
Использование готовых JDBC-операторов Если п р и каждом в ы з о в е п р и л о ж е н и е и с п о л н я е т одну и ту лее S Q L - о п е р а ц и ю с разными параметрами, постсншпое повторение анализа и оптимизации S Q L - о п е р а т о р а н е э ф ф е к т и в н о . П л а н и с п о л н е н и я S Q L - о п е р а т о р а , как п р а в и л о , не з а в и с и т о т п а р а м е т р о в п р и в я з к и , к о т о р ы е д л я S Q L - о п е р а ц и и я в л я ю т с я о б ы ч н ы м и а р г у м е н т а м и . М о ж н о с э к о н о м и т ь в р е м я , п о д в е р г н у в SQL-операт о р анализу л и ш ь однажды, а затем исполнять его снова и снова с разными параметрами привязки. Именно такой алгоритм действия обеспечивает J D B C - т и п PreparedStatement. Т и п java. sql. PreparedStatement — э т о п о д т и п т и п а java.sql.Statement, п р е д о с т а в л я ю щ и й м е т о д ы п р и в я з к и п а р а м е т р о в /утя повторного исполнения. И с п о л н я ю щ а я с и с т е м а SQLJ т о ж е п о л ь з у е т с я г о т о в ы м и о п е р а т о р а м и J D B C . В O r a c l e 8.1.6 и б о л е е с т а р ш и х в е р с и й о н и к э ш и р у ю т с я и п о в т о р н о п р и м е н я ю т с я для и с п о л н е н и я в ц и к л е . И т а к , в с я к и й р а з при использовании SQLJ автоматически применяются готовые операторы JDBC, ч т о весьма п о л е з н о . В к а ч е с т в е п р и м е р а р а с с м о т р и м S Q L - о п е р а т о р , в в о д я щ и й 100 п у н к т о в а с с о р т и м е н т а в т а б л и ц у LINEITEM_LIST б а з ы д а н н ы х з а к а з о в н а п о к у п к у . О д и н и т о т лее о п е р а т о р INSERT н е о б х о д и м о в ы п о л н и т ь в ц и к л е 100 р а з с собс т в е н н ы м и д а н н ы м и д л я к а ж д о й с т р о к и . К а к в э т о м с л у ч а е и с п о л ь з у ю т с я готовые JDBC-операторы, показывает программный фрагмент, приведенный в л и с т и н г е 11.3.
Листинг 11.3. Использование готовых JDBC-операторов •
public void insertLineItems(java.sql.Connection conn) throws java.sql.SQLException { java.sql.PreparedStatement pstmt = conn.prepareStatement( / / подготовим оператор ввода один раз "INSERT INTO LINEITEM_LIST (requestno, lineno, projectno, " + " quantity, description) VALUES( " + " ?, ?, ?, ?, ?)" ); for ( i n t i=1; i<100; i++) { / / введем 100 строк
}
/ / Привяжем значение параметров pstmt.setInt(1, requestno); pstmt.setlnt(2, i ) ; pstmt.setlnt(3, projectno); pstmt.setlnt(4, quantity[:L]); pstmt.setString(5, d e s c r i p t i o n [ i ] ) ; pstmt.executeUpdate(); / / введем строку
pstmt.close(); } О т м е т и м , ч т о о б ъ е к т г о т о в о г о о п е р а т о р а с о з д а е т с я т о л ь к о о д и н р а з метод о м рreparestatement () J D B C - с о е д и н е н и я с у к а з а н и е м S Q L - к о м а н д ы в к а ч е с т в е аргумента. С и м в о л "?" в т е к с т е S Q L - о п е р а т о р а п о з и ц и о н н о п р е д с т а в л я е т к а ж д ы й из п а р а м е т р о в п р и в я з к и . S Q L - о п е р а ц и я INSERT в ы п о л н я е т с я в ц и к л е для ввода 100 с т р о к в т а б л и ц у LINEITEM_LIST. В к а ж д о й о п е р а ц и и в в о д а и с п о л ь зуются с о б с т в е н н ы е з н а ч е н и я д л я с т о л б ц о в lineno, quantity и description. Соо т в е т с т в у ю щ и е з н а ч е н и я п р и в я з ы в а ю т с я к з а п о л н и т е л я м "?" г о т о в о г о о п е р а т о р а с п о м о щ ь ю м е т о д о в s e t l n t ( ) и s e t S t r i n g ( ) . Т и п PreparedStatement п р е д о с т а в л я е т в ы з о в ы set д л я всех т и п о в д а н н ы х , п о д д е р ж и в а е м ы х в J D B C .
Использование JSP вместе с зернами JavaBean
о
После привязки параметров готовый оператор исполняется. В последующих и т е р а ц и я х ц и к л а п о в т о р н ы й а н а л и з S Q L - к о м а н д ы в ы п о л н я т ь с я не будет.
Пакетное обновление В O r a c l e 8.1.6 и б о л е е с т а р ш и х в е р с и й S Q L - о п е р а ц и и INSERT, DELETE и UPDATE м о ж н о о б ъ е д и н я т ь в пакеты (batches) J D B C 2.0 и SQLJ. П а к е т и р о в а н и е оптим и з и р у е т работу следующим о б р а з о м : п р и вводе и л и о б н о в л е н и и д а н н ы х циклически одним оператором DML операции привязки параметров можно г р у п п и р о в а т ь л о к а л ь н о на с т о р о н е к л и е н т а , пока п а к е т не будет п о с л а н на серв е р м е т о д о м executeBatch(). П р и э т о м о п е р а т о р D M L и с п о л н я е т с я о д и н р а з с п р и в я з к о й массива с к о м п о н о в а н н ы х з н а ч е н и й п а р а м е т р о в . С л е д о в а т е л ь н о , пак е т и р о в а н и е с о к р а щ а е т ч и с л о о б р а щ е н и й к базе д а н н ы х . В API J D B C 2.0 существуют я в н ы е м е т о д ы о б ъ е к т а java.sql.Statement, п о з в о л я ю щ и е д о б а в л я т ь с т р о к и в п а к е т и и с п о л н я т ь его. П а к е т и р о в а н и е п о д д е р ж и в а е т с я и в SQLJ за с ч е т и с п о л ь з о в а н и я контекстов исполнения ( e x e c u t i o n c o n t e x t s ) . О п р е д е л е н н ы й к о н т е к с т и с п о л н е н и я указ ы в а е т с я в о п е р а т о р е tfsql и о п и с ы в а е т среду: х а р а к т е р и с т и к и п а к е т и р о в а ния и другие параметры исполнения SQLonepauHH. Для установки п а р а м е т р о в и с п о л н е н и я , в ч а с т н о с т и для р а з р е ш е н и я п а к е т и р о в а н и я и для з а д а н и я в р е м е н н о г о л и м и т а п а к е т а , в ы з ы в а ю т с я м е т о д ы э к з е м п л я р а контекста и с п о л н е н и я . О ж и д а ю щ и й п а к е т м о ж н о п о с л а т ь базе д а н н ы х я в н ы м образом, в ы з в а в м е т о д executeBatch() к о н т е к с т а и с п о л н е н и я , л и б о о н п о с ы л а е т с я н е я в н о и с п о л н я ю щ е й с и с т е м о й SQLJ п р и д о с т и ж е н и и у к а з а н н о г о р а з м е р а пак е т а и л и п р и и с п о л н е н и и п р о г р а м м о й д р у г о г о S Q L J - о п е р а т о р а . Т а к и м образом, в п р о г р а м м а х SQLJ м о ж н о п о л ь з о в а т ь с я в с е м и п р е и м у щ е с т в а м и с р е д с т в п а к е т и р о в а н и я J D B C 2.0.
Кэширование описателей операторов В O r a c l e SQLJ ( O r a c l e 8.1.6 и в ы ш е ) о б е с п е ч и в а е т с я а в т о м а т и ч е с к о е к э ш и р о вание подготовленных в JDBC описателей операторов. Другими словами, о б ъ е к т ы г о т о в ы х о п е р а т о р о в для S Q L J - о п е р а т о р о в п р о г р а м м ы SQLJ с о х р а н я ются и многократно используются, пока о т к р ы т о соединение с базой данных. J D B C - д р а й в е р ы O r a c l e 8.1.7 т а к ж е о б е с п е ч и в а ю т п р о з р а ч н о е к э ш и р о в а н и е о п е р а т о р о в , о с н о в о й к о т о р о г о я в л я е т с я схема "least recently used" (использов а в ш и й с я н а и б о л е е давно). Когда в J D B C р а з р е ш е н о к э ш и р о в а н и е о п е р а т о р о в , з а к р ы т и е о б ъ е к т а Statement н е всегда в л е ч е т за с о б о й з а к р ы т и е о с н о в н о г о курсора базы данных. Вместо этого он кэшируется, что позволяет использовать его впоследствии при исполнении такого ж е SQL-оператора. Альтернативой э т о й с х е м е я в л я е т с я п р и м е н е н и е SQL-зерна с о б л а с т ь ю д е й с т в и я session, котор о е я в н о п р и м е н я е т о п и с а т е л ь г о т о в о г о о п е р а т о р а , не з а к р ы в а я е г о в т е ч е н и е НТТР-сеанса.
Пулинг соединений Пулинг (pooling) соединений — важная технология, позволяющая оптимизир о в а т ь о б р а щ е н и е к б а з е д а н н ы х со с т о р о н ы н е с к о л ь к и х с е а н с о в web-приложения. Идея состоит в совместном использовании физических соединений и з о б щ е г о кэша, ч т о с в о д и т к минимуму з а т р а т ы на с о з д а н и е и з а к р ы т и е соед и н е н и й с б а з о й д а н н ы х , т.е. н а о п е р а ц и и , к о т о р ы е , как п р а в и л о , д о в о л ь н о р е с у р с о е м к и . З а к р ы т и е "логического" с о е д и н е н и я с б а з о й д а н н ы х на с а м о м д е л е н е з а в е р ш а е т его, а в о з в р а щ а е т ф и з и ч е с к о е с о е д и н е н и е в р а з д е л я е м ы й пул. П у л и н г с о е д и н е н и й р а с п р о с т р а н е н в с р е д е п р и к л а д н ы х с е р в е р о в , функц и о н и р у ю щ и х на с р е д н е м у р о в н е , и с л у ж и т д л я о п т и м и з а ц и и доступа к б а з е данных. В A P I J D B C 2.0 введено п о н я т и е о с н о в а н н ы х на J N D I источников данных (data s o u r c e s ) д л я п о д к л ю ч е н и я к базам д а н н ы х (в к а ч е с т в е а л ь т е р н а т и в ы JDBC-cxeме DriverManager b J D B C 1.0). К р о м е т о г о , b J D B C 2.0 о п и с а н а с т а н д а р т н а я схема пулинга с о е д и н е н и й п о с р е д с т в о м javax. sql. ConnectionPoolDataSource и связ а н н ы х с ним и н т е р ф е й с о в . Эти и н т е р ф е й с ы р е а л и з у ю т с я р а з л и ч н ы м и
355
356
ГЛАВА 12
О
JDBC-драйверами, о б е с п е ч и в а я э ф ф е к т и в н ы й пулинг с о е д и н е н и й . Д р а й в е р ы J D B C 2.0 в Oracle т а к ж е п о д д е р ж и в а ю т и н т е р ф е й с ы пулинга с о е д и н е н и й . З а д о п о л н и т е л ь н ы м и сведениями об и с т о ч н и к а х д а н н ы х и пулинге с о е д и н е н и й о б р а щ а й т е с ь к руководству "Огас1е8г J D B C Developer's G u i d e ancl Reference, Release 8.1.6" к о р п о р а ц и и Oracle.
Использование пулинга соединений в JSP Средствами пулинга с о е д и н е н и й J D B C 2.0 м о ж н о воспользоваться и в J S P - п р и л о ж е н и и . Разделяемый пул с о е д и н е н и й с базой д а н н ы х (кэш соединен и й ) связывается с о б ъ е к т о м a p p l i c a t i o n и п р и м е н я е т с я всеми НТТР-сеансами о д н о й и т о й ж е виртуальной м а ш и н ы Java. Т а к о й подход о с о б е н н о выгоден, если р а з н ы е HTTP-сеансы пользуются о д н о й и т о й же схемой базы данных, как, н а п р и м е р , в р а с с м о т р е н н о м выше п р и л о ж е н и и O r d e r Online. К р о м е того, в кэше могут присутствовать с о е д и н е н и я и для других схем. В этом случае о б ъ е к т с о е д и н е н и я с нужной схемой возвращается на о с н о в е имени, п а р о л я пользователя и и н ф о р м а ц и и U R L базы данных. Б и б л и о т е к а з е р е н в O r a c l e J S P 1.1 с о д е р ж и т с т а н д а р т н ы й к о м п о н е н т JavaBean с именем ConnCacheBean, п р е д о с т а в л я ю щ и й в о з м о ж н о с т и кэширован и я с о е д и н е н и й bJSP. Это з е р н о м о ж н о п р и м е н я т ь в области д е й с т в и я a p p l i cation web-приложения, э ф ф е к т и в н о управляя разделяемым пулом ф и з и ч е ских с о е д и н е н и й с базой данных. З е р н о обладает следующими свойствами: •
user И м я схемы в базе данных.
•
password П а р о л ь схемы.
•
URL U R L базы д а н н ы х для установления JSP-соединения.
•
maxLimit М а к с и м а л ь н о е ч и с л о о т к р ы т ы х с о е д и н е н и й с б а з о й д а н н ы х в кэше.
•
minLimit М и н и м а л ь н о е ч и с л о о т к р ы т ы х с о е д и н е н и й с б а з о й д а н н ы х в кэше.
•
stmtCacheSize Размер кэша J D B C - о п е р а т о р о в Oracle (по умолчанию о п е р а т о р ы не кэшируются).
•
cacheScheme Политика для управления кэшированием. Это свойство может иметь одно из следующих значений: DYNAMIC_SCHEME, FIXED_WAIT_SCHEME или FIXED_RETURN_NULL_SCHEME.
Эти схемы кэша реализуют р а з л и ч н ы е р е ж и м ы р а б о т ы в ситуации, когда п р е в ы ш а е т с я м а к с и м а л ь н о д о п у с т и м о е ч и с л о о т к р ы т ы х с о е д и н е н и й кэша. В с х е м е DYNAMIC_SCHEME разрев1ается, ч т о б ы ч и с л о с о е д и н е н и й пула б ы л о бол ь ш е м а к с и м а л ь н о г о числа, но все л и ш н и е ф и з и ч е с к и е с о е д и н е н и я закрываются, если с в о б о д н о л о г и ч е с к о е . В схеме FIXED_WAIT_SCHEME п р и д о с т и ж е н и и м а к с и м а л ь н о г о ч и с л а о т к р ы т ы х с о е д и н е н и й з а п р о с на н о в о е с о е д и н е н и е н е у с т а н а в л и в а е т его, а ж д е т , п о к а не о с в о б о д и т с я с у щ е с т в у ю щ е е . В с х е м е FIXED_RETURN_NULL_SCHEME при д о с т и ж е н и и максимального числа возвращается null-соединение, пока не освободятся какие-либо с о е д и н е н и я . Класс o r a c l e , j s p . d b u t i l . ConnCacheBean р а с и ш р я е т класс Oracle J D B C с именем o r a c l e , jdbc. pool.OracleConnectionCachelmpl, к о т о р ы й , в свою очередь, р а с ш и р я е т класс Oracle J D B C с именем o r a c l e , jdbc. pool. OracleDataSource. Класс ConnCacheBean наследует р я д свойств и их методы доступа из класса oracle.jdbc.pool.OracleDataSource: databaseName, dataSourceName, d e s c r i p t i o n , networkProtocol, portNumber, serverName и d n v e r T y p e . За д о п о л н и т е л ь н ы м и с в е д е н и я м и об этих с в о й с т в а х и с е м а н т и к е их и с п о л ь з о в а н и я о б р а щ а й т е с ь к руководству "Огас1е8г J D B C Developer's G u i d e a n d R e f e r e n c e , Release 8.1.6" корпорации Oracle. Применение ConnCacheBean иллюстрируется программой ConnectlonCaching. jsp, п р и в е д е н н о й в л и с т и н г е 11.4. Сначала JSP устанавливает свойства MaxLimit, CacheScheme, user, password и URL в нужные з н а ч е н и я . В д а н н о й п р о г р а м м е это п о с т о я н н ы е с т р о к и символов, н о о н и могут устанавливаться и на о с н о в а н и и п а р а м е т р о в HTTP-запроса. Метод connCacheBean. getConnection() вызывается для получения л о г и ч е с к о г о с о е д и н е н и я в кэше. П о с л е этого создается
Использование JSP вместе с зернами JavaBean
о
о п е р а т о р и и с п о л н я е т с я з а п р о с . П о с л е п е ч а т и р е з у л ь т а т о в з а п р о с а результ и р у ю щ е е м н о ж е с т в о и о б ъ е к т ы о п е р а т о р а з а к р ы в а ю т с я . С о е д и н е н и е зак р ы в а е т с я в ы з о в о м м е т о д а ConnCacheBean. c l o s e ( ) , н о ф а к т и ч е с к и э т о т м е т о д в о з в р а щ а е т в кэш л и ш ь о п и с а т е л ь с о е д и н е н и я .
Листинг 11.4. Использование ConnCacheBean в JSP-программе •
Result of your query: <% <%
} else { %>
No rows } rset.closeO; stmt.close(); conn.close();
%>
found that match your query.
/ / закроем результирующее множество / / закроем оператор / / вернем соединение в пул
Кэширование результатов запроса В р я д е случаев м о ж н о м н о г о к р а т н о п р и м е н я т ь р е з у л ь т а т ы S Q L - з а п р о с о в в р а з н ы х H T T P - с е а н с а х и л и р а с п р е д е л я т ь их с р е д и р а з н ы х H T T P - с е а н с о в . В кач е с т в е п р и м е р а р а с с м о т р и м web-сайт, п р е д л а г а ю щ и й н е к и е т о в а р ы в т е ч е н и е недели. Запрос, выясняющий, какие т о в а р ы продаются, м о ж н о распределить между р а з н ы м и пользователями и сеансами. К э ш и р о в а н и е , а н а л о г и ч н о е механизму пулинга соединений, можно организовать п р и помощи зерен S Q L - з а п р о с о в 13 Чак. 574
358
ГЛАВА 11
О
с с о о т в е т с т в у ю щ и м и о б л а с т я м и д е й с т в и я (session и л и a p p l i c a t i o n ) и т э г а < j sp: useBean>. З е р н о будет к э ш и р о в а т ь р е з у л ь т а т ы з а п р о с а п о с л е его о б р а б о т ки. К л и е н т ы э к з е м п л я р а з е р н а смогут все в м е с т е п о л ь з о в а т ь с я э т и м результатом, не исполняя запроса. Процесс кэширования результатов запроса предполагает также проверку и х д о с т о в е р н о с т и и и х о б с л у ж и в а н и е . Д р у г и м и с л о в а м и , е с л и и з м е н я ю т с я базовые д а н н ы е или истекает допустимый срок действия результата, его нужно о б н о в и т ь , в ы п о л н и в з а п р о с е щ е раз. А в т о м а т и ч е с к а я о т м е н а и л и р е г е н е р а ция кэшируемых результатов запроса после обновления данных — сложный в о п р о с , т р е б у ю щ и й п р и м е н е н и я т р и г г е р о в б а з ы д а н н ы х . Р е а л и з а ц и я подобн о й ф у н к ц и и каким-то с к р ы т ы м о б р а з о м , б е з я в н о г о п р о г р а м м и р о в а н и я , может оказаться неэффективной. Однако можно предоставить программисту API, к к о т о р о м у гот будет о б р а щ а т ь с я , у к а з ы в а я с в о и т р е б о в а н и я в о т н о ш е н и и к э ш и р о в а н и я . Во в р е м я и з д а н и я э т о й к н и г и в O r a c l e р а б о т а л и над подобн ы м " п р о г р а м м и р у е м ы м " ф у н к ц и о н а л ь н ы м с р е д с т в о м w e b - к э ш и р о в а н и я для с о б с т в е н н ы х с р е д с е р в л е т о в и J S P . В о з м о ж н о , ч т о в будущей р е д а к ц и и O r a c l e J S P т а к о е с р е д с т в о будет п р и с у т с т в о в а т ь .
Итоги В э т о й главе р а с с м а т р и в а л о с ь и с п о л ь з о в а н и е к о м п о н е н т о в J a v a B e a n в JSPп р о г р а м м а х . J a v a B e a n — у н и в е р с а л ь н ы й класс Java, к о т о р ы й с о о т в е т с т в у е т о с о б о й с т р у к т у р н о й схеме, п о з в о л я ю щ е й б е з труда м а н и п у л и р о в а т ь е е свойствами и и н т е г р и р о в а т ь с я с JSP. J a v a B e a n м о ж н о п р и м е н я т ь в к а ч е с т в е модульного J a v a - к о м п о н е н т а д л я и с п о л н е н и я д и н а м и ч е с к и х л о г и ч е с к и х к о н с т р у к ц и й . В с п е ц и ф и к а ц и и JSP определены специальные встроенные тэги, упрощающ и е р а б о т у с з е р н а м и J a v a B e a n и не т о л ь к о ч е т к о о т д е л я ю щ и е H T M L - т е к с т о т п р о г р а м м н ы х к о н с т р у к ц и й Java, н о и п р е д о с т а в л я ю щ и е с р е д с т в а д л я и х инт е г р а ц и и . Т а к и м о б р а з о м , w e b - д и з а й н е р ы могут с о с р е д о т о ч и в а т ь все с в о и у с и л и я на н а п и с а н и и у д о б н ы х д л я п о л ь з о в а т е л я J S P - с т р а н и ц с п о м о щ ь ю H T M L и л и X M L , а J a v a - п р о г р а м м и с т ы — на р а з р а б о т к е з е р е н J a v a B e a n . Впос л е д с т в и и д и н а м и ч е с к у ю л о г и к у м о ж н о "вставить" в J S P , и с п о л ь з у я д л я э т о г о п р о с т ы е , н о э ф ф е к т и в н ы е гэги з е р е н . Мы создали программы с использование JSP-страниц и зерен JavaBean. Рассмотрели разнообразные вопросы, связанные с написанием компонентов J a v a B e a n , п р и ч е м о с о б о е в н и м а н и е у д е л я л о с ь п р и л о ж е н и я м баз д а н н ы х . В час т н о с т и , б ы л и с о з д а н ы классы J a v a B e a n , к их с в о й с т в а м п р и м е н я л и с ь м е т о д ы set и get, п о с л е ч е г о к л а с с ы с в я з ы в а л и с ь с р а з л и ч н ы м и о б л а с т я м и д е й с т в и я JSP. Б ы л о р а з р а б о т а н о J S P - п р и л о ж е н и е с к о н т р о л е м за с е а н с а м и для с и с т е м ы ввода з а к а з о в и со с п е ц и а л ь н о й "корзиной". Э т о п р и л о ж е н и е в в о д и т передавае м ы й заказ в базу д а н н ы х з а к а з о в на покупку, используя в к о м п о н е н т е JavaBean SQLJ-конструкции. П о м и м о э т о г о , м ы создали з е р н о J a v a B e a n , в ы п о л н я ю щ е е с т а т и ч е с к и й з а п р о с п р и п о м о щ и SQLJ и о т о б р а ж а ю щ е е е г о р е з у л ь т а т ы в виде H T M L - т а б л и ц ы . Д л я д и н а м и ч е с к и х SQL-запросов, н е и з в е с т н ы х д о э т а п а исполнения программы, было написано JavaBean с применением JDBC, причем р е з у л ь т а т ы ф о р м а т и р о в а л и с ь в виде H T M L - т а б л и ц ы с п о м о щ ь ю SQLJ-объекта ResultSetMetaData. К р о м е т о г о , в э т о й главе р а с с к а з ы в а л о с ь о г е н е р а ц и и XML-текста из SQL-таблиц базы данных с помощью компонентов JavaBean и з б и б л и о т е к и з е р е н O r a c l e J S P . В з а к л ю ч е н и е м ы у з н а л и о т о м , как о п т и м и з и р о в а т ь производительность доступа к базе данных из web-приложения. В главе 12 г о в о р и т с я о б и с п о л ь з о в а н и и к о м п о н е н т о в EJB и C O R B A д л я модульной разработки JSP-приложений. З е р н а JavaBean можно п р и м е н я т ь для п о в ы ш е н и я к а ч е с т в а доступа к о б ъ е к т а м EJB и C O R B A , с в о д я о б ъ е м Java-конс т р у к ц и й н а J S P - с т р а н и ц е к минимуму. К р о м е т о г о , о п и с ы в а е т с я и с п о л ь з о в а ние библиотек тэгов, содержащих специальные тэги для р а с ш и р е н и я JSP. Э т и о т л и ч н ы е друг о т друга т е х н о л о г и и м о ж н о о б ъ е д и н я т ь , с о з д а в а я э ф ф е к тивные и универсальные web-приложения.
ГЛАВА 12
О
ИспользованиеJSP вместе cEJB, CORBA и библиотеками тэгов
360
ГЛАВА 11
О
^ ^ ^ б ы ч н о w e b - п р и л о ж е н и е с о с т о и т и з с а м ы х р а з л и ч н ы х р е с у р с о в : и з стат и ч е с к и х э л е м е н т о в , н а п р и м е р H T M L - с т р а н и ц и G I F - и з о б р а ж е н и й , и и з дин а м и ч е с к и х м о д у л е й , т а к и х как J S P - с т р а н и ц ы и с е р в л е т ы , з е р н а J a v a B e a n , зерна Enterprise JavaBean и объекты CORBA. Д и н а м и ч е с к и е к о м п о н е н т ы к о м б и н и р у ю т с я друг с д р у г о м , ч т о п о з в о л я е т с о з д а в а т ь м о щ н ы е п р и л о ж е н и я уровня предприятия. В двух п р е д ы д у щ и х главах г о в о р и л о с ь о б и с п о л ь з о в а н и и J S P в м е с т е с другими JSP-страницами и сервлетами, а также о применении в JSP-программе к о м п о н е н т о в J a v a B e a n . В ч а с т и II р а с с к а з ы в а л о с ь о з е р н а х EJB, о т о м , как внед р я т ь их в Огас1е8г и в ы з ы в а т ь и з к л и е н т с к о й п р о г р а м м ы . В ч а с т и III показано, как о п и с ы в а т ь и в н е д р я т ь к о м п о н е н т ы C O R B A в Огас1е8г. В э т о й главе р а с с м а т р и в а е т с я п р и м е н е н и е всех э т и х м е т о д о в к о м п о н е н т н о г о п р о г р а м м и р о в а н и я в о с н о в а н н о м на J S P wcb-прилолеении. В с п е ц и ф и к а ц и ю J S P 1.1 в в е д е н о п о н я т и е р а с ш и р е н и я н а б о р а JSP-тэгов п р и п о м о щ и библиотек тэгов (tag libraries). С х е м а р а с ш и р е н и я т э г о в я в л я е т с я м о д у л ь н о й и п е р е н о с и м о й , п о з в о л я ю щ е й о п и с ы в а т ь и п р и м е н я т ь специальн ы е т э г и , удобно у п а к о в а н н ы е в б и б л и о т е к у т э г о в . О с н о в ы в а я с ь н а э т о й схеме, м о ж н о о п и с а т ь с в о й с о б с т в е н н ы й гэг, х а р а к т е р и з у ю щ и й н е к о т о р о е дейс т в и е в к о м п о н е н т е . Молено т а к ж е в о с п о л ь з о в а т ь с я б и б л и о т е к а м и т э г о в , п р е д л а г а е м ы м и р а з л и ч н ы м и п о с т а в щ и к а м и . Б и б л и о т е к и т э г о в в м е с т е с друг и м и к о м п о н е н т а м и Java, н а п р и м е р с з е р н а м и J a v a B e a n и EJB, и с п о л ь з у ю т с я па J S P - с т р а н и ц а х для п о с т р о е н и я слолсных м о д у л ь н ы х web-прилолсений. В п о д р о б н ы х п р и м е р а х э т о й г л а в ы п о к а з а н о , как: •
В ы з ы в а т ь EJB и з JSP-прилолсения
•
Вызывать компонент CORBA с JSP
•
И с п о л н я т ь S Q L - з а п р о с ы с п о м о щ ь ю б и б л и о т е к и JSP-тэгов O r a c l e
•
И с п о л ь з у я б и б л и о т е к у JSP-тэгов O r a c l e , г е н е р и р о в а т ь X M L - р е з у л ь т а т ы для S Q L - з а п р о с а и п р е о б р а з о в ы в а т ь их п р и п о м о щ и т а б л и ц с т и л е й XSL
•
С о з д а в а т ь с в о й с о б с т в е н н ы й с п е ц и а л ь н ы й JSP-тэг д л я в ы в о д а т е к у щ и х даты и времени
•
С о з д а в а т ь с в о й с о б с т в е н н ы й с п е ц и а л ь н ы й JSP-тэг д л я SQL-запроса и создания HTML-меню элементов
исполнения
Т а к и м о б р а з о м , вы научитесь в п о л н о й мере пользоваться всей м о щ ы о и всеми в о з м о ж н о с т я м и модели к о м п о н е н т н о г о п р о г р а м м и р о в а н и я в прил о ж е н и я х JSP.
Разработка web-приложений с помощью EJB-компонентов E n t e r p r i s e J a v a B e a n — в а ж н а я с о с т а в л я ю щ а я к о м п о н е н т н о й м о д е л и в архитектур е п р о г р а м м и р о в а н и я Java. В ч а с т и II э т о й к н и г и г о в о р и л о с ь о с о з д а н и и и внед р е н и и з е р е н EJB в базе д а н н ы х Огас1е8г. Т е п е р ь п о с м о т р и м , как в ы з ы в а т ь EJB-компоненты с J S P - с т р а н и ц и и з с е р в л е т о в . В з е р н е EJB к о н ц е н т р и р у е т с я бизнес-логика, в т о в р е м я как J S P и с е р в л е т с о д е р ж а т "фронтальную", внешн ю ю логику для и н т е р а к т и в н о г о ввода д а н н ы х , о р г а н и з у ю т в ы з о в FJB и ф о р мируют логику представления результата. Сначала реализуем EJB-компоненг, а потом создадим использующие его JSP-страницы и зерна JavaBean.
Сеансовое EJB для заказов С о з д а д и м п р о с т о е с е а н с о в о е EJB-зерно для о б р а б о т к и з а к а з о в , о б р а щ е н н ы х к б а з е д а н н ы х P u r c h a s e O r d e r (см. в в е д е н и е ) . Н а п о м н и м , ч т о в главе 11 б ы л о н а п и с а н о з е р н о J a v a B e a n — DBQueryBean. s q l j — д л я з а п р о с а и н ф о р м а ц и и о заказах в базе д а н н ы х . Т е п е р ь создадим п р о г р а м м у со с х о ж и м и ф у н к ц и я м и ,
Использование JSP вместе с EJB, CORBA и библиотеками тэгов
о
п р и м е н и в н е J a v a B e a n , a EJB. О с е а н с о в ы х з е р н а х EJB г о в о р и л о с ь в части II. П о с р а в н е н и ю с J a v a B e a n , з е р н о EJB г о р а з д о м о щ н е е и г и б ч е с т о ч к и з р е н и я управления т р а н з а к ц и я м и и организации безопасности в бизнес-логике, хотя нередко его сложнее программировать и внедрять. Использовать JavaBean, и с п о л н я ю щ е е S Q L - з а п р о с ы , у д о б н е е тогда, когда в ы п о л н я е м ы е над д а н н ы м и о п е р а ц и и д о с т а т о ч н о п р о с т ы ; б о л е е с л о ж н а я бизнес-логика и р а б о ч и е с ц е н а р и и т р е б у ю т п р и м е н е н и я EJB. Н и ж е п р и в о д я т с я о п е р а ц и и , н е о б х о д и м ы е д л я р а з р а б о т к и с е а н с о в о г о зерн а OrderEJB и в н е д р е н и я е г о в Огас1е8г. Если вы е щ е не з н а к о м ы с м о д е л ь ю EJB, о б р а т и т е с ь к ч а с т и II к н и г и , где р а с с к а з а н о о с т р у к т у р е з е р е н EJB и о способах их программирования. 1. О п и ш е м д о м а ш н и й и н т е р ф е й с OrderHome для OrderEJB. 2. О п и ш е м у д а л е н н ы й и н т е р ф е й с Order для OrderEJB. 3 . С о з д а д и м Java-K/iacc OrderHeader для п о л у ч е н и я и н ф о р м а ц и и "высшего" у р о в н я о з а г о л о в к а х заказа. 4. С о з д а д и м Java-кл ас с Lineitem для п о л у ч е н и я с в е д е н и й о пунк тах заказа. 5. С о з д а д и м класс р е а л и з а ц и и д л я OrderEJB. 6 . О п и ш е м д е с к р и п т о р в н е д р е н и я EJB. 7. В н е д р и м EJB в OracleSi. Эти о п е р а ц и и рассматриваются в последующих разделах. После создания и в н е д р е н и я EJB п о г о в о р и м о т о м , как в ы з ы в а т ь его из w e b - п р и л о ж е н и я .
Создание домашнего интерфейса Д л я с е а н с о в о г о з е р н а OrderEJB нужно о п и с а т ь д о м а ш н и й интерфейс OrderHome. Н и ж е п р и в о д и т с я е г о п р о г р а м м н ы й текст. О н р а с ш и р я е т с т а н д а р т н ы й интер фейс EJBHome и с о д е р ж и т м е т о д createO, в ы з ы в а е м ы й для с о з д а н и я э к з е м п л я р а EJB. •
/ * * Имя программы: * Назначение:
OrderHome.java Домашний интерфейс для OrderEJB
package order; import javax.ejb.*; import java.rmi.RemoteException; public interface OrderHome extends EJBHome { public Order createO throws CreateException, RemoteException;
}
Создание удаленного интерфейса Т е п е р ь о п и ш е м у д а л е н н ы й интерфейс Order д л я OrderEJB. O n с о с т о и т и з двух м е т о д о в : getOrdeг() и g e t l t e m s ( ) . М е т о д getOrderO в о з в р а щ а е т з а г о л о в о ч ную и н ф о р м а ц и ю : и м е н а и ч и с л о с л у ж а щ и х , р а з м е с т и в ш и х з а к а з , и о б щ е е ч и с л о п у н к т о в заказа. Э т а и н ф о р м а ц и я к о н ц е н т р и р у е т с я в Java-ioiacce с име-. н е м OrderHeader (см. н и ж е ) . М е т о д getltemsO в о з в р а щ а е т х а р а к т е р и с т и к и заказываемого товара; выдается значение, представляемое массивом объектов Lineitem. К л а с с Lineitem будет с о з д а н н и ж е . Метод getOrder() в ы з ы в а е т с я первым, в результате чего п о м е р заказа з а п и с ы в а е т с я в EJB (с с о х р а н е н и е м с о с т о я н и я ) . З а т е м в ы з ы в а е т с я м е т о д g e t l t e m s O д л я п о л у ч е н и я х а р а к т е р и с т и к пункта а с с о р т и м е н т а . П р о г р а м м н ы й т е к с т интерфейса Order: •
/ * * Имя программы: * Назначение:
Order.java Удаленный интерфейс для OrderEJB
361
362
ГЛАВА 12
О package order; import javax.ejb.EJBObject; import java.rmi.RernoteException; public interface Order extends EJBObject { public OrderHeader getOrder ( i n t orderNumber) throws java.sql.SQLException, RernoteException;
}
public Lineltem [ ] getltems() throws java.sql.SQLException, RernoteException;
Создание класса Java для заголовочной информации заказа Т е п е р ь о п и ш е м Java-iamcc OrderHeader. O n п р е д н а з н а ч е н д л я х р а н е н и я и н ф о р м а ц и и в ы с ш е г о у р о в н я , с в я з а н н о й с заказом. Э к з е м п л я р э т о г о класса будет и с п о л ь з о в а т ь с я с е а н с о в ы м з е р н о м OrderEJB для в о з р а щ е н и я к л и е н т у результат о в з а п р о с а заказа. П о л я empName и empNum о п и с ы в а ю т и м я и н о м е р служащего, р а з м е щ а ю щ е г о з а к а з , a itemCount — о б щ е е ч и с л о з а к а з а н н ы х т о в а р о в . П р о г р а м м н ы й т е к с т OrderHeader. java: •
/ * * Имя программы: * Назначение: **/
OrderHeader. java Хранение информации высшего уровня о заказе на покупку.
package order; public class OrderHeader implements java.io.Serializable { public String empName; / / имя служащего public i n t empNum; / / номер служащего public i n t itemCount; / / общее число пунктов / / конструктор public OrderHeader (String empName, int empNum, i n t itemCount) { this.empName = empName; this.empNum = empNum; this.itemCount = itemCount;
}
}
Создание класса Java для информации о пункте ассортимента О п и ш е м Java-класс Lineltem. Э т о т класс п р е д н а з н а ч е н д л я х р а н е н и я и н ф о р м а ц и и о пункте заказа: н о м е р в а с с о р т и м е н т е , н о м е р п р о е к т а , к о л и ч е с т в о и о п и с а н и е пункта в з а к а з е на покупку. П р о г р а м м н ы й т е к с т Lineltem. j a v a : •
/ * * Имя программы: Lineltem.java * Назначение: Хранение информации о пунктах ассортимента для заказа. * * / package order; public class Lineltem implements java.io.Serializable { public i n t lineno; public i n t projectno; public i n t quantity; public String description; / / конструктор public Lineltem(int lineno, int projectno, int quantity, String description^ this.lineno = lineno; this.projectno = projectno; this.quantity = quantity;
Использование JSP вместе с EJB, CORBA и библиотеками тэгов
}
}
о
this.description = description;
С о з д а н и е к л а с с а реализации EJB Н а к о н е ц , о п и ш е м класс р е а л и з а ц и и OrderEJBImpl. s q l j , к о т о р ы й и с п о л н я е т SQLJ-запросы, возвращая и н ф о р м а ц и ю о заголовках и товарах. Класс реализует два метода: getOrder() и getltemsO. Э т и м е т о д ы с ч и т ы в а ю т и н ф о р м а ц и ю о заголовках и ассортименте заказа п р и помощи SQL-запросов, о б р а щ е н н ы х к т а б л и ц а м PURCHASE_LIST, EMPLOYEE_LIST и LINEITEM_LIST б а з ы д а н н ы х Purchase O r d e r (см. в в е д е н и е ) . П о с л е т е к с т а п р о г р а м м ы д а ю т с я п о я с н е н и я . •
/** Имя программы: * Назначение: *
OrderEJBImpl.sqlj Класс реализации для OrderEJB. Запрашивает в базе данных информацию о заказе и ассортименте.
public class OrderEJBImpl implements SessionBean { SessionContext ctx; public void ejbCreateO throws CreateException, RemoteException { } public void ejbActivateO { } public void ejbPassivateO { } puDlic void ejbRemoveO { } public void setSessionContext(SessionContext ctx) { t h i s . c t x = ctx;
}
private int orderNumber = 0; private int itemCount = 0 ;
/ / Сохраним номер заказа / / и счетчик пунктов для get0rder(). / / Они, возможно, будут использованы / / методом getltemsO.
/ / Метод для получения заголовочной информации о заказе public OrderHeader getOrder ( i n t orderNumber) throws SQLException, RemoteException / / (см. пояснение
{
}
1)
String empName; i n t empNum; this.orderNumber = orderNumber; / / (см. пояснение 2) / / Считываем имя и номер служащего, разместившего заказ ffsql { SELECT PURCHASE_LIST.employeeno, firstname || ' ' II lastName INTO :empNum, :empName FROM PURCHASE_LIST, EMPL0YEE_LIST WHERE requestno = :orderNumber AND EMPL0YEE_LIST.employeeno = PURCHASE_LIST.employeeno }; / / (см. пояснение 3) return new OrderHeader (empName, empNum, getltemCountO);
/ / Подсчитаем число заказанных товаров private int getltemCount () throws SQLException { / / (см. пояснение 4)
363
ГЛАВА 12
#sql { SELECT COUNT(>) INTO :itemCount FROM LINEITEM_LIST WHERE requestno = :orderNumber }; return itemCount;
}
/ / SQLJ-итератор для считывания характеристик пунктов ассортимента #sql iterator Lineltemslter ( i n t lineno, int projectno, i n t quantity, String description); / / (см. пояснение 5) / / Метод для считывания характеристик пунктов ассортимента public Lineltem [ ] getltems() throws SQLException { / / (см. пояснение 6) / / Объявление SQLJ-итератора для пунктов ассортимента Lineltemslter l i = null; / / Считываем информацию об ассортименте при помощи SQL-запроса «sql И = { SELECT lineno, projectno, quantity, description FROM LINEITEM_LIST WHERE requestno = :orderNumber ORDER BY lineno }; / / (см. пояснение 7) Lineltem[] items = new Lineltem [itemCount]; //(см. пояснение 8) for ( i n t i = 0; i < itemCount; i++) { li.next(); items[i] = new Lineltem(li.lineno(), li.projectnoO, li.quantityO, / / ( с м . пояснение 9) Li.description());
}
}
}
l i . c l o s e ( ) ; / / Закрываем итератор return items;
/ / (см. пояснение 10)
П о я с н е н и я к OrderEJBImpl.sqlj: 1. Э т о т м е т о д р е а л и з у е т м е т о д get0rder() для у д а л е н н о г о интерфейса Order. 2. Д а н н ы й о п е р а т о р с о х р а н я е т а р г у м е н т orderNumber м е т о д а get0rder() в п е р е м е н н о й э к з е м п л я р а EJB-класса. Э т о EJB будет п р и м е н я т ь с я в качес т в е з е р н а с с о х р а н е н и е м с о с т о я н и я , а с о х р а н е н н ы е н о м е р заказа и числ о п у н к т о в в п о с л е д с т в и и будут п о в т о р н о и с п о л ь з о в а т ь с я п р и в ы з о в е м е т о д а get I terns ( ) . 3 . Э т о т S Q L - о п е р а т о р с о е д и н я е т т а б л и ц ы PURCHASE_LIST и EMPL0YEE_LIST, с ч и т ы в а я п о л н о е и м я и н о м е р служащего, р а з м е с т и в ш е г о заказ. В конс т р у к ц и и WHERE о п е р а т о р а SELECT и с п о л ь з у е т с я а р г у м е н т orderNumber. 4. Э т о т м е т о д п о д с ч и т ы в а е т о б щ е е ч и с л о п у н к т о в в заказе, в ы п о л н я я S Q L - з а п р о с к т а б л и ц е LINEITEM_LIST. Д л я в ы б о р а в е р н о г о м н о ж е с т в а с т р о к в к о н с т р у к ц и и WHERE S Q L - о п е р а т о р а SELECT и с п о л ь з у е т с я а р г у м е н т orderNumber. 5. Э т о т о п е р а т о р о б ъ я в л я е т к л а с с и м е н о в а н н о г о S Q L J - и т е р а т о р а Linel t e m s l t e r для с ч и т ы в а н и я характеристик пунктов ассортимента. 6. Э т о т м е т о д р е а л и з у е т м е т о д g e t l t e m s ( ) , о б ъ я в л е н н ы й на шаге 2 для удал е н н о г о интерфейса Order.
Использование JSP вместе с EJB, CORBA и библиотеками тэгов
о
7. Д а н н ы й S Q L J - о п е р а т о р и н и ц и а л и з и р у е т э к з е м п л я р S Q L J - и т е р а т о р а l i , и с п о л ь з у я р е з у л ь т а т ы SQL-запроса. Э т о т з а п р о с с ч и т ы в а е т х а р а к т е р и с т и к и п у н к т о в к о н к р е т н о г о з а к а з а в т а б л и ц е LINEITEM_LIST. 8. Э т о т о п е р а т о р с о з д а е т м а с с и в о б ъ е к т о в Lineitem, з а п о л н я е м ы й с пом о щ ь ю S Q L J - и т е р а т о р а и в о з в р а щ а е м ы й как р е з у л ь т а т в ы з о в а м е т о д а getltemsO. 9. Э т о т о п е р а т о р с о з д а е т н о в ы й э к з е м п л я р класса Lineitem и з д а н н ы х строки в экземпляре итератора l i . 10. Э т о т о п е р а т о р з а к р ы в а е т э к з е м п л я р и т е р а т о р а l i , о с в о б о ж д а я к у р с о р для SQL-запроса.
Создание дескриптора внедрения EJB Д л я в н е д р е н и я EJB н е о б х о д и м о создать д е с к р и п т о р в н е д р е н и я . Д е с к р и п т о р в н е д р е н и я order, ejb для к о м п о н е н т а OrderEJB п р е д с т а в л е н в л и с т и н г е 12.1. Зерн о OrderEJBImpl о б ъ я в л я е т с я как с е а н с о в о е с д о м а ш н и м и м е н е м /test/OrderEJB и с соответствующими домашним и удаленным интерфейсами.
Внедрение EJB И т а к , п р о г р а м м а OrderEJB создана. Т е п е р ь н е о б х о д и м о с к о м п и л и р о в а т ь исх о д н ы е ф а й л ы ( ф о р м и р у ю щ и й ф а й л (Makefile) п р и л а г а е т с я к тексту п р о г р а м м ы ) и с о з д а т ь j a r - ф а й л OrderEJB. j a r . З а т е м н у ж н о з а г р у з и т ь и в н е д р и т ь OrderEJB в Огас1е8г, н а п р и м е р : •
Вызов OrderEJB из web-приложения О разных архитектурных вариантах написания web-приложений говорилось в р а з д е л е "Архитектура w e b - п р и л о ж е н и я " г л а в ы 2. Д е й с т в и т е л ь н о , в ы з в а т ь OrderEJB и з т е к с т а J S P и л и с е р в л е т а м о ж н о н е с к о л ь к и м и с п о с о б а м и . С р е д и н и х следует о т м е т и т ь : 1. В ы з о в EJB н е п о с р е д с т в е н н о H3jSP-nporpaMMbi. Д л я э т о г о нужно, ч т о б ы на JSP-странице присутствовали п р о г р а м м н ы е к о н с т р у к ц и и Java для поиска, и н и ц и а л и з а ц и и и вызова м е т о д о в EJB. П о л ь з о в а т ь с я таким подходом, как п р а в и л о , не рекомендуют, поскольку J S P - с т р а н и ц ы п р е д н а з н а ч е н ы в первую о ч е р е д ь для л о г и к и п р е д с т а в л е н и я , а не для в ы ч и с л е н и й . Б о л ь ш о й о б ъ е м конструкций Java на J S P у с л о ж н я е т обслуживание п р о г р а м м ы . 2. С о з д а н и е J a v a B e a n - о б о л о ч к и д л я EJB и в ы з о в е е м е т о д о в с J S P . Э т о т подх о д с к р ы в а е т д е т а л и р а б о т ы с EJB о т а в т о р а J S P и п о з в о л я е т и с п о л ь з о в а т ь J a v a B e a n п р и п о м о щ и с т а н д а р т н о г о т э г а <jsp: useBean>. В э т о м р а з д е л е для в ы з о в а OrderEJB п р и м е н я е т с я и м е н н о т а к о й подход. Его м о ж н о р а с ш и р и т ь , с о з д а в с п е ц и а л ь н ы е т э г и для E J B - к о м п о н е н т а . 3. В ы з о в EJB и з с е р в л е т а . М о ж н о в ы з ы в а т ь EJB н е п о с р е д с т в е н н о и з текс т а с е р в л е т а и л и с о з д а т ь д л я EJB J a v a B e a n - о б о л о ч к у , к а к в п.2, и выз ы в а т ь з е р н о из сервлета. В ы з о в з е р е н J a v a B e a n не о г р а н и ч и в а е т с я
365
366
ГЛАВА 12
О
J S P - с т р а н и ц а м и — н и ч т о н е м е ш а е т м н о г о к р а т н о п о л ь з о в а т ь с я программой JavaBean из сервлета. В JSP для установки свойств и области действия JavaBean применяется ряд удобных сокращений, что приход и т с я п р о г р а м м и р о в а т ь я в н ы м о б р а з о м в с е р в л е т е . Д о с т о и н с т в о м использования сервлета является то, что он может содержать более с л о ж н ы е п р о г р а м м н ы е к о н с т р у к ц и и Java (если э т о н у ж н о для web-прил о ж е н и я ) и что его может создавать и обслуживать Java-программист. 4 . И с п о л ь з о в а н и е с е р в л е т а для п о и с к а и и н и ц и а л и з а ц и и EJB, a J S P — для лог и к и п р е д с т а в л е н и я д а н н ы х . Т а к о й п о д х о д н а з ы в а е т с я с т р у к т у р н о й схем о й "модель-представление-контроллер" (MVC, model-view-controller) (см. главу 2). EJB и л и J a v a B e a n — э т о м о д е л ь к о м п о н е н т о в , а с е р в л е т — контроллер, п р и н и м а ю щ и й HTTP-запрос, подтверждающий правильн о с т ь е г о п а р а м е т р о в , и н и ц и а л и з и р у ю щ и й EJB и, н а к о н е ц , п е р е х о д я щ и й к J S P , где п о л ь з о в а т е л ю п р е д с т а в л я ю т с я о б р а б о т а н н ы е д а н н ы е . П р о г р а м м н ы й т е к с т с е р в л е т а с о з д а е т с я р а з р а б о т ч и к о м Java, а не автор о м H T M L - т е к с т а , п о э т о м у в нем п р и с у т с т в у ю т д е т а л и м а н и п у л и р о в а н и я EJB и о б р а б о т к и и с к л ю ч и т е л ь н ы х с и т у а ц и й . П р е д л а г а е м ч и т а т е л ю с о з д а т ь w e b - п р и л о ж е н и е с е р в л е т - E J B - J S P д л я в ы з о в а EJB с и м е н е м ObservationBean (см. г л а в у 3).
Вызов OrderEJB с помощью JavaBean-ободочки С о з д а д и м о с н о в а н н о е H a J S P п р и л о ж е н и е , с ч и т ы в а ю щ е е и н ф о р м а ц и ю о заказах п р и п о м о щ и OrderEJB. К о м п о н е н т ы э т о г о w e b - п р и л о ж е н и я п р е д с т а в л е н ы н а р и с . 12.1. В к а ч е с т в е п р о г р а м м ы - о б о л о ч к и , ч е р е з к о т о р у ю п р о и с х о д и т обращ е н и е к OrderEJB, в п р и л о ж е н и и используется JavaBean-ioiacc OrderEJBWrapper. П р и п р и м е н е н и и для этой цели JavaBean намного снижается объем программ н ы х к о н с т р у к ц и й Java, к о т о р ы е нужно п и с а т ь с о б с т в е н н о в J S P - п р о г р а м м е . З д е с ь д в е J S P - с т р а н и ц ы : CallOrderEJB. jsp и CallOrderEJBForLines. jsp, к о т о р ы е служат т о ч к а м и входа в п р и л о ж е н и е . Э т и J S P - с т р а н и ц ы будут п о л ь з о в а т ь с я о д н и м и т е м ж е э к з е м п л я р о м J a v a B e a n п р и п о м о щ и H T T P - о б ъ е к т а session.
Создание JavaBean-3epHa OrderEJBWrapper Создадим JavaBean-зерно Or-
derEJBWrapper для в ы з о в а к о м п о н е н т а OrderEJB. J a v a B e a n д о л ж н о использоваться в о б л а с т и д е й с т в и я session. OrderEJBWrapper в ы п о л н я е т следующие ф у н к ц и и : •
П о и с к OrderEJB в J N D I - п р о с т р а н с т в е и м е н Огас1е8г и с о з д а н и е э к з е м п л я р а к о м п о н е н т а . Э к з е м п л я р EJB следует у н и ч т о ж а т ь п р и в ы х о д е JavaB e a n и з о б л а с т и д е й с т в и я session.
•
П р е д о с т а в л е н и е м е т о д о в о б о л о ч к и д л я м е т о д о в getOrder() и getltemsO к о м п о н е н т а OrderEJB.
Использование JSP вместе с EJB, CORBA и библиотеками тэгов
о
•
В ы з о в м е т о д о в getOrder() и getltemsO в л ю б о м п о р я д к е . З а м е т и м , ч т о OrderEJB т р е б у е т , ч т о б ы getOrdeг() в ы з ы в а л с я д о getItems(), п о с к о л ь к у при считывании пунктов ассортимента должен быть доступен номер заказа. П р и и с п о л ь з о в а н и и JavaBean-оболочки это т р е б о в а н и е можн о о б о й т и , в ы з ы в а я getOrder() п е р в ы м , е с л и getltemsO в ы з ы в а е т с я напрямую.
•
Н е к о т о р о е п о в ы ш е н и е п р о и з в о д и т е л ь н о с т и путем к э ш и р о в а н и я данн ы х , с ч и т ы в а е м ы х для заказа. Н а п р и м е р , е с л и в н о в о м з а к а з е НТТР-сеанса запрашивается то же, что и в предыдущем, то не повтор я е т с я в ы з о в м е т о д а getOrder() и л и g e t l t e m s O к о м п о н е н т а OrderEJB, а возвраидается к э ш и р о в а н и ы й результат. К о н е ч н о , к э ш и р о в а н и е п о д о б н о г о т и п а п о л е з н о т о л ь к о тогда, когда о д н о в р е м е н н о не обновляется и н ф о р м а ц и я заказов в базовых SQL-таблицах.
Н и ж е приводится программный текст зерна JavaBean. Важные участки п р о г р а м м ы в ы д е л е н ы ж и р н ы м ш р и ф т о м . З е р н о и м е е т о д н о с в о й с т в о с имен е м orderNumber и м е т о д ы set и get э т о г о а т р и б у т а . П о с л е с о з д а н и я м е т о д о м getOrder() э к з е м п л я р к о м п о н е н т а OrderEJB с о х р а н я е т с я л о к а л ь н о и мног о к р а т н о используется в т е ч е н и е существования JavaBean-3epna OrderEJBWrapper. J a v a B e a n р е а л и з у е т интерфейс HttpSessionBindingListener (см. р а з д е л " С о б ы т и я и и н т е р ф е й с ы п р и е м н и к о в с о б ы т и й " г л а в ы 11), т а к как о н о п р е д н а з н а ч е н о для п р и м е н е н и я J S P - с т р а п и ц е й с о б л а с т ь ю д е й с т в и я session. Э к з е м п л я р EJB с т а н о в и т с я н е д е й с т в и т е л ь н ы м , когда и с т е к а е т с р о к д е й с т в и я H T T P - о б ъ е к т а session. О т м е т и м , ч т о у с т а н о в к а н о м е р а з а к а з а в з н а ч е н и е , о т л и ч н о е о т предыдущ е г о , в ы з ы в а е т о т б р а к о в к у к э ш и р о в а н н о й и н ф о р м а ц и и о з а к а з е . Если н о м е р заказа т о т же, что и раньше, возвращается к э ш и р о в а н н о е значение. Если н у ж н о н е т о з н а ч е н и е , к о т о р о е с о д е р ж и т с я в к э ш е , м о ж н о в ы з в а т ь ту ж e J S P в другом H T T P - с е а н с е ; будет создан д р у г о й э к з е м п л я р J a v a B e a n (а с л е д о в а т е л ь но, и OrderEJB), и м о ж н о будет с ч и т а т ь и н ф о р м а ц и ю о п о с л е д н е м заказе. Е щ е о д н а а л ь т е р н а т и в а — указать и н о й н о м е р заказа, о т б р о с и в к э ш и р у е м о е з н а ч е н и е . •
/ * * Имя программы: * Назначение' **/
OrderEJBWrapper.java JavaBean для обращения к OrderEJB.
public class OrderEJBWrapper implements HttpSessionBindingListener
{
public OrderEJBWrapperO {} private i n t orderNumber = 0;
/ / конструктор зерна / / свойство зерна
/ / Кэшируем экземпляр OrderEJB и считаем характеристики заказа и ассортимента p r i v a t e Order orderEJB = null; private OrderHeader OrderHeader = null; private Lineltem[] itemsArray = null; / / Метод для установки свойства orderNumoer public synchronized void setOrderNumber ( i n t orderNum) {
368
ГЛАВА 11
О i f (this.orderNumber != orderNum) { OrderHeader = null; / / отбросим кэшированное значение itemsArray = null; / / отбросим кэшированное значение this.. orderNumber = orderNum;
}
}
public int getOrderNumber () { return orderNumber;
}
public synchronized OrderHeader getOrder ( ) throws Exception { i f (orderHeader != n u l l ) return orderHeader; / / Вновь воспользуемся кэшированным значением, / / если оно доступно i f (orderEJB == n u l l ) { / / создадим экземпляр EJB String serviceURL = "sess_iiop://data-i;2481:ORCL"; String objectName = "/test/OrderEJB"; String user = "jspuser"; String password = "jsp"; / / Клиентская программная конструкция для поиска EJB и / / создания экземпляра Hashtable env = new HashtableO; env.put(Context.URL_PKG_PREFIXES, "oracle.aurora.jndi"); env.put(Context.SECURITY_PRINCIPAL, user); env.put(Context.SECURITY_CREDENTIALS, password); env.put(Context.SECURITY_AUTHENTICATION, ServiceCtx.N0N_SSL_LOGIN); Context ic = new InitialContext(env);
public synchronized Lineltem[] getltemsO throws Exception { i f (itemsArray != null) return itemsArray; / / Вновь воспользуемся кэшированным значением i f (orderEJB == null) orderHeader = getOrder(); / / создадим экземпляр EJB itemsArray = orderEJB.getltemsO; / / затем считаем характеристики return (itemsArray);
}
/ / Метод, исполняемый при помещении зерна в НТТР-сеанс public void valueBound(HttpSessionBindingEvent event) { / / Здесь ничего не делаем! / / EJB будет создано только при передаче запроса.
}
/ / Метод, исполняемый при удалении зерна из НТТР-сеанса public synchronized void valueUnbound( HttpSessionBindingEvent event) { i f (orderEJB != n u l l ) { try { orderEJB. removeO; / / уничтожим экземпляр зерна } catch (Exception ignore) {}
}
}
Использование JSP вместе с EJB, CORBA и библиотеками тэгов
о
П о с л е с о з д а н и я JavaB^an-ic/iacca OrderEJBWrapper н е о б х о д и м о с к о м п и л и р о вать его и у с т а н о в и т ь с к о м п и л и р о в а н н ы й класс па w o b - с е р в е р е (см. п р и л о ж е н и е Е). З а т е м е г о м е т о д ы м о ж н о в ы з ы в а т ь с о д н о й или н е с к о л ь к и х JSP-стран и ц . Т е п е р ь создадим с т р а н и ц ы CallOrderEJB. jsp и CallOrderEJBForLines. jsp, совместно использующие один экземпляр этого JavaBean при помощи H T T P - о б ъ е к т а session. С о з д а н и е CallOrderEJB. j s p Н и ж е п р и в о д и т с я п р о г р а м м н ы й т е к с т с т р а н и ц ы CallOrderEJB. jsp, и с п о л ь з у е м о й в к а ч е с т в е н а ч а л ь н о г о э к р а н а п р и л о ж е н и я . Важные участки программы выделены ж и р н ы м ш р и ф т о м . Здесь применяется э к з е м п л я р з е р н а OrderEJBWrapper с о б л а с т ь ю д е й с т в и я session. Н а J S P - с т р а н и ц е п р и с у т с т в у е т H T M L - ф о р м а д л я ввода н о м е р а заказа, к о т о р ы й и щ е т с я в б а з е д а н н ы х . П о с л е ввода н о м е р а заказа в т е к с т о в о м о к н е и щ е л ч к а м ы ш и на кнопке Submit Query генерируется новый HTTP-запрос, обращенный к той ж е J S P , с в в е д е н н ы м н о м е р о м заказа. Э т о т н о м е р и с п о л ь з у е т с я д л я у с т а н о в к и с о о т в е т с т в у ю щ е г о с в о й с т в а J a v a B e a n - a e p u a OrderEJBWrapper, п о с л е ч е г о вызыв а е т с я е г о м е т о д getOrder(). Д р у г а я H T M L - ф о р м а J S P о т о б р а ж а е т к н о п к у Show I t e m s д л я с ч и т ы в а н и я п у н к т о в заказа. П р и щ е л ч к е м ы ш и на э т о й к н о п к е в ы з ы в а е т с я п р о г р а м м а CallOrderEJBForLines. jsp. •
<-- Имя программы: -- Назначение:
CallOrderEJB.jsp Принять номер заказа от пользователя и запросить информацию о заказе.
- - >
<%@ page import-"order.*" %> <jsp:useBean id="orderBean" class="mybeans.OrderEJBWrapper" scope="session" /> <TITLE> The CallOrderEJB JSP <% String orderNumber = request.getParameter("orderNumber"); i f (orderNumber != null) { %> <jsp: setProperty name="orderBean" property="orderNumber" />
Ч т о б ы п о п я т ь п р и н ц и п д е й с т в и я w e b - п р и л о ж е н и я , п о с м о т р и м е г о в работе. Р е з у л ь т а т в ы п о л н е н и я CallOrderEJB. jsp п о к а з а н на р и с . 12.2. Н а э т о й стран и ц е о т о б р а ж а ю т с я и н ф о р м а ц и я о к а ж д о м служащем, р а з м е с т и в ш е м заказ, и н о м е р служащего. К р о м е т о г о , п р и с у т с т в у е т к н о п к а Show I t e m s , с п о м о щ ь ю к о т о р о й м о ж н о в ы з ы в а т ь CallOrderEJBForLines. jsp (см. н и ж е ) и с ч и т ы в а т ь хар а к т е р и с т и к и п у н к т о в а с с о р т и м е н т а . Весь с м ы с л з а к л ю ч а е т с я н е в а в т о м а т и ч е с к о м о т о б р а ж е н и и п у н к т о в а с с о р т и м е н т а , а в их в ы в о д е т о л ь к о п о с л е т о г о , как п о л ь з о в а т е л ь щ е л к н е т м ы ш ь ю на к н о п к е Show Items.
369
370
ГЛАВА 12
О Рис. 12.2.
Ihe CallOideiEJB JSP • Netscape
Выходные данные № w и®*go соттигтоас» Help CallOrderEJB. j s p ^"Bookmarks £ Golo:|http7^ocalhos^8080/examples/js^^
Details of order number: 500 Employee: Pam Blatt, Emp #: 104 Show Items
Please enter an order number |
Submit Query
I Document Done
' ?•• & ..m
J.^ at
I л
С о з д а н и е CallOrderEJBForLines. j s p С т р а н и ц а CallOrderEJB. jsp р а б о т а е т сов м е с т н о с CallOrderEJBForLines. jsp. Эту J S P м о ж н о в ы з ы в а т ь н а п р я м у ю и л и щ е л ч к о м м ы ш и на кнопке Show Items на CallOrderEJB. jsp. Н а с т р а н и ц е выводятся все п у н к т ы а с с о р т и м е н т а д л я к о н к р е т н о г о заказа на покупку. О т м е т и м , ч т о в т э г е <jsp: useBean> э т о й J S P д л я з е р н а OrderEJBWrapper исп о л ь з у е т с я т о ж е и м я orderBean с о б л а с т ь ю д е й с т в и я session. Н а п о м н и м , ч т о J a v a B e a n с о б л а с т ь ю д е й с т в и я session р а з м е щ а е т с я в H T T P - о б ъ е к т е session, и к нему м о ж е т о б р а щ а т ь с я л ю б а я п р о г р а м м а , у ч а с т в у ю щ а я в т о м ж е H T T P - с е а н с е (см. главу 11). С л е д о в а т е л ь н о , т э г <jsp: useBean> в т е к с т е п р о г р а м м ы CallOrderEJBForLines. j s p и щ е т о б ъ е к т с и м е н е м orderBean, р а н е е соз д а н н ы й п р о г р а м м о й CallOrderEJB. jsp. Д р у г и м и с л о в а м и , э т и д в е JSP-стран и ц ы могут совместно пользоваться и н ф о р м а ц и е й о заказах, с ч и т ы в а е м о й в продолжение одного и того же HTTP-сеанса через один и тот же экземпляр J a v a B e a n - 3 e p n a OrderEJBWrapper. <%@ page import="order.*" %> <jsp:useBean id="orderBean" class="mybeans.OrderEJBWrapper" scope="session" /> <TITLE> The CallOrderEJBForLines JSP <X OrderHeader oh = orderBean.getOrder(); X>
Lineltem[] l i = orderBean.getltemsO; i f (oh.itemCount > 0) { %> CTABLE B0RDER>
Line #
Project ft Quantity
Description for ( i n t i=0; i < oh.itemCount; i++) { %>
<%= l i [ i ] , l i n e n o %>
<%= l i [ i ] . p r o j e c t n o %>
<%= l i [ i ] , q u a n t i t y %>
Использование JSP вместе с EJB, CORBA и библиотеками тэгов
<%= l i [ i ] . d e s c r i p t i o n %>
<% } %> <% }
Please enter an order number:
Р е з у л ь т а т п е р е д а ч и з а п р о с а Show I t e m s и з о б р а ж е н на р и с . 12.3. Н а э т о й с т р а н и ц е п р и с у т с т в у е т к н о п к а S u b m i t Q u e r y , п р и щ е л ч к е м ы ш и на к о т о р о й в о з в р а щ а е т с я с т р а н и ц а CallOrderEJB. jsp.
Рис. 12.3. Выходные данные CallOrderEJBFor Lines.jsp
ГГТоТх]
E j The CallOideiEJBFoiLines JSP - Netscape file
£dil View
;:j
Go Communiciloi
Bookiriaiks • ^
"
fj.
Help
Go to: |hnp:/l/localhost.8090/'examples/lisp/chapter12/Call0rderEJBForltems.isp?
<JgjT Whal'j Related
jjjj
v
Employee: Pain Blatt, Emp #: 104, Order #: 500
iLine^ Project # \Quantily \ Descrtytion Г'" 2 |з н
300 '303 [зоо '303
11 so ! 100 \25
|S0
[OFFICE DESK OFFICE DESK " [raWUTERSHELVES- i COMPUTER SHELVES
Please enter an order number
|
Submit Query
УР<1>- Г
I Document: Done
MJ^kJhSk^M^M^^LA
Вызов зерна OrderEJBWrapper из сервлета Существует т а к ж е в о з м о ж н о с т ь в ы з ы в а т ь J a v a B e a n - о б о л о ч к у д л я OrderEJB и з сервлета, а с помощью JSP отображать данные. Такой подход соответствует а р х и т е к т у р е " м о д е л ь - п р е д с т а в л е н и е - к о н т р о л л е р " , к о т о р а я удобна д л я р а б о т ы со с л о ж н ы м и w e b - п р и л о ж е н и я м и (см. р а з д е л " А р х и т е к т у р а w e b - п р и л о ж е н и я " главы 2). С е р в л е т - " к о н т р о л л е р " в ы п о л н я е т с л е д у ю щ и е з а д а ч и : •
И н и ц и а л и з а ц и я э к з е м п л я р а J a v a B e a n - 3 e p n a OrderEJBWrapper и л и неп о с р е д с т в е н н о к о м п о н е н т а OrderEJB
•
В ы з о в м е т о д а getOrder() д л я с ч и т ы в а н и я и н ф о р м а ц и и о к о н к р е т н о м заказе
•
С в я з ы в а н и е с ч и т а н н о г о о б ъ е к т а OrderHeader и л и з е р н а с Н Т Т Р - с е а н с о м с помощью метода session.setAttribute()
•
П е р е д а ч а у п р а в л е н и я и с п о л н е н и е м п р о г р а м м ы J S P - с т р а н и ц е д л я представления информации
J S P м о ж е т с ч и т ы в а т ь о б ъ е к т OrderHeader и з с о в м е с т н о и с п о л ь з у е м о г о НТТР-сеанса и отображать его данные надлежащим образом; то же самое м о ж н о с к а з а т ь и о в ы з о в е g e t l t e m s O д л я п р е д с т а в л е н и я п у н к т о в заказа. Соз д а т ь п р и л о ж е н и е , и с п о л ь з у ю щ е е п о д о б н у ю а р х и т е к т у р у к о м п о н е н т о в , предлагаем читателю.
372
ГЛАВА 11
О
Разработка web-приложений с помощью компонентов CORBA В ч а с т и III э т о й к н и г и г о в о р и л о с ь о р а з р а б о т к е и в н е д р е н и и к о м п о н е н т о в C O R B A в б а з е д а н н ы х Огас1е8г. П р и м е н и м п о л у ч е н н ы е з н а н и я и с о з д а д и м к о м п о н е н т CORBA, к о т о р ы й будет с ч и т ы в а т ь и н ф о р м а ц и ю о заказе, х р а н и мую в б а з е д а н н ы х P u r c h a s e O r d e r , а т а к ж е в ы з о в е м э к з е м п л я р о б ъ е к т а CORBA из web-приложения. Функциональные возможности этого компонент а с х о ж и с т е м и , к о т о р ы м и о б л а д а е т J S P - с т р а н и ц а OrderEJB (см. в ы ш е ) , н о для е г о п р о г р а м м и р о в а н и я и в н е д р е н и я п р и м е н я е тся т е х н о л о г и я C O R B A . Сначал а с о з д а д и м к о м п о н е н т C O R B A д л я п о л у ч е н и я и н ф о р м а ц и и о з а к а з е в базе данных, а затем построим web-приложение, использующее этот компонент.
Объект CORBA для заказов П р о ц е с с о п и с а н и я и в н е д р е н и я о б ъ е к т а C O R B A с о с т о и т из т р е х шагов: 1. С о з д а н и е и к о м п и л я ц и я I D L - ф а й л а д л я модуля C O R B A . 2. О п и с а н и е с е р в е р н о г о класса р е а л и з а ц и и . 3. В н е д р е н и е о б ъ е к т а C O R B A в Огас1е8г. Р а с с м о т р и м в ы п о л н е н и е э т и х о п е р а ц и й д л я модуля C O R B A з а к а з о в .
Создание IDL-файла CORBA С н а ч а л а н е о б х о д и м о с о з д а т ь ф а й л orderCorba. i d l . О н с о с т о и т и з модуля огderCorba, о п и с ы в а ю щ е г о с т р у к т у р ы и н ф о р м а ц и и о з а г о л о в к а х з а к а з а и пункт а х а с с о р т и м е н т а . И с п о л ь з у е м д в е структуры: Lineltem и Orderlnfo, п р и ч е м в Orderlnfo будет с о д е р ж а т ь с я п о с л е д о в а т е л ь н о с т ь о б ъ е к т о в Lineltem. В интерфейсе Order о п р е д е л я е т с я о д и н м е т о д getOrder(), п р е д н а з н а ч е н н ы й д л я с ч и т ы в а н и я в с е й и н ф о р м а ц и и , с в я з а н н о й с з а к а з о м . Э т а схема н а м е р е н н о о т л и ч а е т с я о т р е а л и з а ц и и OrderEJB (см. в ы ш е ) , в к о т о р о й и м е ю т с я два метода: getOrder() и getltemsO. З д е с ь п р е с л е д у е т с я ц е л ь — п о к а з а т ь и н о й с п о с о б в ы б о р а и н ф о р м а ц и и о заказах. •
/ / Имя программы: / / Назначение:
//
orderCorba. i d l Описать структуру объекта CORBA с помощью IDL.
module orderCorba { struct Lineltem { long lineno; long projectno; long quantity; wstring description;
};
struct Orderlnfo { wstring empName; long empNum; long itemCount; sequence items;
};
exception SQLError { wstring message;
};
interface Order { Orderlnfo getOrder (in long orderNumber) raises (SQLError);
>;
};
Использование JSP вместе с EJB, CORBA и библиотеками тэгов
о
Э т о т I D L - ф а й л м о ж н о с к о м п и л и р о в а т ь с п о м о щ ь ю у т и л и т ы i d l 2 j a v a , сген е р и р о в а в п р и э т о м н у ж н ы е к л а с с ы Java. С р е д и г е н е р и р у е м ы х ф а й л о в будут п р и с у т с т в о в а т ь о п и с а н и я к л а с с о в J a v a д л я orderCorba.Orderlnfo и orderCorba. Lineltem д л я структур Orderlnfo и Lineltem с о о т в е т с т в е н н о , а т а к ж е д р у г и е h e l p e r - и h o l d e r - к л а с с ы , н е о б х о д и м ы е д л я о р г а н и з а ц и и в з а и м о д е й с т в и я между к л и е н т о м и с е р в е р о м . В г е н е р и р у е м о м классе orderCorba.Orderlnfo будет с о д е р ж а т ь с я Java-массив Lineltem[], п р е д с т а в л я ю щ и й п о с л е д о в а т е л ь н о с т ь пунктов ассортимента.
Создание серверного класса реализации Т е п е р ь о п и ш е м с е р в е р н ы й класс р е а л и з а ц и и OrderCorbalmpl. Э т о т класс д о л ж е н р е а л и з о в ы в а т ь о б щ и й метод getOrder() с сигнатурой, о п и с а н н о й в IDL-файле orderCorba. С т а т и ч е с к и е S Q L - з а п р о с ы д л я с ч и т ы в а н и я и н ф о р м а ц и и о з а к а з а х удобно в ы п о л н я т ь с п о м о щ ь ю SQLJ. Н и ж е п о к а з а н ф а й л OrderCorbalmpl. s q l j и д а н ы п о я с н е н и я . Вы уже з н а к о м ы с о б ъ я в л е н и е м S Q L J - и т е р а т о р а и з а п р о с а м и . Схема базы данных Purchase O r d e r приведена во введении к книге. •
/ * * Имя программы: OrderCorbalmpl.sqlj * Назначение: Серверный класс реализации для модуля orderCorba. package orderCorbaServer; import orderCorba.*; import оracle.au rora.Auro raServices.ActivatableObj ect; import java.sql.*; public class OrderCorbalmpl extends _OrderImplBase implements ActivatableObject { public Orderlnfo getOrder ( i n t orderNumber) throws SQLError { / / (см. пояснение 1) try { String empName = null; int empNum = 0; / / Выберем информацию о служащем для заказа #sql { SELECT PURCHASE_LIST.employeeno, firstname || ' ' II lastName INTO :empNum, :empName FROM PURCHASE_LIST, EMPL0YEE_LIST WHERE requestno = :orderNumber AND EMPL0YEE_LIST.employeeno = PURCHASE_LIST.employeeno
};
return new OrderInfo(empName, empNum, getltemCount(orderNumber), Getltems(orderNumber)); //(см. пояснение 2) } catch (SQLException e) { throw new SQLError (e.getMessageO);
}
}
private int itemCount = 0; / / Метод для выбора общего числа пунктов заказа private i n t getltemCount ( i n t orderNumber) throws SQLException { #sql { SELECT C0UNT(*) INTO :itemCount FROM LINEITEM_LIST WHERE requestno = :orderNumber
};
return itemCount;
374
ГЛАВА 12
О } / / Объявление SQLJ-итератора для пунктов ассортимента #sql iterator Lineltemslter ( i n t lineno, int projectno, int quantity, String description); / / Метод для выбора пунктов, соответствующих определенному заказу private Lineltem[] getltems(int orderNumber) throws SQLException { Lineltemslter l i = null; / / (см. пояснение 3) #sql l i = { SELECT lineno, projectno, quantity, description FROM LINEITEM_LIST WHERE requestno = :orderNumber ORDER BY lineno
};
Lineltem[] items = new Lineitem [itemCount]; for ( i n t i = 0; i < itemCount; i++) { li.next(); items[i] = new Lineltem(li.linenoQ, li.projectno(), li.quantityO, li.description());
}
}
}
li.close(); return items;
public org.omg.CORBA.Object _initializeAuroraObject() { return this; }
П о я с н е н и я к OrderCorbalmpl. s q l j : 1. Э т о р е а л и з а ц и я м е т о д а getOrder(), о п и с а н н о г о в м о д у л е orderCorba. И з т а б л и ц PURCHASE_LIST и EMPL0YEE_LIST в ы б и р а е т с я и н ф о р м а ц и я о заголовках заказа, а затем в ы з ы в а е т с я метод getltemsO для с ч и т ы в а н и я и н ф о р м а ц и и об ассортименте. 2. Э т о т о п е р а т о р с т р о и т н о в ы й о б ъ е к т O r d e r l n f o д л я у к а з а н н о г о з а к а з а и в о з в р а щ а е т его. 3. Э т о т метод с ч и т ы в а е т пункты указанного заказа из т а б л и ц ы LINEITEM_LIST с помощью именованного SQLJ-итератора. КОМПИЛЯЦИЯ И
внедрение компонента
CORBA
К л а с с ы к о м п и л и р у ю т с я и з а г р у ж а ю т с я в Огас1е8гс п о м о щ ь ю у т и л и т ы load java (Makefile п р и л а г а е т с я к п р о г р а м м н о м у тексту). П о с л е э т о г о н е о б х о д и м о опубликовать объект CORBA в пространстве имен J N D I с помощью инструмента о б о л о ч к и с е а н с о в Огас1е8г. П р и в е д е м п р и м е р : •
Вызов объекта CORBA из web-приложения К а к и п р и р а б о т е с з е р н а м и EJB, для w e b - п р и л о ж е н и я , и с п о л ь з у ю щ е г о к о м п о н е н т C O R B A , существует н е с к о л ь к о а р х и т е к т у р н ы х в а р и а н т о в . С а м ы м
Использование JSP вместе с EJB, CORBA и библиотеками тэгов
о
о ч е в и д н ы м , н о не о б я з а т е л ь н о л у ч ш и м , п о д х о д о м я в л я е т с я в ы з о в е г о из J S P - п р о г р а м м ы . Э т о п р е д п о л а г а е т н а п и с а н и е в J S P - п р о г р а м м е б о л ь ш о г о объема п р о г р а м м н о г о т е к с т а Java, ч т о у с л о ж н я е т п р о ц е с с с о п р о в о ж д е н и я . Л у ч ш е вызывать объект CORBA при помощи JavaBean или сервлета и применять JSP т о л ь к о д л я ввода д а н н ы х и для о т о б р а ж е н и я результатов. И м е н н о т а к и м подх о д о м м ы и в о с п о л ь з у е м с я . О п и ш е м для о б ъ е к т а OrderCorba JavaBean-оболочку OrderCorbaWrapper и п р и м е н и м э т о з е р н о на J S P - с т р а н и ц е .
Вызов объекта OrderCorba при помощи JavaBean-оболочки С о з д а д и м п р и л о ж е н и е на о с н о в е J S P , и с п о л ь з у ю щ е е OrderCorba для с ч и т ы в а н и я и н ф о р м а ц и и о заказе. К о м п о н е н т ы э т о г о w e b - п р и л о ж е н и я п р е д с т а в л е н ы на р и с . 12.4. Д л я о б р а щ е н и я к к о м п о н е н т у OrderCorba в п р и л о ж е н и и п р и м е н я е т с я JavaBean-ioiacc OrderCorbaWrapper. П р и и с п о л ь з о в а н и и к о м п о н е н т а JavaB e a n с н и ж а е т с я о б ъ е м п р о г р а м м н ы х к о н с т р у к ц и й Java, к о т о р ы е нужно п и с а т ь с о б с т в е н н о в J S P - п р о г р а м м е . J S P - с т р а н и ц а CallOrderCorba. jsp будет т о ч к о й входа в э т о п р и л о ж е н и е .
База данных Purchase Order С о з д а н и е JavaBean-3epHa OrderCorbaWrapper Н и ж е п р и в о д и т с я п р о г р а м м н ы й т е к с т J a v a B e a n - 3 e p n a OrderCorbaWrapper, к о т о р о е и щ е т и а к т и в и з и р у е т о б ъ е к т C O R B A , а т а к ж е п р е д о с т а в л я е т м е т о д о б о л о ч к и для е г о м е т о д а getOrder(). Д о п о л н и т е л ь н о й ф у н к ц и е й м е т о д а getOrdeг() я в л я е т с я п о п ы т к а п о в т о р н о г о и с п о л ь з о в а н и я к э ш и р о в а н н о й и н ф о р м а ц и и о з а к а з е в т о м случае, е с л и н о м е р з а к а з а н е и з м е н и л с я с м о м е н т а п о с л е д н е г о в ы з о в а э т о г о м е т о д а . Л о г и к а предл а г а е м о г о J a v a B e a n д о в о л ь н о п о х о ж а на л о г и к у OrderEJBWrapper (см. в ы ш е ) . Важные участки текста программы выделены ж и р н ы м ш р и ф т о м . •
/ * * Имя программы: * Назначение:
ч
OrderCorbaWrapper.java Обратиться к объекту OrderCorba и считать информацию о заказе.
package mybeans; import import import import import import public
{
orderCorba.*; oracle.aurora.jndi.sess_iiop.ServiceCtx; javax.naming.Context: javax.naming.InitialContext; java.util.Hashtable; javax.servlet.http.*; class OrderCorbaWrapper implements HttpSessionBindingListener
public OrderCorbaWrapper() {} private Order order = null;
/ / объект CORBA
375
376
ГЛАВА 12
О private Orderlnfo orderlnfo = null;
/ / считываемая информация о заказе
private int orderNumber; public void setOrderNumber ( i n t orderNum) { i f (this.orderNumber l= orderNum) { orderlnfo = null; / / отбросим ранее кэшированное значение this.orderNumber = orderNum; }
} public Orderlnfo getOrderQ throws Exception { i f (orderlnfo != null) return orderlnfo; / / повторно воспользуемся ранее кэшированным значением i f (order == n u l l ) { / / найдем объект String serviceURL = "sess._iiop://data-i:2481:0RCL"; String objectName = "/test/OrderCorba"; String user = "jspuser"; String password = "jsp"; Hashtable env = new HashtableO; env.put(Context.URL_.PKG_PREFIXES, "oracle.aurora.jndi"); env. put(Context. SECURITY_.PRINCIPAL, user); env.put(Context.SECURITY_CREDENTIALS, password); env.put(Context.SECURITY_AUTHENTICATION, ServiceCtx.N0N_SSL_L0GIN); Context ic = new InitialContext(env);
} }
order = (Order)ic.lookup (serviceURL + objectName);
/ / Метод, исполняемый при размещении зерна в НТТР-сеансе public void valueBound(HttpSessionBindingEvent event) { / / Здесь ничего не делаем! / / Объект CORBA будет создан только при передаче запроса
}
/ / Метод, исполняемый при удалении зерна из сеанса public synchronized void valueUnbound( HttpSessionBindingEvent event) { i f (order l= null) { try { order.deactivate(); } catch (Exception e) {} } }
}
С о з д а н и е CallOrderCorba. j s p В э т о й J S P - п р о г р а м м е д л я в ы з о в а о б ъ е к т а O r derCorba и с п о л ь з у е т с я о п и с а н н о е в ы ш е J a v a B e a n - з е р н о OrderCorbaWrapper. Текст программы приводится ниже. Важные участки текста выделены жирн ы м ш р и ф т о м . Н а JSPr-странице п р и с у т с т в у ю т H T M L - ф о р м а д л я в в о д а номер а з а к а з а и к н о п к а S u b m i t Q u e r y д л я с ч и т ы в а н и я х а р а к т е р и с т и к заказа. Э т а кнопка и н и ц и и р у е т вызов компонента OrderCorba ч е р е з JavaBean. Д а н н ы е форматируются и выдаются пользователю в виде HTML-таблицы. •
<%@ taglib uri="/WEB-INF/jml.tld" prefix="jml" %> <%@ taglib uri="/WEB-INF/sqltaglib.tld" prefix="ora" %> <jml:transform href="mystyle1.xsl" > SELECT * FROM PURCHASF__LIST <jml:transform href="/styles/mystyle2.xsl" > 1.0 <jspversion>1.1 <shortname>mytags My simple tab l i b r a r y dateTimechapter12.DateTimeTagempty Prints the current date and/or the time in different formats. output <required>false format < requi red>false 3 . П р о т е с т и р у е м т э г dateTime. Э т а п р о с т а я J S P с и м е н е м TestDateTime. jsp с н а ч а л а и м п о р т и р у е т ф а й л mytaglib. t l d д л я т э г а dateTime п р и п о м о щ и д и р е к т и в ы t a g l i b , а з а т е м вызывает тэг в трех местах с разными параметрами:
Объявление переменных и функций В JSP можно объявлять для страницы переменные и функции:
• <%!
int к = 0; int calculateSum (int a, int b) { // Производим вычисления }
%>
Скриптлеты Скриптлеты применяются для встраивания программных конструкций Java в JSP-программы. Например:
• <% %>
// Здесь введем программные конструкции Java
439
440
ПРИЛОЖЕНИЕ F
О Выражения
В JSP-программах можно использовать выражения, возвращающие на страницу значение из программы Java: •
Hello, <%=username %>
Тэг j s p : plugin Этот тэг разрешает JSP-программам включать зерна и апплеть* в состав клиентской страницы: •
Неявные объекты Неявным называется серверный объект, описанный в JSP-контейнере. Неявные объекты представлены в таблице D.I. Таблица D.1. Неявные объекты JSP Неявный объект
Тип
Область действия
request
javax.servlet.ServletRequest
Request
response
javax.servlet.ServletResponse
Page
pageContext
javax.servlet.jsp.PageContext
Page
session
javax.servlet.HttpSession
Session
application
javax.servlet.ServletContext
Application
out
javax.servlet.jsp.JspWriter
Page
config
javax.servlet.ServletConfig
Page
exception
java.lang.Throwable
Page
page
java.lang.Object
Page
Справочник по JSP API В этом разделе дается общий обзор JSP API. За дополнительными сведениями о различных пакетах, интерфейсах и классах обращайтесь по адресам java.sun.com/j2ee/j2sdkee/techdocs/api/javax/servlet/jsp/package-summary, html и java.sun.com/j2ee/j2ee/j 2sdkee/techdocs/api/javax/servlet/jsp/tag e x t / package-summary.html.
Краткий справочник по JavaServer Pages
о
JSP API состоит из двух пакетов: •
javax.servlet.jsp
•
javax.servlet.jsp.tagext
Пакет j a v a x . s e r v l e t . j s p Пакет javax.servlet.jsp состоит из нескольких интерфейсов и классов. JSP-интерфейсы и их методы представлены в листинге D.I. Листинг D.I. JSP-интерфейсы •
/ / Интерфейс HttpJspPage
public interface HttpJspPage extends JspPage { public void _jspService (HttpServletRequest request,
public interface JspPage extends Servlet { public void jspDestroyO; public void jsplnit(); } // Конец интерфейса JspPage JSP-классы и их методы представлены в листинге D.2. Листинг D.2. JSP-классы •
/ / Класс J s p E n g i n e l n f o
public abstract class JspEnginelnfo extends Object { // Конструктор public JspEnginelnfoO; // Метод public abstract String getSpecificationVersion(); } // Конец класса JspEnginelnfo / / Класс J s p F a c t o r y
public abstract class JspFactory extends Object { // Конструктор public JspFactoryO; / / Методы
public static getDefaultFactory(); public static void setDefaultFactory (JspFactory aJspFactory); public abstract JspEnginelnfo getEnginelnfoQ; / / Методы PageContext
public abstract PageContext getPageContext (Servlet requestServlet, ServletRequest request, ServletResponse response, String errorPagellrl, boolean needsSession, int buffer, boolean autoFlush); public abstract void releasePageContext (PageContext pc); } // Конец класса JspFactory / / Класс J s p W r i t e r
public abstract class JspWriter extends Writer { // Конструктор protected JspWriter (int bufferSize, boolean autoFlush); / / Методы
public abstract public abstract public abstract public abstract public abstract public abstract public abstract public abstract public abstract public abstract } // Конец класса
public abstract class PageContext extends Object { // Конструктор public PageContext(); / / Константы области действия
public public public public
static static static static
final final final final
int APPLICATION_SCOPE; int PAGE_SCOPE; int REQUEST_SCOPE; int SESSI0N_SC0PE;
/ / Методы атрибутов
public abstract Object findAttribute(String name); public abstract Object getAttribute(String name); public abstract Object getAttribute(String name, int scope); public abstract Enumeration getAttributeNamesInScope(int scope); public abstract int getAttributeScope(String name); public abstract void removeAttribute(String name); public abstract void removeAttribute (String name, int scope); public abstract void setAttribite (String name, Object obj); public abstract void setAttribLte (String name, Object obj, int scope); / / Методы исключительных ситуаций
public abstract Exception getException(); public abstract void handlePageException(Exception e ) throws ServletException, IOException; / / Метод f o r w a r d
public abstract void forward(String relativePath) throws ServletException, IOException;
Краткий справочник по JavaServer Pages
о
/ / Метод getOut
public abstract JspWriter getOut(); / / Метод I n c l u d e
public abstract void include(String relativePath) throws ServletException, IOException; / / Метод i n i t i a l i z e
public abstract void initialize (Servlet requestServlet, ServletRequest request, ServletResponse response, String errorPagellrl, boolean needsSession, int buffer, boolean autoFlush) throws IOException, IllegalStateException, IllegalArgumentException; / / Метод popBody
public JspWriter popBodyO; / / Метод pushBody
public BodyContent pushBodyO; / / Метод r e l e a s e
public abstract void release(); / / Методы для получения компонентов сервлета
public abstract public abstract public abstract public abstract public abstract public abstract } // Конец класса Пакет
Этот пакет состоит из нескольких интерфейсов и классов. В листинге D.3 представлены интерфейсы и их методы, а в листинге D.4 — классы и их методы. Листинг D.3. Интерфейсы тэгов •
/ / Интерфейс BodyTag
public interface BodyTag extends Tag { // Константа public static final int EVAL_BODY_TAG; / / Методы
public int doAfterBodyO throws JspTagException; public int doInitBodyO throws JspTagException; public void setBodyContent(BodyContent be); } // Конец интерфейса BodyTag / / Интерфейс Tag
public interface // Константы public static public static public static public static
Tag { final final final final
int SKIP_B0DY; int EVAL_BODY_INCLUDE; int SKIP_PAGE; int EVAL_PAGE;
/ / Методы
public int doEndTagO throws JspTagException; public int doStartTagO throws JspTagException;
443
public Tag getParentO; public void releaseO; public void setPageContext(PageContext pc); public void setParent(Tag tag); } // Конец интерфейса Tag
Листинг D.4. Классы тэгов / / Класс BodyContent
public abstract class BodyContent extends JspWriter // Конструктор protected BodyContentO; / / Методы
public void clearBodyO; •public void flush() throws IOException; public JspWriter getEnclosingWriter(); public abstract Reader getReader(); public abstract String getStringO; public abstract void writeOut(Writer out) throws IOException; } // Конец класса BodyContent / / Класс BodyTagSupport
public class BodyTagSupport extends TagSupport implements BodyTag { // Конструктор public BodyTagSupportO; / / Методы
public public public public public public public
int doAfterBodyO throws JspTagException; int doEndTagO throws JspTagException; int doInitBodyO; BodyContent getBodyContentO; JspWriter getPreviousOut(); void releaseO; void setBodyContent(BodyContent be);
} // Конец класса BodyTagSupport / / Класс T a g A t t r i b u t e l n f o
public class TagAttributelnfo extends Object { // Конструктор public TagAttnbuteInfo(String name, boolear required, boolear rtexprvalue, String type, boolear reqTime); / / Методы
public boolean canBeRequestTime(); public static TagAttributelnfo getIdAttribute(TagAttributeInfo[] lists); public String getName(); public String getTypeName(); public boolean isRequiredO; public String toStringO; } // Конец класса TagAttributelnfo / / Класс TagData
public class TagData extends Object implements Cloneable { // Конструктор
Краткий справочник по JavaServer Pages
public TagData(Object [][] attrs); public TagData(Hashtable attrs); / / Методы
public Object getAttribute(String name); public String getAttributeString(String name); public String getld(); public void setAttribute(String name, Object value); } // Конец класса TagData / / Класс T a g E x t r a l n f o
public abstract class TagExtralnfo extends Object { // Конструктор public TagExtralnfoO; / / Методы
} // Конец класса TagExtralnfo / / Класс T a g l n f o
public class Taglnfo extends Object public static final int BODY_CONTENT_JSP; public static final int BODY_CONTENT_TAG_DEPENDENT; public static final int B0DY_C0NTENT_EMPTY; // Конструктор public TagInfo(String name, String class, String content, String infoString, TagLibrarylnfo lib, TagExtralnfo tsi, TagAttributeInfo[] attr); / / Методы
public public public public public public public public public public
} // Конец класса TagSupport / / Класс V a r i a b l e l n f o
public class Variablelnfo extends Object { // Конструктор public VariableInfo(String varName, String classname boolean declare, int scope; / / Методы и константы
public public public public public public public
static final int NESTED; static final int AT_BEGIN; static final int AT_END; String getVarNameO; String getClassName(); boolean getDeclareO; int getScopeO;
} // Конец класса TagSupport За дополнительными сведениями о JSP обращайтесь к главам 2, 10 — 12, j a v a . s u n . c o m / p r o d u c t s / j s p / и r-с библиографическому справочнику в конце книги.
ПРИЛОЖЕНИЕ Е
О
Установка и конфигурирование web-cepeepoe для работы с OracleJSP
448
ПРИЛОЖЕНИЕ F
О
D ш т этом приложении говорится о том, как устанавливать и настраивать для работы с Oracle JSP следующие web-серверы: • Tomcat (Servlet 2.2 API) • Java Web Server (Servlet 2.1 API) • Apache и JServ (Servlet 2.0 API) В Oracle Internet Application Server (iAS) версии 1.0 используется среда Apache/JServ. Двигатель Oracle JSP устанавливается в процессе инсталляции iAS. В Oracle версии 8.1.7 также предусмотрена возможность выполнения сервлетов и JSP-программ в базе данных. В этом случае двигатель Oracle JSP устанавливается при инсталляции базы данных. Дополнительно в Oracle 8.1.7 включен Oracle HTTP Server, который функционирует вне базы данных и усилен комбинацией Apache/JServ и двигателем Oracle JSP. Кроме того, JSP-npoграммы можно редактировать и отлаживать при помощи Oracle JDeveloper (см. приложение F).
Установка Oracle JSP в Tomcat Tomcat — это эталонная реализация Servlet 2 2 API и JSP 1.1 с бесплатно распространяемым доступным исходным текстом, разработанная совместно фондом Apache Software Foundation, Sun Microsystems и др. Tomcat довольно просто настраивается для работы с Oracle JSP. Ниже описываются этапы установки и конфигурирования Tomcat и Oracle JSP.
Этапы установки Tomcat может функционировать вместе с web-сервером Apache или автономно в качестве упрощенного web-сервера. Рассмотрим этапы установки и выполнения Tomcat в автономном режиме. За информацией об установке Tomcat вместе с Apache в другой конфигурации обращайтесь к документации на Tomcat. Для выполнения JSP-программ с помощью Oracle JSP и Tomcat необходимо: • Установить JDK • Установить Tomcat • Установить Oracle JSP • Установить базу данных Oracle с JDBC и SQLJ • Установить утилиты Oracle XML (необязательно) Рассмотрим подробнее эти операции.
Установка JDK Загрузите JDK 1.1 или выше cjava.sun.com и установите его. Рекомендуется JDK 1.2 (Java 2), так как он содержит средства пулинга соединений JDBC 2.0 и другие новые полезные библиотеки. Предположим, что инструментарий установлен в каталоге ${JDK_H0ME} системы. Укажите в переменной среды CLASSPATH компилятор javac — он-понадобится для компиляции исходных программ Java, генерируемых для JSP- файлов. Этот этап зависит от установленной версии JDK: • Для JDK 1.2 укажите
${JDK_HOME}/lib/tools.
jar в CLASSPATH.
• Для JDK 1.1 * укажите ${ JDK_HOME}/lib/classes. zip в CLASSPATH. Для NT используйте в маршрутах к каталогам соответствующие символы разделителей файлов (\) и маршрутов (;).
Установка и конфигурирование web-серверов для работы с Oracle JSP
449
Установка Tomcat Загрузите последнюю версию Tomcat для своей платформы с web-сайта jakarta.apache.org и установите сервер. Задайте переменную среды ${ТОМСАТ_НОМЕ} так, чтобы она указывала на корневой каталог инсталляции. Эта переменная используется сценариями запуска и остановки Tomcat (по умолчанию ее значением является текущий или родительский каталог относительно того, откуда вызываются сценарии). Для применения Tomcat не в качестве автономного web-cepeepa, а вместе с Apache обратитесь к инструкциям, приведенным в файле "Tomcat+Apache-HOWTO" в каталоге ${TOMCAT_HOME}/docs.
Установка Oracle JSP Загрузите последнюю версию (1.1 или выше) Oracle JSP по сети Oracle Technology Network (technet.oracle.com/tech/servlels). Установите переменную среды ${OJSP_HOME} надлежащим образом. Компонентом системы Oracle 8.1.7 являются еще и библиотеки Oracle JSP 1.1.
Установка Oracle с JDBC и SQLJ Если сервлеты и JSP-программы взаимодействуют с базой данных, нужно также обращаться к экземпляру базы данных. Пробные варианты Огас1е8г для NT и Linux можно загрузить с сайта сети Oracle Technology Network (technet.oracle.com/). Для установки базы данных следуйте предлагаемым инструкциям. Задайте переменную среды ${ORACLE_HOME} так, чтобы она указывала на корневой каталог инсталляции. Библиотеки JDBC и SQLJ являются компонентами системы Oracle. Кроме того, можно загрузить их по отдельности с сайта сети Oracle Technology Network (technet.oracle.com/tech/java/sqlj_jdbc).
УстановкаУгилит Oracle XML При использовании XML в JSP-программах необходимо установить библиотеки Oracle XML. К ним относятся синтаксический анализатор Oracle XML (версии 2) и утилита Oracle XML-SQL (XSU). Они входят в состав Oracle 8.1.7, и, кроме того, их можно загрузить по отдельности с сайта сети Oracle Technology Network (technet.oracle.com/tech/xml) как часть инструментария разработчика Oracle XML Developer's Kit (XDK). Установите переменную среды ${XML_HOME} надлежащим образом.
Этапы конфигурирования Tomcat обладает своим собственным двигателем JSP, но ничто не мешает настроить Tomcat для работы с Oracle JSP, установив параметры Oracle JSP в соответствии с потребностями применяемой среды. Молено также модифицировать стандартную конфигурацию Tomcat (например, заменить порт прослушивающего процесса по умолчанию 8080 каким-либо иным). Для настройки Tomcat используются файлы двух типов: server.xml и web.xml. Ниже описываются этапы конфигурирования Tomcat: • Конфигурирование сервера Tomcat при помощи server.xml • Конфигурирование Tomcat с Oracle JSP при помощи web.xml
Конфигурирование сервера Tomcat Работу
двигателя
Tomcat
можно
настроить
с
помощью
XML-файла
${TOMCAT_HOME}/conf/server. xml. Например, чтобы изменить номер порта по
умолчанию 8080 на номер 8085, нужно модифицировать этот файл следующим образом (строка выделена жирным шрифтом): •
<Parameter name="handler" value="org.apache.tomcat.service.http.HttpConnectionHandler"/> <Parameter name="port" v a l u e = " 8 0 8 5 " / >
450
ПРИЛОЖЕНИЕ Е :
О
Использование Oracle JSP вместе с Tomcat Tomcat поставляется с собственным двигателем JSP (с именем Jasper). Однако конфигурацию сервера Tomcat молено изменить так, чтобы использовать в нем Oracle JSP, поставляемый вместе с дополнительными зернами и библиотеками для обращения к базам данных, а также с другими ценными средствами. Для указания Tomcat на необходимость использования двигателя Oracle JSP нужно: • Добавить oracle, jsp. JspServlet к набору сервлетов. Этот сервлет является точкой входа для двигателя Oracle JSP. • Отобразить JSP-расширсния в URL на этот сервлет. Это называется отображением расширений (extension mapping). • Добавить необходимые библиотеки в CLASSPATH. Первые два шага выполняются при помощи файла web.xml. В нем содержатся имена сервлетов и их URL-отображения, а также сведения о конфигурации сеансов: таймаут, отображения библиотек тэгов и т.д. Глобальный файл web.xml находится в каталоге ${T0MCAT_H0ME}/conf. Если требуется применить для устанавливаемого web-приложения другие параметры, обновите файл web. xml, расположенный в WEB-INF ниже корня данного приложения. Например, для выполнения Oracle JSP в Tomcat можно модифицировать файл ${TOMCAT_HOME}/webapps/examples/WEB-INF/web.xml. Добавление oracle.jsp.JspServlet В раздел <web-app> файла web.xml добавьте следующие записи для сервлета Oracle JSP: •
<servlet> <servlet-name> ojsp
<servlet-class> oracle.jsp.JspServlet
<param-name> external_resource
<param-value> true
<param-name> unsafe_reload
<param-value> true
Этим объявлением сервлет с именем oracle.jsp.JspServlet добавляется к набору сервлетов данного приложения. Ему присваивается краткое имя ojsp, используемое в качестве псевдонима (см. следующий шаг). Здесь указаны два параметра инициализации: external_resource и unsafe_reload; они описываются для сервлета Oracle JSP при помощи элемента . Имя и значение параметра задаются элементами <param-name> и <param- value>, которые включаются в блок . Описание параметров конфигурации Oracle JSP приводится ниже. О т о б р а ж е н и е JSP-расширений Необходимо отобразить JSP-сервлет на указатели URL, ссылающиеся на JSP-файлы. Для этого отобразите oracle.jsp.JspServlet на четыре различных шаблона URL: *.jsp, *. JSP, *.sqljspH *. SQLJSP. Это значит, что данный сервлет должен вызываться web-сервером
Установка и конфигурирование web-серверов для работы с Oracle JSP
для всех указателей URL запросов, заканчивающихся расширением jsp, JSP, .sqljsp или .SQLJSP. С этой целыо добавьте в раздел отображения сервлетов файла web.xml следующие строки: •
servlet-mapping> <servlet-name> оj s p
*. jsp
<servlet-mapping> <servlet-name> ojsp
JSP
<servlet-mapping> <servlet-name> ojsp
*.sqljsp
<servlet-mapping> <servlet-name> ojsp
SQLJSP В данном отображении для класса oracle.jsp.fJspServlet используется краткое имя ojsp (этот псевдоним был создан на шаге 2) и указывается, что сервлет должен вызываться для четырех суффиксов файлов. Добавление библиотек Рассмотрим библиотеки трех различных типов: • Oracle JSP • JDBC и SQLJ • XML Опишем этапы добавления этих библиотек в среду Tomcat. • Добавление библиотек Oracle JSP В системах, основанных на UNIX, скопируйте (или символически свяжите) библиотеки Oracle JSP ${OJSP_HOME}/lib/ojsp.jar и ${OJSP_HOME}/lib/ojsputil.jar с каталогом ${T0MCAT_H0ME}/lib. Файлы jar этого каталога автоматически включаются в CLASSPATH сервера Tomcat. В.системах, основанных на Windows, отредактируйте файл tomcat.bat в каталоге ${T0MCAT_H0ME}\bin, включив эти два файла jar в переменную среды CLASSPATH. В качестве альтернативы можно добавить эти библиотеки в CLASSPATH до запуска сервера Tomcat. • Добаь <*ние библиотек JDBC и SQLJ Если в сервлетах и JSP-программах вь: .^лняются операции над базой данных, необходимо, помимо всего проче; о, добавить в CLASSPATH библиотеки JDBC и SQLJ. Обычно они помещаются в каталог ${T0MCAT_H0ME}/lib. Можно непосредственно
451
452 :
ПРИЛОЖЕНИЕ Е
О
скопировать эти библиотеки либо указать на них символической ссылкой в системе Oracle. Библиотеки JDBC находятся в $ {0RACLE_H0ME}/lib/ classeslll.zip (для JDK 1.1) и ${0RACLE_H0ME}/lib/classes12. zip (для JDK 1.2). Библиотеки транслятораSQIJ размещаются в ${0RACLE_H0ME}/ l i b / t r a n s l a t o r , zip. Кроме того, нужно добавить надлежащие классы исполняющей системы SQLJ в одну из следующих библиотек: • runiime12.zip (для использования cJDK 1.2 и Oracle JDBC 8.1.7) • runtime12ee. zip (для JDK 1.2.* Enterprise Edition с Oracle JDBC 8.1.7) • runtime11.zip (для JDK 1.1 * с Oracle JDBC 8.1.7) • runtime.zip (общие: для JDK 1.2 или 1.1 с любой версией Oracle JDBC) В версии JDK 1.2 Enterprise Edition (ее) библиотек SQLJ поддерживаются источники данных (datasources) JDBC 2.0, согласующиеся с ISO-спецификацией SQLJ. • Добавление библиотек Oracle XML При использовании в JSP-npoграммах XML-конструкций добавьте библиотеки ORACLE XML ~ ${XML_H0ME}/lib/xmlparserv2.jar и ${XML_H0ME}/.1 .ib/oraclexmlsql. jar в ${T0MCAT_H0ME}/lib. В качестве а л ь т е р н а т и в ы можно добавить их в CLASSPATH до запуска сервера T o m c a t .
Запуск с е р в е р а Tomcat После установки перейдите в каталог ${Т0МСАТ_Н0МЕ}/bin и запустите сервер Tomcat. В системе UNIX для запуска сервера используется сценарий startup, sh, а для остановки — shutdown, sh. В системах Windows для запуска и остановки сервера применяются пакетные (командные) файлы startup.bat и shutdown.bat. После запуска сервера начальная страница выводится при указании нужного URL в браузере, например http://localhost:8085/.
Выполнение JSP-программ в Tomcat В комплект поставки Tomcat входит ряд примеров использования JSP. Ссылки на эти примеры находятся на начальной странице Tomcat, и мы рекомендуем выполнить их, прежде чем приступить к работе с собственными JSP-программами. Ниже показано, как выполнять в Tomcat программу Hello.jsp (см. главу 10) и приложение Order Online (см. главу 11).
Выполнение Hello.jsp Разместите файл Hello, jsp, созданный в главе 10, в каталоге ${Т0МСАТ_Н0МЕ}/ webapps/examples/jsp/chapter10/Hello. jsp. Затем можно выполнить JSP, указав в браузере URL http://localhost:8085/examples/jsp/chapterl0/Hello.jsp. Можно также установить в Tomcat собственное web-приложение и файл Hello, jsp. В этом случае выполняются те же действия, что и при инсталляции приложения Order Online (см. ниже).
Выполнение приложения Order Online Приложение Order Online было создано в главе 11. Оно состоит из следующих файлов: • JSP-страницы EnterOrder. jsp, InsertOrder. jsp, QueryOrder. jsp • Зерна CartBean. java, DBInsertBean. sqlj и DBQueryBean. sqlj, которые входят в состав Java-пакета mybeans Внедрить приложение в Tomcat можно двумя способами: • Как часть существующего приложения examples • Как новое приложение OrderOnline
Установка и конфигурирование web-серверов для работы с Oracle JSP
В первом случае нужно разместитьJSP-файлы в каталоге ${Т0МСАТ_Н0МЕ}/ webapps/examples/j sp/chap Ler11/, а классы JavaBean после к о м п и л я ц и и — в ${TOMCAT_HOME}/webapps/examples/WEB-INF/classes. Для к о м п и л я ц и и зерен в системе UNIX и среде JDK 1.2 применяются следующие команды: •
${JDK_HOME}/bin/javac -g \ -d ${TOMCAT_HOME}/webapps/examples/WEB-INF/classes \ -classpath ${TOMCAT_HOME}/lib/servlet.jar \ CartBean.java ${0RACLE HOME}/bin/sqlj -g \ -d ${TOMCAT_HOME}/webapps/exaniples/WEB-INF/classes \ -classpath ${0RACLE_H0ME}/jdbc/llb/classes12.zip:\ ${ORACLE_HOME}/sqlj/lib/translator,zip:\ ${ORACLE_HOME}/sqlj/lib/runtime.zip:${TOMCAT_HOME}/lib/servlet.jar \ DBInsertBean.sqlj DBQueryBean.sqlj В системе Windows NT используются аналогичные команды. Компилируемые к л а с с ы зерен помещаются в каталог ${TOMCAT_HOME}/webapps/examples/ WEB-INF/classes, для чего служит параметр -d в javac. Этот каталог включается в CLASSPATH web-сервера Tomcat для приложения examples. После этого молено вызвать первый экран приложения, введя нужный URL в браузере, например h t t p : / / l o c a l h o s t : 8 0 8 5 / e x a m p l e s / j s p / c h a p t e r l l / EnterOrder.jsp. Во в тором случае, когда создается отдельное \уеЬ-приложение с именем ОгderOnline, необходимо ввести запись контекста в файл server, xml (см. выше):
•
В этом объявлении URL-путь к приложению указывается как /OrderOnline, а корень приложения — как каталог ${TOMCAT_HOME}/webapps/OrderOnline. В подкаталоге jsp молено разместить три JSP-файла. Параметр reloadable говорит о том, что зерна и другие классы следует перезагружать автоматически (без перезапуска сервера Tomcat), что ускоряет время разработки программ. Скомпилированные классы JavaBean размещаются, как правило, в каталоге ${TOMCAT_HOME}/webapps/OrderOnline/WEB-INF/classes. К каталогу WEB-INF нельзя получить доступ с помощью URL браузера, этот каталог по умолчанию включается в CLASSPATH сервера Tomcat. Другие вспомогательные классы (если они есть) пулено размещать в каталоге $ {Т0МСАТ_Н0МЕ} /webapps/О rdeгОп1 ine/WEB - INF/lib. Все jar- и zip-файлы этого каталога автоматически добавляются в CLASSPATH сервера. После этого можно вызвать первый экран приложения Order Online, введя нулшый URL, например
Установка и конфигурирование Java Web Server Web-ссрвср Java (JWS, Java Web Server) входит в состав инструментария разработки Java Server Web Development Kit (JSWDK) и служит эталонной реализацией для Servlet 2.1 API и спецификации JSP 1.0. Сегодня JWS по большей части вытеснен сервером Tomcat, но некоторые пользователи продолжают применять эту среду.
Этапы установки 1. Установка JDK. См. процесс установки Tomcat, описанный выше. Не забудьте включить библиотеки компилятора javac в CLASSPATH.
453
454 : О
ПРИЛОЖЕНИЕ Е
2. Установка JSWDK. Загрузите JSWDK с web-сайтаjava.sun.com/products/ servlet/index.html и установите его. Предположим, что он установлен в каталоге ${JWS_HOME}. 3. Установка Oracle JSP. См. процесс установки Tomcat, описанный выше. 4. Установка Oracle с JDBC и SQLJ. См. процесс установки Tomcat, описанный выше. 5. Установка Oracle XML. См. процесс установки Tomcat, описанный выше.
Этапы конфигурирования В этом разделе описывается функционирование Oracle JSP на web-сервере Java Web Server (JWS).
Использование Oracle JSP вместе с JWS Как и Tomcat, JWS поставляется с собственным двигателем JSP, но его без труда можно настроить для выполнения Oracle JSP. Эта процедура аналогична той, что использовалась для Tomcat, и состоит из трех этапов: • Добавление сервлета Oracle JSP к JWS • Отображение JSP-расширений • Добавление необходимых библиотек в среду JWS Рассмотрим подробнее эти :>тапы. Добавление сервлета Oracle JSP Модифицируйте файл servlets. properties в каталоге WEB-INF для каждого контекста сервлета, указав oracle, jsp. JspServlet в качестве сервлета, обрабатывающего JSP. Кроме того, пометьте символами комментариев отображение, ранее описанное для эталонной реализации JSP. Например, измените файл ${JWS_HOME}/examples/WEB-INF/servlets.properties следующим образом: •
Режим работы двигателя Oracle JSP определяет строка jsp. initparams. Здесь указаны два параметра инициализации: external_resource и unsafe_reload. Описание этих и других параметров конфигурации Oracle JSP можно найти в конце приложения. Отображение расширений JSP Отредактируйте файл mappings, properties в каталоге WEB-INF для каждого контекста сервлета, отобразив JSP- расширения следующим образом: •
# Отобразим JSP-расширения .jsp=jsp .JSP=jsp .sqljsp=jsp .SQLJSP=jsp Добавление библиотек Вам понадобятся библиотеки Oracle JSP, библиотеки Oracle JDBC и SQLJ и (необязательно) библиотеки Oracle XML: • Добавление библиотек Oracle JSP Поместите библиотеки Oracle JSP - ${OJSP_HOME}/lib/ojsp.jar и ${OJSP_HOME}/lib/ojsputil.jar - в каталог ${JWS_HOME}/lib. Кроме того, необходимо модифицировать сценарий startserver в корневом каталоге ${JWS_HOME}, добавив библиотеки ojsp. jar и ojsputil. jar в переменную среды jspJars: set jspJars=./lib/ojsp.jar:/lib/ojsputil.jar
Установка и конфигурирование web-серверов для работы с Oracle JSP
С
• Добавление библиотек Oracle JDBC и SQLJ Поместите библиотеки JDBC и SQLJ (набор необходимых библиотек рассматривался выше при конфигурировании T o m c a t ) в каталог ${ JWS_HOME}/lib. Помимо этого, нужно модифицировать сценарий startserver в корневом каталоге ${JWS_H0ME}, добавив эти библиотеки в переменную среды miscJars: miscJars=./lib/translator.zip;./lib/runtime.zip:./Iib/classes12.zip • Добавление библиотек Oracle XML Скопируйте записанные библиотеки Oracle XML - ${XML_H0ME}/xmlparserv2.jar и ${XML_HOME}/lib/oraclexmlsql.jar — в каталог ${JWS_HOME}/lib . Кроме того, необходимо модифицировать сценарий startserver в корневом каталоге ${JWS_H0ME}, добавив эти библиотеки в переменную среды miscJars.
Выполнение JSP-программ в JWS В состав JWS входит несколько примеров JSP, которые можно выполнить при помощи браузера. Ссылки на эти примеры размещены на начальной странице JWS, и мы рекомендуем запустить их, прежде чем приступить к работе с собственными JSP-программами. Убедившись в нормальной работе web-сервера, выполните uJWS программу Hello, jsp и приложение Order Online.
Выполнение Hello, jsp Поместите файл Hello, jsp (см. главу 10) в каталог ${JWS_HOME}/examples/jsp/chapter10/Hello. jsp. Теперь можно выполнить JSP, указав в браузере нужный URL, например http://localhost:8080/examples/jsp/chapterl0/Hello.jsp.
Выполнение приложения Order Online Три JSP-файла можно поместить в каталог ${JWS_HOME}/webapps/examples/j sp/chapte г 11/. Скомпилированные классы JavaBean размещаются, как правило, в каталоге ${JWS_HOME}/examples/jsp/beans/classes, который включается в CLASSPATH для JWS. После этого можно вызвать первый экран приложения при помощи соответствующего URL, например http://localhost:8080/ examples / j s p / c h a p t e r 1 1 /EnterOrder.jsp. В качестве альтернативы можно установить прилол<ение Order Online как самостоятельное web-приложение (см. документацию на JSWDK).
Установка и конфигурирование Apache и JServ Apache — популярный web-сервер с открытым программным текстом, распространяемый бесплатно. JServ — двигатель сервлетов, который реализует Servlet 2.0 API и для работы с web-сервером Apache применяет модуль mod_jserv. Apache и JServ используются в Oracle Internet Application Server (iAS) версии 1.0, в состав которого входит еще и двигатель Oracle JSP для исполнения страниц JavaServer Page. В этом разделе рассказывается об установке Apache и JServ, причем предполагается, что отдельные программные модули уже загружены. При использовании Oracle Internet Application Server установка и конфигурирование web-сервера Apache, двигателя сервлетов JServ и Oracle JSP являются частью процесса инсталляции iAS. Рекомендуем применять последний подход.
Этапы установки Рассмотрим этапы установки Apache, JServ и Oracle JSP: 1. Установка JDK. См. процесс установки Tomcat, описанный выше. 2. Установка Apache. Загрузите с сайта Apache (www.apache.org/dist) последнюю версию web-сервера Apache для своей платформы. Выполните программу инсталляции. Предположим, что web-сервер установлен в каталоге ${АРАСНЕ_Н0МЕ}. Отредактируйте файл конфигурации ${АРАСНЕ_.НОМЕ}/со nf/httpd. conf и удалите символ комментариев в строке
455
456 :
ПРИЛОЖЕНИЕ Е
О
ffServerName localhost Это позволит ссылаться на сервер в web-браузере при помощи URL http: / / l o c a l h o s t . 3. Установка JServ и modj s e r v . Загрузите исполнитель сервлетов JServ и модуль mod_jserv с web-сайта Apache (java.apache.org/jserv/dist) и установите их. Надлежащим образом задайте переменную среды ${ JSERV_HOME}. 4. Установка Oracle JSP. См. процесс установки Tomcat, описанный выше. 5. Установка Oracle JDBC и SQLJ. См. процесс установки Tomcat, описанный выше. 6. Установка библиотек Servlet 2.0 и 2.2. Исполнитель сервлетов JServ реализует Servlet 2.0 API, упакованный как библиотека jsdk. jar, которая входит в состав JSDK 2.0 (www.javasoft.com/products/servlet/index.html). Хотя JServ использует только Servlet 2.0, двигателю Oracle JSP 1.1 для своих внутренних операций необходимы библиотеки Servlet 2.2. Загрузите файл servlet . jar с web-сайта www.javasoft.com/servlet/index.htmI, а затем выполните предлагаемые инструкции по настройке.
Этапы конфигурирования 1. Конфигурирование JServ с Apache. Чтобы двигатель сервлетов JServ мог работать вместе с web-сервером Apache, выполните инструкции, приведенные в документации на JServ. 2. Отображение JSP-расширений на сервлет Oracle JSP. Обновите файл ${JSERV_HOME}/conf/jserv. ccnf или файл ${JSERV_HOME}/conf/modJserv. conf (в зависимости от того, какой из них включен в файл $ {АРАСНЕ_Н0МЕ}/ conf/httpd. conf), добавив команды ApJServAction для отображения JSP-расширений: # Отображение ApJServAction ApJServAction ApJServAction ApJServAction
3. Добавление библиотек. Необходимо добавить соответствующие команды wrapper, classpath в файл ${JSERV_HOME}/conf/jserv. properties. Файлы для среды JDK должны уже присутствовать в CLASSPATH. В следующем примере (где используются маршруты каталогов UNIX) подключаются файлы для библиотек Servlet 2.0 и 2.2, Oracle JSP, JDBC, SQLJ и XML: # servlet 2.0 APIs (необходима для Apache/JServ; из Sun JSDK 2.0): wrapper.classpath=${JSDK_HOME}/lib/jsdk.jar tt servlet 2.2 APIs (загружаются в составе Oracle JSP): wrapper.classpath=${OJSP_HOME}/lib/servlet. jar tt Пакеты OracleJSP: wrapper.classpath=${OJSP_HOME^/lib/ojsp.jar wrapper.classpath=${OJSP_HOMEf/lib/ojsputil.jar tt Библиотеки JDBC 2.0 (JDK 1.2) wrapper.classpath=${0RACLE_H0ME}/lib/classes12.zip # SQLJ-транслятор и классы исполняющей системы wrapper.classpath=${ORACLE_HOME}/lib/translator. zip wrapper.classpath=${0RACLE_H0ME}/lib/runtime12.zip tt Библиотеки Oracle XML (применяются для XML/XSL) wrapper.classpath=${XML_H0ME}/lib/xmlparserv2.jar wrapper.classpath=${XML_HOME}]ib/oraclexmlsql. jar
Выполнение JSP-программ в Apache/JServ Apache/JServ — это среда Servlet 2.0, поэтому понятие web-приложения в ней не сформулировано (в отличие от Tomcat, который является реализацией
Установка и конфигурирование web-серверов для работы с Oracle JSP
Servlet 2.2). Однако в JServ принята концепция зон сервлетов. Концептуально зона (zone) сервлетов аналогична их контексту. Страницы Oracle JSP можно настроить так, чтобы они выполнялись в отдельной зоне. Об установке зон сервлетов рассказывается в документации на JServ.
Выполнение Hello, jsp ДЛЯ выполнения Hello, jsp нужно поместить этот JSP-файл в каталог ${APACHE_HOME}/htdocs/examples/jsp/. После этого можно вызывать JSP, указывая нужный URL в браузере, н а п р и м е р URL h t t p : / / l o c a l h o s t : 8 0 8 0 / examples/jsp/Hello.jsp.
Выполнение приложения Order Online Поместите три файла — EnterOrder. jsp, InsertOrder. jsp и QueryOrder. jsp — в каталог ${APACHE_HOME}/htdocs/examples/jsp/OrderOnline. В файле EnterOrder.jsp этого приложения присутствует следующая команда useBean: •
<jsp: useBean id="cartBean" class="mybeans.CartBean" scope="session" /> В файл jserv. properties добавьте запись wrapper. classpath:
•
wrapper.classpath=${APACHE_HOME}/beans/ После этого скомпилируйте класс зерна и поместите его в каталог ${АРАСНЕ_ HOME}/beans/mybeans/. Теперь можно вызывать первую страницу EnterOrder.jsp этого приложения, используя соответствующий URL, например h t t p : / / I o c a l h o s t : 8 0 8 0 / examples/jsp/OrderOnline/EnterOrder.jsp.
Параметры конфигурации Oracle JSP В этом разделе представлены параметры конфигурации Oracle JSP версии 1.1.0.0.0. Двигатель Oracle JSP вызывается как сервлет oracle, jsp. JspServlet, который имеет несколько параметров конфигурации, определяющих его поведение. Эти параметры устанавливаются в качестве инициализационных параметров сервлета oracle.jsp.JspServlet в соответствии с правилами для web-cepeepa и двигателя сервлетов (см. выше этапы конфигурирования web-cepeepa). Список параметров Oracle JSP и их краткое описание приводятся ниже. Некоторые из них имеют отношение только к определенным средам, например к Apache/JServ. Эти параметры указываются отдельно. •
alias_translation Этот параметр специфичен для Apache/Jserv. On содержит логическое значение, которое позволяет Oracle JSP обходить ограничения, налагаемые на способ обработки псевдонимов каталогов в Apache/JServ. Например, в файле ${APACHE_HOME}/conf/httpd. conf можно указать следующую команду, назначающую псевдоним каталогу:
•
alias /images/ "/home/apache/images/" Для того чтобы система Oracle JSP правильно обрабатывала ссылки на подобные маршруты с псевдонимами, необходимо установить параметр конфигурации alias_translation в значение true. По умолчанию значением этого параметра является false.
•
bypass_source Этот параметр имеет логическое значение и определяет, будет ли Oracle JSP проверять наличие исходного jsp-файла. Такой режим удобен, когда разработчик хочет внедрить только скомпилированные JSP-классы, а не JSP-источник. При установке этого параметра в значение true двигатель Oracle JSP
457
458
—:
ПРИЛОЖЕНИЕ Е
О
будет загружать и исполнять скомпилированный JSP-класс, даже если исходный JSP-файл отсутствует. Если источник доступен, его временная метка будет проверяться для определения, нужна ли трансляция (при условии, что параметр developerjnode (см. ниже) установлен в true). По умолчанию значением этого параметра является f alse. •
classpath Этот параметр служит для добавления записей в CLASSPATH, используемый по умолчанию Oracle JSP. Двигатель Oracle JSP загружает классы из своего собственного CLASSPATH (включая записи из данного параметра CLASSPATH), CLASSPATH системы, CLASSPATH web-сервера, из репозитория страниц и из других областей, относительных для корневых каталогов JSP-приложения. Отметим, что классы, указанные этим параметром, загружаются средством загрузки JSP-классов, а не загрузчиком классов системы (JDK). Смысл добавления записи двояк: • Эти классы (загружаемые средством загрузки JSP-классов) не могут ссылаться па классы, загружаемые системным или другими загрузчиками классов, и наоборот. • После модификации jar-файла в этом CIASSPATH в Oracle JSP выполняется автоматическая перезагрузка классов. По умолчанию значением данного параметра является null.
•
developerjnode Этот параметр имеет логическое значение и определяет, нужно ли сопоставлять временную метку исходного JSP-файла с метками компилируемых файлов JSP-классов при вызове JSP-страницы. Если значением флага является false, Oracle JS1' не проверяет временную метку, что ускоряет обработку JSP-запросов. Поэтому, если JSP-страницы не меняются, например в среде внедрения, устанавливайте флаг в значение false. В этом случае Oracle JSP будет проверять временные метки только первого запроса страницы и в последующих вызовах будет по-новому исполня ть скомпилированный JSP-класс. По умолчанию значением параметра является true.
•
emit jJebuginfo Этот параметр имеет логическое значение и используется для указания транслятору Oracle JSP на необходимость генерации карты строк исходного JSP-файла для отладки. Параметр разрешается для отладки JSP-программ уровня источника в JDeveloper. По умолчанию значением этого параметра является false.
•
external_resource Этот параметр с логическим значением управляет программным текстом, генерируемым транслятором Oracle JSP. Если значением этого флага является true, статическое содержимое JSP-страницы (т.е. HTML- или XML-текст) помещается в файл ресурса Java, а не в метод _jspService() генерируемого JSP-класса. Имя этого файла устанавливается по имени JSP-файла, но имеет расширение . res. Файл ресурса помещается в тот же каталог, что и файлы классов. Использование подобных файлов внешних ресурсов ускоряет трансляцию и исполнение JSP, особенно при наличии большого объема статического программного текста. Кроме того, это иногда помогает избежать превышения методом _jspService() размера в 64 Кбайт, что является ограничением Java. По умолчанию значение параметра — false.
•
javaccrnd Этот параметр указывает команду для компиляции класса Java, генерируемого для JSP. Он полезен при использовании компилятора, отличного от стандартного javac из JDK (э тот компилятор применяется в Oracle JSP по умолчанию), или при указании для javac таких параметров командной строки, как:
Установка и конфигурирование web-серверов для работы с Oracle JSP
О
javac -vernose -О Использование этого параметра обязывает Oracle JSP вызывать не стандартный компилятор в той же виртуальной машине Java, где исполняется Oracle JSP, а другой компилятор в отдельном процессе. Для исполняемой программы компилятора можно указывать полностью определенный или неопределенный путь; в последнем случае Oracle JSP ищет исполняемую программу по системному маршруту. По умолчанию этот параметр не устанавливается.
•
page_repository_root Этот параметр указывает полностью определенный корневой каталог для JSP-страниц. По умолчанию корневым каталогом является корневой каталог документов среды web-сервера Apache/JServ, а в средах Servlet 2.1 и 2.2 это корень контекстов сервлетов приложения, которому принадлежит JSP-страница. Параметр используется для указания другого корневого каталога. JSP-страницы должны находиться в этом корневом каталоге или в каком-либо подкаталоге. По умолчанию этот параметр не устанавливается.
•
session_sharing Этот параметр специфичен для Apache/JServ. Он действует при использовании файла globals. jsa в качестве маркера приложения в средах Servlet 2.0, подобных Apache/JServ (см. документацию на Oracle JSP). Если параметр установлен в значение true (значение по умолчанию), для каждого вызоваJSP двигатель Oracle JSP создает объект-оболочку для объекта session сервлетов, предоставляемого двигателем сервлетов. В этом случае данные JSP-сеанса (например, значение, связываемое cJSP-сеансом методом session. putValue()) передаются базовому сеансу сервлетов. Это позволяет JSP-программам одного приложения совместно пользоваться данными сеансов. Если же значением параметра session_sharing является false, данные JSP-сеанса не передаются сеансу сервлетов, и сервлеты не могут к ним обращаться. Этот параметр не действует, если файл globals. j sa не применяется для JSP-приложения.
•
sqljcmd Этот параметр определяет команду для вызова SQLJ-транслятора. Он полезен при использовании SQLJ-транслятора, отличного от стандартного, или при указании параметров командной строки SQLJ, например, для проверки семантики: sqljcmd= sqlj -ser2class -user scott -password tiger Кроме того, в некоторых средах (JDK 1.1) при использовании этого параметра сообщения об ошибках становятся более информативными. Oracle JSP вызывает SQLJ-транслятор не в той же самой виртуальной машине Java, а в отдельном процессе (т.е. в отдельной виртуальной машине Java). Можно указать для исполняемой программы SQLJ полностью определенный пугь либо разрешить ее обнаружение по системному маршругу. По умолчанию этот параметр не устанавливается.
•
translate_params Этот параметр с логическим значением определяет кодировку многобайтовых (NLS) параметров в HTTP-объекте request. В большинстве двигателей сервлетов NLS-кодировка параметров запроса не учитывается, поэтому верную кодировку во время трансляции должен обеспечивать JSP- программист. Если параметр установлен в значение true, данная задача автоматически решается двигателем Oracle JSP, т.е. он транслирует параметры HTTP-запроса и установки свойств зерен при помощи кодировки HTTP-объекта request. По умолчанию значением параметра является false, при этом Oracle JSP возвращает параметры HTTP-запроса в точности такими, какими они были получены от базового двигателя сервлетов (без какой бы то ни было дополнительной NLS-обработки).
459
460 :
ПРИЛОЖЕНИЕ Е
О
•
unsafe_reload Этот параметр определяет поведение двигателя Oracle JSP, когда JSPстраница автоматически меняется в процессе работы JSP-приложения. В этом случае стандартным режимом работы двигателя Oracle JSP является перезапуск приложения и сеансов сервлетов, что делает существующие сеансы недействительными. Такой режим не всегда желателен. Если установить параметр в значение true, Oracle JSP не будет перезапускать приложение после динамической трансляции JSP-страниц. Это защищает существующие сеансы и не позволяет делать их недостоверными. Заметим, однако, что данный режим небезопасен тем, что внесение в JSP-класс некорректных изменений может привести к установлению в классе исключительных ситуаций и к другим овшбкам этапа исполнения. Таким образом, этот параметр следует применять только в режиме разработки программ, но не в средах внедрения. По умолчанию значением параметра является false. За дополнительными сведениями о параметрах конфигурации Oracle JSP обращайтесь к руководству "OracleJSP Developer's Guide and Reference, Release 8.1.7" корпорации Oracle.
ПРИЛОЖЕНИЕ F
О
Инструментальные средства ОгасШ EJB и CORBA и поддержкаJSP в JDeveloper
462
ПРИЛОЖЕНИЕ F
О
Э
^ ^ т о приложение состоит из двух частей: инструментальные средства Огас1е8г EJB и CORBA и поддержка JSP в JDeveloper. Инструментальные средства для EJB и CORBA рассматриваются вместе потому, что их наборы во многом совпадают.
Инструментальные средства Огас1е8/ EJB и CORBA Это часть состоит из трех разделов: • Инструментальные средства Огас1е8г, используемые для EJB • Инструментальные средства Огас1е8г, используемые как для EJB, так и для CORBA • Инструментальные средства Огас1е8г, используемые для CORBA
Инструментальные с р е д с т в а Огас1е8/, используемые для EJB В этом разделе описываются: • deployejb • ejbdescriptor
deployejb Инструментальное средство dep oyejb готовит компонент EJB к использованию его клиентами. Оно работает с дескриптором внедрения зерна и с j a r - ф а й л о м , содержащим интерфейсы, классы и подчиненные им классы EJB. Инструмент превращает создаваемый для зерна файл дескриптора внедрения в сериализованный объект Java, а также генерирует и компилирует классы, обеспечивающие связь между клиентами и опубликованными объектами. Напомним, что для публикации объектов в базе данных нужно иметь специальные системные привилегии Oracle. Скорее всего, эту задачу будет выполнять администратор базы данных Oracle. Отличным примером использования этого инструмента является шаг 9, описанный в разделе "Создание первого Enterprise JavaBean" главы 3. В Oracle версии 8.1.7 инструмент deployejb принимает дескриптор внедрения XML, требуемый новой спецификацией EJB 1.1. Синтаксис инструмента deplovejb: •
Инструментальные с р е д с т в а Oracle8i EJB и CORBA и п о д д е р ж к а JSP в JDeveloper
Аргументы deployejb описаны и таблице F.1 ("Огас1е8 i Enterprise JavaBeans and CORBA,Developer's Guide, Release 8.1.5" [52, стр. 6-37 - 6-38, таблица 6-18]). Таблица F.1. Краткие сведения
об аргументах
deployejb
Аргумент
Описание и значения
-user
Указывает схему, в которую будут загружены EJB-классы.
-password
Указывает пароль для <username>.
-service
URL, идентифицирующий базу данных, в пространстве имен сеансов которой нужно опубликовать EJB. serviceURL имеет вид: sess_iiop://::<sid> — компьютер, на котором расположена целевая база данных; < l p o r f > — порт прослушивающего процесса, настроенный для прослушивания сеансового ПОР; <sid> — идентификатор экземпляра базы данных. Пример: sess_iiop://localhost:2481:ORCL что соответствует установке по умолчанию на машине вызывающего.
-descriptor
Указывает текстовый файл, содержащий дескриптор внедрения EJB.
-temp
Задает временный каталог для хранения промежуточных файлов, создаваемых утилитой deployejb. Если не указан -keep, d e p l o y e j b по завершении работы удаляет файлы и каталог.
Указывает имя jar-файла, содержащего интерфейс и классы реализации зерна.
-addclasspath
Указывает каталоги, в которых находятся интерфейс и/или зависящие от реализации классы, не содержащиеся в . Формат < d i r l i s t > такой же, что и у аргумента c l a s s p a t h программы javac. Обязателен для -beanonly.
-beanonly
Пропускает этап генерации файлов интерфейсов. Полезен при изменении только реализации зерна.
-describe
Кратко описывает действие инструмента, а затем осуществляет выход из программы.
-generated
Задает имя выходного (генерируемого) jar-файла, в котором содержатся коммуникационные файлы, необходимые клиенту. Если не указан, именем выходного jar-файла становится имя входного jar-файла с добавлением -generaLed.
-help
Кратко описывает синтаксис инструмента, а затем осуществляет выход из программы.
-iiop
Устанавливает соединение с целевой базой данных с помощью ПОР вместо заданного по умолчанию сеансового НОР. Используется при внедрении на сервере базы данных, сконфигурированном без сеансового ПОР.
-keep
Сохраняет временные файлы, генерируемые инструментом. Может быть полезен при отладке, поскольку обеспечивает доступ к исходным файлам, генерируемым утилитой deployejb.
-republish
Заменяет опубликованные атрибуты BeanHomeName, если BeanHomeName уже опубликовано; в противном случае публикует его.
-role
Указывает роль, принимаемую при подключении к базе данных; значения по умолчанию нет.
-ssl
Устанавливает соединение с базой данных посредством аутентификации и шифрования SSL.
-verbose
Выдает сообщения с подробным описанием состояния во время работы.
-version
Показывает версию инструмента, а затем осуществляет выход из программы.
463
464 :
ПРИЛОЖЕНИЕ Е
О
ejbdescriptor Инструментальное средство ejbdescriptor позволяет разработчику преобразовывать читаемый формат ASCII (. t x t ) файла дескриптора внедрения в нечитаемый ( . e j b ) . Синтаксис команды: •
ejbdescriptor {-parse | -dump} Параметр -parse используется для создания сериализованного выходного файла дескриптора внедрения из входного :
•
ejbdescriptor -parse My8iEJB.txt My8iEJB.ejb Параметр -dump служит для создания текстового файла из сериализованного дескриптора внедрения:
•
ejbdescriptor -dump My8iEJB.ejb My8iEJB.txt В Oracle версии 8.1.7 инструмент ejbdescriptor преобразует собственный текстовый дескрип тор Oracle, совместимый с предыдущими версиями Огас1е8г, в XML-дескриптор, предписанный к применению спецификацией EJB 1.1.
Инструментальные с р е д с т в а Огас1е8/, используемые к а к для EJB, так и для CORBA В этом разделе описываются: •
sqlj
• dropjava •
remove
•
sess_sh
sqlj Огас1е-инструмент s q l j используется для преобразования исходного программного текста SQLJ и для вызова компилятора Java. Синтаксис, применяемый для исполнения s q l j из командной строки: •
sqlj file_list option_list — список значений параметров SQLJ, разделенных пробелами. f i l e _ l i s t — список файлов . s q l j , .java, .ser или . j a r , разделенных пробелами. В именах файлов можно указывать трафаретный символ *. SQLJ-параметры описаны в таблице F.2 ("Огас1е8 г SQLJ Programming" [37, стр. 520 — 521]). Таблица F.2. Список