Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Ajax в действии

.pdf
Скачиваний:
95
Добавлен:
01.05.2014
Размер:
6.34 Mб
Скачать

Глава 11. Улучшенный Web-портал Ajax 451

Листинг 11.5. Правила CSS регистрационной формы

<style type="text/css">

<! — О Элементы html и body —>

h t m l ,

body{ m a r g i n : Opx; padding:Орх;

 

 

height:100%;

}

< ! — © Определить стиль элемента заголовка -->

#header{

b a c k g r o u n d - c o l o r :

#C0C0C0;

 

 

h e i g h t :

ЮОрх;

 

 

b o r d e r - b o t t o m : lpx

s o l i d b l a c k ;

 

f o n t - w e i g h t : b o l d ; J

 

< ! — © Разместить элемент span регистрационной формы —> #login { t e x t - a l i g n : r i g h t ; f l o a t : r i g h t ;

m a r g i n - t o p : 1 5 p x ;

m a r g i n - r i g h t : 1 5 p x ; )

< ! - - О Отформатировать текст заголовка -->

#sloganText{ f o n t - s i z e : 25px;

 

m a r g i n - l e f t :

15px;

l i n e - h e i g h t :

ЮОрх; }

< / s t y l e >

 

Вначале мы удаляем все поля или заполнения из тела О документа. Высоту (свойство height) мы задаем равной 100%. Важно отметить, что нам необходимо задать данные свойства в дескрипторах HTML И body, поскольку различные браузеры получают данную информацию из одного из указанных дескрипторов.

Разрабатывая стилевое оформление заголовка ©, мы можем задать цвет фона элемента div. Кроме того, можно установить высоту и добавить границу кнопки, чтобы отделить заголовок от содержимого. Помимо этого, можно изменить свойства шрифтов, которые мы посчитаем нужными.

Мы принимаем регистрационную информацию © и перемещаем ее в правую сторону экрана. Для этого используется свойство float со значением right. Для выравнивания текстовых блоков применяется свойство textalign, поэтому содержимое элемента span также выравнивается по правому полю. Благодаря этому текстовые окна выглядят более унифицировано. В противном случае они не были бы выровнены правильно, поскольку имя строки короче, чем пароль. Кроме того, для выравнивания положения регистрационной информации можно добавить поля, чтобы правый край соответствующего окна не примыкал непосредственно к границе элемента div заголовка.

В заключение необходимо определить стиль текста заголовка О. Задавая высоту строки (свойство lineheight) равной высоте элемента div, мы позволяем центрировать текст заголовка вертикально. Кроме того, свойства шрифта задаются так, чтобы текст был заметен. Далее мы добавили поле, поэтому первая буква в слове Ajax не выровнена по краю заголовка. После применения правил CSS к заголовку можно записать документ и посмотреть, как таблицы CSS изменили его внешний вид (рис 11.8).

Рис. 11.8. Страница регистрации портала Ajax с разработанной таблицей стилей

На рисунке видно, что текстовые окна выровнены по правому краю, а текст заголовка — по левому. Таким образом, мы взяли стандартную HTMLструктуру и создали привлекательную шапку страницы регистрации, не использовав при этом ни одной таблицы. Разработав стилевое оформление заголовка, можно добавить к форме ряд функциональных возможностей. Например, нам нужны возможности JavaScript, чтобы мы могли передать запрос на сервер, не отправляя всю страницу.

Код регистрации (JavaScript)

Написав код регистрации JavaScript, мы, используя возможности Ajax, сможем передавать имя пользователя и пароль на сервер, не отправляя при этом всю страницу. Для этого потребуется обратиться к внешнему файлу JavaScript net . js, содержащему объект ContentLoader, чтобы мы могли задействовать Ajax для отправки и извлечения запроса.

<script type="text/javascript" src="net.js"x/script>

Файл ContentLoader выполняет все действия, связанные с отправкой ин-3 формации на сервер, сокрытием кода, зависящего от конкретного браузера, за удобным интерфейсным объектом, введенным в главе 3. Итак, обратив- ' шись к файлу net . js, мы можем выполнить запрос. Этот запрос инициируется щелчком на кнопке в нашей форме регистрации. Сама форма при этом должна выполнить три действия: во-первых, сообщить пользователю, что его запрос обрабатывается; во-вторых, собрать информацию и, в-третьих, отправить запрос на сервер (листинг 11.6).

Листинг 11.6. Запрос регистрации XMLHttpRequest

function LoginReguest(){ document.getElementById("spanProcessing").innerHTML =

" Verifying Credentials"; var url = 'portalLogin.servlet';

var strName = document.Forml.username.value; var strPass = document.Forml.password.value;

var strParams = "user="+strName + "&pass=" + strPass var loaderl = new net.ContentLoader(

url,CreateScript,null,"POST",strParams);

_ J

-

Рис. 11.9. Сообщение об ошибке, вызванное предоставлением неверных сведений

Прежде чем отправлять информацию на сервер, необходимо отобразить для пользователя сообщение о том, что щелчок на кнопке позволяет ему войти в систему. Благодаря этому пользователь не будет повторно щелкать на кнопке, думая, что ничего не происходит.

Итак, мы получаем поля имени пользователя и пароля и помещаем их в строку, отправляемую на сервер. Значения отправляются на сервер с помощью объекта ContentLoader, принимающего в качестве параметров URL, функцию, вызываемую при удачном завершении действия, функцию, вызываемую в случае ошибки, действие формы POST, а также строку, содержащую отправляемые параметры. Рассмотрим подробнее функцию, вызываемую при успешном возврате данных с сервера и обрабатывающую эти данные: CreateScript{).

function CreateScript() {

strText - this.req.responseText; eval(strText);

}

При создании серверной части сценария мы возвращали текстовые строки, содержащие выражения JavaScript в свойстве responseText возвращаемого объекта. Чтобы эффективно использовать выражения JavaScript, их необходимо обработать с помощью метода eval (), точно определяющего, что содержит строка, и выполняющего указанные в ней действия. В данном случае строка либо будет содержать сообщение об ошибке, сгенерированное при сбое LoginFilter, либо код создания окна, если фильтр пропускает данные к SelectServlet (листинг 11.8).

Из чего состоит строка? В данном приложении мы не собираемся возвращать в ответ на запрос XML-документ, как мы поступали во многих других примерах. Вместо этого мы вернем структурированные выражения JavaScript, которые смогут использовать метод eval(). Используя термины, сформулированные в главе 5, можно сказать, что наше решение ориентировано скорее на сценарий, чем на данные. Как и ранее, мы приняли данный подход только ради разнообразия. В качестве среды передачи при разработке кода портала можно использовать XML или JSON.

Теперь можно сохранить портал и запустить его, чтобы посмотреть, как работает процедура регистрации. Как видно на рис. 11.9, в поля были введены неверное имя пользователя и пароль.

Ниже кнопки "login" на рис. 11.9 отображено сообщение об ошибке, информирующее пользователя, что предоставленные им данные неверны.

Если, с другой стороны, регистрация прошла успешно, запрос перенаправляется на основную страницу портала. В этом случае следующим шагом является создание окон. Чтобы получить намеченный богатый пользовательский интерфейс, нам придется разработать довольно много кода DHTML, но на самом деле эта тяжелая работа уже выполнена, поскольку мы используем готовую DHTML-библиотеку JavaScript.

11.4. Реализация окон DHTML

Наш портал Ajax имеет богатый пользовательский интерфейс, позволяющий пользователю динамически размещать окна. Кроме того, пользователь может устанавливать размер окна (желательную ширину и высоту). При изменении указанных настроек мы можем с помощью Ajax реализовать взаимодействие с сервером и записать новые значения в собственной базе данных (причем пользователь даже не будет знать об этом). Чтобы разрешить подобное поведение, требуется разработать таблицу базы данных, в которой будут храниться свойства окна — высота, ширина и положение. Код серверной части сценария должен получать данные значения и соответствующим образом обновлять величины в базе данных. Написание DHTML-кода, совместимого с основными браузерами, может оказаться сложным, поэтому для реализации перетаскивания и изменения размеров окна мы используем сценарий библиотеки DHTML. Данная библиотека, JSWindow. js, представляет собой внешний файл JavaScript, содержащий код всех требуемых нам функций . (Эту библиотеку можно найти на Web-сайте данной книги.) Чтобы активизировать инфраструктуру Ajax, нам потребуется лишь незначительно изменить код данной библиотеки.

11.4.1. База данных окон портала

Нам нужна таблица базы данных, способная содержать свойства нескольких окон DHTML для каждого пользователя. Каждый пользователь может иметь несколько строк в данной таблице — по одной на каждое окно портала. Таблица применяется для извлечения последнего запомненного положения и размера окна при первом входе пользователя в систему. Когда пользователь что-то меняет, значения обновляются, чтобы при следующем посещении окна располагаться точно так же. Для создания таблицы portal_windows используется следующий SQL-код:

create table portal_windows(

id int primary key not null, user_id int not null, xPos int not null, yPos int not null,

width int not null, height int not null,

url varchar(255) not null, title varchar(255) not null

);

Рис. 11.10. Структура таблицы p o r t a l _ w i n d o w s

Каждый пользователь может иметь несколько окон с различными настройками. Эта проблема решается следующим образом. Столбец user_id связан с базой данных пользователей. Каждое окно должно иметь идентификатор и первичный ключ, которые можно использовать для хранения и обновления свойств. Не забудьте добавить к столбцу идентификатора окна автоматический инкремент. Данный идентифицирующий столбец используется кодом Ajax и библиотекой окон DHTML для получения и обновления СВОЙСТЕ окон, определенных пользователем.

Для хранения координат х и у нашего окна DHTML потребуются два столбца. Данная информация определяет положение окна на экране относительно левого верхнего окна браузера. Данные столбцы, содержащие координаты, обозначаются xPos и yPos. Кроме того, нужны еще два свойстве окна DHTML: ширина и высота. Они хранятся в таблице как целочисленные величины.

Последние два столбца базы данных определяют URL содержимого окна, а также заголовок содержимого, присвоенный пользователем для быстрого доступа. Все свойства, фигурирующие в таблице portal_windows базы данных, показаны на рис 11.10.

Далее требуется ввести определенные значения, заданные по умолчанию, и выполнить тестирование. В таблицу users мы можем добавлять любое число пользователей. Как показано на рис. 11.10, для пользователя 1 мы добавили три окна DHTML.

На рис. 11.11 показано, как три параметра окна DHTML предоставляю! информацию, требуемую для создания трех окон на экране, имеющих различные размеры и положения. В данном случае в трех окнах отображаются тр* Web-сайта: JavaRanch, Google и Eric's Ajax Blog. Создав таблицу базы данных, мы можем предоставлять указанную информацию пользователю прр его входе на портал. Насколько это просто, вы узнаете в следующем разделе

11.4.2. Серверный код окна портала

Предположим, что запрос регистрации прошел через фильтр безопасности Следующий этап — извлечение списка окон портала для аутентифицированного пользователя и возврат JavaScript-кода, сообщающего браузеру, чтс

Рис. 11.11. Данные, введенные для пользователя с идентификатором 1

нужно отображать на экране. В связи с этим мы определяем объект PortalWindow, представляющий строку информации в базе данных, как показано в листинге 11.7.

Листинг 11.7. PortalWindow.java public class PortalWindow { private int id=-l;

private User user=null; private int xPos=0; private int yPos=0; private int width=0; private int height=0; private String url=null; private String title=null;

public PortalWindow(

int id. User user, int xPos, int yPos, int width,int height,

String url, String title

) {

this.id = id; this.user = user; this.xPos = xPos; this.yPos = yPos; this.width = width; this.height = height; this.url = url; this.title = title;

}

public int getHeight() {return height;}

public void setHeight(int height) {this.height » height;} public int getld() {return id;}

public void setld(int id) {this.id = id;} public String getTitle() {return title;}

public void setTitle(String title) {this.title = title;} public String getUrl() {return url;}

public void setUrlfString url) {this.url = url;} public User getUser() {return user;}

public void setUser(User user) {this.user = user;} public int getWidth() {return width;}

public void setWidth(int width) {this.width • width;} public int getXPos() {return xPos;}

public void setXPos(int pos) {xPos = pos;J public int getYPos() {return yPos;}

public void setYPos(int pos) {yPos = pos;}

}

Как и прежде, объект представляет собой достаточно прямолинейное отображение структуры базы данных. В реальной задаче мы, возможно, использовали бы для облечения жизни ORM-систему, например Hibernate или iBATIS, но сейчас нам требуется, чтобы все было довольно простым и платформенно-независимым. Обратите внимание на то, что мы предоставляем для этого объекта как методы установки, так и методы получения, поскольку нам нужно, чтобы объекты обновлялись динамически в ответ на события на стороне клиента. Запрошенный при регистрации URL, portalLogin,servlet, отображается в сервлет, извлекающий все окна портала для этого пользователя и возвращающий в ответ указания JavaScript. Основной сервлет показан в листинге 11.8.

Листинг11.8.СервлетSelectServlet.Java

public class SelectServlet extends HttpServlet { protected void doPost(

HttpServletRequest request, HttpServletResponse response

) throws ServletException, IOException { HttpSession session=request.getSession(); User user={User)

// О Проверить сеанс (session.getAttributef"user"));

StringBuffer jsBuf=new StringBuffer(); if (user==null){

jsBuf.append(JSUtil.logout()) ; }else{

List windows=DBUtil // 0 Определить объект

.getPortalWindows(user); // в Использовать объект JSUtil

j sBuf.append(JSUtil.initUI() );

for (Iterator iter=windows.iterator();iter.hasNext();) PortalWindow window=(PortalWindow)(iter.next()); session.setAttribute("window_"+window.getld(),window) jsBuf.append

// О Объявить окно портала

(JSUtil.initWindow(window));

}

J

Writer writer=response.getWriter(); // 0 Записать в выходной поток.

writer.write(j sBuf.toString()); writer.flush();

> }

.

J

 

 

 

 

 

458 Часть IV. Ajax в примерах

Здесь мы снова используем объект DBUtil для абстрагирования взаимодействий с базой данных и JSUtil — для генерации кода JavaScript. DBUtil предоставляет метод getPortalWindows () ©, принимающий в качестве аргумента объект User. Один из таких объектов фигурировал в информации о сеансе, поэтому теперь мы его извлекаем О. Фактический код JavaScript генерируется (как и ранее) объектом JSUtil. создающим код инициализации пользовательского интерфейса ©, объявляющим окна портала, извлеченные из базы данных О. и записывающим их непосредственно в выходной поток сервлета 0.

Напомним коротко, что представляют собой вспомогательные объекты которые мы постоянно используем, — DBUtil и JSUtil. Объект DBUtil используется для получения списка окон портала. Как отмечалось выше, в реальной задаче этот процесс было бы неплохо автоматизировать, используя Hibernate или похожую систему; но с обучающей целью мы используем приведенный в листинге 11.9 метод объекта DBUtil, являющийся реализацией доступа к таблице portal_windows в базе данных. В данном случае применяется прямолинейный код SQL, но представленный принцип легко перенести на любой удобный для вас язык.

Листинг 11.9. Метод getPortalWindows О.

-

public static List getPortalWmdows (User user){

 

 

List list=new ArrayList();

 

 

Connection conn=getConnection();

 

 

try{

 

 

String sql="SELECT * FROM portal_windows " +"WHERE user_id="+user.getld();

//О Построить выражение SQL

 

 

 

S t a t e m e n t s t m t = c o n n . c r e a t e S t a t e m e n t ( ) ;

 

 

 

R e s u l t S e t r s = s t m t . e x e c u t e Q u e r y ( s q l ) ;

 

 

 

PortalWindow

w i n = n u l l ;

 

 

 

w h i l e ( r s . n e x t ( ) ) {

//

@

Последовательно пройти результаты

 

 

 

i n t i d = r s . g e t l n t ( " i d " ) ;

 

 

 

i n t x = r s . g e t l n t ( " x P o s " ) ;

 

 

 

i n t y = r s . g e t l n t ( " y P o s " ) ;

 

 

 

i n t w = r s . g e t l n t ( " w i d t h " ) ;

 

 

 

i n t h = r s . g e t l n t ( " h e i g h t " ) ;

 

 

 

S t r i n g u r l = r s . g e t S t r i n g ( " u r l " ) ;

 

 

 

S t r i n g t i t l e - r s . g e t S t r i n g ( " t i t l e " ) ;

 

 

 

win=new

PortalWindow(

//

©

Добавить объект

 

 

 

 

i d , u s e r , x , y , w , h , u r l , t i t l e ) ;

 

 

 

l i s t . a d d ( w i n ) ; }

 

 

r s . c l o s e ( ) ;

 

 

 

s t r a t . c l o s e ( ) ;

 

 

 

}catch

(SQLException

s q l e x ) {

 

 

}

 

 

 

r e t u r n

l i s t ;

 

}

Глава 11. Улучшенный Web-портал Ajax 459

Итак, мы формируем выражение SQL О, последовательно проходим по сгенерированному этим выражением набору результатов © и во всех случаях добавляем к нашему списку объект PortalWindow ©.

Далее мы используем вспомогательный объект JSUtil, генерируем код инициализации и объявляем объекты окна на JavaScript. Соответствующие методы по сути представляют собой упражнения по конкатенации строк, поэтому мы не будем приводить здесь класс целиком. Принцип его действия демонстрируется в приведенном ниже коде.

public static String initwindow(PortalWindow window) { StringBuEfer jsBuf=new StringBuffer{)

.append("CreateWindow{new NewWin('")

.append(window.getId())

.append("',")

,append(window.getXPos())

.append(",")

.append(window.getYPos())

.append(",")

.append(window.getWidth())

.append(",")

.append(window.getHeight())

.append(",'")

.append(window.getUrK))

.append("','")

.append(window.getTitle{))

. a p p e n d ^ " ) ) ; (BBSS)n11); return j s B u f . t o S t r i n g ( ) ;

}

Метод initwindow () генерирует код JavaScript для инициализации одного окна портала. Код JavaScript успешного запроса может выглядеть приблизительно так, как показано ниже: для всех окон последовательно вызывается функция initwindow () (для улучшения читаемости код был соответствующим образом отформатирован):

document.getElementByld('login' )

.innerHTML='Welcome back!' document.getElementByld('defaultConten')

.style.display=tquotenonetquote;

CreateWindow( new NewWin(

tquoteltquote,612,115,615,260,

tquotehttp://www.j avaranch.comtquote,tquoteJavaRanchtquote

)

);

CreateWindow( new NewWin(

tquote2tquote,10,115,583,260,

tquotehttp://www.google.comtquote,tquoteGoogletquote

)

>;

CreateWindow(

new NewWin(

460 Часть IV. Ajaxв примерах

tquote3tquote,10,387,1220,300, tquotehttp://radio.j avaranch.com/pascarellotquote, tquoteAjax Blog!tquote

)

>;

Поскольку мы уже вошли в систему, текстовое окно регистрации и кнопку "Отправить" можно убирать; вместо них отображается приветственное сообщение. Чтобы разместить это сообщение, необходимо будет скрыть содержимое, по умолчанию располагающееся на экране. Для этого свойство display элемента DOM defaultContent устанавливается равным попе, поэтому оно убирается из поля зрения пользователя.

Обрабатывающий окно оператор JavaScript состоит из двух частей. Первая часть представляет собой вызов функции CreateWindow(), являющейся частью добавленной нами библиотеки JavaScript. В вызове функции мы вызовем новый конструктор объекта. Конструктор создает класс окна, облегчающий обращение к свойствам окна. Функция JavaScript, создающая класс окна, должна получить параметры OKHaid, width, height, xPos, yPos, url и t i t l e . Когда сервлет возвратит эту строку клиенту, метод JavaScript eval () выполнит ее.

Как правило, мы придерживаемся договоренностей относительно генерации кода, дающих простой, повторяемый код, вызывающий функции нашей библиотеки JavaScript. Код инициализации можно поместить в один вызов, привязав его к клиенту, но реализовать данную возможность мы предоставляем читателю в качестве самостоятельного упражнения.

Использованная нами библиотека JavaScript создает плавающие окна JavaScript. Давайте посмотрим, как сделать эти функции создания окон доступными на стороне клиента.

11.4.3. Добавление внешней библиотеки JavaScript

Как отмечалось ранее, мы используем библиотеку DHTML, которую можно загрузить с Web-сайта www.manning.com. Файл JSWindow. js содержит все методы DOM JavaScript, необходимые для создания элементов окон. Кроме того, библиотека применяет обработчики событий к объектам окон, так что мы можем использовать возможности перетаскивания. Готовые библиотеки кода удобны тем, что позволяют сокращать время разработки и обычно работают во всех браузерах.

Первым делом требуется переименовать файл, чтобы мы могли модифицировать его. Запишем файл JavaScript под именем A j axWindow. j s в рабочей папке.

Чтобы использовать функции, содержащиеся в AjaxWindow. js, необходимо сослаться на внешний файл JavaScript посредством дескриптора script. В дескрипторе JavaScript element мы используем атрибут src. Элемент script, связывающийся с требуемым файлом . js, необходимо включить в заголовок нашей HTML-страницы.

<script type="text/javascript" src="AjaxWindow.js"X/script>